1 //*****************************************************************************
2 //
3 //! @file am_hal_pdm.h
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 #ifndef AM_HAL_PDM_H
49 #define AM_HAL_PDM_H
50 
51 #ifdef __cplusplus
52 extern "C"
53 {
54 #endif
55 
56 //*****************************************************************************
57 //
58 //! CMSIS-style macro for handling a variable IOS module number.
59 //
60 //*****************************************************************************
61 #define AM_REG_PDM_NUM_MODULES                       1
62 #define PDMn(n) ((PDM_Type*)(PDM_BASE + (n * (PDM_BASE - PDM_BASE))))
63 
64 //*****************************************************************************
65 //
66 //! DMA threshold minimum.
67 //!
68 //! The PDM DMA works best if its threshold value is set to a multiple of 4
69 //! between 16 and 24, but it will technically allow threshold settings between
70 //! 4 and 24. This macro sets the minimum threshold value that the HAL layer
71 //! will allow.
72 //
73 //*****************************************************************************
74 #define AM_HAL_PDM_DMA_THRESHOLD_MIN        16
75 
76 //*****************************************************************************
77 //
78 //! PDM-specific error conditions.
79 //
80 //*****************************************************************************
81 typedef enum
82 {
83     //
84     //! The PDM HAL will throw this error if it can't find a threshold value to
85     //! match the total-count value passed in by a caller requesting a DMA
86     //! transfer. The PDM hardware requires all DMA transactions to be evenly
87     //! divisible in chunks of one FIFO size or smaller. Try changing your
88     //! ui32TotalCount value to a more evenly divisible number.
89     //
90     AM_HAL_PDM_STATUS_BAD_TOTALCOUNT = AM_HAL_STATUS_MODULE_SPECIFIC_START,
91 }
92 am_hal_pdm_status_e;
93 
94 //*****************************************************************************
95 //
96 //! Gain settings.
97 //
98 //*****************************************************************************
99 typedef enum
100 {
101     AM_HAL_PDM_GAIN_P405DB = PDM_PCFG_PGALEFT_P405DB,
102     AM_HAL_PDM_GAIN_P390DB = PDM_PCFG_PGALEFT_P390DB,
103     AM_HAL_PDM_GAIN_P375DB = PDM_PCFG_PGALEFT_P375DB,
104     AM_HAL_PDM_GAIN_P360DB = PDM_PCFG_PGALEFT_P360DB,
105     AM_HAL_PDM_GAIN_P345DB = PDM_PCFG_PGALEFT_P345DB,
106     AM_HAL_PDM_GAIN_P330DB = PDM_PCFG_PGALEFT_P330DB,
107     AM_HAL_PDM_GAIN_P315DB = PDM_PCFG_PGALEFT_P315DB,
108     AM_HAL_PDM_GAIN_P300DB = PDM_PCFG_PGALEFT_P300DB,
109     AM_HAL_PDM_GAIN_P285DB = PDM_PCFG_PGALEFT_P285DB,
110     AM_HAL_PDM_GAIN_P270DB = PDM_PCFG_PGALEFT_P270DB,
111     AM_HAL_PDM_GAIN_P255DB = PDM_PCFG_PGALEFT_P255DB,
112     AM_HAL_PDM_GAIN_P240DB = PDM_PCFG_PGALEFT_P240DB,
113     AM_HAL_PDM_GAIN_P225DB = PDM_PCFG_PGALEFT_P225DB,
114     AM_HAL_PDM_GAIN_P210DB = PDM_PCFG_PGALEFT_P210DB,
115     AM_HAL_PDM_GAIN_P195DB = PDM_PCFG_PGALEFT_P195DB,
116     AM_HAL_PDM_GAIN_P180DB = PDM_PCFG_PGALEFT_P180DB,
117     AM_HAL_PDM_GAIN_P165DB = PDM_PCFG_PGALEFT_P165DB,
118     AM_HAL_PDM_GAIN_P150DB = PDM_PCFG_PGALEFT_P150DB,
119     AM_HAL_PDM_GAIN_P135DB = PDM_PCFG_PGALEFT_P135DB,
120     AM_HAL_PDM_GAIN_P120DB = PDM_PCFG_PGALEFT_P120DB,
121     AM_HAL_PDM_GAIN_P105DB = PDM_PCFG_PGALEFT_P105DB,
122     AM_HAL_PDM_GAIN_P90DB  = PDM_PCFG_PGALEFT_P90DB,
123     AM_HAL_PDM_GAIN_P75DB  = PDM_PCFG_PGALEFT_P75DB,
124     AM_HAL_PDM_GAIN_P60DB  = PDM_PCFG_PGALEFT_P60DB,
125     AM_HAL_PDM_GAIN_P45DB  = PDM_PCFG_PGALEFT_P45DB,
126     AM_HAL_PDM_GAIN_P30DB  = PDM_PCFG_PGALEFT_P30DB,
127     AM_HAL_PDM_GAIN_P15DB  = PDM_PCFG_PGALEFT_P15DB,
128     AM_HAL_PDM_GAIN_0DB    = PDM_PCFG_PGALEFT_0DB,
129     AM_HAL_PDM_GAIN_M15DB  = PDM_PCFG_PGALEFT_M15DB,
130     AM_HAL_PDM_GAIN_M300DB = PDM_PCFG_PGALEFT_M300DB,
131     AM_HAL_PDM_GAIN_M45DB  = PDM_PCFG_PGALEFT_M45DB,
132     AM_HAL_PDM_GAIN_M60DB  = PDM_PCFG_PGALEFT_M60DB,
133 }
134 am_hal_pdm_gain_e;
135 
136 //*****************************************************************************
137 //
138 //! Clock Source selection.
139 //
140 //*****************************************************************************
141 typedef enum
142 {
143     AM_HAL_PDM_INTERNAL_CLK = PDM_VCFG_SELAP_INTERNAL,
144     AM_HAL_PDM_I2S_CLK      = PDM_VCFG_SELAP_I2S,
145 }
146 am_hal_pdm_clksrc_e;
147 
148 //*****************************************************************************
149 //
150 //! PDM internal clock speed selection.
151 //
152 //*****************************************************************************
153 typedef enum
154 {
155     AM_HAL_PDM_CLK_DISABLE = PDM_VCFG_PDMCLKSEL_DISABLE,
156     AM_HAL_PDM_CLK_12MHZ   = PDM_VCFG_PDMCLKSEL_12MHz,
157     AM_HAL_PDM_CLK_6MHZ    = PDM_VCFG_PDMCLKSEL_6MHz,
158     AM_HAL_PDM_CLK_3MHZ    = PDM_VCFG_PDMCLKSEL_3MHz,
159     AM_HAL_PDM_CLK_1_5MHZ  = PDM_VCFG_PDMCLKSEL_1_5MHz,
160     AM_HAL_PDM_CLK_750KHZ  = PDM_VCFG_PDMCLKSEL_750KHz,
161     AM_HAL_PDM_CLK_375KHZ  = PDM_VCFG_PDMCLKSEL_375KHz,
162     AM_HAL_PDM_CLK_187KHZ  = PDM_VCFG_PDMCLKSEL_187KHz,
163 }
164 am_hal_pdm_clkspd_e;
165 
166 //*****************************************************************************
167 //
168 //! PDM clock divider setting.
169 //
170 //*****************************************************************************
171 typedef enum
172 {
173     AM_HAL_PDM_MCLKDIV_4 = PDM_PCFG_MCLKDIV_MCKDIV4,
174     AM_HAL_PDM_MCLKDIV_3 = PDM_PCFG_MCLKDIV_MCKDIV3,
175     AM_HAL_PDM_MCLKDIV_2 = PDM_PCFG_MCLKDIV_MCKDIV2,
176     AM_HAL_PDM_MCLKDIV_1 = PDM_PCFG_MCLKDIV_MCKDIV1,
177 }
178 am_hal_pdm_mclkdiv_e;
179 
180 //*****************************************************************************
181 //
182 //! PCM Channel Select.
183 //
184 //*****************************************************************************
185 typedef enum
186 {
187     AM_HAL_PDM_CHANNEL_LEFT   = PDM_VCFG_CHSET_LEFT,
188     AM_HAL_PDM_CHANNEL_RIGHT  = PDM_VCFG_CHSET_RIGHT,
189     AM_HAL_PDM_CHANNEL_STEREO = PDM_VCFG_CHSET_STEREO,
190 }
191 am_hal_pdm_chset_e;
192 
193 //*****************************************************************************
194 //
195 //! PDM power state settings.
196 //
197 //*****************************************************************************
198 #define AM_HAL_PDM_POWER_ON           AM_HAL_SYSCTRL_WAKE
199 #define AM_HAL_PDM_POWER_OFF          AM_HAL_SYSCTRL_NORMALSLEEP
200 
201 //*****************************************************************************
202 //
203 //! PDM interrupts.
204 //
205 //*****************************************************************************
206 #define AM_HAL_PDM_INT_DERR           PDM_INTSTAT_DERR_Msk
207 #define AM_HAL_PDM_INT_DCMP           PDM_INTSTAT_DCMP_Msk
208 #define AM_HAL_PDM_INT_UNDFL          PDM_INTSTAT_UNDFL_Msk
209 #define AM_HAL_PDM_INT_OVF            PDM_INTSTAT_OVF_Msk
210 #define AM_HAL_PDM_INT_THR            PDM_INTSTAT_THR_Msk
211 
212 //*****************************************************************************
213 //
214 //! Configuration structure for the PDM
215 //
216 //*****************************************************************************
217 typedef struct
218 {
219     //! Clock
220     am_hal_pdm_mclkdiv_e eClkDivider;
221 
222     //! Gain
223     am_hal_pdm_gain_e eLeftGain;
224     //! Gain
225     am_hal_pdm_gain_e eRightGain;
226 
227     //! Decimation Rate
228     uint32_t ui32DecimationRate;
229 
230     //! Filters
231     bool bHighPassEnable;
232     //! Filters
233     uint32_t ui32HighPassCutoff;
234 
235     //! PDMCLKSEL
236     am_hal_pdm_clkspd_e ePDMClkSpeed;
237 
238     //! BCLKINV
239     bool bInvertI2SBCLK;
240 
241     //! SELAP
242     am_hal_pdm_clksrc_e ePDMClkSource;
243 
244     //! DMICKDEL
245     bool bPDMSampleDelay;
246 
247     //! PCMPACK
248     bool bDataPacking;
249 
250     //! CHSET
251     am_hal_pdm_chset_e ePCMChannels;
252 
253     uint32_t ui32GainChangeDelay;
254 
255     bool bI2SEnable;
256 
257     bool bSoftMute;
258 
259     bool bLRSwap;
260 
261     bool bDoNotStartPdm;
262 }
263 am_hal_pdm_config_t;
264 
265 //*****************************************************************************
266 //
267 //! DMA transfer structure
268 //
269 //*****************************************************************************
270 typedef struct
271 {
272     uint32_t ui32TargetAddr;
273     //
274     //! second buffer when double buffering
275     //
276     uint32_t ui32TargetAddrReverse;
277 
278     //
279     //! when double buffering, if this is non zero, it is the addres
280     //! of the buffer with data
281     //! it should be zeroed once the data is read from the buffer
282     //
283     uint32_t ui32BufferWithDataAddr;
284 
285     //
286     //! number of byes for each DMA transfer
287     //
288     uint32_t ui32TotalCount;
289 
290     //
291     //! start DMA transfer in ISR to keep data flowing
292     //
293     volatile bool     bRestartDMA;
294 
295     uint8_t  align[3];  //! longword align struct
296 }
297 am_hal_pdm_transfer_t;
298 
299 typedef struct
300 {
301     uint32_t isrStat;
302     uint32_t dmaStat;
303 
304 }
305 am_hal_interupt_service_msg_t;
306 
307 
308 //*****************************************************************************
309 //
310 //! @brief Initialization function
311 //!
312 //! @param ui32Module
313 //! @param ppHandle
314 //! @return uint32_t
315 //
316 //*****************************************************************************
317 extern uint32_t am_hal_pdm_initialize(uint32_t ui32Module, void **ppHandle);
318 
319 //*****************************************************************************
320 //
321 //! @brief De-Initialization function
322 //!
323 //! @param pHandle
324 //! @return uint32_t
325 //
326 //*****************************************************************************
327 extern uint32_t am_hal_pdm_deinitialize(void *pHandle);
328 
329 //*****************************************************************************
330 //
331 //! @brief Power control function
332 //!
333 //! @param pHandle
334 //! @param ePowerState
335 //! @param bRetainState
336 //! @return uint32_t
337 //
338 //*****************************************************************************
339 extern uint32_t am_hal_pdm_power_control(void *pHandle, am_hal_sysctrl_power_state_e ePowerState, bool bRetainState);
340 
341 //*****************************************************************************
342 //
343 //! @brief Configure the PDM
344 //!
345 //! @param pHandle
346 //! @param psConfig
347 //! @return uint32_t
348 //
349 //*****************************************************************************
350 extern uint32_t am_hal_pdm_configure(void *pHandle, const am_hal_pdm_config_t *psConfig);
351 
352 // Enable/Disable
353 //*****************************************************************************
354 //
355 //! @brief Enable the PDM
356 //!
357 //! @param pHandle
358 //! @return uint32_t
359 //
360 //*****************************************************************************
361 extern uint32_t am_hal_pdm_enable(void *pHandle);
362 
363 //*****************************************************************************
364 //
365 //! @brief Disable the PDM
366 //!
367 //! @param pHandle
368 //! @return uint32_t
369 //
370 //*****************************************************************************
371 extern uint32_t am_hal_pdm_disable(void *pHandle);
372 
373 
374 //*****************************************************************************
375 //
376 //! @brief  setup dma parameters,
377 //! this will not start a DMA transfer
378 //!
379 //! @param pHandle
380 //!
381 //! @return
382 //
383 //*****************************************************************************
384 extern uint32_t am_hal_dma_param_setup(void *pHandle, am_hal_pdm_transfer_t *pDmaCfg);
385 
386 //*****************************************************************************
387 //
388 //! @brief  start dma with perviously setup parameters
389 //!
390 //! @param pHandle
391 //!
392 //! @return
393 //
394 //*****************************************************************************
395 extern uint32_t am_hal_dma_restart(void *pHandle);
396 //*****************************************************************************
397 //
398 //! @brief Setup and start a DMA transaction from the PDM directly to SRAM
399 //!
400 //! @param pHandle
401 //! @param pDmaCfg  DMA config params
402 //! @return uint32_t
403 //
404 //*****************************************************************************
405 extern uint32_t am_hal_pdm_dma_start(void *pHandle, am_hal_pdm_transfer_t *pDmaCfg);
406 //*****************************************************************************
407 //
408 //! @brief Set FIFOTHR Value
409 //!
410 //! @param pHandle - handle for the interface.
411 //! @param value   - value for the threshold.
412 //!
413 //! @return AM_HAL_STATUS_SUCCESS
414 //
415 //*****************************************************************************
416 uint32_t am_hal_pdm_fifo_threshold_setup(void *pHandle, uint32_t value);
417 
418 //*****************************************************************************
419 //
420 //! @brief PDM DMA Get Buffer
421 //!
422 //! @param pHandle - handle for the interface.
423 //!
424 //! @return Pointer to the DMA Buffer
425 //
426 //*****************************************************************************
427 extern uint32_t am_hal_pdm_dma_get_buffer(void *pHandle);
428 
429 //*****************************************************************************
430 
431 //*****************************************************************************
432 //
433 //! @brief Flush the PDM FIFO
434 //!
435 //! @param pHandle
436 //! @return uint32_t
437 //
438 //*****************************************************************************
439 extern uint32_t am_hal_pdm_fifo_flush(void *pHandle);
440 
441 //*****************************************************************************
442 //
443 //! @brief Enable PDM passthrough to the I2S slave.
444 //!
445 //! @param pHandle
446 //! @return uint32_t
447 //
448 //*****************************************************************************
449 extern uint32_t am_hal_pdm_i2s_enable(void *pHandle);
450 
451 //*****************************************************************************
452 //
453 //! @brief Disable PDM passthrough to the I2S slave.
454 //!
455 //! @param pHandle
456 //! @return uint32_t
457 //
458 //*****************************************************************************
459 extern uint32_t am_hal_pdm_i2s_disable(void *pHandle);
460 
461 //*****************************************************************************
462 //
463 //! @brief Interrupt enable
464 //!
465 //! @param pHandle
466 //! @param ui32IntMask
467 //! @return uint32_t
468 //
469 //*****************************************************************************
470 extern uint32_t am_hal_pdm_interrupt_enable(void *pHandle, uint32_t ui32IntMask);
471 
472 //*****************************************************************************
473 //
474 //! @brief Interrupt disable
475 //!
476 //! @param pHandle
477 //! @param ui32IntMask
478 //! @return uint32_t
479 //
480 //*****************************************************************************
481 extern uint32_t am_hal_pdm_interrupt_disable(void *pHandle, uint32_t ui32IntMask);
482 
483 //*****************************************************************************
484 //
485 //! @brief Interrupt clear
486 //!
487 //! @param pHandle
488 //! @param ui32IntMask
489 //! @return uint32_t
490 //
491 //*****************************************************************************
492 extern uint32_t am_hal_pdm_interrupt_clear(void *pHandle, uint32_t ui32IntMask);
493 
494 //*****************************************************************************
495 //
496 //! @brief Returns the interrupt status
497 //!
498 //! @param pHandle
499 //! @param pui32Status
500 //! @param bEnabledOnly
501 //! @return uint32_t
502 //
503 //*****************************************************************************
504 extern uint32_t am_hal_pdm_interrupt_status_get(void *pHandle, uint32_t *pui32Status, bool bEnabledOnly);
505 
506 //*****************************************************************************
507 //
508 //! @brief PDM Interrupt Service Routine
509 //!
510 //! @details This is called from an ISR, this will manage
511 //! double buffered PDM dma transfers
512 //!
513 //! @param pHandle     - handle for the module instance.
514 //! @param ptIsrData   - returns module status
515 //! @param pTransferCfg    - Pointer to the PDM Config
516 //!
517 //! @return AM_HAL_STATUS_SUCCESS
518 //
519 //*****************************************************************************
520 extern uint32_t am_hal_pdm_interrupt_service(void *pHandle,
521                     am_hal_interupt_service_msg_t *ptIsrData,
522                     am_hal_pdm_transfer_t* pTransferCfg);
523 
524 
525 
526 #ifdef __cplusplus
527 }
528 #endif
529 
530 #endif // AM_HAL_PDM_H
531 
532 //*****************************************************************************
533 //
534 // End Doxygen group.
535 //! @}
536 //
537 //*****************************************************************************
538