1 //*****************************************************************************
2 //
3 //! @file am_hal_pdm.c
4 //!
5 //! @brief HAL implementation for the PDM module.
6 //!
7 //! @addtogroup pdm3p PDM - Pulse Density Modulated Functions
8 //! @ingroup apollo3p_hal
9 //! @{
10 //
11 //*****************************************************************************
12 
13 //*****************************************************************************
14 //
15 // Copyright (c) 2024, Ambiq Micro, Inc.
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are met:
20 //
21 // 1. Redistributions of source code must retain the above copyright notice,
22 // this list of conditions and the following disclaimer.
23 //
24 // 2. Redistributions in binary form must reproduce the above copyright
25 // notice, this list of conditions and the following disclaimer in the
26 // documentation and/or other materials provided with the distribution.
27 //
28 // 3. Neither the name of the copyright holder nor the names of its
29 // contributors may be used to endorse or promote products derived from this
30 // software without specific prior written permission.
31 //
32 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
33 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
36 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
37 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
38 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
39 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
40 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
41 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 // POSSIBILITY OF SUCH DAMAGE.
43 //
44 // This is part of revision release_sdk_3_2_0-dd5f40c14b of the AmbiqSuite Development Package.
45 //
46 //*****************************************************************************
47 
48 #include <stdint.h>
49 #include <stdbool.h>
50 #include "am_mcu_apollo.h"
51 
52 //*****************************************************************************
53 //
54 // PDM magic number for handle verification.
55 //
56 //*****************************************************************************
57 #define AM_HAL_MAGIC_PDM                0xF956E2
58 
59 #define AM_HAL_PDM_HANDLE_VALID(h)                                            \
60     ((h) &&                                                                   \
61      ((am_hal_handle_prefix_t *)(h))->s.bInit &&                              \
62      (((am_hal_handle_prefix_t *)(h))->s.magic == AM_HAL_MAGIC_PDM))
63 
64 //*****************************************************************************
65 //
66 // Convenience macro for passing errors.
67 //
68 //*****************************************************************************
69 #define RETURN_ON_ERROR(x)                                                    \
70     if ((x) != AM_HAL_STATUS_SUCCESS)                                         \
71     {                                                                         \
72         return (x);                                                           \
73     };
74 
75 //*****************************************************************************
76 //
77 // Abbreviation for validating handles and returning errors.
78 //
79 //*****************************************************************************
80 #ifndef AM_HAL_DISABLE_API_VALIDATION
81 
82 #define AM_HAL_PDM_HANDLE_CHECK(h)                                            \
83     if (!AM_HAL_PDM_HANDLE_VALID(h))                                          \
84     {                                                                         \
85         return AM_HAL_STATUS_INVALID_HANDLE;                                  \
86     }
87 
88 #else
89 
90 #define AM_HAL_PDM_HANDLE_CHECK(h)
91 
92 #endif // AM_HAL_DISABLE_API_VALIDATION
93 
94 //*****************************************************************************
95 //
96 // Helper macros for delays.
97 //
98 //*****************************************************************************
99 #define delay_ms(ms)                                                          \
100     if (1)                                                                    \
101     {                                                                         \
102         am_hal_clkgen_status_t sClkGenStatus;                                 \
103         am_hal_clkgen_status_get(&sClkGenStatus);                             \
104         am_hal_flash_delay((ms) * (sClkGenStatus.ui32SysclkFreq / 3000));     \
105     }
106 
107 #define delay_us(us)                                                          \
108     if (1)                                                                    \
109     {                                                                         \
110         am_hal_clkgen_status_t sClkGenStatus;                                 \
111         am_hal_clkgen_status_get(&sClkGenStatus);                             \
112         am_hal_flash_delay((us) * (sClkGenStatus.ui32SysclkFreq / 3000000));  \
113     }
114 
115 //*****************************************************************************
116 //
117 // Structure for handling PDM register state information for power up/down
118 //
119 //*****************************************************************************
120 typedef struct
121 {
122     bool bValid;
123 }
124 am_hal_pdm_register_state_t;
125 
126 //*****************************************************************************
127 //
128 // Structure for handling PDM HAL state information.
129 //
130 //*****************************************************************************
131 typedef struct
132 {
133     am_hal_handle_prefix_t prefix; //!< Don't move, This has to be first in this structure
134     uint32_t ui32XfrCount;  //!< used for dma restart
135     uint32_t ui32Module;
136     uint32_t ui32BufferPtr;
137     uint32_t ui32BufferPong;
138     uint32_t ui32BufferPing;
139     uint32_t ui32Threshold;
140     am_hal_pdm_register_state_t sRegState;
141 
142 }
143 am_hal_pdm_state_t;
144 
145 //*****************************************************************************
146 //
147 // State structure for each module.
148 //
149 //*****************************************************************************
150 am_hal_pdm_state_t g_am_hal_pdm_states[AM_REG_PDM_NUM_MODULES];
151 
152 //*****************************************************************************
153 //
154 // Static function definitions.
155 //
156 //*****************************************************************************
157 static uint32_t find_dma_threshold(uint32_t ui32TotalCount);
158 
159 //*****************************************************************************
160 //
161 // Initialization function.
162 //
163 //*****************************************************************************
164 uint32_t
am_hal_pdm_initialize(uint32_t ui32Module,void ** ppHandle)165 am_hal_pdm_initialize(uint32_t ui32Module, void **ppHandle)
166 {
167     //
168     // Check that the request module is in range.
169     //
170     if ( ui32Module >= AM_REG_PDM_NUM_MODULES )
171     {
172         return AM_HAL_STATUS_OUT_OF_RANGE;
173     }
174 
175     //
176     // Check for valid arguements.
177     //
178     if (!ppHandle)
179     {
180         return AM_HAL_STATUS_INVALID_ARG;
181     }
182 
183     //
184     // Check if the handle is unallocated.
185     //
186     if (g_am_hal_pdm_states[ui32Module].prefix.s.bInit)
187     {
188         return AM_HAL_STATUS_INVALID_OPERATION;
189     }
190 
191     //
192     // Initialize the handle.
193     //
194     g_am_hal_pdm_states[ui32Module].prefix.s.bInit = true;
195     g_am_hal_pdm_states[ui32Module].prefix.s.magic = AM_HAL_MAGIC_PDM;
196     g_am_hal_pdm_states[ui32Module].ui32Module = ui32Module;
197     g_am_hal_pdm_states[ui32Module].sRegState.bValid = false;
198 
199     //
200     // Return the handle.
201     //
202     *ppHandle = (void *)&g_am_hal_pdm_states[ui32Module];
203 
204     //
205     // Return the status.
206     //
207     return AM_HAL_STATUS_SUCCESS;
208 }
209 
210 //*****************************************************************************
211 //
212 // De-Initialization function.
213 //
214 //*****************************************************************************
215 uint32_t
am_hal_pdm_deinitialize(void * pHandle)216 am_hal_pdm_deinitialize(void *pHandle)
217 {
218     //
219     // Check the handle.
220     //
221     AM_HAL_PDM_HANDLE_CHECK(pHandle);
222 
223     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *)pHandle;
224 
225     //
226     // Reset the handle.
227     //
228     pState->prefix.s.bInit = false;
229     pState->prefix.s.magic = 0;
230     pState->ui32Module = 0;
231 
232     //
233     // Return the status.
234     //
235     return AM_HAL_STATUS_SUCCESS;
236 }
237 
238 //*****************************************************************************
239 //
240 // Power control function.
241 //
242 //*****************************************************************************
243 uint32_t
am_hal_pdm_power_control(void * pHandle,am_hal_sysctrl_power_state_e ePowerState,bool bRetainState)244 am_hal_pdm_power_control(void *pHandle,
245                          am_hal_sysctrl_power_state_e ePowerState,
246                          bool bRetainState)
247 {
248     //
249     // Check the handle.
250     //
251     AM_HAL_PDM_HANDLE_CHECK(pHandle);
252 
253     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
254     uint32_t ui32Module = pState->ui32Module;
255 
256     am_hal_pwrctrl_periph_e ePDMPowerModule = ((am_hal_pwrctrl_periph_e)
257                                                (AM_HAL_PWRCTRL_PERIPH_PDM +
258                                                 ui32Module));
259 
260     //
261     // Decode the requested power state and update PDM operation accordingly.
262     //
263     switch (ePowerState)
264     {
265         //
266         // Turn on the PDM.
267         //
268         case AM_HAL_SYSCTRL_WAKE:
269             //
270             // Make sure we don't try to restore an invalid state.
271             //
272             if (bRetainState && !pState->sRegState.bValid)
273             {
274                 return AM_HAL_STATUS_INVALID_OPERATION;
275             }
276 
277             //
278             // Enable power control.
279             //
280             am_hal_pwrctrl_periph_enable(ePDMPowerModule);
281 
282             if (bRetainState)
283             {
284                 //
285                 // Restore PDM registers
286                 //
287                 AM_CRITICAL_BEGIN;
288 
289                 pState->sRegState.bValid = false;
290 
291                 AM_CRITICAL_END;
292             }
293             break;
294 
295         //
296         // Turn off the PDM.
297         //
298         case AM_HAL_SYSCTRL_NORMALSLEEP:
299         case AM_HAL_SYSCTRL_DEEPSLEEP:
300             if (bRetainState)
301             {
302                 AM_CRITICAL_BEGIN;
303 
304                 pState->sRegState.bValid = true;
305 
306                 AM_CRITICAL_END;
307             }
308 
309             //
310             // Disable power control.
311             //
312             am_hal_pwrctrl_periph_disable(ePDMPowerModule);
313             break;
314 
315         default:
316             return AM_HAL_STATUS_INVALID_ARG;
317     }
318 
319     //
320     // Return the status.
321     //
322     return AM_HAL_STATUS_SUCCESS;
323 }
324 
325 //*****************************************************************************
326 //
327 // Configure the PDM.
328 //
329 //*****************************************************************************
330 uint32_t
am_hal_pdm_configure(void * pHandle,const am_hal_pdm_config_t * psConfig)331 am_hal_pdm_configure(void *pHandle, const am_hal_pdm_config_t *psConfig)
332 {
333     AM_HAL_PDM_HANDLE_CHECK(pHandle);
334     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
335     uint32_t ui32Module = pState->ui32Module;
336 
337     //
338     // Apply the config structure settings to the PCFG register.
339     //
340     uint32_t ui32ResMask = ~(PDM_PCFG_LRSWAP_Msk | PDM_PCFG_PGARIGHT_Msk | PDM_PCFG_PGALEFT_Msk |
341         PDM_PCFG_MCLKDIV_Msk | PDM_PCFG_SINCRATE_Msk | PDM_PCFG_ADCHPD_Msk | PDM_PCFG_HPCUTOFF_Msk |
342         PDM_PCFG_CYCLES_Msk | PDM_PCFG_SOFTMUTE_Msk | PDM_PCFG_PDMCOREEN_Msk);
343 
344 
345     uint32_t ui32Temp = PDMn(ui32Module)->PCFG & ui32ResMask;
346 
347     ui32Temp |= _VAL2FLD(PDM_PCFG_SOFTMUTE, psConfig->bSoftMute)
348                 | _VAL2FLD( PDM_PCFG_CYCLES, psConfig->ui32GainChangeDelay)
349                 | _VAL2FLD( PDM_PCFG_HPCUTOFF, psConfig->ui32HighPassCutoff)
350                 | _VAL2FLD( PDM_PCFG_ADCHPD, psConfig->bHighPassEnable)
351                 | _VAL2FLD( PDM_PCFG_SINCRATE, psConfig->ui32DecimationRate)
352                 | _VAL2FLD( PDM_PCFG_MCLKDIV, psConfig->eClkDivider)
353                 | _VAL2FLD( PDM_PCFG_PGALEFT, psConfig->eLeftGain)
354                 | _VAL2FLD( PDM_PCFG_PGARIGHT, psConfig->eRightGain)
355                 | _VAL2FLD( PDM_PCFG_LRSWAP, psConfig->bLRSwap);
356 
357 
358     if (!psConfig->bDoNotStartPdm)
359     {
360         //
361         // Set the PDM Core enable bit to enable PDM to PCM conversions.
362         //
363         ui32Temp |=  _VAL2FLD(PDM_PCFG_PDMCOREEN, 1);
364     }
365 
366     PDMn(ui32Module)->PCFG = ui32Temp;
367 
368     //
369     // Program the "voice" registers.
370     //
371     ui32ResMask = ~(
372         PDM_VCFG_PDMCLKEN_Msk | PDM_VCFG_IOCLKEN_Msk | PDM_VCFG_RSTB_Msk |
373         PDM_VCFG_CHSET_Msk | PDM_VCFG_PCMPACK_Msk | PDM_VCFG_SELAP_Msk | PDM_VCFG_DMICKDEL_Msk |
374         PDM_VCFG_BCLKINV_Msk | PDM_VCFG_I2SEN_Msk | PDM_VCFG_PDMCLKSEL_Msk);
375 
376     ui32Temp = PDMn(ui32Module)->VCFG & ui32ResMask;
377     ui32Temp |=
378         _VAL2FLD(PDM_VCFG_PDMCLKEN, PDM_VCFG_PDMCLKEN_DIS) |
379         _VAL2FLD(PDM_VCFG_IOCLKEN, PDM_VCFG_IOCLKEN_DIS) |
380         _VAL2FLD(PDM_VCFG_RSTB, PDM_VCFG_RSTB_RESET) |
381         _VAL2FLD(PDM_VCFG_CHSET, psConfig->ePCMChannels) |
382         _VAL2FLD(PDM_VCFG_PCMPACK, psConfig->bDataPacking) |
383         _VAL2FLD(PDM_VCFG_SELAP, psConfig->ePDMClkSource) |
384         _VAL2FLD(PDM_VCFG_DMICKDEL, psConfig->bPDMSampleDelay) |
385         _VAL2FLD(PDM_VCFG_BCLKINV, psConfig->bInvertI2SBCLK) |
386         _VAL2FLD(PDM_VCFG_I2SEN, psConfig->bI2SEnable) |
387         _VAL2FLD(PDM_VCFG_PDMCLKSEL, psConfig->ePDMClkSpeed);
388 
389     PDMn(ui32Module)->VCFG = ui32Temp;
390 
391     delay_us(100);
392 
393     PDMn(ui32Module)->VCFG_b.RSTB = PDM_VCFG_RSTB_NORM;
394 
395     return AM_HAL_STATUS_SUCCESS;
396 }
397 
398 //*****************************************************************************
399 //
400 // Enable the PDM.
401 //
402 //*****************************************************************************
403 uint32_t
am_hal_pdm_enable(void * pHandle)404 am_hal_pdm_enable(void *pHandle)
405 {
406     AM_HAL_PDM_HANDLE_CHECK(pHandle)
407     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
408     uint32_t ui32Module = pState->ui32Module;
409 
410     PDMn(ui32Module)->VCFG_b.IOCLKEN = PDM_VCFG_IOCLKEN_EN;
411     PDMn(ui32Module)->VCFG_b.PDMCLKEN = PDM_VCFG_PDMCLKEN_EN;
412 
413     return AM_HAL_STATUS_SUCCESS;
414 }
415 
416 //*****************************************************************************
417 //
418 // Disable the PDM.
419 //
420 //*****************************************************************************
421 uint32_t
am_hal_pdm_disable(void * pHandle)422 am_hal_pdm_disable(void *pHandle)
423 {
424     AM_HAL_PDM_HANDLE_CHECK(pHandle)
425     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
426     uint32_t ui32Module = pState->ui32Module;
427 
428     PDMn(ui32Module)->VCFG_b.IOCLKEN = PDM_VCFG_IOCLKEN_DIS;
429     PDMn(ui32Module)->VCFG_b.PDMCLKEN = PDM_VCFG_PDMCLKEN_DIS;
430 
431     return AM_HAL_STATUS_SUCCESS;
432 }
433 //*****************************************************************************
434 //
435 // set the PDM FIFO Threshold value
436 //
437 //*****************************************************************************
438 uint32_t
am_hal_pdm_fifo_threshold_setup(void * pHandle,uint32_t value)439 am_hal_pdm_fifo_threshold_setup(void *pHandle, uint32_t value)
440 {
441     //
442     // Check the handle.
443     //
444     AM_HAL_PDM_HANDLE_CHECK(pHandle);
445 
446     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
447     uint32_t ui32Module = pState->ui32Module;
448 
449     PDMn(ui32Module)->FIFOTHR = value;
450 
451     return AM_HAL_STATUS_SUCCESS;
452 }
453 //*****************************************************************************
454 //
455 // Get the DMA Bufffer.
456 //
457 //*****************************************************************************
458 uint32_t
am_hal_pdm_dma_get_buffer(void * pHandle)459 am_hal_pdm_dma_get_buffer(void *pHandle)
460 {
461     //
462     // Check the handle.
463     //
464     AM_HAL_PDM_HANDLE_CHECK(pHandle);
465 
466     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
467 
468     uint32_t ui32BufferPtr = (pState->ui32BufferPtr == pState->ui32BufferPong)? pState->ui32BufferPing: pState->ui32BufferPong;
469 
470     return ui32BufferPtr;
471 }
472 
473 //*****************************************************************************
474 //
475 // Given the total number of bytes in a DMA transaction, find a reasonable
476 // threshold setting.
477 //
478 //*****************************************************************************
479 static uint32_t
find_dma_threshold(uint32_t ui32TotalCount)480 find_dma_threshold(uint32_t ui32TotalCount)
481 {
482     //
483     // Start with a threshold value of 24, and search downward for values that
484     // fit our criteria.
485     //
486     uint32_t ui32Threshold;
487     uint32_t ui32Minimum = AM_HAL_PDM_DMA_THRESHOLD_MIN;
488 
489     for ( ui32Threshold = 24; ui32Threshold >= ui32Minimum; ui32Threshold -= 4 )
490     {
491         //
492         // With our loop parameters, we've already guaranteed that the
493         // threshold will be no higher than 24, and that it will be divisible
494         // by 4. The only remaining requirement is that ui32TotalCount must
495         // also be divisible by the threshold.
496         //
497         if ((ui32TotalCount % ui32Threshold) == 0)
498         {
499             break;
500         }
501     }
502 
503     //
504     // If we found an appropriate value, we'll return it here. Otherwise, we
505     // will return zero.
506     //
507     if (ui32Threshold < ui32Minimum)
508     {
509         ui32Threshold = 0;
510     }
511 
512     return ui32Threshold;
513 }
514 
515 //*****************************************************************************
516 //
517 // Sets up, but doesn't start, a DMA transaction
518 //
519 //*****************************************************************************
520 uint32_t
am_hal_dma_param_setup(void * pHandle,am_hal_pdm_transfer_t * pDmaCfg)521 am_hal_dma_param_setup(void *pHandle, am_hal_pdm_transfer_t *pDmaCfg)
522 {
523 
524     AM_HAL_PDM_HANDLE_CHECK(pHandle)
525 
526     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
527 
528 #ifndef AM_HAL_DISABLE_API_VALIDATION
529     //
530     // Check for DMA to/from DTCM.
531     //
532     if ( (pDmaCfg->ui32TargetAddr >= AM_HAL_FLASH_DTCM_START) &&
533          (pDmaCfg->ui32TargetAddr <= AM_HAL_FLASH_DTCM_END) )
534     {
535         return AM_HAL_STATUS_OUT_OF_RANGE;
536     }
537 #endif
538 
539 
540 
541     pDmaCfg->ui32BufferWithDataAddr = 0;
542 
543     pState->ui32BufferPtr = pDmaCfg->ui32TargetAddr;
544     pState->ui32BufferPing = pDmaCfg->ui32TargetAddr;
545     pState->ui32BufferPong = pDmaCfg->ui32TargetAddrReverse;
546     pState->ui32XfrCount   = pDmaCfg->ui32TotalCount;
547 
548     //
549     // Find an appropriate threshold size for this transfer.
550     //
551     pState->ui32Threshold = find_dma_threshold(pDmaCfg->ui32TotalCount);
552 
553     //
554     // If we didn't find a threshold that will work, throw an error.
555     //
556     if (pState->ui32Threshold == 0)
557     {
558         return AM_HAL_PDM_STATUS_BAD_TOTALCOUNT;
559     }
560 
561     return AM_HAL_STATUS_SUCCESS;
562 
563 }
564 
565 //*****************************************************************************
566 //
567 // Starts a DMA transaction from the PDM directly to SRAM using previous parameters
568 //
569 //*****************************************************************************
570 uint32_t
am_hal_dma_restart(void * pHandle)571 am_hal_dma_restart(void *pHandle)
572 {
573     //
574     // Check the handle.
575     //
576     AM_HAL_PDM_HANDLE_CHECK(pHandle);
577 
578     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
579     uint32_t ui32Module = pState->ui32Module;
580 
581     PDMn(ui32Module)->FIFOTHR = pState->ui32Threshold;
582 
583     //
584     // Configure DMA.
585     //
586     PDMn(ui32Module)->DMACFG = 0;
587     //
588     //! flush the fifo
589     //
590     PDMn(ui32Module)->FIFOFLUSH = 1;
591 
592     //
593     // Configure DMA.
594     //
595     PDMn(ui32Module)->DMACFG_b.DMAPRI = PDM_DMACFG_DMAPRI_HIGH;
596     PDMn(ui32Module)->DMACFG_b.DMADIR = PDM_DMACFG_DMADIR_P2M;
597     PDMn(ui32Module)->DMATOTCOUNT = pState->ui32XfrCount;
598     PDMn(ui32Module)->DMATARGADDR = pState->ui32BufferPtr;
599     PDMn(ui32Module)->DMASTAT = 0;
600 
601     //
602     // Make sure the trigger is set for threshold.
603     //
604     PDMn(ui32Module)->DMATRIGEN_b.DTHR = 1;
605 
606     //
607     // clear all interrupts
608     //
609     PDMn(ui32Module)->INTCLR = PDMn(ui32Module)->INTSTAT;
610 
611     //
612     // Enable DMA
613     //
614     PDMn(ui32Module)->DMACFG_b.DMAEN = PDM_DMACFG_DMAEN_EN;
615 
616     //
617     // Set the PDM Core enable bit to enable PDM to PCM conversions.
618     //
619     PDMn(ui32Module)->PCFG_b.PDMCOREEN = PDM_PCFG_PDMCOREEN_EN;
620 
621     return AM_HAL_STATUS_SUCCESS;
622 }
623 
624 //*****************************************************************************
625 //
626 // Starts a DMA transaction from the PDM directly to SRAM
627 //
628 //*****************************************************************************
629 uint32_t
am_hal_pdm_dma_start(void * pHandle,am_hal_pdm_transfer_t * pDmaCfg)630 am_hal_pdm_dma_start(void *pHandle, am_hal_pdm_transfer_t *pDmaCfg)
631 {
632     uint32_t ui32Status = am_hal_dma_param_setup(pHandle, pDmaCfg);
633     if (ui32Status)
634     {
635         return ui32Status;
636     }
637 
638     return am_hal_dma_restart(pHandle);
639 }
640 
641 
642 //*****************************************************************************
643 //
644 // Flush the PDM FIFO
645 //
646 //*****************************************************************************
647 uint32_t
am_hal_pdm_fifo_flush(void * pHandle)648 am_hal_pdm_fifo_flush(void *pHandle)
649 {
650     AM_HAL_PDM_HANDLE_CHECK(pHandle);
651     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
652     uint32_t ui32Module = pState->ui32Module;
653 
654     PDMn(ui32Module)->FIFOFLUSH = 1;
655 
656     return AM_HAL_STATUS_SUCCESS;
657 }
658 
659 //*****************************************************************************
660 //
661 // Enable PDM passthrough to the I2S slave.
662 //
663 //*****************************************************************************
664 uint32_t
am_hal_pdm_i2s_enable(void * pHandle)665 am_hal_pdm_i2s_enable(void *pHandle)
666 {
667     AM_HAL_PDM_HANDLE_CHECK(pHandle);
668     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
669 
670     uint32_t ui32Module = pState->ui32Module;
671 
672     PDMn(ui32Module)->VCFG_b.I2SEN = PDM_VCFG_I2SEN_EN;
673 
674     return AM_HAL_STATUS_SUCCESS;
675 }
676 
677 //*****************************************************************************
678 //
679 // Disable PDM passthrough to the I2S slave.
680 //
681 //*****************************************************************************
682 uint32_t
am_hal_pdm_i2s_disable(void * pHandle)683 am_hal_pdm_i2s_disable(void *pHandle)
684 {
685     AM_HAL_PDM_HANDLE_CHECK(pHandle);
686     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
687     uint32_t ui32Module = pState->ui32Module;
688 
689     PDMn(ui32Module)->VCFG_b.I2SEN = PDM_VCFG_I2SEN_DIS;
690 
691     return AM_HAL_STATUS_SUCCESS;
692 }
693 //*****************************************************************************
694 //
695 // PDM interrupt service assistant, for dma transfers
696 //
697 //*****************************************************************************
am_hal_pdm_interrupt_service(void * pHandle,am_hal_interupt_service_msg_t * ptIsrData,am_hal_pdm_transfer_t * pTransferCfg)698 uint32_t am_hal_pdm_interrupt_service(void *pHandle,
699                                       am_hal_interupt_service_msg_t *ptIsrData,
700                                       am_hal_pdm_transfer_t *pTransferCfg)
701 {
702 
703     AM_HAL_PDM_HANDLE_CHECK(pHandle);
704 
705     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
706 
707     uint32_t ui32Module = pState->ui32Module;
708     uint32_t ui32Status = AM_HAL_STATUS_SUCCESS;
709 
710     PDM_Type *pPdm  = PDMn(ui32Module);
711 
712     uint32_t ui32IntStatus =  pPdm->INTSTAT;
713     ui32IntStatus &= pPdm->INTEN;  // apply interrupt mask
714     ptIsrData->isrStat = ui32IntStatus;
715     ptIsrData->dmaStat = pPdm->DMASTAT;
716 
717     if (ui32IntStatus & AM_HAL_PDM_INT_OVF)
718     {
719 
720 
721         uint32_t dmaCfg = pPdm->DMACFG;
722         // stop dma
723         pPdm->DMACFG_b.DMAEN = 0;
724 
725         //
726         // fifo overflow
727         //
728         pPdm->FIFOFLUSH = 1;
729 
730         //
731         // clear overflow status
732         //
733 
734         pPdm->INTCLR_b.OVF = 1;
735 
736         pPdm->DMACFG = dmaCfg;
737 
738         ui32Status = AM_HAL_STATUS_FAIL;
739     } // fifo overflow
740 
741     if ( ui32IntStatus & AM_HAL_PDM_INT_DERR)
742     {
743         //
744         // dma error
745         //
746         uint32_t dmaCfg = pPdm->DMACFG;
747         //
748         // stop dma
749         //
750         pPdm->DMACFG_b.DMAEN = 0;
751 
752         pPdm->DMASTAT = ptIsrData->dmaStat & 0x01;
753 
754         pPdm->INTCLR_b.DERR = 1;  // clear interrupt
755 
756         pPdm->DMACFG = dmaCfg;
757 
758         ui32Status = AM_HAL_STATUS_FAIL;
759     } // dma error
760 
761     if ( ui32IntStatus & AM_HAL_PDM_INT_UNDFL)
762     {
763         pPdm->INTCLR_b.UNDFL = 1;
764 
765     } // underflow
766 
767     if (ui32IntStatus & AM_HAL_PDM_INT_DCMP)
768     {
769         //
770         // dma complete
771         //
772 
773         //
774         // disable dma first
775         //
776         pPdm->DMACFG_b.DMAEN = PDM_DMACFG_DMAEN_DIS;
777 
778         //
779         // swap the buffer.
780         //
781         uint32_t currBuffer = pState->ui32BufferPtr;
782         pTransferCfg->ui32BufferWithDataAddr = pState->ui32BufferPtr;  // save address of buffer that has data
783 
784         pState->ui32BufferPtr = (currBuffer == pState->ui32BufferPong) ? pState->ui32BufferPing: pState->ui32BufferPong;
785 
786         pPdm->DMATARGADDR = pState->ui32BufferPtr ;
787         pPdm->DMATOTCOUNT = pTransferCfg->ui32TotalCount; // reset dma count
788 
789         pPdm->INTCLR_b.DCMP = 1; // clear interrupt
790 
791         if ( pTransferCfg->bRestartDMA)
792         {
793             //
794             // want continuous transfers, re-enable DMA
795             //
796             pPdm->DMACFG_b.DMAEN = PDM_DMACFG_DMAEN_EN;
797         }
798         else
799         {
800             //
801             // disable DMA (done above) and streaming
802             //
803             pPdm->PCFG_b.PDMCOREEN = 0 ;
804         }
805 
806     } // dma complete
807 
808 
809     return ui32Status;
810 }
811 
812 //*****************************************************************************
813 //
814 // Interrupt enable.
815 //
816 //*****************************************************************************
817 uint32_t
am_hal_pdm_interrupt_enable(void * pHandle,uint32_t ui32IntMask)818 am_hal_pdm_interrupt_enable(void *pHandle, uint32_t ui32IntMask)
819 {
820     //
821     // Check the handle.
822     //
823     AM_HAL_PDM_HANDLE_CHECK(pHandle);
824 
825     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
826     uint32_t ui32Module = pState->ui32Module;
827 
828     PDMn(ui32Module)->INTEN |= ui32IntMask;
829 
830     return AM_HAL_STATUS_SUCCESS;
831 }
832 
833 //*****************************************************************************
834 //
835 // Interrupt disable.
836 //
837 //*****************************************************************************
838 uint32_t
am_hal_pdm_interrupt_disable(void * pHandle,uint32_t ui32IntMask)839 am_hal_pdm_interrupt_disable(void *pHandle, uint32_t ui32IntMask)
840 {
841     //
842     // Check the handle.
843     //
844     AM_HAL_PDM_HANDLE_CHECK(pHandle);
845 
846     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
847     uint32_t ui32Module = pState->ui32Module;
848 
849     PDMn(ui32Module)->INTEN &= ~ui32IntMask;
850 
851     return AM_HAL_STATUS_SUCCESS;
852 }
853 
854 //*****************************************************************************
855 //
856 // Interrupt clear.
857 //
858 //*****************************************************************************
859 uint32_t
am_hal_pdm_interrupt_clear(void * pHandle,uint32_t ui32IntMask)860 am_hal_pdm_interrupt_clear(void *pHandle, uint32_t ui32IntMask)
861 {
862     //
863     // Check the handle.
864     //
865     AM_HAL_PDM_HANDLE_CHECK(pHandle);
866 
867     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
868     uint32_t ui32Module = pState->ui32Module;
869 
870     PDMn(ui32Module)->INTCLR = ui32IntMask;
871 
872     return AM_HAL_STATUS_SUCCESS;
873 }
874 
875 //*****************************************************************************
876 //
877 // Returns the interrupt status.
878 //
879 //*****************************************************************************
880 uint32_t
am_hal_pdm_interrupt_status_get(void * pHandle,uint32_t * pui32Status,bool bEnabledOnly)881 am_hal_pdm_interrupt_status_get(void *pHandle, uint32_t *pui32Status, bool bEnabledOnly)
882 {
883     //
884     // Check the handle.
885     //
886     AM_HAL_PDM_HANDLE_CHECK(pHandle);
887 
888     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
889     uint32_t ui32Module = pState->ui32Module;
890 
891     //
892     // If requested, only return the interrupts that are enabled.
893     //
894     if ( bEnabledOnly )
895     {
896         uint32_t ui32Status = PDMn(ui32Module)->INTSTAT;
897         *pui32Status = ui32Status & PDMn(ui32Module)->INTEN;
898     }
899     else
900     {
901         *pui32Status = PDMn(ui32Module)->INTSTAT;
902     }
903 
904     return AM_HAL_STATUS_SUCCESS;
905 }
906 
907 //*****************************************************************************
908 //
909 // Read the FIFO.
910 //
911 //*****************************************************************************
912 uint32_t
am_hal_pdm_fifo_data_read(void * pHandle)913 am_hal_pdm_fifo_data_read(void *pHandle)
914 {
915     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
916     uint32_t ui32Module = pState->ui32Module;
917 
918     return PDMn(ui32Module)->FIFOREAD;
919 }
920 
921 //*****************************************************************************
922 //
923 // Read the FIFOs.
924 //
925 //*****************************************************************************
am_hal_pdm_fifo_data_reads(void * pHandle,uint8_t * buffer,uint32_t size)926 uint32_t am_hal_pdm_fifo_data_reads(void *pHandle, uint8_t* buffer, uint32_t size)
927 {
928     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
929     uint32_t ui32Module = pState->ui32Module;
930 
931     uint32_t fiforead;
932 
933     uint8_t buf_size = 0;
934     for ( uint32_t i = 0; i < size; i++ )
935     {
936         {
937             fiforead = PDMn(ui32Module)->FIFOREAD; //left/right channel
938             buffer[buf_size++] = fiforead & 0xFF;
939             buffer[buf_size++] = (fiforead & 0xFF00)>>8;
940             buffer[buf_size++] = (fiforead & 0x00FF0000)>>16;
941         }
942     }
943 
944     return 0;
945 }
946 
947 //*****************************************************************************
948 //
949 // am_hal_pdm_fifo_count_get
950 //
951 //*****************************************************************************
am_hal_pdm_fifo_count_get(void * pHandle)952 uint32_t am_hal_pdm_fifo_count_get(void *pHandle)
953 {
954     // this is not available on apollo3
955     return 0;
956 }
957 
958 //*****************************************************************************
959 //
960 // am_hal_pdm_dma_state
961 //
962 //*****************************************************************************
am_hal_pdm_dma_state(void * pHandle)963 uint32_t am_hal_pdm_dma_state(void *pHandle)
964 {
965     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
966     uint32_t ui32Module = pState->ui32Module;
967 
968     return PDMn(ui32Module)->DMASTAT;
969 }
970 
971 //*****************************************************************************
972 //
973 // disable PDM DMA
974 //
975 //*****************************************************************************
976 uint32_t
am_hal_pdm_dma_disable(void * pHandle)977 am_hal_pdm_dma_disable(void *pHandle)
978 {
979     //
980     // Check the handle.
981     //
982     AM_HAL_PDM_HANDLE_CHECK(pHandle);
983     am_hal_pdm_state_t *pState = (am_hal_pdm_state_t *) pHandle;
984     uint32_t ui32Module = pState->ui32Module;
985 
986     //
987     // disable dma interrupts
988     //
989     PDMn(ui32Module)->INTEN &= ~(AM_HAL_PDM_INT_DERR | AM_HAL_PDM_INT_DCMP);
990 
991     //
992     // clear interrupts
993     //
994     PDMn(ui32Module)->INTCLR = (AM_HAL_PDM_INT_DERR | AM_HAL_PDM_INT_DCMP);
995 
996     PDMn(ui32Module)->DMATOTCOUNT = 0;
997 
998 
999     return AM_HAL_STATUS_SUCCESS;
1000 }
1001 
1002 // End Doxygen group.
1003 //! @}
1004 //
1005 //*****************************************************************************
1006