1 /*
2  * Copyright (c) 2018, Freescale Semiconductor, Inc.
3  * Copyright 2019-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_pdm.h"
10 /* Component ID definition, used by tools. */
11 #ifndef FSL_COMPONENT_ID
12 #define FSL_COMPONENT_ID "platform.drivers.pdm"
13 #endif
14 
15 /*******************************************************************************
16  * Definitations
17  ******************************************************************************/
18 /*! @brief Typedef for pdm rx interrupt handler. */
19 typedef void (*pdm_isr_t)(PDM_Type *base, pdm_handle_t *pdmHandle);
20 /*******************************************************************************
21  * Prototypes
22  ******************************************************************************/
23 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
24 /*!
25  * @brief Get the instance number for PDM.
26  *
27  * @param channelMask enabled channel.
28  * @param qualitymode selected quality mode.
29  * @param osr      oversample rate.
30  * @param regdiv   register divider.
31  */
32 static status_t PDM_ValidateSrcClockRate(uint32_t channelMask,
33                                          pdm_df_quality_mode_t qualityMode,
34                                          uint8_t osr,
35                                          uint32_t regDiv);
36 #endif
37 
38 /*******************************************************************************
39  * Variables
40  ******************************************************************************/
41 /* Base pointer array */
42 static PDM_Type *const s_pdmBases[] = PDM_BASE_PTRS;
43 /*!@brief PDM handle pointer */
44 static pdm_handle_t *s_pdmHandle[ARRAY_SIZE(s_pdmBases)];
45 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
46 /* Clock name array */
47 static const clock_ip_name_t s_pdmClock[] = PDM_CLOCKS;
48 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
49 
50 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
51 #if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
52 /* Clock name array */
53 static const clock_ip_name_t s_pdmFilterClock[] = PDM_FILTER_CLOCKS;
54 #endif
55 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
56 
57 /*! @brief Pointer to tx IRQ handler for each instance. */
58 static pdm_isr_t s_pdmIsr;
59 #if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
60 /*! @brief callback for hwvad. */
61 static pdm_hwvad_notification_t s_pdm_hwvad_notification[ARRAY_SIZE(s_pdmBases)];
62 #endif
63 /*******************************************************************************
64  * Code
65  ******************************************************************************/
PDM_GetInstance(PDM_Type * base)66 uint32_t PDM_GetInstance(PDM_Type *base)
67 {
68     uint32_t instance;
69 
70     /* Find the instance index from base address mappings. */
71     for (instance = 0; instance < ARRAY_SIZE(s_pdmBases); instance++)
72     {
73         if (s_pdmBases[instance] == base)
74         {
75             break;
76         }
77     }
78 
79     assert(instance < ARRAY_SIZE(s_pdmBases));
80 
81     return instance;
82 }
83 
84 /*!
85  * brief PDM read fifo.
86  * Note: This function support 16 bit only for IP version that only supports 16bit.
87  *
88  * param base PDM base pointer.
89  * param startChannel start channel number.
90  * param channelNums total enabled channelnums.
91  * param buffer received buffer address.
92  * param size number of samples to read.
93  * param dataWidth sample width.
94  */
PDM_ReadFifo(PDM_Type * base,uint32_t startChannel,uint32_t channelNums,void * buffer,size_t size,uint32_t dataWidth)95 void PDM_ReadFifo(
96     PDM_Type *base, uint32_t startChannel, uint32_t channelNums, void *buffer, size_t size, uint32_t dataWidth)
97 {
98     uint32_t i = 0, j = 0U;
99     uint32_t *dataAddr = (uint32_t *)buffer;
100 
101     for (i = 0U; i < size; i++)
102     {
103         for (j = 0; j < channelNums; j++)
104         {
105 #if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH != 2U)
106             *dataAddr = base->DATACH[startChannel + j] >> (dataWidth == 4U ? 0U : 8U);
107             dataAddr  = (uint32_t *)((uint32_t)dataAddr + dataWidth);
108 #else
109             *dataAddr = base->DATACH[startChannel + j];
110             dataAddr  = (uint32_t *)((uint32_t)dataAddr + 2U);
111 #endif
112         }
113     }
114 }
115 
116 #if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 2U)
117 /*!
118  * brief PDM read data non blocking, only support 16bit data read.
119  * So the actually read data byte size in this function is (size * 2 * channelNums).
120  * param base PDM base pointer.
121  * param startChannel start channel number.
122  * param channelNums total enabled channelnums.
123  * param buffer received buffer address.
124  * param size number of 16bit data to read.
125  */
PDM_ReadNonBlocking(PDM_Type * base,uint32_t startChannel,uint32_t channelNums,int16_t * buffer,size_t size)126 void PDM_ReadNonBlocking(PDM_Type *base, uint32_t startChannel, uint32_t channelNums, int16_t *buffer, size_t size)
127 {
128     uint32_t i = 0, j = 0U;
129 
130     for (i = 0U; i < size; i++)
131     {
132         for (j = 0; j < channelNums; j++)
133         {
134             *buffer++ = (int16_t)base->DATACH[startChannel + j];
135         }
136     }
137 }
138 #endif
139 
140 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
PDM_ValidateSrcClockRate(uint32_t channelMask,pdm_df_quality_mode_t qualityMode,uint8_t osr,uint32_t regDiv)141 static status_t PDM_ValidateSrcClockRate(uint32_t channelMask,
142                                          pdm_df_quality_mode_t qualityMode,
143                                          uint8_t osr,
144                                          uint32_t regDiv)
145 {
146     uint32_t enabledChannel = 0U, i = 0U, factor = 0U, k = 0U;
147 
148     for (i = 0U; i < (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM; i++)
149     {
150         if (((channelMask >> i) & 0x01U) != 0U)
151         {
152             enabledChannel++;
153         }
154     }
155 
156     switch (qualityMode)
157     {
158         case kPDM_QualityModeMedium:
159             factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
160             k      = 2U;
161             break;
162 
163         case kPDM_QualityModeHigh:
164             factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
165             k      = 1U;
166             break;
167 
168         case kPDM_QualityModeLow:
169             factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
170             k      = 4U;
171             break;
172 
173         case kPDM_QualityModeVeryLow0:
174             factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
175             k      = 2U;
176             break;
177 
178         case kPDM_QualityModeVeryLow1:
179             factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
180             k      = 4U;
181             break;
182 
183         case kPDM_QualityModeVeryLow2:
184             factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
185             k      = 8U;
186             break;
187 
188         default:
189             assert(false);
190             break;
191     }
192 
193     /* validate the minimum clock divider */
194     /* 2U is for canculating k, 100U is for determing the specific float number of clock divider */
195     if (((regDiv * k) / 2U * 100U) < (((10U + factor * enabledChannel) * 100U / (8U * osr)) * k / 2U))
196     {
197         return kStatus_Fail;
198     }
199 
200     return kStatus_Success;
201 }
202 #endif
203 
204 /*!
205  * brief PDM set sample rate.
206  *
207  * note This function is depend on the configuration of the PDM and PDM channel, so the correct call sequence is
208  * code
209  * PDM_Init(base, pdmConfig)
210  * PDM_SetChannelConfig(base, channel, &channelConfig)
211  * PDM_SetSampleRateConfig(base, source, sampleRate)
212  * endcode
213  * param base PDM base pointer
214  * param sourceClock_HZ PDM source clock frequency.
215  * param sampleRate_HZ PDM sample rate.
216  */
PDM_SetSampleRateConfig(PDM_Type * base,uint32_t sourceClock_HZ,uint32_t sampleRate_HZ)217 status_t PDM_SetSampleRateConfig(PDM_Type *base, uint32_t sourceClock_HZ, uint32_t sampleRate_HZ)
218 {
219     uint32_t osr = (base->CTRL_2 & PDM_CTRL_2_CICOSR_MASK) >> PDM_CTRL_2_CICOSR_SHIFT;
220 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
221     pdm_df_quality_mode_t qualityMode =
222         (pdm_df_quality_mode_t)(uint32_t)((base->CTRL_2 & PDM_CTRL_2_QSEL_MASK) >> PDM_CTRL_2_QSEL_SHIFT);
223     uint32_t enabledChannelMask = base->CTRL_1 & (uint32_t)kPDM_EnableChannelAll;
224 #endif
225 
226     uint32_t pdmClockRate = 0U;
227     uint32_t regDiv       = 0U;
228 
229     /* get divider */
230     osr          = 16U - osr;
231     pdmClockRate = sampleRate_HZ * osr * 8U;
232     regDiv       = sourceClock_HZ / pdmClockRate;
233 
234     if (regDiv > PDM_CTRL_2_CLKDIV_MASK)
235     {
236         return kStatus_Fail;
237     }
238 
239 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
240     if (PDM_ValidateSrcClockRate(enabledChannelMask, qualityMode, (uint8_t)osr, regDiv) == kStatus_Fail)
241     {
242         return kStatus_Fail;
243     }
244 #endif
245 
246     base->CTRL_2 = (base->CTRL_2 & (~PDM_CTRL_2_CLKDIV_MASK)) | PDM_CTRL_2_CLKDIV(regDiv);
247 
248     return kStatus_Success;
249 }
250 
251 /*!
252  * brief PDM set sample rate.
253  *
254  * deprecated Do not use this function.  It has been superceded by @ref PDM_SetSampleRateConfig
255  * param base PDM base pointer
256  * param enableChannelMask PDM channel enable mask.
257  * param qualityMode quality mode.
258  * param osr cic oversample rate
259  * param clkDiv clock divider
260  */
PDM_SetSampleRate(PDM_Type * base,uint32_t enableChannelMask,pdm_df_quality_mode_t qualityMode,uint8_t osr,uint32_t clkDiv)261 status_t PDM_SetSampleRate(
262     PDM_Type *base, uint32_t enableChannelMask, pdm_df_quality_mode_t qualityMode, uint8_t osr, uint32_t clkDiv)
263 {
264 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
265     uint8_t realOsr = 16U - (osr & (PDM_CTRL_2_CICOSR_MASK >> PDM_CTRL_2_CICOSR_SHIFT));
266 #endif
267     uint32_t regDiv = clkDiv >> 1U;
268 
269     switch (qualityMode)
270     {
271         case kPDM_QualityModeHigh:
272             regDiv <<= 1U;
273             break;
274         case kPDM_QualityModeLow:
275         case kPDM_QualityModeVeryLow1:
276             regDiv >>= 1U;
277             break;
278         case kPDM_QualityModeVeryLow2:
279             regDiv >>= 2U;
280             break;
281         default:
282             assert(false);
283             break;
284     }
285 
286 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
287     if (PDM_ValidateSrcClockRate(enableChannelMask, qualityMode, realOsr, regDiv) == kStatus_Fail)
288     {
289         return kStatus_Fail;
290     }
291 #endif
292 
293     assert(regDiv <= PDM_CTRL_2_CLKDIV_MASK);
294     base->CTRL_2 = (base->CTRL_2 & (~PDM_CTRL_2_CLKDIV_MASK)) | PDM_CTRL_2_CLKDIV(regDiv);
295 
296     return kStatus_Success;
297 }
298 
299 /*!
300  * brief Initializes the PDM peripheral.
301  *
302  * Ungates the PDM clock, resets the module, and configures PDM with a configuration structure.
303  * The configuration structure can be custom filled or set with default values by
304  * PDM_GetDefaultConfig().
305  *
306  * note  This API should be called at the beginning of the application to use
307  * the PDM driver. Otherwise, accessing the PDM module can cause a hard fault
308  * because the clock is not enabled.
309  *
310  * param base PDM base pointer
311  * param config PDM configuration structure.
312  */
PDM_Init(PDM_Type * base,const pdm_config_t * config)313 void PDM_Init(PDM_Type *base, const pdm_config_t *config)
314 {
315     assert(config != NULL);
316     assert(config->fifoWatermark <= PDM_FIFO_CTRL_FIFOWMK_MASK);
317 
318 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
319     /* Enable the PDM clock */
320     CLOCK_EnableClock(s_pdmClock[PDM_GetInstance(base)]);
321 #if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
322     CLOCK_EnableClock(s_pdmFilterClock[PDM_GetInstance(base)]);
323 #endif
324 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
325 
326     /* Enable the module and disable the interface/all channel */
327     base->CTRL_1 &=
328         ~(PDM_CTRL_1_MDIS_MASK | PDM_CTRL_1_PDMIEN_MASK | PDM_CTRL_1_ERREN_MASK | (uint32_t)kPDM_EnableChannelAll);
329 
330     /* wait all filter stopped */
331     while ((base->STAT & PDM_STAT_BSY_FIL_MASK) != 0U)
332     {
333     }
334 
335     /* software reset */
336     base->CTRL_1 |= PDM_CTRL_1_SRES_MASK;
337 
338     /* Set the configure settings */
339     base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DOZEN_MASK)) | PDM_CTRL_1_DOZEN(config->enableDoze);
340 
341     base->CTRL_2 = (base->CTRL_2 & (~(PDM_CTRL_2_CICOSR_MASK | PDM_CTRL_2_QSEL_MASK))) |
342                    PDM_CTRL_2_CICOSR(config->cicOverSampleRate) | PDM_CTRL_2_QSEL(config->qualityMode);
343 
344     /* Set the watermark */
345     base->FIFO_CTRL = PDM_FIFO_CTRL_FIFOWMK(config->fifoWatermark);
346 }
347 
348 /*!
349  * brief De-initializes the PDM peripheral.
350  *
351  * This API gates the PDM clock. The PDM module can't operate unless PDM_Init
352  * is called to enable the clock.
353  *
354  * param base PDM base pointer
355  */
PDM_Deinit(PDM_Type * base)356 void PDM_Deinit(PDM_Type *base)
357 {
358     /* disable PDM interface */
359     PDM_Enable(base, false);
360 
361 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
362     CLOCK_DisableClock(s_pdmClock[PDM_GetInstance(base)]);
363 #if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
364     CLOCK_DisableClock(s_pdmFilterClock[PDM_GetInstance(base)]);
365 #endif
366 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
367 }
368 
369 /*!
370  * brief Enables the PDM interrupt requests.
371  *
372  * param base PDM base pointer
373  * param mask interrupt source
374  *     The parameter can be a combination of the following sources if defined.
375  *     arg kPDM_ErrorInterruptEnable
376  *     arg kPDM_FIFOInterruptEnable
377  */
PDM_EnableInterrupts(PDM_Type * base,uint32_t mask)378 void PDM_EnableInterrupts(PDM_Type *base, uint32_t mask)
379 {
380     if ((mask & (uint32_t)kPDM_FIFOInterruptEnable) != 0U)
381     {
382         base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DISEL_MASK)) | (uint32_t)kPDM_FIFOInterruptEnable;
383     }
384     if ((mask & (uint32_t)kPDM_ErrorInterruptEnable) != 0U)
385     {
386         base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_ERREN_MASK)) | (uint32_t)kPDM_ErrorInterruptEnable;
387     }
388 }
389 
390 /*!
391  * brief PDM one channel configurations.
392  *
393  * param base PDM base pointer
394  * param config PDM channel configurations.
395  * param channel channel number.
396  * after completing the current frame in debug mode.
397  */
PDM_SetChannelConfig(PDM_Type * base,uint32_t channel,const pdm_channel_config_t * config)398 void PDM_SetChannelConfig(PDM_Type *base, uint32_t channel, const pdm_channel_config_t *config)
399 {
400     assert(config != NULL);
401     assert(channel <= (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
402 
403     uint32_t dcCtrl = 0U;
404 
405 #if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
406     dcCtrl = base->DC_OUT_CTRL;
407     /* configure gain and cut off freq */
408     dcCtrl &= ~((uint32_t)PDM_DC_OUT_CTRL_DCCONFIG0_MASK << (channel << 1U));
409     dcCtrl |= (uint32_t)config->outputCutOffFreq << (channel << 1U);
410     base->DC_OUT_CTRL = dcCtrl;
411 #endif
412 
413 #if !(defined(FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED) && (FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED))
414     dcCtrl = base->DC_CTRL;
415     /* configure gain and cut off freq */
416     dcCtrl &= ~((uint32_t)PDM_DC_CTRL_DCCONFIG0_MASK << (channel << 1U));
417     dcCtrl |= (uint32_t)config->cutOffFreq << (channel << 1U);
418     base->DC_CTRL = dcCtrl;
419 #endif
420 
421     PDM_SetChannelGain(base, channel, config->gain);
422 
423     /* enable channel */
424     base->CTRL_1 |= 1UL << channel;
425 }
426 
427 /*!
428  * brief Set the PDM channel gain.
429  *
430  * Please note for different quality mode, the valid gain value is different, reference RM for detail.
431  * param base PDM base pointer.
432  * param channel PDM channel index.
433  * param gain channel gain, the register gain value range is 0 - 15.
434  */
PDM_SetChannelGain(PDM_Type * base,uint32_t channel,pdm_df_output_gain_t gain)435 void PDM_SetChannelGain(PDM_Type *base, uint32_t channel, pdm_df_output_gain_t gain)
436 {
437     assert(channel <= (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
438 
439 #if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
440     uint32_t outCtrl = base->RANGE_CTRL;
441 #else
442     uint32_t outCtrl = base->OUT_CTRL;
443 #endif
444 
445 #if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
446     outCtrl &= ~((uint32_t)PDM_RANGE_CTRL_RANGEADJ0_MASK << (channel << 2U));
447 #else
448     outCtrl &= ~((uint32_t)PDM_OUT_CTRL_OUTGAIN0_MASK << (channel << 2U));
449 #endif
450 
451     outCtrl |= (uint32_t)gain << (channel << 2U);
452 
453 #if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
454     base->RANGE_CTRL = outCtrl;
455 #else
456     base->OUT_CTRL = outCtrl;
457 #endif
458 }
459 
460 /*!
461  * brief PDM set channel transfer config.
462  *
463  * param base PDM base pointer.
464  * param handle PDM handle pointer.
465  * param channel PDM channel.
466  * param config channel config.
467  * param format data format.
468  */
PDM_TransferSetChannelConfig(PDM_Type * base,pdm_handle_t * handle,uint32_t channel,const pdm_channel_config_t * config,uint32_t format)469 status_t PDM_TransferSetChannelConfig(
470     PDM_Type *base, pdm_handle_t *handle, uint32_t channel, const pdm_channel_config_t *config, uint32_t format)
471 {
472     assert(handle != NULL);
473 
474     PDM_SetChannelConfig(base, channel, config);
475 
476     handle->format = format;
477 
478     if (handle->channelNums == 0U)
479     {
480         handle->startChannel = (uint8_t)channel;
481     }
482 
483     handle->channelNums++;
484 
485     if (handle->channelNums > (uint8_t)FSL_FEATURE_PDM_CHANNEL_NUM)
486     {
487         return kStatus_PDM_ChannelConfig_Failed;
488     }
489 
490     return kStatus_Success;
491 }
492 
493 /*!
494  * brief Initializes the PDM handle.
495  *
496  * This function initializes the handle for the PDM transactional APIs. Call
497  * this function once to get the handle initialized.
498  *
499  * param base PDM base pointer.
500  * param handle PDM handle pointer.
501  * param callback Pointer to the user callback function.
502  * param userData User parameter passed to the callback function.
503  */
PDM_TransferCreateHandle(PDM_Type * base,pdm_handle_t * handle,pdm_transfer_callback_t callback,void * userData)504 void PDM_TransferCreateHandle(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_callback_t callback, void *userData)
505 {
506     assert(handle != NULL);
507 
508     /* Zero the handle */
509     (void)memset(handle, 0, sizeof(*handle));
510 
511     s_pdmHandle[PDM_GetInstance(base)] = handle;
512 
513     handle->callback  = callback;
514     handle->userData  = userData;
515     handle->watermark = (uint8_t)(base->FIFO_CTRL & PDM_FIFO_CTRL_FIFOWMK_MASK);
516 
517     /* Set the isr pointer */
518     s_pdmIsr = PDM_TransferHandleIRQ;
519 
520     /* Enable RX event IRQ */
521     (void)EnableIRQ(PDM_EVENT_IRQn);
522 #if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
523     /* Enable FIFO error IRQ */
524     (void)EnableIRQ(PDM_ERROR_IRQn);
525 #endif
526 }
527 
528 /*!
529  * brief Performs an interrupt non-blocking receive transfer on PDM.
530  *
531  * note This API returns immediately after the transfer initiates.
532  * Call the PDM_RxGetTransferStatusIRQ to poll the transfer status and check whether
533  * the transfer is finished. If the return status is not kStatus_PDM_Busy, the transfer
534  * is finished.
535  *
536  * param base PDM base pointer
537  * param handle Pointer to the pdm_handle_t structure which stores the transfer state.
538  * param xfer Pointer to the pdm_transfer_t structure.
539  * retval kStatus_Success Successfully started the data receive.
540  * retval kStatus_PDM_Busy Previous receive still not finished.
541  */
PDM_TransferReceiveNonBlocking(PDM_Type * base,pdm_handle_t * handle,pdm_transfer_t * xfer)542 status_t PDM_TransferReceiveNonBlocking(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_t *xfer)
543 {
544     assert(handle != NULL);
545 
546     /* Check if the queue is full */
547     if (handle->pdmQueue[handle->queueUser].data != NULL)
548     {
549         return kStatus_PDM_QueueFull;
550     }
551 
552     /* Add into queue */
553     handle->transferSize[handle->queueUser]      = xfer->dataSize;
554     handle->pdmQueue[handle->queueUser].data     = xfer->data;
555     handle->pdmQueue[handle->queueUser].dataSize = xfer->dataSize;
556     handle->queueUser                            = (handle->queueUser + 1U) % PDM_XFER_QUEUE_SIZE;
557 
558     /* Set state to busy */
559     handle->state = kStatus_PDM_Busy;
560 
561     /* Enable interrupt */
562     PDM_EnableInterrupts(base, (uint32_t)kPDM_FIFOInterruptEnable);
563 
564     PDM_Enable(base, true);
565 
566     return kStatus_Success;
567 }
568 
569 /*!
570  * brief Aborts the current IRQ receive.
571  *
572  * note This API can be called when an interrupt non-blocking transfer initiates
573  * to abort the transfer early.
574  *
575  * param base PDM base pointer
576  * param handle Pointer to the pdm_handle_t structure which stores the transfer state.
577  */
PDM_TransferAbortReceive(PDM_Type * base,pdm_handle_t * handle)578 void PDM_TransferAbortReceive(PDM_Type *base, pdm_handle_t *handle)
579 {
580     assert(handle != NULL);
581 
582     /* Use FIFO request interrupt and fifo error */
583     PDM_DisableInterrupts(base, (uint32_t)kPDM_FIFOInterruptEnable | (uint32_t)kPDM_ErrorInterruptEnable);
584     PDM_Enable(base, false);
585     handle->state = kStatus_PDM_Idle;
586     /* Clear the queue */
587     (void)memset(handle->pdmQueue, 0, sizeof(pdm_transfer_t) * PDM_XFER_QUEUE_SIZE);
588     handle->queueDriver = 0;
589     handle->queueUser   = 0;
590 }
591 
592 /*!
593  * brief Tx interrupt handler.
594  *
595  * param base PDM base pointer.
596  * param handle Pointer to the pdm_handle_t structure.
597  */
PDM_TransferHandleIRQ(PDM_Type * base,pdm_handle_t * handle)598 void PDM_TransferHandleIRQ(PDM_Type *base, pdm_handle_t *handle)
599 {
600     assert(handle != NULL);
601 
602 #if (defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
603     uint32_t status = 0U;
604 
605 #if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
606     if (PDM_GetStatus(base) & PDM_STAT_LOWFREQF_MASK)
607     {
608         PDM_ClearStatus(base, PDM_STAT_LOWFREQF_MASK);
609         if (handle->callback != NULL)
610         {
611             (handle->callback)(base, handle, kStatus_PDM_CLK_LOW, handle->userData);
612         }
613     }
614 #endif
615     status = PDM_GetFifoStatus(base);
616     if (status != 0U)
617     {
618         PDM_ClearFIFOStatus(base, status);
619         if (handle->callback != NULL)
620         {
621             (handle->callback)(base, handle, kStatus_PDM_FIFO_ERROR, handle->userData);
622         }
623     }
624 
625 #if !(defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL)
626     status = PDM_GetOutputStatus(base);
627     if (status != 0U)
628     {
629         PDM_ClearOutputStatus(base, status);
630         if (handle->callback != NULL)
631         {
632             (handle->callback)(base, handle, kStatus_PDM_Output_ERROR, handle->userData);
633         }
634     }
635 #endif
636 #endif
637 
638     /* Handle transfer */
639     if (((base->STAT & 0xFFU) != 0U) && (handle->channelNums != 0U) &&
640         ((base->CTRL_1 & PDM_CTRL_1_DISEL_MASK) == (0x2UL << PDM_CTRL_1_DISEL_SHIFT)))
641     {
642         PDM_ClearStatus(base, 0xFFU);
643         /* Judge if the data need to transmit is less than space */
644         uint8_t size = (uint8_t)MIN((handle->pdmQueue[handle->queueDriver].dataSize),
645                                     ((uint32_t)handle->watermark * handle->channelNums * handle->format));
646 
647         PDM_ReadFifo(base, handle->startChannel, handle->channelNums,
648                      (uint8_t *)(uint32_t)handle->pdmQueue[handle->queueDriver].data,
649                      ((size_t)size / handle->channelNums / handle->format), handle->format);
650 
651         /* Update the internal counter */
652         handle->pdmQueue[handle->queueDriver].dataSize -= size;
653         handle->pdmQueue[handle->queueDriver].data = &(handle->pdmQueue[handle->queueDriver].data[size]);
654     }
655 
656     /* If finished a block, call the callback function */
657     if (handle->pdmQueue[handle->queueDriver].dataSize == 0U)
658     {
659         handle->pdmQueue[handle->queueDriver].data = NULL;
660         handle->queueDriver                        = (handle->queueDriver + 1U) % PDM_XFER_QUEUE_SIZE;
661         if (handle->callback != NULL)
662         {
663             (handle->callback)(base, handle, kStatus_PDM_Idle, handle->userData);
664         }
665     }
666 
667     /* If all data finished, just stop the transfer */
668     if (handle->pdmQueue[handle->queueDriver].data == NULL)
669     {
670         PDM_TransferAbortReceive(base, handle);
671     }
672 }
673 
674 #if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
675 /*!
676  * brief set HWVAD in envelope based mode .
677  * Recommand configurations,
678  * code
679  * static const pdm_hwvad_config_t hwvadConfig = {
680  *   .channel           = 0,
681  *   .initializeTime    = 10U,
682  *   .cicOverSampleRate = 0U,
683  *   .inputGain         = 0U,
684  *   .frameTime         = 10U,
685  *   .cutOffFreq        = kPDM_HwvadHpfBypassed,
686  *   .enableFrameEnergy = false,
687  *   .enablePreFilter   = true,
688 };
689 
690  * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
691  *   .enableAutoNoiseFilter = false,
692  *   .enableNoiseMin        = true,
693  *   .enableNoiseDecimation = true,
694  *   .noiseFilterAdjustment = 0U,
695  *   .noiseGain             = 7U,
696  *   .enableNoiseDetectOR   = true,
697  * };
698  * code
699  * param base PDM base pointer.
700  * param hwvadConfig internal filter status.
701  * param noiseConfig Voice activity detector noise filter configure structure pointer.
702  * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
703  * param signalGain signal gain value.
704  */
PDM_SetHwvadInEnvelopeBasedMode(PDM_Type * base,const pdm_hwvad_config_t * hwvadConfig,const pdm_hwvad_noise_filter_t * noiseConfig,const pdm_hwvad_zero_cross_detector_t * zcdConfig,uint32_t signalGain)705 void PDM_SetHwvadInEnvelopeBasedMode(PDM_Type *base,
706                                      const pdm_hwvad_config_t *hwvadConfig,
707                                      const pdm_hwvad_noise_filter_t *noiseConfig,
708                                      const pdm_hwvad_zero_cross_detector_t *zcdConfig,
709                                      uint32_t signalGain)
710 {
711     assert(hwvadConfig != NULL);
712     assert(noiseConfig != NULL);
713 
714     uint32_t i = 0U;
715 
716     PDM_SetHwvadConfig(base, hwvadConfig);
717     PDM_SetHwvadSignalFilterConfig(base, true, signalGain);
718     PDM_SetHwvadNoiseFilterConfig(base, noiseConfig);
719     PDM_EnableHwvad(base, true);
720 
721     if (NULL != zcdConfig)
722     {
723         PDM_SetHwvadZeroCrossDetectorConfig(base, zcdConfig);
724     }
725 
726     PDM_Enable(base, true);
727 
728     while (PDM_GetHwvadInitialFlag(base) != 0U)
729     {
730     }
731 
732     for (i = 0; i < 3U; i++)
733     {
734         /* set HWVAD interal filter stauts initial */
735         PDM_SetHwvadInternalFilterStatus(base, kPDM_HwvadInternalFilterInitial);
736     }
737 
738     PDM_SetHwvadInternalFilterStatus(base, kPDM_HwvadInternalFilterNormalOperation);
739 }
740 
741 /*!
742  * brief set HWVAD in energy based mode .
743  * Recommand configurations,
744  * code
745  * static const pdm_hwvad_config_t hwvadConfig = {
746  *   .channel           = 0,
747  *   .initializeTime    = 10U,
748  *   .cicOverSampleRate = 0U,
749  *   .inputGain         = 0U,
750  *   .frameTime         = 10U,
751  *   .cutOffFreq        = kPDM_HwvadHpfBypassed,
752  *   .enableFrameEnergy = true,
753  *   .enablePreFilter   = true,
754 };
755 
756  * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
757  *   .enableAutoNoiseFilter = true,
758  *   .enableNoiseMin        = false,
759  *   .enableNoiseDecimation = false,
760  *   .noiseFilterAdjustment = 0U,
761  *   .noiseGain             = 7U,
762  *   .enableNoiseDetectOR   = false,
763  * };
764  * code
765  * param base PDM base pointer.
766  * param hwvadConfig internal filter status.
767  * param noiseConfig Voice activity detector noise filter configure structure pointer.
768  * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
769  * param signalGain signal gain value, signal gain value should be properly according to application.
770  */
PDM_SetHwvadInEnergyBasedMode(PDM_Type * base,const pdm_hwvad_config_t * hwvadConfig,const pdm_hwvad_noise_filter_t * noiseConfig,const pdm_hwvad_zero_cross_detector_t * zcdConfig,uint32_t signalGain)771 void PDM_SetHwvadInEnergyBasedMode(PDM_Type *base,
772                                    const pdm_hwvad_config_t *hwvadConfig,
773                                    const pdm_hwvad_noise_filter_t *noiseConfig,
774                                    const pdm_hwvad_zero_cross_detector_t *zcdConfig,
775                                    uint32_t signalGain)
776 {
777     assert(hwvadConfig != NULL);
778     assert(noiseConfig != NULL);
779 
780     PDM_SetHwvadConfig(base, hwvadConfig);
781     /* signal filter need to disable, but signal gain value should be set */
782     base->VAD0_SCONFIG = PDM_VAD0_SCONFIG_VADSGAIN(signalGain);
783     PDM_SetHwvadNoiseFilterConfig(base, noiseConfig);
784     PDM_EnableHwvad(base, true);
785 
786     if (NULL != zcdConfig)
787     {
788         PDM_SetHwvadZeroCrossDetectorConfig(base, zcdConfig);
789     }
790 
791     PDM_Enable(base, true);
792 }
793 
794 /*!
795  * brief Configure voice activity detector.
796  *
797  * param base PDM base pointer
798  * param config Voice activity detector configure structure pointer .
799  */
PDM_SetHwvadConfig(PDM_Type * base,const pdm_hwvad_config_t * config)800 void PDM_SetHwvadConfig(PDM_Type *base, const pdm_hwvad_config_t *config)
801 {
802     assert(config != NULL);
803 
804     uint32_t ctrl1 = base->VAD0_CTRL_1;
805 
806     /* Configure VAD0_CTRL_1 register */
807     ctrl1 &= ~(PDM_VAD0_CTRL_1_VADCHSEL_MASK | PDM_VAD0_CTRL_1_VADCICOSR_MASK | PDM_VAD0_CTRL_1_VADINITT_MASK);
808     ctrl1 |= (PDM_VAD0_CTRL_1_VADCHSEL(config->channel) | PDM_VAD0_CTRL_1_VADCICOSR(config->cicOverSampleRate) |
809               PDM_VAD0_CTRL_1_VADINITT(config->initializeTime));
810     base->VAD0_CTRL_1 = ctrl1;
811 
812     /* Configure VAD0_CTRL_2 register */
813     base->VAD0_CTRL_2 =
814         (PDM_VAD0_CTRL_2_VADFRENDIS((config->enableFrameEnergy == true) ? 0U : 1U) |
815          PDM_VAD0_CTRL_2_VADPREFEN(config->enablePreFilter) | PDM_VAD0_CTRL_2_VADFRAMET(config->frameTime) |
816          PDM_VAD0_CTRL_2_VADINPGAIN(config->inputGain) | PDM_VAD0_CTRL_2_VADHPF(config->cutOffFreq));
817 }
818 
819 /*!
820  * brief Configure voice activity detector signal filter.
821  *
822  * param base PDM base pointer
823  * param enableMaxBlock If signal maximum block enabled.
824  * param signalGain Gain value for the signal energy.
825  */
PDM_SetHwvadSignalFilterConfig(PDM_Type * base,bool enableMaxBlock,uint32_t signalGain)826 void PDM_SetHwvadSignalFilterConfig(PDM_Type *base, bool enableMaxBlock, uint32_t signalGain)
827 {
828     uint32_t signalConfig = base->VAD0_SCONFIG;
829 
830     signalConfig &= ~(PDM_VAD0_SCONFIG_VADSMAXEN_MASK | PDM_VAD0_SCONFIG_VADSGAIN_MASK);
831     signalConfig |= (PDM_VAD0_SCONFIG_VADSMAXEN(enableMaxBlock) | PDM_VAD0_SCONFIG_VADSGAIN(signalGain)) |
832                     PDM_VAD0_SCONFIG_VADSFILEN_MASK;
833     base->VAD0_SCONFIG = signalConfig;
834 }
835 
836 /*!
837  * brief Configure voice activity detector noise filter.
838  *
839  * param base PDM base pointer
840  * param config Voice activity detector noise filter configure structure pointer .
841  */
PDM_SetHwvadNoiseFilterConfig(PDM_Type * base,const pdm_hwvad_noise_filter_t * config)842 void PDM_SetHwvadNoiseFilterConfig(PDM_Type *base, const pdm_hwvad_noise_filter_t *config)
843 {
844     assert(config != NULL);
845 
846     base->VAD0_NCONFIG =
847         (PDM_VAD0_NCONFIG_VADNFILAUTO(config->enableAutoNoiseFilter) |
848          PDM_VAD0_NCONFIG_VADNOREN(config->enableNoiseDetectOR) | PDM_VAD0_NCONFIG_VADNMINEN(config->enableNoiseMin) |
849          PDM_VAD0_NCONFIG_VADNDECEN(config->enableNoiseDecimation) |
850          PDM_VAD0_NCONFIG_VADNFILADJ(config->noiseFilterAdjustment) | PDM_VAD0_NCONFIG_VADNGAIN(config->noiseGain));
851 }
852 
853 /*!
854  * brief Configure voice activity detector zero cross detector.
855  *
856  * param base PDM base pointer
857  * param config Voice activity detector zero cross detector configure structure pointer .
858  */
PDM_SetHwvadZeroCrossDetectorConfig(PDM_Type * base,const pdm_hwvad_zero_cross_detector_t * config)859 void PDM_SetHwvadZeroCrossDetectorConfig(PDM_Type *base, const pdm_hwvad_zero_cross_detector_t *config)
860 {
861     assert(config != NULL);
862 
863     uint32_t zcd = (base->VAD0_ZCD & (~(PDM_VAD0_ZCD_VADZCDTH_MASK | PDM_VAD0_ZCD_VADZCDADJ_MASK |
864                                         PDM_VAD0_ZCD_VADZCDAUTO_MASK | PDM_VAD0_ZCD_VADZCDAND_MASK)));
865 
866     zcd |= (PDM_VAD0_ZCD_VADZCDTH(config->threshold) | PDM_VAD0_ZCD_VADZCDADJ(config->adjustmentThreshold) |
867             PDM_VAD0_ZCD_VADZCDAUTO(config->enableAutoThreshold) | PDM_VAD0_ZCD_VADZCDAND(config->zcdAnd)) |
868            PDM_VAD0_ZCD_VADZCDEN_MASK;
869 
870     base->VAD0_ZCD = zcd;
871 }
872 
873 /*!
874  * brief   Enable/Disable  hwvad callback.
875 
876  * This function enable/disable the hwvad interrupt for the selected PDM peripheral.
877  *
878  * param base Base address of the PDM peripheral.
879  * param vadCallback callback Pointer to store callback function, should be NULL when disable.
880  * param userData user data.
881  * param enable true is enable, false is disable.
882  * retval None.
883  */
PDM_EnableHwvadInterruptCallback(PDM_Type * base,pdm_hwvad_callback_t vadCallback,void * userData,bool enable)884 void PDM_EnableHwvadInterruptCallback(PDM_Type *base, pdm_hwvad_callback_t vadCallback, void *userData, bool enable)
885 {
886     uint32_t instance = PDM_GetInstance(base);
887 
888     if (enable)
889     {
890         PDM_EnableHwvadInterrupts(base, (uint32_t)kPDM_HwvadErrorInterruptEnable | (uint32_t)kPDM_HwvadInterruptEnable);
891         NVIC_ClearPendingIRQ(PDM_HWVAD_EVENT_IRQn);
892         (void)EnableIRQ(PDM_HWVAD_EVENT_IRQn);
893 #if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
894         NVIC_ClearPendingIRQ(PDM_HWVAD_ERROR_IRQn);
895         (void)EnableIRQ(PDM_HWVAD_ERROR_IRQn);
896 #endif
897         s_pdm_hwvad_notification[instance].callback = vadCallback;
898         s_pdm_hwvad_notification[instance].userData = userData;
899     }
900     else
901     {
902         PDM_DisableHwvadInterrupts(base,
903                                    (uint32_t)kPDM_HwvadErrorInterruptEnable | (uint32_t)kPDM_HwvadInterruptEnable);
904         (void)DisableIRQ(PDM_HWVAD_EVENT_IRQn);
905 #if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
906         (void)DisableIRQ(PDM_HWVAD_ERROR_IRQn);
907         NVIC_ClearPendingIRQ(PDM_HWVAD_ERROR_IRQn);
908 #endif
909         s_pdm_hwvad_notification[instance].callback = NULL;
910         s_pdm_hwvad_notification[instance].userData = NULL;
911         NVIC_ClearPendingIRQ(PDM_HWVAD_EVENT_IRQn);
912     }
913 }
914 
915 #if (defined PDM)
916 void PDM_HWVAD_EVENT_DriverIRQHandler(void);
PDM_HWVAD_EVENT_DriverIRQHandler(void)917 void PDM_HWVAD_EVENT_DriverIRQHandler(void)
918 {
919     if ((PDM_GetHwvadInterruptStatusFlags(PDM) & (uint32_t)kPDM_HwvadStatusVoiceDetectFlag) != 0U)
920     {
921         PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusVoiceDetectFlag);
922         if (s_pdm_hwvad_notification[0].callback != NULL)
923         {
924             s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_VoiceDetected, s_pdm_hwvad_notification[0].userData);
925         }
926     }
927 #if (defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
928     else
929     {
930         PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusInputSaturation);
931         if (s_pdm_hwvad_notification[0].callback != NULL)
932         {
933             s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_Error, s_pdm_hwvad_notification[0].userData);
934         }
935     }
936 #endif
937     SDK_ISR_EXIT_BARRIER;
938 }
939 
940 #if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
941 void PDM_HWVAD_ERROR_DriverIRQHandler(void);
PDM_HWVAD_ERROR_DriverIRQHandler(void)942 void PDM_HWVAD_ERROR_DriverIRQHandler(void)
943 {
944     PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusInputSaturation);
945     if (s_pdm_hwvad_notification[0].callback != NULL)
946     {
947         s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_Error, s_pdm_hwvad_notification[0].userData);
948     }
949     SDK_ISR_EXIT_BARRIER;
950 }
951 #endif
952 #endif
953 #endif
954 
955 #if defined(PDM)
956 void PDM_EVENT_DriverIRQHandler(void);
PDM_EVENT_DriverIRQHandler(void)957 void PDM_EVENT_DriverIRQHandler(void)
958 {
959     assert(s_pdmHandle[0] != NULL);
960     s_pdmIsr(PDM, s_pdmHandle[0]);
961     SDK_ISR_EXIT_BARRIER;
962 }
963 #endif
964