1 //*****************************************************************************
2 //
3 //! @file am_hal_pdm.c
4 //!
5 //! @brief HAL implementation for the PDM module.
6 //!
7 //! @addtogroup pdm3 PDM - Pulse Density Modulated Functions
8 //! @ingroup apollo3_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 //! @note In apollo3 it has been observed there may be buffer overruns if DMAPRI is not set. (DMA does not stop correctly)
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