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