Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:00

0001 /*
0002  * Copyright (c) 2018, Freescale Semiconductor, Inc.
0003  * Copyright 2019-2020 NXP
0004  * All rights reserved.
0005  *
0006  * SPDX-License-Identifier: BSD-3-Clause
0007  */
0008 
0009 #include "fsl_pdm.h"
0010 /* Component ID definition, used by tools. */
0011 #ifndef FSL_COMPONENT_ID
0012 #define FSL_COMPONENT_ID "platform.drivers.pdm"
0013 #endif
0014 
0015 /*******************************************************************************
0016  * Definitations
0017  ******************************************************************************/
0018 /*! @brief Typedef for pdm rx interrupt handler. */
0019 typedef void (*pdm_isr_t)(PDM_Type *base, pdm_handle_t *pdmHandle);
0020 /*******************************************************************************
0021  * Prototypes
0022  ******************************************************************************/
0023 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
0024 /*!
0025  * @brief Get the instance number for PDM.
0026  *
0027  * @param channelMask enabled channel.
0028  * @param qualitymode selected quality mode.
0029  * @param osr      oversample rate.
0030  * @param regdiv   register divider.
0031  */
0032 static status_t PDM_ValidateSrcClockRate(uint32_t channelMask,
0033                                          pdm_df_quality_mode_t qualityMode,
0034                                          uint8_t osr,
0035                                          uint32_t regDiv);
0036 #endif
0037 
0038 /*******************************************************************************
0039  * Variables
0040  ******************************************************************************/
0041 /* Base pointer array */
0042 static PDM_Type *const s_pdmBases[] = PDM_BASE_PTRS;
0043 /*!@brief PDM handle pointer */
0044 static pdm_handle_t *s_pdmHandle[ARRAY_SIZE(s_pdmBases)];
0045 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0046 /* Clock name array */
0047 static const clock_ip_name_t s_pdmClock[] = PDM_CLOCKS;
0048 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0049 
0050 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0051 #if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
0052 /* Clock name array */
0053 static const clock_ip_name_t s_pdmFilterClock[] = PDM_FILTER_CLOCKS;
0054 #endif
0055 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0056 
0057 /*! @brief Pointer to tx IRQ handler for each instance. */
0058 static pdm_isr_t s_pdmIsr;
0059 #if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
0060 /*! @brief callback for hwvad. */
0061 static pdm_hwvad_notification_t s_pdm_hwvad_notification[ARRAY_SIZE(s_pdmBases)];
0062 #endif
0063 /*******************************************************************************
0064  * Code
0065  ******************************************************************************/
0066 uint32_t PDM_GetInstance(PDM_Type *base)
0067 {
0068     uint32_t instance;
0069 
0070     /* Find the instance index from base address mappings. */
0071     for (instance = 0; instance < ARRAY_SIZE(s_pdmBases); instance++)
0072     {
0073         if (s_pdmBases[instance] == base)
0074         {
0075             break;
0076         }
0077     }
0078 
0079     assert(instance < ARRAY_SIZE(s_pdmBases));
0080 
0081     return instance;
0082 }
0083 
0084 /*!
0085  * brief PDM read fifo.
0086  * Note: This function support 16 bit only for IP version that only supports 16bit.
0087  *
0088  * param base PDM base pointer.
0089  * param startChannel start channel number.
0090  * param channelNums total enabled channelnums.
0091  * param buffer received buffer address.
0092  * param size number of samples to read.
0093  * param dataWidth sample width.
0094  */
0095 void PDM_ReadFifo(
0096     PDM_Type *base, uint32_t startChannel, uint32_t channelNums, void *buffer, size_t size, uint32_t dataWidth)
0097 {
0098     uint32_t i = 0, j = 0U;
0099     uint32_t *dataAddr = (uint32_t *)buffer;
0100 
0101     for (i = 0U; i < size; i++)
0102     {
0103         for (j = 0; j < channelNums; j++)
0104         {
0105 #if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH != 2U)
0106             *dataAddr = base->DATACH[startChannel + j] >> (dataWidth == 4U ? 0U : 8U);
0107             dataAddr  = (uint32_t *)((uint32_t)dataAddr + dataWidth);
0108 #else
0109             *dataAddr = base->DATACH[startChannel + j];
0110             dataAddr  = (uint32_t *)((uint32_t)dataAddr + 2U);
0111 #endif
0112         }
0113     }
0114 }
0115 
0116 #if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 2U)
0117 /*!
0118  * brief PDM read data non blocking, only support 16bit data read.
0119  * So the actually read data byte size in this function is (size * 2 * channelNums).
0120  * param base PDM base pointer.
0121  * param startChannel start channel number.
0122  * param channelNums total enabled channelnums.
0123  * param buffer received buffer address.
0124  * param size number of 16bit data to read.
0125  */
0126 void PDM_ReadNonBlocking(PDM_Type *base, uint32_t startChannel, uint32_t channelNums, int16_t *buffer, size_t size)
0127 {
0128     uint32_t i = 0, j = 0U;
0129 
0130     for (i = 0U; i < size; i++)
0131     {
0132         for (j = 0; j < channelNums; j++)
0133         {
0134             *buffer++ = (int16_t)base->DATACH[startChannel + j];
0135         }
0136     }
0137 }
0138 #endif
0139 
0140 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
0141 static status_t PDM_ValidateSrcClockRate(uint32_t channelMask,
0142                                          pdm_df_quality_mode_t qualityMode,
0143                                          uint8_t osr,
0144                                          uint32_t regDiv)
0145 {
0146     uint32_t enabledChannel = 0U, i = 0U, factor = 0U, k = 0U;
0147 
0148     for (i = 0U; i < (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM; i++)
0149     {
0150         if (((channelMask >> i) & 0x01U) != 0U)
0151         {
0152             enabledChannel++;
0153         }
0154     }
0155 
0156     switch (qualityMode)
0157     {
0158         case kPDM_QualityModeMedium:
0159             factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
0160             k      = 2U;
0161             break;
0162 
0163         case kPDM_QualityModeHigh:
0164             factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
0165             k      = 1U;
0166             break;
0167 
0168         case kPDM_QualityModeLow:
0169             factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
0170             k      = 4U;
0171             break;
0172 
0173         case kPDM_QualityModeVeryLow0:
0174             factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
0175             k      = 2U;
0176             break;
0177 
0178         case kPDM_QualityModeVeryLow1:
0179             factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
0180             k      = 4U;
0181             break;
0182 
0183         case kPDM_QualityModeVeryLow2:
0184             factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
0185             k      = 8U;
0186             break;
0187 
0188         default:
0189             assert(false);
0190             break;
0191     }
0192 
0193     /* validate the minimum clock divider */
0194     /* 2U is for canculating k, 100U is for determing the specific float number of clock divider */
0195     if (((regDiv * k) / 2U * 100U) < (((10U + factor * enabledChannel) * 100U / (8U * osr)) * k / 2U))
0196     {
0197         return kStatus_Fail;
0198     }
0199 
0200     return kStatus_Success;
0201 }
0202 #endif
0203 
0204 /*!
0205  * brief PDM set sample rate.
0206  *
0207  * note This function is depend on the configuration of the PDM and PDM channel, so the correct call sequence is
0208  * code
0209  * PDM_Init(base, pdmConfig)
0210  * PDM_SetChannelConfig(base, channel, &channelConfig)
0211  * PDM_SetSampleRateConfig(base, source, sampleRate)
0212  * endcode
0213  * param base PDM base pointer
0214  * param sourceClock_HZ PDM source clock frequency.
0215  * param sampleRate_HZ PDM sample rate.
0216  */
0217 status_t PDM_SetSampleRateConfig(PDM_Type *base, uint32_t sourceClock_HZ, uint32_t sampleRate_HZ)
0218 {
0219     uint32_t osr = (base->CTRL_2 & PDM_CTRL_2_CICOSR_MASK) >> PDM_CTRL_2_CICOSR_SHIFT;
0220 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
0221     pdm_df_quality_mode_t qualityMode =
0222         (pdm_df_quality_mode_t)(uint32_t)((base->CTRL_2 & PDM_CTRL_2_QSEL_MASK) >> PDM_CTRL_2_QSEL_SHIFT);
0223     uint32_t enabledChannelMask = base->CTRL_1 & (uint32_t)kPDM_EnableChannelAll;
0224 #endif
0225 
0226     uint32_t pdmClockRate = 0U;
0227     uint32_t regDiv       = 0U;
0228 
0229     /* get divider */
0230     osr          = 16U - osr;
0231     pdmClockRate = sampleRate_HZ * osr * 8U;
0232     regDiv       = sourceClock_HZ / pdmClockRate;
0233 
0234     if (regDiv > PDM_CTRL_2_CLKDIV_MASK)
0235     {
0236         return kStatus_Fail;
0237     }
0238 
0239 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
0240     if (PDM_ValidateSrcClockRate(enabledChannelMask, qualityMode, (uint8_t)osr, regDiv) == kStatus_Fail)
0241     {
0242         return kStatus_Fail;
0243     }
0244 #endif
0245 
0246     base->CTRL_2 = (base->CTRL_2 & (~PDM_CTRL_2_CLKDIV_MASK)) | PDM_CTRL_2_CLKDIV(regDiv);
0247 
0248     return kStatus_Success;
0249 }
0250 
0251 /*!
0252  * brief PDM set sample rate.
0253  *
0254  * deprecated Do not use this function.  It has been superceded by @ref PDM_SetSampleRateConfig
0255  * param base PDM base pointer
0256  * param enableChannelMask PDM channel enable mask.
0257  * param qualityMode quality mode.
0258  * param osr cic oversample rate
0259  * param clkDiv clock divider
0260  */
0261 status_t PDM_SetSampleRate(
0262     PDM_Type *base, uint32_t enableChannelMask, pdm_df_quality_mode_t qualityMode, uint8_t osr, uint32_t clkDiv)
0263 {
0264 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
0265     uint8_t realOsr = 16U - (osr & (PDM_CTRL_2_CICOSR_MASK >> PDM_CTRL_2_CICOSR_SHIFT));
0266 #endif
0267     uint32_t regDiv = clkDiv >> 1U;
0268 
0269     switch (qualityMode)
0270     {
0271         case kPDM_QualityModeHigh:
0272             regDiv <<= 1U;
0273             break;
0274         case kPDM_QualityModeLow:
0275         case kPDM_QualityModeVeryLow1:
0276             regDiv >>= 1U;
0277             break;
0278         case kPDM_QualityModeVeryLow2:
0279             regDiv >>= 2U;
0280             break;
0281         default:
0282             assert(false);
0283             break;
0284     }
0285 
0286 #if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
0287     if (PDM_ValidateSrcClockRate(enableChannelMask, qualityMode, realOsr, regDiv) == kStatus_Fail)
0288     {
0289         return kStatus_Fail;
0290     }
0291 #endif
0292 
0293     assert(regDiv <= PDM_CTRL_2_CLKDIV_MASK);
0294     base->CTRL_2 = (base->CTRL_2 & (~PDM_CTRL_2_CLKDIV_MASK)) | PDM_CTRL_2_CLKDIV(regDiv);
0295 
0296     return kStatus_Success;
0297 }
0298 
0299 /*!
0300  * brief Initializes the PDM peripheral.
0301  *
0302  * Ungates the PDM clock, resets the module, and configures PDM with a configuration structure.
0303  * The configuration structure can be custom filled or set with default values by
0304  * PDM_GetDefaultConfig().
0305  *
0306  * note  This API should be called at the beginning of the application to use
0307  * the PDM driver. Otherwise, accessing the PDM module can cause a hard fault
0308  * because the clock is not enabled.
0309  *
0310  * param base PDM base pointer
0311  * param config PDM configuration structure.
0312  */
0313 void PDM_Init(PDM_Type *base, const pdm_config_t *config)
0314 {
0315     assert(config != NULL);
0316     assert(config->fifoWatermark <= PDM_FIFO_CTRL_FIFOWMK_MASK);
0317 
0318 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0319     /* Enable the PDM clock */
0320     CLOCK_EnableClock(s_pdmClock[PDM_GetInstance(base)]);
0321 #if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
0322     CLOCK_EnableClock(s_pdmFilterClock[PDM_GetInstance(base)]);
0323 #endif
0324 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0325 
0326     /* Enable the module and disable the interface/all channel */
0327     base->CTRL_1 &=
0328         ~(PDM_CTRL_1_MDIS_MASK | PDM_CTRL_1_PDMIEN_MASK | PDM_CTRL_1_ERREN_MASK | (uint32_t)kPDM_EnableChannelAll);
0329 
0330     /* wait all filter stopped */
0331     while ((base->STAT & PDM_STAT_BSY_FIL_MASK) != 0U)
0332     {
0333     }
0334 
0335     /* software reset */
0336     base->CTRL_1 |= PDM_CTRL_1_SRES_MASK;
0337 
0338     /* Set the configure settings */
0339     base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DOZEN_MASK)) | PDM_CTRL_1_DOZEN(config->enableDoze);
0340 
0341     base->CTRL_2 = (base->CTRL_2 & (~(PDM_CTRL_2_CICOSR_MASK | PDM_CTRL_2_QSEL_MASK))) |
0342                    PDM_CTRL_2_CICOSR(config->cicOverSampleRate) | PDM_CTRL_2_QSEL(config->qualityMode);
0343 
0344     /* Set the watermark */
0345     base->FIFO_CTRL = PDM_FIFO_CTRL_FIFOWMK(config->fifoWatermark);
0346 }
0347 
0348 /*!
0349  * brief De-initializes the PDM peripheral.
0350  *
0351  * This API gates the PDM clock. The PDM module can't operate unless PDM_Init
0352  * is called to enable the clock.
0353  *
0354  * param base PDM base pointer
0355  */
0356 void PDM_Deinit(PDM_Type *base)
0357 {
0358     /* disable PDM interface */
0359     PDM_Enable(base, false);
0360 
0361 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
0362     CLOCK_DisableClock(s_pdmClock[PDM_GetInstance(base)]);
0363 #if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
0364     CLOCK_DisableClock(s_pdmFilterClock[PDM_GetInstance(base)]);
0365 #endif
0366 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
0367 }
0368 
0369 /*!
0370  * brief Enables the PDM interrupt requests.
0371  *
0372  * param base PDM base pointer
0373  * param mask interrupt source
0374  *     The parameter can be a combination of the following sources if defined.
0375  *     arg kPDM_ErrorInterruptEnable
0376  *     arg kPDM_FIFOInterruptEnable
0377  */
0378 void PDM_EnableInterrupts(PDM_Type *base, uint32_t mask)
0379 {
0380     if ((mask & (uint32_t)kPDM_FIFOInterruptEnable) != 0U)
0381     {
0382         base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DISEL_MASK)) | (uint32_t)kPDM_FIFOInterruptEnable;
0383     }
0384     if ((mask & (uint32_t)kPDM_ErrorInterruptEnable) != 0U)
0385     {
0386         base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_ERREN_MASK)) | (uint32_t)kPDM_ErrorInterruptEnable;
0387     }
0388 }
0389 
0390 /*!
0391  * brief PDM one channel configurations.
0392  *
0393  * param base PDM base pointer
0394  * param config PDM channel configurations.
0395  * param channel channel number.
0396  * after completing the current frame in debug mode.
0397  */
0398 void PDM_SetChannelConfig(PDM_Type *base, uint32_t channel, const pdm_channel_config_t *config)
0399 {
0400     assert(config != NULL);
0401     assert(channel <= (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
0402 
0403     uint32_t dcCtrl = 0U;
0404 
0405 #if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
0406     dcCtrl = base->DC_OUT_CTRL;
0407     /* configure gain and cut off freq */
0408     dcCtrl &= ~((uint32_t)PDM_DC_OUT_CTRL_DCCONFIG0_MASK << (channel << 1U));
0409     dcCtrl |= (uint32_t)config->outputCutOffFreq << (channel << 1U);
0410     base->DC_OUT_CTRL = dcCtrl;
0411 #endif
0412 
0413 #if !(defined(FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED) && (FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED))
0414     dcCtrl = base->DC_CTRL;
0415     /* configure gain and cut off freq */
0416     dcCtrl &= ~((uint32_t)PDM_DC_CTRL_DCCONFIG0_MASK << (channel << 1U));
0417     dcCtrl |= (uint32_t)config->cutOffFreq << (channel << 1U);
0418     base->DC_CTRL = dcCtrl;
0419 #endif
0420 
0421     PDM_SetChannelGain(base, channel, config->gain);
0422 
0423     /* enable channel */
0424     base->CTRL_1 |= 1UL << channel;
0425 }
0426 
0427 /*!
0428  * brief Set the PDM channel gain.
0429  *
0430  * Please note for different quality mode, the valid gain value is different, reference RM for detail.
0431  * param base PDM base pointer.
0432  * param channel PDM channel index.
0433  * param gain channel gain, the register gain value range is 0 - 15.
0434  */
0435 void PDM_SetChannelGain(PDM_Type *base, uint32_t channel, pdm_df_output_gain_t gain)
0436 {
0437     assert(channel <= (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
0438 
0439 #if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
0440     uint32_t outCtrl = base->RANGE_CTRL;
0441 #else
0442     uint32_t outCtrl = base->OUT_CTRL;
0443 #endif
0444 
0445 #if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
0446     outCtrl &= ~((uint32_t)PDM_RANGE_CTRL_RANGEADJ0_MASK << (channel << 2U));
0447 #else
0448     outCtrl &= ~((uint32_t)PDM_OUT_CTRL_OUTGAIN0_MASK << (channel << 2U));
0449 #endif
0450 
0451     outCtrl |= (uint32_t)gain << (channel << 2U);
0452 
0453 #if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
0454     base->RANGE_CTRL = outCtrl;
0455 #else
0456     base->OUT_CTRL = outCtrl;
0457 #endif
0458 }
0459 
0460 /*!
0461  * brief PDM set channel transfer config.
0462  *
0463  * param base PDM base pointer.
0464  * param handle PDM handle pointer.
0465  * param channel PDM channel.
0466  * param config channel config.
0467  * param format data format.
0468  */
0469 status_t PDM_TransferSetChannelConfig(
0470     PDM_Type *base, pdm_handle_t *handle, uint32_t channel, const pdm_channel_config_t *config, uint32_t format)
0471 {
0472     assert(handle != NULL);
0473 
0474     PDM_SetChannelConfig(base, channel, config);
0475 
0476     handle->format = format;
0477 
0478     if (handle->channelNums == 0U)
0479     {
0480         handle->startChannel = (uint8_t)channel;
0481     }
0482 
0483     handle->channelNums++;
0484 
0485     if (handle->channelNums > (uint8_t)FSL_FEATURE_PDM_CHANNEL_NUM)
0486     {
0487         return kStatus_PDM_ChannelConfig_Failed;
0488     }
0489 
0490     return kStatus_Success;
0491 }
0492 
0493 /*!
0494  * brief Initializes the PDM handle.
0495  *
0496  * This function initializes the handle for the PDM transactional APIs. Call
0497  * this function once to get the handle initialized.
0498  *
0499  * param base PDM base pointer.
0500  * param handle PDM handle pointer.
0501  * param callback Pointer to the user callback function.
0502  * param userData User parameter passed to the callback function.
0503  */
0504 void PDM_TransferCreateHandle(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_callback_t callback, void *userData)
0505 {
0506     assert(handle != NULL);
0507 
0508     /* Zero the handle */
0509     (void)memset(handle, 0, sizeof(*handle));
0510 
0511     s_pdmHandle[PDM_GetInstance(base)] = handle;
0512 
0513     handle->callback  = callback;
0514     handle->userData  = userData;
0515     handle->watermark = (uint8_t)(base->FIFO_CTRL & PDM_FIFO_CTRL_FIFOWMK_MASK);
0516 
0517     /* Set the isr pointer */
0518     s_pdmIsr = PDM_TransferHandleIRQ;
0519 
0520     /* Enable RX event IRQ */
0521     (void)EnableIRQ(PDM_EVENT_IRQn);
0522 #if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
0523     /* Enable FIFO error IRQ */
0524     (void)EnableIRQ(PDM_ERROR_IRQn);
0525 #endif
0526 }
0527 
0528 /*!
0529  * brief Performs an interrupt non-blocking receive transfer on PDM.
0530  *
0531  * note This API returns immediately after the transfer initiates.
0532  * Call the PDM_RxGetTransferStatusIRQ to poll the transfer status and check whether
0533  * the transfer is finished. If the return status is not kStatus_PDM_Busy, the transfer
0534  * is finished.
0535  *
0536  * param base PDM base pointer
0537  * param handle Pointer to the pdm_handle_t structure which stores the transfer state.
0538  * param xfer Pointer to the pdm_transfer_t structure.
0539  * retval kStatus_Success Successfully started the data receive.
0540  * retval kStatus_PDM_Busy Previous receive still not finished.
0541  */
0542 status_t PDM_TransferReceiveNonBlocking(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_t *xfer)
0543 {
0544     assert(handle != NULL);
0545 
0546     /* Check if the queue is full */
0547     if (handle->pdmQueue[handle->queueUser].data != NULL)
0548     {
0549         return kStatus_PDM_QueueFull;
0550     }
0551 
0552     /* Add into queue */
0553     handle->transferSize[handle->queueUser]      = xfer->dataSize;
0554     handle->pdmQueue[handle->queueUser].data     = xfer->data;
0555     handle->pdmQueue[handle->queueUser].dataSize = xfer->dataSize;
0556     handle->queueUser                            = (handle->queueUser + 1U) % PDM_XFER_QUEUE_SIZE;
0557 
0558     /* Set state to busy */
0559     handle->state = kStatus_PDM_Busy;
0560 
0561     /* Enable interrupt */
0562     PDM_EnableInterrupts(base, (uint32_t)kPDM_FIFOInterruptEnable);
0563 
0564     PDM_Enable(base, true);
0565 
0566     return kStatus_Success;
0567 }
0568 
0569 /*!
0570  * brief Aborts the current IRQ receive.
0571  *
0572  * note This API can be called when an interrupt non-blocking transfer initiates
0573  * to abort the transfer early.
0574  *
0575  * param base PDM base pointer
0576  * param handle Pointer to the pdm_handle_t structure which stores the transfer state.
0577  */
0578 void PDM_TransferAbortReceive(PDM_Type *base, pdm_handle_t *handle)
0579 {
0580     assert(handle != NULL);
0581 
0582     /* Use FIFO request interrupt and fifo error */
0583     PDM_DisableInterrupts(base, (uint32_t)kPDM_FIFOInterruptEnable | (uint32_t)kPDM_ErrorInterruptEnable);
0584     PDM_Enable(base, false);
0585     handle->state = kStatus_PDM_Idle;
0586     /* Clear the queue */
0587     (void)memset(handle->pdmQueue, 0, sizeof(pdm_transfer_t) * PDM_XFER_QUEUE_SIZE);
0588     handle->queueDriver = 0;
0589     handle->queueUser   = 0;
0590 }
0591 
0592 /*!
0593  * brief Tx interrupt handler.
0594  *
0595  * param base PDM base pointer.
0596  * param handle Pointer to the pdm_handle_t structure.
0597  */
0598 void PDM_TransferHandleIRQ(PDM_Type *base, pdm_handle_t *handle)
0599 {
0600     assert(handle != NULL);
0601 
0602 #if (defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
0603     uint32_t status = 0U;
0604 
0605 #if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
0606     if (PDM_GetStatus(base) & PDM_STAT_LOWFREQF_MASK)
0607     {
0608         PDM_ClearStatus(base, PDM_STAT_LOWFREQF_MASK);
0609         if (handle->callback != NULL)
0610         {
0611             (handle->callback)(base, handle, kStatus_PDM_CLK_LOW, handle->userData);
0612         }
0613     }
0614 #endif
0615     status = PDM_GetFifoStatus(base);
0616     if (status != 0U)
0617     {
0618         PDM_ClearFIFOStatus(base, status);
0619         if (handle->callback != NULL)
0620         {
0621             (handle->callback)(base, handle, kStatus_PDM_FIFO_ERROR, handle->userData);
0622         }
0623     }
0624 
0625 #if !(defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL)
0626     status = PDM_GetOutputStatus(base);
0627     if (status != 0U)
0628     {
0629         PDM_ClearOutputStatus(base, status);
0630         if (handle->callback != NULL)
0631         {
0632             (handle->callback)(base, handle, kStatus_PDM_Output_ERROR, handle->userData);
0633         }
0634     }
0635 #endif
0636 #endif
0637 
0638     /* Handle transfer */
0639     if (((base->STAT & 0xFFU) != 0U) && (handle->channelNums != 0U) &&
0640         ((base->CTRL_1 & PDM_CTRL_1_DISEL_MASK) == (0x2UL << PDM_CTRL_1_DISEL_SHIFT)))
0641     {
0642         PDM_ClearStatus(base, 0xFFU);
0643         /* Judge if the data need to transmit is less than space */
0644         uint8_t size = (uint8_t)MIN((handle->pdmQueue[handle->queueDriver].dataSize),
0645                                     ((uint32_t)handle->watermark * handle->channelNums * handle->format));
0646 
0647         PDM_ReadFifo(base, handle->startChannel, handle->channelNums,
0648                      (uint8_t *)(uint32_t)handle->pdmQueue[handle->queueDriver].data,
0649                      ((size_t)size / handle->channelNums / handle->format), handle->format);
0650 
0651         /* Update the internal counter */
0652         handle->pdmQueue[handle->queueDriver].dataSize -= size;
0653         handle->pdmQueue[handle->queueDriver].data = &(handle->pdmQueue[handle->queueDriver].data[size]);
0654     }
0655 
0656     /* If finished a block, call the callback function */
0657     if (handle->pdmQueue[handle->queueDriver].dataSize == 0U)
0658     {
0659         handle->pdmQueue[handle->queueDriver].data = NULL;
0660         handle->queueDriver                        = (handle->queueDriver + 1U) % PDM_XFER_QUEUE_SIZE;
0661         if (handle->callback != NULL)
0662         {
0663             (handle->callback)(base, handle, kStatus_PDM_Idle, handle->userData);
0664         }
0665     }
0666 
0667     /* If all data finished, just stop the transfer */
0668     if (handle->pdmQueue[handle->queueDriver].data == NULL)
0669     {
0670         PDM_TransferAbortReceive(base, handle);
0671     }
0672 }
0673 
0674 #if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
0675 /*!
0676  * brief set HWVAD in envelope based mode .
0677  * Recommand configurations,
0678  * code
0679  * static const pdm_hwvad_config_t hwvadConfig = {
0680  *   .channel           = 0,
0681  *   .initializeTime    = 10U,
0682  *   .cicOverSampleRate = 0U,
0683  *   .inputGain         = 0U,
0684  *   .frameTime         = 10U,
0685  *   .cutOffFreq        = kPDM_HwvadHpfBypassed,
0686  *   .enableFrameEnergy = false,
0687  *   .enablePreFilter   = true,
0688 };
0689 
0690  * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
0691  *   .enableAutoNoiseFilter = false,
0692  *   .enableNoiseMin        = true,
0693  *   .enableNoiseDecimation = true,
0694  *   .noiseFilterAdjustment = 0U,
0695  *   .noiseGain             = 7U,
0696  *   .enableNoiseDetectOR   = true,
0697  * };
0698  * code
0699  * param base PDM base pointer.
0700  * param hwvadConfig internal filter status.
0701  * param noiseConfig Voice activity detector noise filter configure structure pointer.
0702  * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
0703  * param signalGain signal gain value.
0704  */
0705 void PDM_SetHwvadInEnvelopeBasedMode(PDM_Type *base,
0706                                      const pdm_hwvad_config_t *hwvadConfig,
0707                                      const pdm_hwvad_noise_filter_t *noiseConfig,
0708                                      const pdm_hwvad_zero_cross_detector_t *zcdConfig,
0709                                      uint32_t signalGain)
0710 {
0711     assert(hwvadConfig != NULL);
0712     assert(noiseConfig != NULL);
0713 
0714     uint32_t i = 0U;
0715 
0716     PDM_SetHwvadConfig(base, hwvadConfig);
0717     PDM_SetHwvadSignalFilterConfig(base, true, signalGain);
0718     PDM_SetHwvadNoiseFilterConfig(base, noiseConfig);
0719     PDM_EnableHwvad(base, true);
0720 
0721     if (NULL != zcdConfig)
0722     {
0723         PDM_SetHwvadZeroCrossDetectorConfig(base, zcdConfig);
0724     }
0725 
0726     PDM_Enable(base, true);
0727 
0728     while (PDM_GetHwvadInitialFlag(base) != 0U)
0729     {
0730     }
0731 
0732     for (i = 0; i < 3U; i++)
0733     {
0734         /* set HWVAD interal filter stauts initial */
0735         PDM_SetHwvadInternalFilterStatus(base, kPDM_HwvadInternalFilterInitial);
0736     }
0737 
0738     PDM_SetHwvadInternalFilterStatus(base, kPDM_HwvadInternalFilterNormalOperation);
0739 }
0740 
0741 /*!
0742  * brief set HWVAD in energy based mode .
0743  * Recommand configurations,
0744  * code
0745  * static const pdm_hwvad_config_t hwvadConfig = {
0746  *   .channel           = 0,
0747  *   .initializeTime    = 10U,
0748  *   .cicOverSampleRate = 0U,
0749  *   .inputGain         = 0U,
0750  *   .frameTime         = 10U,
0751  *   .cutOffFreq        = kPDM_HwvadHpfBypassed,
0752  *   .enableFrameEnergy = true,
0753  *   .enablePreFilter   = true,
0754 };
0755 
0756  * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
0757  *   .enableAutoNoiseFilter = true,
0758  *   .enableNoiseMin        = false,
0759  *   .enableNoiseDecimation = false,
0760  *   .noiseFilterAdjustment = 0U,
0761  *   .noiseGain             = 7U,
0762  *   .enableNoiseDetectOR   = false,
0763  * };
0764  * code
0765  * param base PDM base pointer.
0766  * param hwvadConfig internal filter status.
0767  * param noiseConfig Voice activity detector noise filter configure structure pointer.
0768  * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
0769  * param signalGain signal gain value, signal gain value should be properly according to application.
0770  */
0771 void PDM_SetHwvadInEnergyBasedMode(PDM_Type *base,
0772                                    const pdm_hwvad_config_t *hwvadConfig,
0773                                    const pdm_hwvad_noise_filter_t *noiseConfig,
0774                                    const pdm_hwvad_zero_cross_detector_t *zcdConfig,
0775                                    uint32_t signalGain)
0776 {
0777     assert(hwvadConfig != NULL);
0778     assert(noiseConfig != NULL);
0779 
0780     PDM_SetHwvadConfig(base, hwvadConfig);
0781     /* signal filter need to disable, but signal gain value should be set */
0782     base->VAD0_SCONFIG = PDM_VAD0_SCONFIG_VADSGAIN(signalGain);
0783     PDM_SetHwvadNoiseFilterConfig(base, noiseConfig);
0784     PDM_EnableHwvad(base, true);
0785 
0786     if (NULL != zcdConfig)
0787     {
0788         PDM_SetHwvadZeroCrossDetectorConfig(base, zcdConfig);
0789     }
0790 
0791     PDM_Enable(base, true);
0792 }
0793 
0794 /*!
0795  * brief Configure voice activity detector.
0796  *
0797  * param base PDM base pointer
0798  * param config Voice activity detector configure structure pointer .
0799  */
0800 void PDM_SetHwvadConfig(PDM_Type *base, const pdm_hwvad_config_t *config)
0801 {
0802     assert(config != NULL);
0803 
0804     uint32_t ctrl1 = base->VAD0_CTRL_1;
0805 
0806     /* Configure VAD0_CTRL_1 register */
0807     ctrl1 &= ~(PDM_VAD0_CTRL_1_VADCHSEL_MASK | PDM_VAD0_CTRL_1_VADCICOSR_MASK | PDM_VAD0_CTRL_1_VADINITT_MASK);
0808     ctrl1 |= (PDM_VAD0_CTRL_1_VADCHSEL(config->channel) | PDM_VAD0_CTRL_1_VADCICOSR(config->cicOverSampleRate) |
0809               PDM_VAD0_CTRL_1_VADINITT(config->initializeTime));
0810     base->VAD0_CTRL_1 = ctrl1;
0811 
0812     /* Configure VAD0_CTRL_2 register */
0813     base->VAD0_CTRL_2 =
0814         (PDM_VAD0_CTRL_2_VADFRENDIS((config->enableFrameEnergy == true) ? 0U : 1U) |
0815          PDM_VAD0_CTRL_2_VADPREFEN(config->enablePreFilter) | PDM_VAD0_CTRL_2_VADFRAMET(config->frameTime) |
0816          PDM_VAD0_CTRL_2_VADINPGAIN(config->inputGain) | PDM_VAD0_CTRL_2_VADHPF(config->cutOffFreq));
0817 }
0818 
0819 /*!
0820  * brief Configure voice activity detector signal filter.
0821  *
0822  * param base PDM base pointer
0823  * param enableMaxBlock If signal maximum block enabled.
0824  * param signalGain Gain value for the signal energy.
0825  */
0826 void PDM_SetHwvadSignalFilterConfig(PDM_Type *base, bool enableMaxBlock, uint32_t signalGain)
0827 {
0828     uint32_t signalConfig = base->VAD0_SCONFIG;
0829 
0830     signalConfig &= ~(PDM_VAD0_SCONFIG_VADSMAXEN_MASK | PDM_VAD0_SCONFIG_VADSGAIN_MASK);
0831     signalConfig |= (PDM_VAD0_SCONFIG_VADSMAXEN(enableMaxBlock) | PDM_VAD0_SCONFIG_VADSGAIN(signalGain)) |
0832                     PDM_VAD0_SCONFIG_VADSFILEN_MASK;
0833     base->VAD0_SCONFIG = signalConfig;
0834 }
0835 
0836 /*!
0837  * brief Configure voice activity detector noise filter.
0838  *
0839  * param base PDM base pointer
0840  * param config Voice activity detector noise filter configure structure pointer .
0841  */
0842 void PDM_SetHwvadNoiseFilterConfig(PDM_Type *base, const pdm_hwvad_noise_filter_t *config)
0843 {
0844     assert(config != NULL);
0845 
0846     base->VAD0_NCONFIG =
0847         (PDM_VAD0_NCONFIG_VADNFILAUTO(config->enableAutoNoiseFilter) |
0848          PDM_VAD0_NCONFIG_VADNOREN(config->enableNoiseDetectOR) | PDM_VAD0_NCONFIG_VADNMINEN(config->enableNoiseMin) |
0849          PDM_VAD0_NCONFIG_VADNDECEN(config->enableNoiseDecimation) |
0850          PDM_VAD0_NCONFIG_VADNFILADJ(config->noiseFilterAdjustment) | PDM_VAD0_NCONFIG_VADNGAIN(config->noiseGain));
0851 }
0852 
0853 /*!
0854  * brief Configure voice activity detector zero cross detector.
0855  *
0856  * param base PDM base pointer
0857  * param config Voice activity detector zero cross detector configure structure pointer .
0858  */
0859 void PDM_SetHwvadZeroCrossDetectorConfig(PDM_Type *base, const pdm_hwvad_zero_cross_detector_t *config)
0860 {
0861     assert(config != NULL);
0862 
0863     uint32_t zcd = (base->VAD0_ZCD & (~(PDM_VAD0_ZCD_VADZCDTH_MASK | PDM_VAD0_ZCD_VADZCDADJ_MASK |
0864                                         PDM_VAD0_ZCD_VADZCDAUTO_MASK | PDM_VAD0_ZCD_VADZCDAND_MASK)));
0865 
0866     zcd |= (PDM_VAD0_ZCD_VADZCDTH(config->threshold) | PDM_VAD0_ZCD_VADZCDADJ(config->adjustmentThreshold) |
0867             PDM_VAD0_ZCD_VADZCDAUTO(config->enableAutoThreshold) | PDM_VAD0_ZCD_VADZCDAND(config->zcdAnd)) |
0868            PDM_VAD0_ZCD_VADZCDEN_MASK;
0869 
0870     base->VAD0_ZCD = zcd;
0871 }
0872 
0873 /*!
0874  * brief   Enable/Disable  hwvad callback.
0875 
0876  * This function enable/disable the hwvad interrupt for the selected PDM peripheral.
0877  *
0878  * param base Base address of the PDM peripheral.
0879  * param vadCallback callback Pointer to store callback function, should be NULL when disable.
0880  * param userData user data.
0881  * param enable true is enable, false is disable.
0882  * retval None.
0883  */
0884 void PDM_EnableHwvadInterruptCallback(PDM_Type *base, pdm_hwvad_callback_t vadCallback, void *userData, bool enable)
0885 {
0886     uint32_t instance = PDM_GetInstance(base);
0887 
0888     if (enable)
0889     {
0890         PDM_EnableHwvadInterrupts(base, (uint32_t)kPDM_HwvadErrorInterruptEnable | (uint32_t)kPDM_HwvadInterruptEnable);
0891         NVIC_ClearPendingIRQ(PDM_HWVAD_EVENT_IRQn);
0892         (void)EnableIRQ(PDM_HWVAD_EVENT_IRQn);
0893 #if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
0894         NVIC_ClearPendingIRQ(PDM_HWVAD_ERROR_IRQn);
0895         (void)EnableIRQ(PDM_HWVAD_ERROR_IRQn);
0896 #endif
0897         s_pdm_hwvad_notification[instance].callback = vadCallback;
0898         s_pdm_hwvad_notification[instance].userData = userData;
0899     }
0900     else
0901     {
0902         PDM_DisableHwvadInterrupts(base,
0903                                    (uint32_t)kPDM_HwvadErrorInterruptEnable | (uint32_t)kPDM_HwvadInterruptEnable);
0904         (void)DisableIRQ(PDM_HWVAD_EVENT_IRQn);
0905 #if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
0906         (void)DisableIRQ(PDM_HWVAD_ERROR_IRQn);
0907         NVIC_ClearPendingIRQ(PDM_HWVAD_ERROR_IRQn);
0908 #endif
0909         s_pdm_hwvad_notification[instance].callback = NULL;
0910         s_pdm_hwvad_notification[instance].userData = NULL;
0911         NVIC_ClearPendingIRQ(PDM_HWVAD_EVENT_IRQn);
0912     }
0913 }
0914 
0915 #if (defined PDM)
0916 void PDM_HWVAD_EVENT_DriverIRQHandler(void);
0917 void PDM_HWVAD_EVENT_DriverIRQHandler(void)
0918 {
0919     if ((PDM_GetHwvadInterruptStatusFlags(PDM) & (uint32_t)kPDM_HwvadStatusVoiceDetectFlag) != 0U)
0920     {
0921         PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusVoiceDetectFlag);
0922         if (s_pdm_hwvad_notification[0].callback != NULL)
0923         {
0924             s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_VoiceDetected, s_pdm_hwvad_notification[0].userData);
0925         }
0926     }
0927 #if (defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
0928     else
0929     {
0930         PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusInputSaturation);
0931         if (s_pdm_hwvad_notification[0].callback != NULL)
0932         {
0933             s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_Error, s_pdm_hwvad_notification[0].userData);
0934         }
0935     }
0936 #endif
0937     SDK_ISR_EXIT_BARRIER;
0938 }
0939 
0940 #if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
0941 void PDM_HWVAD_ERROR_DriverIRQHandler(void);
0942 void PDM_HWVAD_ERROR_DriverIRQHandler(void)
0943 {
0944     PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusInputSaturation);
0945     if (s_pdm_hwvad_notification[0].callback != NULL)
0946     {
0947         s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_Error, s_pdm_hwvad_notification[0].userData);
0948     }
0949     SDK_ISR_EXIT_BARRIER;
0950 }
0951 #endif
0952 #endif
0953 #endif
0954 
0955 #if defined(PDM)
0956 void PDM_EVENT_DriverIRQHandler(void);
0957 void PDM_EVENT_DriverIRQHandler(void)
0958 {
0959     assert(s_pdmHandle[0] != NULL);
0960     s_pdmIsr(PDM, s_pdmHandle[0]);
0961     SDK_ISR_EXIT_BARRIER;
0962 }
0963 #endif