1 /******************************************************************************
2 * Filename: i2s.c
3 *
4 * Description: Driver for the I2S.
5 *
6 * Copyright (c) 2015 - 2022, Texas Instruments Incorporated
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 *
12 * 1) Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
14 *
15 * 2) Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 *
19 * 3) Neither the name of the ORGANIZATION nor the names of its contributors may
20 * be used to endorse or promote products derived from this software without
21 * specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 *
35 ******************************************************************************/
36
37 #include "i2s.h"
38
39 //*****************************************************************************
40 //
41 // Handle support for DriverLib in ROM:
42 // This section will undo prototype renaming made in the header file
43 //
44 //*****************************************************************************
45 #if !defined(DOXYGEN)
46 #undef I2SEnable
47 #define I2SEnable NOROM_I2SEnable
48 #undef I2SAudioFormatConfigure
49 #define I2SAudioFormatConfigure NOROM_I2SAudioFormatConfigure
50 #undef I2SChannelConfigure
51 #define I2SChannelConfigure NOROM_I2SChannelConfigure
52 #undef I2SBufferConfig
53 #define I2SBufferConfig NOROM_I2SBufferConfig
54 #undef I2SPointerUpdate
55 #define I2SPointerUpdate NOROM_I2SPointerUpdate
56 #undef I2SPointerSet
57 #define I2SPointerSet NOROM_I2SPointerSet
58 #undef I2SSampleStampConfigure
59 #define I2SSampleStampConfigure NOROM_I2SSampleStampConfigure
60 #undef I2SSampleStampGet
61 #define I2SSampleStampGet NOROM_I2SSampleStampGet
62 #endif
63
64 //*****************************************************************************
65 //
66 // Global pointer to the current I2S data structure
67 //
68 //*****************************************************************************
69 I2SControlTable *g_pControlTable;
70
71 //*****************************************************************************
72 //
73 // Enables the I2S module for operation
74 //
75 //*****************************************************************************
76 void
I2SEnable(uint32_t ui32Base)77 I2SEnable(uint32_t ui32Base)
78 {
79 // Check the arguments.
80 ASSERT(I2SBaseValid(ui32Base));
81
82 // Make sure the control table pointer is setup to a memory location.
83 if(!(g_pControlTable))
84 {
85 return;
86 }
87
88 // Write the address to the first input/output buffer.
89 HWREG(I2S0_BASE + I2S_O_AIFINPTRNEXT) = g_pControlTable->ui32InBase;
90 g_pControlTable->ui32InOffset = 0;
91 HWREG(I2S0_BASE + I2S_O_AIFOUTPTRNEXT) = g_pControlTable->ui32OutBase;
92 g_pControlTable->ui32OutOffset = 0;
93
94 // Enable the I2S module.
95 HWREG(I2S0_BASE + I2S_O_AIFDMACFG) = (uint32_t)g_pControlTable->ui16DMABufSize - 1;
96 }
97
98 //*****************************************************************************
99 //
100 // Configures the I2S module
101 //
102 //*****************************************************************************
103 void
I2SAudioFormatConfigure(uint32_t ui32Base,uint32_t ui32FmtCfg,uint32_t ui32BitClkDelay)104 I2SAudioFormatConfigure(uint32_t ui32Base, uint32_t ui32FmtCfg,
105 uint32_t ui32BitClkDelay)
106 {
107 // Check the arguments.
108 ASSERT(I2SBaseValid(ui32Base));
109 ASSERT(ui32BitClkDelay <= 255);
110
111 // Save the length of the audio words stored in memory.
112 g_pControlTable->ui16MemLen = (ui32FmtCfg & I2S_MEM_LENGTH_24) ? 24 : 16;
113
114 // Write the configuration.
115 HWREG(I2S0_BASE + I2S_O_AIFFMTCFG) = ui32FmtCfg | (ui32BitClkDelay << I2S_AIFFMTCFG_DATA_DELAY_S);
116 }
117
118 //****************************************************************************
119 //
120 // Setup the audio channel configuration
121 //
122 //****************************************************************************
123 void
I2SChannelConfigure(uint32_t ui32Base,uint32_t ui32Chan0Cfg,uint32_t ui32Chan1Cfg)124 I2SChannelConfigure(uint32_t ui32Base, uint32_t ui32Chan0Cfg,
125 uint32_t ui32Chan1Cfg)
126 {
127 uint32_t ui32InChan;
128 uint32_t ui32OutChan;
129 uint32_t ui32ChanMask;
130
131 // Check the arguments.
132 ASSERT(I2SBaseValid(ui32Base));
133 ASSERT(ui32Chan0Cfg & (I2S_CHAN_CFG_MASK | I2S_LINE_MASK))
134 ASSERT(ui32Chan1Cfg & (I2S_CHAN_CFG_MASK | I2S_LINE_MASK))
135
136 ui32InChan = 0;
137 ui32OutChan = 0;
138
139 // Configure input/output channels.
140 HWREG(I2S0_BASE + I2S_O_AIFDIRCFG) = (
141 (( ui32Chan0Cfg << I2S_AIFDIRCFG_AD0_S) & I2S_AIFDIRCFG_AD0_M ) |
142 (( ui32Chan1Cfg << I2S_AIFDIRCFG_AD1_S) & I2S_AIFDIRCFG_AD1_M ) );
143
144 // Configure the valid channel mask.
145 HWREG(I2S0_BASE + I2S_O_AIFWMASK0) = (ui32Chan0Cfg >> 8) & I2S_AIFWMASK0_MASK_M;
146 HWREG(I2S0_BASE + I2S_O_AIFWMASK1) = (ui32Chan1Cfg >> 8) & I2S_AIFWMASK1_MASK_M;
147
148 // Resolve and save the number of input and output channels.
149 ui32ChanMask = (ui32Chan0Cfg & I2S_CHAN_CFG_MASK) >> 8;
150 if(ui32Chan0Cfg & I2S_LINE_INPUT)
151 {
152 while(ui32ChanMask)
153 {
154 if(ui32ChanMask & 0x1)
155 {
156 ui32InChan++;
157 }
158 // Shift down channel mask
159 ui32ChanMask >>= 1;
160 }
161
162 }
163 else if(ui32Chan0Cfg & I2S_LINE_OUTPUT)
164 {
165 while(ui32ChanMask)
166 {
167 if(ui32ChanMask & 0x1)
168 {
169 ui32OutChan++;
170 }
171 // Shift down channel mask
172 ui32ChanMask >>= 1;
173 }
174 }
175
176 ui32ChanMask = (ui32Chan1Cfg & I2S_CHAN_CFG_MASK) >> 8;
177 if(ui32Chan1Cfg & I2S_LINE_INPUT)
178 {
179 while(ui32ChanMask)
180 {
181 if(ui32ChanMask & 0x1)
182 {
183 ui32InChan++;
184 }
185 // Shift down channel mask
186 ui32ChanMask >>= 1;
187 }
188 }
189 else if(ui32Chan1Cfg & I2S_LINE_OUTPUT)
190 {
191 while(ui32ChanMask)
192 {
193 if(ui32ChanMask & 0x1)
194 {
195 ui32OutChan++;
196 }
197 // Shift down channel mask
198 ui32ChanMask >>= 1;
199 }
200 }
201
202 g_pControlTable->ui8InChan = (uint8_t)ui32InChan;
203 g_pControlTable->ui8OutChan = (uint8_t)ui32OutChan;
204 }
205
206 //****************************************************************************
207 //
208 // Set the input buffer pointers
209 //
210 //****************************************************************************
211 void
I2SBufferConfig(uint32_t ui32Base,uint32_t ui32InBufBase,uint32_t ui32OutBufBase,uint16_t ui16DMABufSize,uint16_t ui16ChanBufSize)212 I2SBufferConfig(uint32_t ui32Base, uint32_t ui32InBufBase,
213 uint32_t ui32OutBufBase, uint16_t ui16DMABufSize,
214 uint16_t ui16ChanBufSize)
215 {
216 // Check the arguments.
217 ASSERT(I2SBaseValid(ui32Base));
218 ASSERT(ui16DMABufSize > 0);
219
220 // Setup the input data pointer and buffer sizes.
221 g_pControlTable->ui16DMABufSize = ui16DMABufSize;
222 g_pControlTable->ui16ChBufSize = ui16ChanBufSize;
223 g_pControlTable->ui32InBase = ui32InBufBase;
224 g_pControlTable->ui32OutBase = ui32OutBufBase;
225 }
226
227 //****************************************************************************
228 //
229 // Set the buffer pointers
230 //
231 //****************************************************************************
232 void
I2SPointerSet(uint32_t ui32Base,bool bInput,void * pNextPointer)233 I2SPointerSet(uint32_t ui32Base, bool bInput, void * pNextPointer)
234 {
235 // Check the arguments.
236 ASSERT(I2SBaseValid(ui32Base));
237
238 // Update the next input/output pointer with the correct address.
239 if(bInput == true)
240 {
241 HWREG(I2S0_BASE + I2S_O_AIFINPTRNEXT) = (uint32_t)pNextPointer;
242 }
243 else
244 {
245 HWREG(I2S0_BASE + I2S_O_AIFOUTPTRNEXT) = (uint32_t)pNextPointer;
246 }
247 }
248
249 //****************************************************************************
250 //
251 // Update the buffer pointers
252 //
253 //****************************************************************************
254 void
I2SPointerUpdate(uint32_t ui32Base,bool bInput)255 I2SPointerUpdate(uint32_t ui32Base, bool bInput)
256 {
257 uint32_t ui32NextPtr;
258
259 // Check the arguments.
260 ASSERT(I2SBaseValid(ui32Base));
261
262 // Update the next input/output pointer with the correct address.
263 if(bInput == true)
264 {
265 ui32NextPtr = (g_pControlTable->ui8InChan *
266 (g_pControlTable->ui16MemLen >> 3)) *
267 g_pControlTable->ui16DMABufSize;
268 g_pControlTable->ui32InOffset = ((g_pControlTable->ui32InOffset +
269 ui32NextPtr) %
270 g_pControlTable->ui16ChBufSize);
271 HWREG(I2S0_BASE + I2S_O_AIFINPTRNEXT) = g_pControlTable->ui32InOffset +
272 g_pControlTable->ui32InBase;
273 }
274 else
275 {
276 ui32NextPtr = (g_pControlTable->ui8OutChan *
277 (g_pControlTable->ui16MemLen >> 3)) *
278 g_pControlTable->ui16DMABufSize;
279 g_pControlTable->ui32OutOffset = ((g_pControlTable->ui32OutOffset +
280 ui32NextPtr) %
281 g_pControlTable->ui16ChBufSize);
282 HWREG(I2S0_BASE + I2S_O_AIFOUTPTRNEXT) =
283 g_pControlTable->ui32OutOffset +
284 g_pControlTable->ui32OutBase;
285 }
286 }
287
288 //*****************************************************************************
289 //
290 // Configure the sample stamp generator
291 //
292 //*****************************************************************************
293 void
I2SSampleStampConfigure(uint32_t ui32Base,bool bInput,bool bOutput)294 I2SSampleStampConfigure(uint32_t ui32Base, bool bInput, bool bOutput)
295 {
296 uint32_t ui32Trigger;
297
298 // Check the arguments.
299 ASSERT(I2SBaseValid(ui32Base));
300
301 ui32Trigger = HWREG(I2S0_BASE + I2S_O_STMPWCNT);
302 ui32Trigger = (ui32Trigger + 2) % g_pControlTable->ui16ChBufSize;
303
304 // Setup the sample stamp trigger for input streams.
305 if(bInput)
306 {
307 HWREG(I2S0_BASE + I2S_O_STMPINTRIG) = ui32Trigger;
308 }
309
310 // Setup the sample stamp trigger for output streams.
311 if(bOutput)
312 {
313 HWREG(I2S0_BASE + I2S_O_STMPOUTTRIG) = ui32Trigger;
314 }
315
316 }
317
318 //*****************************************************************************
319 //
320 // Get the current value of a sample stamp counter
321 //
322 //*****************************************************************************
323 uint32_t
I2SSampleStampGet(uint32_t ui32Base,uint32_t ui32Channel)324 I2SSampleStampGet(uint32_t ui32Base, uint32_t ui32Channel)
325 {
326 uint32_t ui32FrameClkCnt;
327 uint32_t ui32SysClkCnt;
328 uint32_t ui32PeriodSysClkCnt;
329 uint32_t ui32SampleStamp;
330
331 // Get the number of Frame clock counts since last stamp.
332 ui32FrameClkCnt = HWREG(I2S0_BASE + I2S_O_STMPWCNTCAPT0);
333
334 // Get the number of system clock ticks since last frame clock edge.
335 ui32SysClkCnt = HWREG(I2S0_BASE + I2S_O_STMPXCNTCAPT0);
336
337 // Get the number system clock ticks in the last frame clock period.
338 ui32PeriodSysClkCnt = HWREG(I2S0_BASE + I2S_O_STMPXPER);
339
340 // Calculate the sample stamp.
341 ui32SampleStamp = (ui32SysClkCnt << 16) / ui32PeriodSysClkCnt;
342 ui32SampleStamp = (ui32SampleStamp > I2S_STMP_SATURATION) ?
343 I2S_STMP_SATURATION : ui32SampleStamp;
344 ui32SampleStamp |= (ui32FrameClkCnt << 16);
345
346 return (ui32SampleStamp);
347 }
348