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