]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_MPU_M23_Nuvoton_NuMaker_PFM_M2351_IAR_GCC/Nuvoton_Code/StdDriver/src/i2s.c
Add Cortex M23 GCC and IAR ports. Add demo projects for Nuvoton NuMaker-PFM-2351.
[freertos] / FreeRTOS / Demo / CORTEX_MPU_M23_Nuvoton_NuMaker_PFM_M2351_IAR_GCC / Nuvoton_Code / StdDriver / src / i2s.c
1 /**************************************************************************//**\r
2  * @file     i2s.c\r
3  * @version  V3.00\r
4  * @brief    M2351 series I2S driver source file\r
5  *\r
6  * @copyright (C) 2016 Nuvoton Technology Corp. All rights reserved.\r
7 *****************************************************************************/\r
8 \r
9 #include <stdio.h>\r
10 #include "NuMicro.h"\r
11 \r
12 /** @addtogroup Standard_Driver Standard Driver\r
13   @{\r
14 */\r
15 \r
16 /** @addtogroup I2S_Driver I2S Driver\r
17   @{\r
18 */\r
19 \r
20 /** @addtogroup I2S_EXPORTED_FUNCTIONS I2S Exported Functions\r
21   @{\r
22 */\r
23 \r
24 static uint32_t I2S_GetSourceClockFreq(I2S_T *i2s);\r
25 \r
26 /**\r
27   * @brief  This function is used to get I2S source clock frequency.\r
28   * @param[in]  i2s The base address of I2S module.\r
29   * @return I2S source clock frequency (Hz).\r
30   * @details Return the source clock frequency according to the setting of I2S0_SEL (CLK_CLKSEL3[17:16]).\r
31   */\r
32 static uint32_t I2S_GetSourceClockFreq(I2S_T *i2s)\r
33 {\r
34     uint32_t u32Freq, u32ClkSrcSel;\r
35 \r
36     u32ClkSrcSel = CLK_GetModuleClockSource(I2S0_MODULE) << CLK_CLKSEL3_I2S0SEL_Pos;\r
37 \r
38     switch(u32ClkSrcSel)\r
39     {\r
40         case CLK_CLKSEL3_I2S0SEL_HXT:\r
41             u32Freq = __HXT;\r
42             break;\r
43 \r
44         case CLK_CLKSEL3_I2S0SEL_PLL:\r
45             u32Freq = CLK_GetPLLClockFreq();\r
46             break;\r
47 \r
48         case CLK_CLKSEL3_I2S0SEL_HIRC:\r
49             u32Freq = __HIRC;\r
50             break;\r
51 \r
52         case CLK_CLKSEL3_I2S0SEL_PCLK0:\r
53             u32Freq = CLK_GetPCLK0Freq();\r
54             break;\r
55 \r
56         default:\r
57             u32Freq = __HXT;\r
58             break;\r
59     }\r
60 \r
61     return u32Freq;\r
62 }\r
63 \r
64 /**\r
65   * @brief  This function configures some parameters of I2S interface for general purpose use.\r
66   * @param[in] i2s The base address of I2S module.\r
67   * @param[in] u32MasterSlave I2S operation mode. Valid values are:\r
68   *                                     - \ref I2S_MODE_MASTER\r
69   *                                     - \ref I2S_MODE_SLAVE\r
70   * @param[in] u32SampleRate Sample rate\r
71   * @param[in] u32WordWidth Data length. Valid values are:\r
72   *                                     - \ref I2S_DATABIT_8\r
73   *                                     - \ref I2S_DATABIT_16\r
74   *                                     - \ref I2S_DATABIT_24\r
75   *                                     - \ref I2S_DATABIT_32\r
76   * @param[in] u32MonoData: Set audio data to mono or not. Valid values are:\r
77   *                                     - \ref I2S_ENABLE_MONO\r
78   *                                     - \ref I2S_DISABLE_MONO\r
79   * @param[in] u32DataFormat Data format. This is also used to select I2S or PCM(TDM) function. Valid values are:\r
80   *                                     - \ref I2S_FORMAT_I2S\r
81   *                                     - \ref I2S_FORMAT_I2S_MSB\r
82   *                                     - \ref I2S_FORMAT_I2S_LSB\r
83   *                                     - \ref I2S_FORMAT_PCM\r
84   *                                     - \ref I2S_FORMAT_PCM_MSB\r
85   *                                     - \ref I2S_FORMAT_PCM_LSB\r
86   * @return Real sample rate.\r
87   * @details Set TX and RX FIFO threshold to middle value.\r
88   *          The sample rate may not be used from the parameter, it depends on system's clock settings,\r
89   *          but real sample rate used by system will be returned for reference.\r
90   * @note   I2S will be reset in initialization only for Secure.\r
91   */\r
92 uint32_t I2S_Open(I2S_T *i2s, uint32_t u32MasterSlave, uint32_t u32SampleRate, uint32_t u32WordWidth, uint32_t u32MonoData, uint32_t u32DataFormat)\r
93 {\r
94     uint16_t u16Divider;\r
95     uint32_t u32BitRate, u32SrcClk;\r
96 \r
97     if(!(__PC() & (1UL << 28UL)))\r
98     {\r
99         /* Reset I2S */\r
100         SYS->IPRST1 |= SYS_IPRST1_I2S0RST_Msk;\r
101         SYS->IPRST1 &= ~SYS_IPRST1_I2S0RST_Msk;\r
102     }\r
103 \r
104     /* Configure I2S controller according to input parameters. */\r
105     i2s->CTL0 = u32MasterSlave | u32WordWidth | u32MonoData | u32DataFormat | I2S_FIFO_TX_LEVEL_WORD_8 | I2S_FIFO_RX_LEVEL_WORD_8;\r
106 \r
107     /* Get I2S source clock frequency */\r
108     u32SrcClk = I2S_GetSourceClockFreq(i2s);\r
109 \r
110     /* Calculate bit clock rate */\r
111     u32BitRate = u32SampleRate * (((u32WordWidth >> 4UL) & 0x3UL) + 1UL) * 16UL;\r
112     u16Divider = (uint16_t)((((((u32SrcClk * 10UL) / u32BitRate) >> 1UL) + 5UL) / 10UL) - 1UL); /* Round to the nearest integer */\r
113     i2s->CLKDIV = (i2s->CLKDIV & ~I2S_CLKDIV_BCLKDIV_Msk) | ((uint32_t)u16Divider << 8UL);\r
114 \r
115     /* Calculate real sample rate */\r
116     u32BitRate = u32SrcClk / (((uint32_t)u16Divider + 1UL) * 2UL);\r
117     u32SampleRate = u32BitRate / ((((u32WordWidth >> 4UL) & 0x3UL) + 1UL) * 16UL);\r
118 \r
119     /* Enable I2S controller */\r
120     i2s->CTL0 |= I2S_CTL0_I2SEN_Msk;\r
121 \r
122     return u32SampleRate;\r
123 }\r
124 \r
125 /**\r
126   * @brief  Disable I2S function.\r
127   * @param[in]  i2s The base address of I2S module.\r
128   * @return None\r
129   * @details Clear I2SEN (I2S_CTL0[0]) to disable I2S function.\r
130   */\r
131 void I2S_Close(I2S_T *i2s)\r
132 {\r
133     i2s->CTL0 &= ~I2S_CTL0_I2SEN_Msk;\r
134 }\r
135 \r
136 /**\r
137   * @brief Enable interrupt function.\r
138   * @param[in] i2s The base address of I2S module.\r
139   * @param[in] u32Mask The combination of all related interrupt enable bits.\r
140   *            Each bit corresponds to a interrupt bit.\r
141   * @return None\r
142   * @details This function enables the interrupt according to the mask parameter.\r
143   */\r
144 void I2S_EnableInt(I2S_T *i2s, uint32_t u32Mask)\r
145 {\r
146     i2s->IEN |= u32Mask;\r
147 }\r
148 \r
149 /**\r
150   * @brief Disable interrupt function.\r
151   * @param[in] i2s The base address of I2S module.\r
152   * @param[in] u32Mask The combination of all related interrupt enable bits.\r
153   *            Each bit corresponds to a interrupt bit.\r
154   * @return None\r
155   * @details This function disables the interrupt according to the mask parameter.\r
156   */\r
157 void I2S_DisableInt(I2S_T *i2s, uint32_t u32Mask)\r
158 {\r
159     i2s->IEN &= ~u32Mask;\r
160 }\r
161 \r
162 /**\r
163   * @brief  Enable master clock (MCLK).\r
164   * @param[in] i2s The base address of I2S module.\r
165   * @param[in] u32BusClock The target MCLK clock.\r
166   * @return Actual MCLK clock\r
167   * @details Set the master clock rate according to u32BusClock parameter and enable master clock output.\r
168   *          The actual master clock rate may be different from the target master clock rate. The real master clock rate will be returned for reference.\r
169   */\r
170 uint32_t I2S_EnableMCLK(I2S_T *i2s, uint32_t u32BusClock)\r
171 {\r
172     uint8_t u8Divider;\r
173     uint32_t u32SrcClk, u32Reg, u32Clock;\r
174 \r
175     u32SrcClk = I2S_GetSourceClockFreq(i2s);\r
176     if(u32BusClock == u32SrcClk)\r
177     {\r
178         u8Divider = (uint8_t)0UL;\r
179     }\r
180     else\r
181     {\r
182         u8Divider = (uint8_t)(u32SrcClk / u32BusClock) >> 1UL;\r
183     }\r
184 \r
185     i2s->CLKDIV = (i2s->CLKDIV & ~I2S_CLKDIV_MCLKDIV_Msk) | u8Divider;\r
186 \r
187     i2s->CTL0 |= I2S_CTL0_MCLKEN_Msk;\r
188 \r
189     u32Reg = i2s->CLKDIV & I2S_CLKDIV_MCLKDIV_Msk;\r
190 \r
191     if(u32Reg == 0UL)\r
192     {\r
193         u32Clock = u32SrcClk;\r
194     }\r
195     else\r
196     {\r
197         u32Clock = ((u32SrcClk >> 1UL) / u32Reg);\r
198     }\r
199 \r
200     return u32Clock;\r
201 }\r
202 \r
203 /**\r
204   * @brief  Disable master clock (MCLK).\r
205   * @param[in] i2s The base address of I2S module.\r
206   * @return None\r
207   * @details Disable master clock output.\r
208   */\r
209 void I2S_DisableMCLK(I2S_T *i2s)\r
210 {\r
211     i2s->CTL0 &= ~I2S_CTL0_MCLKEN_Msk;\r
212 }\r
213 \r
214 /**\r
215   * @brief  Configure FIFO threshold setting.\r
216   * @param[in]  i2s The pointer of the specified I2S module.\r
217   * @param[in]  u32TxThreshold Decides the TX FIFO threshold. It could be 0 ~ 15.\r
218   * @param[in]  u32RxThreshold Decides the RX FIFO threshold. It could be 0 ~ 15.\r
219   * @return None\r
220   * @details Set TX FIFO threshold and RX FIFO threshold configurations.\r
221   */\r
222 void I2S_SetFIFO(I2S_T *i2s, uint32_t u32TxThreshold, uint32_t u32RxThreshold)\r
223 {\r
224     i2s->CTL1 = (i2s->CTL1 & ~(I2S_CTL1_TXTH_Msk | I2S_CTL1_RXTH_Msk)) |\r
225                 (u32TxThreshold << I2S_CTL1_TXTH_Pos) |\r
226                 (u32RxThreshold << I2S_CTL1_RXTH_Pos);\r
227 }\r
228 \r
229 /**\r
230   * @brief  Configure PCM(TDM) function parameters, such as channel width, channel number and sync pulse width\r
231   * @param[in]  i2s The pointer of the specified I2S module.\r
232   * @param[in]  u32ChannelWidth Channel width. Valid values are:\r
233   *                                                             - \ref I2S_TDM_WIDTH_8BIT\r
234   *                                                             - \ref I2S_TDM_WIDTH_16BIT\r
235   *                                                             - \ref I2S_TDM_WIDTH_24BIT\r
236   *                                                             - \ref I2S_TDM_WIDTH_32BIT\r
237   * @param[in]  u32ChannelNum Channel number. Valid values are:\r
238   *                                                             - \ref I2S_TDM_2CH\r
239   *                                                             - \ref I2S_TDM_4CH\r
240   *                                                             - \ref I2S_TDM_6CH\r
241   *                                                             - \ref I2S_TDM_8CH\r
242   * @param[in]  u32SyncWidth Width for sync pulse. Valid values are:\r
243   *                                                             - \ref I2S_TDM_SYNC_ONE_BCLK\r
244   *                                                             - \ref I2S_TDM_SYNC_ONE_CHANNEL\r
245   * @return None\r
246   * @details Set TX FIFO threshold and RX FIFO threshold configurations.\r
247   */\r
248 void I2S_ConfigureTDM(I2S_T *i2s, uint32_t u32ChannelWidth, uint32_t u32ChannelNum, uint32_t u32SyncWidth)\r
249 {\r
250     i2s->CTL0 = (i2s->CTL0 & ~(I2S_CTL0_TDMCHNUM_Msk | I2S_CTL0_CHWIDTH_Msk | I2S_CTL0_PCMSYNC_Msk)) |\r
251                 (u32ChannelWidth << I2S_CTL0_CHWIDTH_Pos) |\r
252                 (u32ChannelNum << I2S_CTL0_TDMCHNUM_Pos) |\r
253                 (u32SyncWidth << I2S_CTL0_PCMSYNC_Pos);\r
254 }\r
255 \r
256 /*@}*/ /* end of group I2S_EXPORTED_FUNCTIONS */\r
257 \r
258 /*@}*/ /* end of group I2S_Driver */\r
259 \r
260 /*@}*/ /* end of group Standard_Driver */\r
261 \r
262 /*** (C) COPYRIGHT 2016 Nuvoton Technology Corp. ***/\r
263 \r