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