summaryrefslogtreecommitdiffstats
path: root/bsps/arm/imxrt/mcux-sdk/drivers/pdm
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.c963
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.h1213
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.c459
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.h254
-rw-r--r--bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_sdma.h140
5 files changed, 3029 insertions, 0 deletions
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.c b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.c
new file mode 100644
index 0000000000..bfdc89384c
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.c
@@ -0,0 +1,963 @@
+/*
+ * Copyright (c) 2018, Freescale Semiconductor, Inc.
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pdm.h"
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pdm"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/*! @brief Typedef for pdm rx interrupt handler. */
+typedef void (*pdm_isr_t)(PDM_Type *base, pdm_handle_t *pdmHandle);
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+/*!
+ * @brief Get the instance number for PDM.
+ *
+ * @param channelMask enabled channel.
+ * @param qualitymode selected quality mode.
+ * @param osr oversample rate.
+ * @param regdiv register divider.
+ */
+static status_t PDM_ValidateSrcClockRate(uint32_t channelMask,
+ pdm_df_quality_mode_t qualityMode,
+ uint8_t osr,
+ uint32_t regDiv);
+#endif
+
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+/* Base pointer array */
+static PDM_Type *const s_pdmBases[] = PDM_BASE_PTRS;
+/*!@brief PDM handle pointer */
+static pdm_handle_t *s_pdmHandle[ARRAY_SIZE(s_pdmBases)];
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+/* Clock name array */
+static const clock_ip_name_t s_pdmClock[] = PDM_CLOCKS;
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+#if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
+/* Clock name array */
+static const clock_ip_name_t s_pdmFilterClock[] = PDM_FILTER_CLOCKS;
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+/*! @brief Pointer to tx IRQ handler for each instance. */
+static pdm_isr_t s_pdmIsr;
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*! @brief callback for hwvad. */
+static pdm_hwvad_notification_t s_pdm_hwvad_notification[ARRAY_SIZE(s_pdmBases)];
+#endif
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+uint32_t PDM_GetInstance(PDM_Type *base)
+{
+ uint32_t instance;
+
+ /* Find the instance index from base address mappings. */
+ for (instance = 0; instance < ARRAY_SIZE(s_pdmBases); instance++)
+ {
+ if (s_pdmBases[instance] == base)
+ {
+ break;
+ }
+ }
+
+ assert(instance < ARRAY_SIZE(s_pdmBases));
+
+ return instance;
+}
+
+/*!
+ * brief PDM read fifo.
+ * Note: This function support 16 bit only for IP version that only supports 16bit.
+ *
+ * param base PDM base pointer.
+ * param startChannel start channel number.
+ * param channelNums total enabled channelnums.
+ * param buffer received buffer address.
+ * param size number of samples to read.
+ * param dataWidth sample width.
+ */
+void PDM_ReadFifo(
+ PDM_Type *base, uint32_t startChannel, uint32_t channelNums, void *buffer, size_t size, uint32_t dataWidth)
+{
+ uint32_t i = 0, j = 0U;
+ uint32_t *dataAddr = (uint32_t *)buffer;
+
+ for (i = 0U; i < size; i++)
+ {
+ for (j = 0; j < channelNums; j++)
+ {
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH != 2U)
+ *dataAddr = base->DATACH[startChannel + j] >> (dataWidth == 4U ? 0U : 8U);
+ dataAddr = (uint32_t *)((uint32_t)dataAddr + dataWidth);
+#else
+ *dataAddr = base->DATACH[startChannel + j];
+ dataAddr = (uint32_t *)((uint32_t)dataAddr + 2U);
+#endif
+ }
+ }
+}
+
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 2U)
+/*!
+ * brief PDM read data non blocking, only support 16bit data read.
+ * So the actually read data byte size in this function is (size * 2 * channelNums).
+ * param base PDM base pointer.
+ * param startChannel start channel number.
+ * param channelNums total enabled channelnums.
+ * param buffer received buffer address.
+ * param size number of 16bit data to read.
+ */
+void PDM_ReadNonBlocking(PDM_Type *base, uint32_t startChannel, uint32_t channelNums, int16_t *buffer, size_t size)
+{
+ uint32_t i = 0, j = 0U;
+
+ for (i = 0U; i < size; i++)
+ {
+ for (j = 0; j < channelNums; j++)
+ {
+ *buffer++ = (int16_t)base->DATACH[startChannel + j];
+ }
+ }
+}
+#endif
+
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+static status_t PDM_ValidateSrcClockRate(uint32_t channelMask,
+ pdm_df_quality_mode_t qualityMode,
+ uint8_t osr,
+ uint32_t regDiv)
+{
+ uint32_t enabledChannel = 0U, i = 0U, factor = 0U, k = 0U;
+
+ for (i = 0U; i < (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM; i++)
+ {
+ if (((channelMask >> i) & 0x01U) != 0U)
+ {
+ enabledChannel++;
+ }
+ }
+
+ switch (qualityMode)
+ {
+ case kPDM_QualityModeMedium:
+ factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
+ k = 2U;
+ break;
+
+ case kPDM_QualityModeHigh:
+ factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
+ k = 1U;
+ break;
+
+ case kPDM_QualityModeLow:
+ factor = FSL_FEATURE_PDM_HIGH_QUALITY_CLKDIV_FACTOR;
+ k = 4U;
+ break;
+
+ case kPDM_QualityModeVeryLow0:
+ factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
+ k = 2U;
+ break;
+
+ case kPDM_QualityModeVeryLow1:
+ factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
+ k = 4U;
+ break;
+
+ case kPDM_QualityModeVeryLow2:
+ factor = FSL_FEATURE_PDM_VERY_LOW_QUALITY_CLKDIV_FACTOR;
+ k = 8U;
+ break;
+
+ default:
+ assert(false);
+ break;
+ }
+
+ /* validate the minimum clock divider */
+ /* 2U is for canculating k, 100U is for determing the specific float number of clock divider */
+ if (((regDiv * k) / 2U * 100U) < (((10U + factor * enabledChannel) * 100U / (8U * osr)) * k / 2U))
+ {
+ return kStatus_Fail;
+ }
+
+ return kStatus_Success;
+}
+#endif
+
+/*!
+ * brief PDM set sample rate.
+ *
+ * note This function is depend on the configuration of the PDM and PDM channel, so the correct call sequence is
+ * code
+ * PDM_Init(base, pdmConfig)
+ * PDM_SetChannelConfig(base, channel, &channelConfig)
+ * PDM_SetSampleRateConfig(base, source, sampleRate)
+ * endcode
+ * param base PDM base pointer
+ * param sourceClock_HZ PDM source clock frequency.
+ * param sampleRate_HZ PDM sample rate.
+ */
+status_t PDM_SetSampleRateConfig(PDM_Type *base, uint32_t sourceClock_HZ, uint32_t sampleRate_HZ)
+{
+ uint32_t osr = (base->CTRL_2 & PDM_CTRL_2_CICOSR_MASK) >> PDM_CTRL_2_CICOSR_SHIFT;
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+ pdm_df_quality_mode_t qualityMode =
+ (pdm_df_quality_mode_t)(uint32_t)((base->CTRL_2 & PDM_CTRL_2_QSEL_MASK) >> PDM_CTRL_2_QSEL_SHIFT);
+ uint32_t enabledChannelMask = base->CTRL_1 & (uint32_t)kPDM_EnableChannelAll;
+#endif
+
+ uint32_t pdmClockRate = 0U;
+ uint32_t regDiv = 0U;
+
+ /* get divider */
+ osr = 16U - osr;
+ pdmClockRate = sampleRate_HZ * osr * 8U;
+ regDiv = sourceClock_HZ / pdmClockRate;
+
+ if (regDiv > PDM_CTRL_2_CLKDIV_MASK)
+ {
+ return kStatus_Fail;
+ }
+
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+ if (PDM_ValidateSrcClockRate(enabledChannelMask, qualityMode, (uint8_t)osr, regDiv) == kStatus_Fail)
+ {
+ return kStatus_Fail;
+ }
+#endif
+
+ base->CTRL_2 = (base->CTRL_2 & (~PDM_CTRL_2_CLKDIV_MASK)) | PDM_CTRL_2_CLKDIV(regDiv);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief PDM set sample rate.
+ *
+ * deprecated Do not use this function. It has been superceded by @ref PDM_SetSampleRateConfig
+ * param base PDM base pointer
+ * param enableChannelMask PDM channel enable mask.
+ * param qualityMode quality mode.
+ * param osr cic oversample rate
+ * param clkDiv clock divider
+ */
+status_t PDM_SetSampleRate(
+ PDM_Type *base, uint32_t enableChannelMask, pdm_df_quality_mode_t qualityMode, uint8_t osr, uint32_t clkDiv)
+{
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+ uint8_t realOsr = 16U - (osr & (PDM_CTRL_2_CICOSR_MASK >> PDM_CTRL_2_CICOSR_SHIFT));
+#endif
+ uint32_t regDiv = clkDiv >> 1U;
+
+ switch (qualityMode)
+ {
+ case kPDM_QualityModeHigh:
+ regDiv <<= 1U;
+ break;
+ case kPDM_QualityModeLow:
+ case kPDM_QualityModeVeryLow1:
+ regDiv >>= 1U;
+ break;
+ case kPDM_QualityModeVeryLow2:
+ regDiv >>= 2U;
+ break;
+ default:
+ assert(false);
+ break;
+ }
+
+#if !(defined FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV && FSL_FEATURE_PDM_HAS_NO_MINIMUM_CLKDIV)
+ if (PDM_ValidateSrcClockRate(enableChannelMask, qualityMode, realOsr, regDiv) == kStatus_Fail)
+ {
+ return kStatus_Fail;
+ }
+#endif
+
+ assert(regDiv <= PDM_CTRL_2_CLKDIV_MASK);
+ base->CTRL_2 = (base->CTRL_2 & (~PDM_CTRL_2_CLKDIV_MASK)) | PDM_CTRL_2_CLKDIV(regDiv);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the PDM peripheral.
+ *
+ * Ungates the PDM clock, resets the module, and configures PDM with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * PDM_GetDefaultConfig().
+ *
+ * note This API should be called at the beginning of the application to use
+ * the PDM driver. Otherwise, accessing the PDM module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * param base PDM base pointer
+ * param config PDM configuration structure.
+ */
+void PDM_Init(PDM_Type *base, const pdm_config_t *config)
+{
+ assert(config != NULL);
+ assert(config->fifoWatermark <= PDM_FIFO_CTRL_FIFOWMK_MASK);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ /* Enable the PDM clock */
+ CLOCK_EnableClock(s_pdmClock[PDM_GetInstance(base)]);
+#if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
+ CLOCK_EnableClock(s_pdmFilterClock[PDM_GetInstance(base)]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+
+ /* Enable the module and disable the interface/all channel */
+ base->CTRL_1 &=
+ ~(PDM_CTRL_1_MDIS_MASK | PDM_CTRL_1_PDMIEN_MASK | PDM_CTRL_1_ERREN_MASK | (uint32_t)kPDM_EnableChannelAll);
+
+ /* wait all filter stopped */
+ while ((base->STAT & PDM_STAT_BSY_FIL_MASK) != 0U)
+ {
+ }
+
+ /* software reset */
+ base->CTRL_1 |= PDM_CTRL_1_SRES_MASK;
+
+ /* Set the configure settings */
+ base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DOZEN_MASK)) | PDM_CTRL_1_DOZEN(config->enableDoze);
+
+ base->CTRL_2 = (base->CTRL_2 & (~(PDM_CTRL_2_CICOSR_MASK | PDM_CTRL_2_QSEL_MASK))) |
+ PDM_CTRL_2_CICOSR(config->cicOverSampleRate) | PDM_CTRL_2_QSEL(config->qualityMode);
+
+ /* Set the watermark */
+ base->FIFO_CTRL = PDM_FIFO_CTRL_FIFOWMK(config->fifoWatermark);
+}
+
+/*!
+ * brief De-initializes the PDM peripheral.
+ *
+ * This API gates the PDM clock. The PDM module can't operate unless PDM_Init
+ * is called to enable the clock.
+ *
+ * param base PDM base pointer
+ */
+void PDM_Deinit(PDM_Type *base)
+{
+ /* disable PDM interface */
+ PDM_Enable(base, false);
+
+#if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
+ CLOCK_DisableClock(s_pdmClock[PDM_GetInstance(base)]);
+#if defined(FSL_PDM_HAS_FILTER_CLOCK_GATE) && FSL_PDM_HAS_FILTER_CLOCK_GATE
+ CLOCK_DisableClock(s_pdmFilterClock[PDM_GetInstance(base)]);
+#endif
+#endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
+}
+
+/*!
+ * brief Enables the PDM interrupt requests.
+ *
+ * param base PDM base pointer
+ * param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * arg kPDM_ErrorInterruptEnable
+ * arg kPDM_FIFOInterruptEnable
+ */
+void PDM_EnableInterrupts(PDM_Type *base, uint32_t mask)
+{
+ if ((mask & (uint32_t)kPDM_FIFOInterruptEnable) != 0U)
+ {
+ base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DISEL_MASK)) | (uint32_t)kPDM_FIFOInterruptEnable;
+ }
+ if ((mask & (uint32_t)kPDM_ErrorInterruptEnable) != 0U)
+ {
+ base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_ERREN_MASK)) | (uint32_t)kPDM_ErrorInterruptEnable;
+ }
+}
+
+/*!
+ * brief PDM one channel configurations.
+ *
+ * param base PDM base pointer
+ * param config PDM channel configurations.
+ * param channel channel number.
+ * after completing the current frame in debug mode.
+ */
+void PDM_SetChannelConfig(PDM_Type *base, uint32_t channel, const pdm_channel_config_t *config)
+{
+ assert(config != NULL);
+ assert(channel <= (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
+
+ uint32_t dcCtrl = 0U;
+
+#if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
+ dcCtrl = base->DC_OUT_CTRL;
+ /* configure gain and cut off freq */
+ dcCtrl &= ~((uint32_t)PDM_DC_OUT_CTRL_DCCONFIG0_MASK << (channel << 1U));
+ dcCtrl |= (uint32_t)config->outputCutOffFreq << (channel << 1U);
+ base->DC_OUT_CTRL = dcCtrl;
+#endif
+
+#if !(defined(FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED) && (FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED))
+ dcCtrl = base->DC_CTRL;
+ /* configure gain and cut off freq */
+ dcCtrl &= ~((uint32_t)PDM_DC_CTRL_DCCONFIG0_MASK << (channel << 1U));
+ dcCtrl |= (uint32_t)config->cutOffFreq << (channel << 1U);
+ base->DC_CTRL = dcCtrl;
+#endif
+
+ PDM_SetChannelGain(base, channel, config->gain);
+
+ /* enable channel */
+ base->CTRL_1 |= 1UL << channel;
+}
+
+/*!
+ * brief Set the PDM channel gain.
+ *
+ * Please note for different quality mode, the valid gain value is different, reference RM for detail.
+ * param base PDM base pointer.
+ * param channel PDM channel index.
+ * param gain channel gain, the register gain value range is 0 - 15.
+ */
+void PDM_SetChannelGain(PDM_Type *base, uint32_t channel, pdm_df_output_gain_t gain)
+{
+ assert(channel <= (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+ uint32_t outCtrl = base->RANGE_CTRL;
+#else
+ uint32_t outCtrl = base->OUT_CTRL;
+#endif
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+ outCtrl &= ~((uint32_t)PDM_RANGE_CTRL_RANGEADJ0_MASK << (channel << 2U));
+#else
+ outCtrl &= ~((uint32_t)PDM_OUT_CTRL_OUTGAIN0_MASK << (channel << 2U));
+#endif
+
+ outCtrl |= (uint32_t)gain << (channel << 2U);
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+ base->RANGE_CTRL = outCtrl;
+#else
+ base->OUT_CTRL = outCtrl;
+#endif
+}
+
+/*!
+ * brief PDM set channel transfer config.
+ *
+ * param base PDM base pointer.
+ * param handle PDM handle pointer.
+ * param channel PDM channel.
+ * param config channel config.
+ * param format data format.
+ */
+status_t PDM_TransferSetChannelConfig(
+ PDM_Type *base, pdm_handle_t *handle, uint32_t channel, const pdm_channel_config_t *config, uint32_t format)
+{
+ assert(handle != NULL);
+
+ PDM_SetChannelConfig(base, channel, config);
+
+ handle->format = format;
+
+ if (handle->channelNums == 0U)
+ {
+ handle->startChannel = (uint8_t)channel;
+ }
+
+ handle->channelNums++;
+
+ if (handle->channelNums > (uint8_t)FSL_FEATURE_PDM_CHANNEL_NUM)
+ {
+ return kStatus_PDM_ChannelConfig_Failed;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Initializes the PDM handle.
+ *
+ * This function initializes the handle for the PDM transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * param base PDM base pointer.
+ * param handle PDM handle pointer.
+ * param callback Pointer to the user callback function.
+ * param userData User parameter passed to the callback function.
+ */
+void PDM_TransferCreateHandle(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_callback_t callback, void *userData)
+{
+ assert(handle != NULL);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ s_pdmHandle[PDM_GetInstance(base)] = handle;
+
+ handle->callback = callback;
+ handle->userData = userData;
+ handle->watermark = (uint8_t)(base->FIFO_CTRL & PDM_FIFO_CTRL_FIFOWMK_MASK);
+
+ /* Set the isr pointer */
+ s_pdmIsr = PDM_TransferHandleIRQ;
+
+ /* Enable RX event IRQ */
+ (void)EnableIRQ(PDM_EVENT_IRQn);
+#if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ /* Enable FIFO error IRQ */
+ (void)EnableIRQ(PDM_ERROR_IRQn);
+#endif
+}
+
+/*!
+ * brief Performs an interrupt non-blocking receive transfer on PDM.
+ *
+ * note This API returns immediately after the transfer initiates.
+ * Call the PDM_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_PDM_Busy, the transfer
+ * is finished.
+ *
+ * param base PDM base pointer
+ * param handle Pointer to the pdm_handle_t structure which stores the transfer state.
+ * param xfer Pointer to the pdm_transfer_t structure.
+ * retval kStatus_Success Successfully started the data receive.
+ * retval kStatus_PDM_Busy Previous receive still not finished.
+ */
+status_t PDM_TransferReceiveNonBlocking(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_t *xfer)
+{
+ assert(handle != NULL);
+
+ /* Check if the queue is full */
+ if (handle->pdmQueue[handle->queueUser].data != NULL)
+ {
+ return kStatus_PDM_QueueFull;
+ }
+
+ /* Add into queue */
+ handle->transferSize[handle->queueUser] = xfer->dataSize;
+ handle->pdmQueue[handle->queueUser].data = xfer->data;
+ handle->pdmQueue[handle->queueUser].dataSize = xfer->dataSize;
+ handle->queueUser = (handle->queueUser + 1U) % PDM_XFER_QUEUE_SIZE;
+
+ /* Set state to busy */
+ handle->state = kStatus_PDM_Busy;
+
+ /* Enable interrupt */
+ PDM_EnableInterrupts(base, (uint32_t)kPDM_FIFOInterruptEnable);
+
+ PDM_Enable(base, true);
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts the current IRQ receive.
+ *
+ * note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * param base PDM base pointer
+ * param handle Pointer to the pdm_handle_t structure which stores the transfer state.
+ */
+void PDM_TransferAbortReceive(PDM_Type *base, pdm_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Use FIFO request interrupt and fifo error */
+ PDM_DisableInterrupts(base, (uint32_t)kPDM_FIFOInterruptEnable | (uint32_t)kPDM_ErrorInterruptEnable);
+ PDM_Enable(base, false);
+ handle->state = kStatus_PDM_Idle;
+ /* Clear the queue */
+ (void)memset(handle->pdmQueue, 0, sizeof(pdm_transfer_t) * PDM_XFER_QUEUE_SIZE);
+ handle->queueDriver = 0;
+ handle->queueUser = 0;
+}
+
+/*!
+ * brief Tx interrupt handler.
+ *
+ * param base PDM base pointer.
+ * param handle Pointer to the pdm_handle_t structure.
+ */
+void PDM_TransferHandleIRQ(PDM_Type *base, pdm_handle_t *handle)
+{
+ assert(handle != NULL);
+
+#if (defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ uint32_t status = 0U;
+
+#if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
+ if (PDM_GetStatus(base) & PDM_STAT_LOWFREQF_MASK)
+ {
+ PDM_ClearStatus(base, PDM_STAT_LOWFREQF_MASK);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_PDM_CLK_LOW, handle->userData);
+ }
+ }
+#endif
+ status = PDM_GetFifoStatus(base);
+ if (status != 0U)
+ {
+ PDM_ClearFIFOStatus(base, status);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_PDM_FIFO_ERROR, handle->userData);
+ }
+ }
+
+#if !(defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL)
+ status = PDM_GetOutputStatus(base);
+ if (status != 0U)
+ {
+ PDM_ClearOutputStatus(base, status);
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_PDM_Output_ERROR, handle->userData);
+ }
+ }
+#endif
+#endif
+
+ /* Handle transfer */
+ if (((base->STAT & 0xFFU) != 0U) && (handle->channelNums != 0U) &&
+ ((base->CTRL_1 & PDM_CTRL_1_DISEL_MASK) == (0x2UL << PDM_CTRL_1_DISEL_SHIFT)))
+ {
+ PDM_ClearStatus(base, 0xFFU);
+ /* Judge if the data need to transmit is less than space */
+ uint8_t size = (uint8_t)MIN((handle->pdmQueue[handle->queueDriver].dataSize),
+ ((uint32_t)handle->watermark * handle->channelNums * handle->format));
+
+ PDM_ReadFifo(base, handle->startChannel, handle->channelNums,
+ (uint8_t *)(uint32_t)handle->pdmQueue[handle->queueDriver].data,
+ ((size_t)size / handle->channelNums / handle->format), handle->format);
+
+ /* Update the internal counter */
+ handle->pdmQueue[handle->queueDriver].dataSize -= size;
+ handle->pdmQueue[handle->queueDriver].data = &(handle->pdmQueue[handle->queueDriver].data[size]);
+ }
+
+ /* If finished a block, call the callback function */
+ if (handle->pdmQueue[handle->queueDriver].dataSize == 0U)
+ {
+ handle->pdmQueue[handle->queueDriver].data = NULL;
+ handle->queueDriver = (handle->queueDriver + 1U) % PDM_XFER_QUEUE_SIZE;
+ if (handle->callback != NULL)
+ {
+ (handle->callback)(base, handle, kStatus_PDM_Idle, handle->userData);
+ }
+ }
+
+ /* If all data finished, just stop the transfer */
+ if (handle->pdmQueue[handle->queueDriver].data == NULL)
+ {
+ PDM_TransferAbortReceive(base, handle);
+ }
+}
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*!
+ * brief set HWVAD in envelope based mode .
+ * Recommand configurations,
+ * code
+ * static const pdm_hwvad_config_t hwvadConfig = {
+ * .channel = 0,
+ * .initializeTime = 10U,
+ * .cicOverSampleRate = 0U,
+ * .inputGain = 0U,
+ * .frameTime = 10U,
+ * .cutOffFreq = kPDM_HwvadHpfBypassed,
+ * .enableFrameEnergy = false,
+ * .enablePreFilter = true,
+};
+
+ * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
+ * .enableAutoNoiseFilter = false,
+ * .enableNoiseMin = true,
+ * .enableNoiseDecimation = true,
+ * .noiseFilterAdjustment = 0U,
+ * .noiseGain = 7U,
+ * .enableNoiseDetectOR = true,
+ * };
+ * code
+ * param base PDM base pointer.
+ * param hwvadConfig internal filter status.
+ * param noiseConfig Voice activity detector noise filter configure structure pointer.
+ * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
+ * param signalGain signal gain value.
+ */
+void 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)
+{
+ assert(hwvadConfig != NULL);
+ assert(noiseConfig != NULL);
+
+ uint32_t i = 0U;
+
+ PDM_SetHwvadConfig(base, hwvadConfig);
+ PDM_SetHwvadSignalFilterConfig(base, true, signalGain);
+ PDM_SetHwvadNoiseFilterConfig(base, noiseConfig);
+ PDM_EnableHwvad(base, true);
+
+ if (NULL != zcdConfig)
+ {
+ PDM_SetHwvadZeroCrossDetectorConfig(base, zcdConfig);
+ }
+
+ PDM_Enable(base, true);
+
+ while (PDM_GetHwvadInitialFlag(base) != 0U)
+ {
+ }
+
+ for (i = 0; i < 3U; i++)
+ {
+ /* set HWVAD interal filter stauts initial */
+ PDM_SetHwvadInternalFilterStatus(base, kPDM_HwvadInternalFilterInitial);
+ }
+
+ PDM_SetHwvadInternalFilterStatus(base, kPDM_HwvadInternalFilterNormalOperation);
+}
+
+/*!
+ * brief set HWVAD in energy based mode .
+ * Recommand configurations,
+ * code
+ * static const pdm_hwvad_config_t hwvadConfig = {
+ * .channel = 0,
+ * .initializeTime = 10U,
+ * .cicOverSampleRate = 0U,
+ * .inputGain = 0U,
+ * .frameTime = 10U,
+ * .cutOffFreq = kPDM_HwvadHpfBypassed,
+ * .enableFrameEnergy = true,
+ * .enablePreFilter = true,
+};
+
+ * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
+ * .enableAutoNoiseFilter = true,
+ * .enableNoiseMin = false,
+ * .enableNoiseDecimation = false,
+ * .noiseFilterAdjustment = 0U,
+ * .noiseGain = 7U,
+ * .enableNoiseDetectOR = false,
+ * };
+ * code
+ * param base PDM base pointer.
+ * param hwvadConfig internal filter status.
+ * param noiseConfig Voice activity detector noise filter configure structure pointer.
+ * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
+ * param signalGain signal gain value, signal gain value should be properly according to application.
+ */
+void 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)
+{
+ assert(hwvadConfig != NULL);
+ assert(noiseConfig != NULL);
+
+ PDM_SetHwvadConfig(base, hwvadConfig);
+ /* signal filter need to disable, but signal gain value should be set */
+ base->VAD0_SCONFIG = PDM_VAD0_SCONFIG_VADSGAIN(signalGain);
+ PDM_SetHwvadNoiseFilterConfig(base, noiseConfig);
+ PDM_EnableHwvad(base, true);
+
+ if (NULL != zcdConfig)
+ {
+ PDM_SetHwvadZeroCrossDetectorConfig(base, zcdConfig);
+ }
+
+ PDM_Enable(base, true);
+}
+
+/*!
+ * brief Configure voice activity detector.
+ *
+ * param base PDM base pointer
+ * param config Voice activity detector configure structure pointer .
+ */
+void PDM_SetHwvadConfig(PDM_Type *base, const pdm_hwvad_config_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t ctrl1 = base->VAD0_CTRL_1;
+
+ /* Configure VAD0_CTRL_1 register */
+ ctrl1 &= ~(PDM_VAD0_CTRL_1_VADCHSEL_MASK | PDM_VAD0_CTRL_1_VADCICOSR_MASK | PDM_VAD0_CTRL_1_VADINITT_MASK);
+ ctrl1 |= (PDM_VAD0_CTRL_1_VADCHSEL(config->channel) | PDM_VAD0_CTRL_1_VADCICOSR(config->cicOverSampleRate) |
+ PDM_VAD0_CTRL_1_VADINITT(config->initializeTime));
+ base->VAD0_CTRL_1 = ctrl1;
+
+ /* Configure VAD0_CTRL_2 register */
+ base->VAD0_CTRL_2 =
+ (PDM_VAD0_CTRL_2_VADFRENDIS((config->enableFrameEnergy == true) ? 0U : 1U) |
+ PDM_VAD0_CTRL_2_VADPREFEN(config->enablePreFilter) | PDM_VAD0_CTRL_2_VADFRAMET(config->frameTime) |
+ PDM_VAD0_CTRL_2_VADINPGAIN(config->inputGain) | PDM_VAD0_CTRL_2_VADHPF(config->cutOffFreq));
+}
+
+/*!
+ * brief Configure voice activity detector signal filter.
+ *
+ * param base PDM base pointer
+ * param enableMaxBlock If signal maximum block enabled.
+ * param signalGain Gain value for the signal energy.
+ */
+void PDM_SetHwvadSignalFilterConfig(PDM_Type *base, bool enableMaxBlock, uint32_t signalGain)
+{
+ uint32_t signalConfig = base->VAD0_SCONFIG;
+
+ signalConfig &= ~(PDM_VAD0_SCONFIG_VADSMAXEN_MASK | PDM_VAD0_SCONFIG_VADSGAIN_MASK);
+ signalConfig |= (PDM_VAD0_SCONFIG_VADSMAXEN(enableMaxBlock) | PDM_VAD0_SCONFIG_VADSGAIN(signalGain)) |
+ PDM_VAD0_SCONFIG_VADSFILEN_MASK;
+ base->VAD0_SCONFIG = signalConfig;
+}
+
+/*!
+ * brief Configure voice activity detector noise filter.
+ *
+ * param base PDM base pointer
+ * param config Voice activity detector noise filter configure structure pointer .
+ */
+void PDM_SetHwvadNoiseFilterConfig(PDM_Type *base, const pdm_hwvad_noise_filter_t *config)
+{
+ assert(config != NULL);
+
+ base->VAD0_NCONFIG =
+ (PDM_VAD0_NCONFIG_VADNFILAUTO(config->enableAutoNoiseFilter) |
+ PDM_VAD0_NCONFIG_VADNOREN(config->enableNoiseDetectOR) | PDM_VAD0_NCONFIG_VADNMINEN(config->enableNoiseMin) |
+ PDM_VAD0_NCONFIG_VADNDECEN(config->enableNoiseDecimation) |
+ PDM_VAD0_NCONFIG_VADNFILADJ(config->noiseFilterAdjustment) | PDM_VAD0_NCONFIG_VADNGAIN(config->noiseGain));
+}
+
+/*!
+ * brief Configure voice activity detector zero cross detector.
+ *
+ * param base PDM base pointer
+ * param config Voice activity detector zero cross detector configure structure pointer .
+ */
+void PDM_SetHwvadZeroCrossDetectorConfig(PDM_Type *base, const pdm_hwvad_zero_cross_detector_t *config)
+{
+ assert(config != NULL);
+
+ uint32_t zcd = (base->VAD0_ZCD & (~(PDM_VAD0_ZCD_VADZCDTH_MASK | PDM_VAD0_ZCD_VADZCDADJ_MASK |
+ PDM_VAD0_ZCD_VADZCDAUTO_MASK | PDM_VAD0_ZCD_VADZCDAND_MASK)));
+
+ zcd |= (PDM_VAD0_ZCD_VADZCDTH(config->threshold) | PDM_VAD0_ZCD_VADZCDADJ(config->adjustmentThreshold) |
+ PDM_VAD0_ZCD_VADZCDAUTO(config->enableAutoThreshold) | PDM_VAD0_ZCD_VADZCDAND(config->zcdAnd)) |
+ PDM_VAD0_ZCD_VADZCDEN_MASK;
+
+ base->VAD0_ZCD = zcd;
+}
+
+/*!
+ * brief Enable/Disable hwvad callback.
+
+ * This function enable/disable the hwvad interrupt for the selected PDM peripheral.
+ *
+ * param base Base address of the PDM peripheral.
+ * param vadCallback callback Pointer to store callback function, should be NULL when disable.
+ * param userData user data.
+ * param enable true is enable, false is disable.
+ * retval None.
+ */
+void PDM_EnableHwvadInterruptCallback(PDM_Type *base, pdm_hwvad_callback_t vadCallback, void *userData, bool enable)
+{
+ uint32_t instance = PDM_GetInstance(base);
+
+ if (enable)
+ {
+ PDM_EnableHwvadInterrupts(base, (uint32_t)kPDM_HwvadErrorInterruptEnable | (uint32_t)kPDM_HwvadInterruptEnable);
+ NVIC_ClearPendingIRQ(PDM_HWVAD_EVENT_IRQn);
+ (void)EnableIRQ(PDM_HWVAD_EVENT_IRQn);
+#if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ NVIC_ClearPendingIRQ(PDM_HWVAD_ERROR_IRQn);
+ (void)EnableIRQ(PDM_HWVAD_ERROR_IRQn);
+#endif
+ s_pdm_hwvad_notification[instance].callback = vadCallback;
+ s_pdm_hwvad_notification[instance].userData = userData;
+ }
+ else
+ {
+ PDM_DisableHwvadInterrupts(base,
+ (uint32_t)kPDM_HwvadErrorInterruptEnable | (uint32_t)kPDM_HwvadInterruptEnable);
+ (void)DisableIRQ(PDM_HWVAD_EVENT_IRQn);
+#if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ (void)DisableIRQ(PDM_HWVAD_ERROR_IRQn);
+ NVIC_ClearPendingIRQ(PDM_HWVAD_ERROR_IRQn);
+#endif
+ s_pdm_hwvad_notification[instance].callback = NULL;
+ s_pdm_hwvad_notification[instance].userData = NULL;
+ NVIC_ClearPendingIRQ(PDM_HWVAD_EVENT_IRQn);
+ }
+}
+
+#if (defined PDM)
+void PDM_HWVAD_EVENT_DriverIRQHandler(void);
+void PDM_HWVAD_EVENT_DriverIRQHandler(void)
+{
+ if ((PDM_GetHwvadInterruptStatusFlags(PDM) & (uint32_t)kPDM_HwvadStatusVoiceDetectFlag) != 0U)
+ {
+ PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusVoiceDetectFlag);
+ if (s_pdm_hwvad_notification[0].callback != NULL)
+ {
+ s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_VoiceDetected, s_pdm_hwvad_notification[0].userData);
+ }
+ }
+#if (defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+ else
+ {
+ PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusInputSaturation);
+ if (s_pdm_hwvad_notification[0].callback != NULL)
+ {
+ s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_Error, s_pdm_hwvad_notification[0].userData);
+ }
+ }
+#endif
+ SDK_ISR_EXIT_BARRIER;
+}
+
+#if !(defined FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ && FSL_FEATURE_PDM_HAS_NO_INDEPENDENT_ERROR_IRQ)
+void PDM_HWVAD_ERROR_DriverIRQHandler(void);
+void PDM_HWVAD_ERROR_DriverIRQHandler(void)
+{
+ PDM_ClearHwvadInterruptStatusFlags(PDM, (uint32_t)kPDM_HwvadStatusInputSaturation);
+ if (s_pdm_hwvad_notification[0].callback != NULL)
+ {
+ s_pdm_hwvad_notification[0].callback(kStatus_PDM_HWVAD_Error, s_pdm_hwvad_notification[0].userData);
+ }
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
+#endif
+#endif
+
+#if defined(PDM)
+void PDM_EVENT_DriverIRQHandler(void);
+void PDM_EVENT_DriverIRQHandler(void)
+{
+ assert(s_pdmHandle[0] != NULL);
+ s_pdmIsr(PDM, s_pdmHandle[0]);
+ SDK_ISR_EXIT_BARRIER;
+}
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.h b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.h
new file mode 100644
index 0000000000..f7c263a188
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm.h
@@ -0,0 +1,1213 @@
+/*
+ * Copyright (c) 2018, Freescale Semiconductor, Inc.
+ * Copyright 2019-2020 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_PDM_H_
+#define _FSL_PDM_H_
+
+#include "fsl_common.h"
+
+/*!
+ * @addtogroup pdm_driver PDM Driver
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_PDM_DRIVER_VERSION (MAKE_VERSION(2, 8, 0)) /*!< Version 2.8.0 */
+/*@}*/
+
+/*! @brief PDM XFER QUEUE SIZE */
+#define PDM_XFER_QUEUE_SIZE (4U)
+
+/*! @brief PDM return status*/
+enum
+{
+ kStatus_PDM_Busy = MAKE_STATUS(kStatusGroup_PDM, 0), /*!< PDM is busy. */
+#if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
+ kStatus_PDM_CLK_LOW = MAKE_STATUS(kStatusGroup_PDM, 1), /*!< PDM clock frequency low */
+#endif
+ kStatus_PDM_FIFO_ERROR = MAKE_STATUS(kStatusGroup_PDM, 2), /*!< PDM FIFO underrun or overflow */
+ kStatus_PDM_QueueFull = MAKE_STATUS(kStatusGroup_PDM, 3), /*!< PDM FIFO underrun or overflow */
+ kStatus_PDM_Idle = MAKE_STATUS(kStatusGroup_PDM, 4), /*!< PDM is idle */
+ kStatus_PDM_Output_ERROR = MAKE_STATUS(kStatusGroup_PDM, 5), /*!< PDM is output error */
+ kStatus_PDM_ChannelConfig_Failed = MAKE_STATUS(kStatusGroup_PDM, 6), /*!< PDM channel config failed */
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+ kStatus_PDM_HWVAD_VoiceDetected = MAKE_STATUS(kStatusGroup_PDM, 7), /*!< PDM hwvad voice detected */
+ kStatus_PDM_HWVAD_Error = MAKE_STATUS(kStatusGroup_PDM, 8), /*!< PDM hwvad error */
+#endif
+};
+
+/*! @brief The PDM interrupt enable flag */
+enum _pdm_interrupt_enable
+{
+ kPDM_ErrorInterruptEnable = PDM_CTRL_1_ERREN_MASK, /*!< PDM channel error interrupt enable. */
+ kPDM_FIFOInterruptEnable = PDM_CTRL_1_DISEL(2U), /*!< PDM channel FIFO interrupt */
+};
+
+/*! @brief The PDM status */
+enum _pdm_internal_status
+{
+ kPDM_StatusDfBusyFlag = (int)PDM_STAT_BSY_FIL_MASK, /*!< Decimation filter is busy processing data */
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_FIR_RDY) && FSL_FEATURE_PDM_HAS_NO_FIR_RDY)
+ kPDM_StatusFIRFilterReady = PDM_STAT_FIR_RDY_MASK, /*!< FIR filter data is ready */
+#endif
+#if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
+ kPDM_StatusFrequencyLow = PDM_STAT_LOWFREQF_MASK, /*!< Mic app clock frequency not high enough */
+#endif
+ kPDM_StatusCh0FifoDataAvaliable = PDM_STAT_CH0F_MASK, /*!< channel 0 fifo data reached watermark level */
+ kPDM_StatusCh1FifoDataAvaliable = PDM_STAT_CH1F_MASK, /*!< channel 1 fifo data reached watermark level */
+ kPDM_StatusCh2FifoDataAvaliable = PDM_STAT_CH2F_MASK, /*!< channel 2 fifo data reached watermark level */
+ kPDM_StatusCh3FifoDataAvaliable = PDM_STAT_CH3F_MASK, /*!< channel 3 fifo data reached watermark level */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_StatusCh4FifoDataAvaliable = PDM_STAT_CH4F_MASK, /*!< channel 4 fifo data reached watermark level */
+ kPDM_StatusCh5FifoDataAvaliable = PDM_STAT_CH5F_MASK, /*!< channel 5 fifo data reached watermark level */
+ kPDM_StatusCh6FifoDataAvaliable = PDM_STAT_CH6F_MASK, /*!< channel 6 fifo data reached watermark level */
+ kPDM_StatusCh7FifoDataAvaliable = PDM_STAT_CH7F_MASK, /*!< channel 7 fifo data reached watermark level */
+#endif
+};
+
+/*! @brief PDM channel enable mask */
+enum _pdm_channel_enable_mask
+{
+ kPDM_EnableChannel0 = PDM_STAT_CH0F_MASK, /*!< channgel 0 enable mask */
+ kPDM_EnableChannel1 = PDM_STAT_CH1F_MASK, /*!< channgel 1 enable mask */
+ kPDM_EnableChannel2 = PDM_STAT_CH2F_MASK, /*!< channgel 2 enable mask */
+ kPDM_EnableChannel3 = PDM_STAT_CH3F_MASK, /*!< channgel 3 enable mask */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_EnableChannel4 = PDM_STAT_CH4F_MASK, /*!< channgel 4 enable mask */
+ kPDM_EnableChannel5 = PDM_STAT_CH5F_MASK, /*!< channgel 5 enable mask */
+ kPDM_EnableChannel6 = PDM_STAT_CH6F_MASK, /*!< channgel 6 enable mask */
+ kPDM_EnableChannel7 = PDM_STAT_CH7F_MASK, /*!< channgel 7 enable mask */
+
+ kPDM_EnableChannelAll = kPDM_EnableChannel0 | kPDM_EnableChannel1 | kPDM_EnableChannel2 | kPDM_EnableChannel3 |
+ kPDM_EnableChannel4 | kPDM_EnableChannel5 | kPDM_EnableChannel6 | kPDM_EnableChannel7,
+#else
+ kPDM_EnableChannelAll = kPDM_EnableChannel0 | kPDM_EnableChannel1 | kPDM_EnableChannel2 | kPDM_EnableChannel3,
+#endif
+};
+
+/*! @brief The PDM fifo status */
+enum _pdm_fifo_status
+{
+ kPDM_FifoStatusUnderflowCh0 = PDM_FIFO_STAT_FIFOUND0_MASK, /*!< channel0 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh1 = PDM_FIFO_STAT_FIFOUND1_MASK, /*!< channel1 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh2 = PDM_FIFO_STAT_FIFOUND2_MASK, /*!< channel2 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh3 = PDM_FIFO_STAT_FIFOUND3_MASK, /*!< channel3 fifo status underflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_FifoStatusUnderflowCh4 = PDM_FIFO_STAT_FIFOUND4_MASK, /*!< channel4 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh5 = PDM_FIFO_STAT_FIFOUND5_MASK, /*!< channel5 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh6 = PDM_FIFO_STAT_FIFOUND6_MASK, /*!< channel6 fifo status underflow */
+ kPDM_FifoStatusUnderflowCh7 = PDM_FIFO_STAT_FIFOUND6_MASK, /*!< channel7 fifo status underflow */
+#endif
+
+ kPDM_FifoStatusOverflowCh0 = PDM_FIFO_STAT_FIFOOVF0_MASK, /*!< channel0 fifo status overflow */
+ kPDM_FifoStatusOverflowCh1 = PDM_FIFO_STAT_FIFOOVF1_MASK, /*!< channel1 fifo status overflow */
+ kPDM_FifoStatusOverflowCh2 = PDM_FIFO_STAT_FIFOOVF2_MASK, /*!< channel2 fifo status overflow */
+ kPDM_FifoStatusOverflowCh3 = PDM_FIFO_STAT_FIFOOVF3_MASK, /*!< channel3 fifo status overflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_FifoStatusOverflowCh4 = PDM_FIFO_STAT_FIFOOVF4_MASK, /*!< channel4 fifo status overflow */
+ kPDM_FifoStatusOverflowCh5 = PDM_FIFO_STAT_FIFOOVF5_MASK, /*!< channel5 fifo status overflow */
+ kPDM_FifoStatusOverflowCh6 = PDM_FIFO_STAT_FIFOOVF6_MASK, /*!< channel6 fifo status overflow */
+ kPDM_FifoStatusOverflowCh7 = PDM_FIFO_STAT_FIFOOVF7_MASK, /*!< channel7 fifo status overflow */
+#endif
+};
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+/*! @brief The PDM output status */
+enum _pdm_range_status
+{
+ kPDM_RangeStatusUnderFlowCh0 = PDM_RANGE_STAT_RANGEUNF0_MASK, /*!< channel0 range status underflow */
+ kPDM_RangeStatusUnderFlowCh1 = PDM_RANGE_STAT_RANGEUNF1_MASK, /*!< channel1 range status underflow */
+ kPDM_RangeStatusUnderFlowCh2 = PDM_RANGE_STAT_RANGEUNF2_MASK, /*!< channel2 range status underflow */
+ kPDM_RangeStatusUnderFlowCh3 = PDM_RANGE_STAT_RANGEUNF3_MASK, /*!< channel3 range status underflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_RangeStatusUnderFlowCh4 = PDM_RANGE_STAT_RANGEUNF4_MASK, /*!< channel4 range status underflow */
+ kPDM_RangeStatusUnderFlowCh5 = PDM_RANGE_STAT_RANGEUNF5_MASK, /*!< channel5 range status underflow */
+ kPDM_RangeStatusUnderFlowCh6 = PDM_RANGE_STAT_RANGEUNF6_MASK, /*!< channel6 range status underflow */
+ kPDM_RangeStatusUnderFlowCh7 = PDM_RANGE_STAT_RANGEUNF7_MASK, /*!< channel7 range status underflow */
+#endif
+ kPDM_RangeStatusOverFlowCh0 = PDM_RANGE_STAT_RANGEOVF0_MASK, /*!< channel0 range status overflow */
+ kPDM_RangeStatusOverFlowCh1 = PDM_RANGE_STAT_RANGEOVF1_MASK, /*!< channel1 range status overflow */
+ kPDM_RangeStatusOverFlowCh2 = PDM_RANGE_STAT_RANGEOVF2_MASK, /*!< channel2 range status overflow */
+ kPDM_RangeStatusOverFlowCh3 = PDM_RANGE_STAT_RANGEOVF3_MASK, /*!< channel3 range status overflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_RangeStatusOverFlowCh4 = PDM_RANGE_STAT_RANGEOVF4_MASK, /*!< channel4 range status overflow */
+ kPDM_RangeStatusOverFlowCh5 = PDM_RANGE_STAT_RANGEOVF5_MASK, /*!< channel5 range status overflow */
+ kPDM_RangeStatusOverFlowCh6 = PDM_RANGE_STAT_RANGEOVF6_MASK, /*!< channel6 range status overflow */
+ kPDM_RangeStatusOverFlowCh7 = PDM_RANGE_STAT_RANGEOVF7_MASK, /*!< channel7 range status overflow */
+#endif
+};
+#else
+/*! @brief The PDM output status */
+enum _pdm_output_status
+{
+ kPDM_OutputStatusUnderFlowCh0 = PDM_OUT_STAT_OUTUNF0_MASK, /*!< channel0 output status underflow */
+ kPDM_OutputStatusUnderFlowCh1 = PDM_OUT_STAT_OUTUNF1_MASK, /*!< channel1 output status underflow */
+ kPDM_OutputStatusUnderFlowCh2 = PDM_OUT_STAT_OUTUNF2_MASK, /*!< channel2 output status underflow */
+ kPDM_OutputStatusUnderFlowCh3 = PDM_OUT_STAT_OUTUNF3_MASK, /*!< channel3 output status underflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_OutputStatusUnderFlowCh4 = PDM_OUT_STAT_OUTUNF4_MASK, /*!< channel4 output status underflow */
+ kPDM_OutputStatusUnderFlowCh5 = PDM_OUT_STAT_OUTUNF5_MASK, /*!< channel5 output status underflow */
+ kPDM_OutputStatusUnderFlowCh6 = PDM_OUT_STAT_OUTUNF6_MASK, /*!< channel6 output status underflow */
+ kPDM_OutputStatusUnderFlowCh7 = PDM_OUT_STAT_OUTUNF7_MASK, /*!< channel7 output status underflow */
+#endif
+ kPDM_OutputStatusOverFlowCh0 = PDM_OUT_STAT_OUTOVF0_MASK, /*!< channel0 output status overflow */
+ kPDM_OutputStatusOverFlowCh1 = PDM_OUT_STAT_OUTOVF1_MASK, /*!< channel1 output status overflow */
+ kPDM_OutputStatusOverFlowCh2 = PDM_OUT_STAT_OUTOVF2_MASK, /*!< channel2 output status overflow */
+ kPDM_OutputStatusOverFlowCh3 = PDM_OUT_STAT_OUTOVF3_MASK, /*!< channel3 output status overflow */
+#if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
+ kPDM_OutputStatusOverFlowCh4 = PDM_OUT_STAT_OUTOVF4_MASK, /*!< channel4 output status overflow */
+ kPDM_OutputStatusOverFlowCh5 = PDM_OUT_STAT_OUTOVF5_MASK, /*!< channel5 output status overflow */
+ kPDM_OutputStatusOverFlowCh6 = PDM_OUT_STAT_OUTOVF6_MASK, /*!< channel6 output status overflow */
+ kPDM_OutputStatusOverFlowCh7 = PDM_OUT_STAT_OUTOVF7_MASK, /*!< channel7 output status overflow */
+#endif
+};
+#endif
+
+#if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
+/*! @brief PDM DC remover configurations */
+typedef enum _pdm_dc_remover
+{
+ kPDM_DcRemoverCutOff20Hz = 0U, /*!< DC remover cut off 20HZ */
+ kPDM_DcRemoverCutOff13Hz = 1U, /*!< DC remover cut off 13.3HZ */
+ kPDM_DcRemoverCutOff40Hz = 2U, /*!< DC remover cut off 40HZ */
+ kPDM_DcRemoverBypass = 3U, /*!< DC remover bypass */
+} pdm_dc_remover_t;
+#else
+/*! @brief PDM DC remover configurations */
+typedef enum _pdm_dc_remover
+{
+ kPDM_DcRemoverCutOff21Hz = 0U, /*!< DC remover cut off 21HZ */
+ kPDM_DcRemoverCutOff83Hz = 1U, /*!< DC remover cut off 83HZ */
+ kPDM_DcRemoverCutOff152Hz = 2U, /*!< DC remover cut off 152HZ */
+ kPDM_DcRemoverBypass = 3U, /*!< DC remover bypass */
+} pdm_dc_remover_t;
+#endif
+
+/*! @brief PDM decimation filter quality mode */
+typedef enum _pdm_df_quality_mode
+{
+ kPDM_QualityModeMedium = 0U, /*!< quality mode memdium */
+ kPDM_QualityModeHigh = 1U, /*!< quality mode high */
+ kPDM_QualityModeLow = 7U, /*!< quality mode low */
+ kPDM_QualityModeVeryLow0 = 6U, /*!< quality mode very low0 */
+ kPDM_QualityModeVeryLow1 = 5U, /*!< quality mode very low1 */
+ kPDM_QualityModeVeryLow2 = 4U, /*!< quality mode very low2 */
+} pdm_df_quality_mode_t;
+
+/*! @brief PDM quality mode K factor */
+enum _pdm_qulaity_mode_k_factor
+{
+ kPDM_QualityModeHighKFactor = 1U, /*!< high quality mode K factor = 1 / 2 */
+ kPDM_QualityModeMediumKFactor = 2U, /*!< medium/very low0 quality mode K factor = 2 / 2 */
+ kPDM_QualityModeLowKFactor = 4U, /*!< low/very low1 quality mode K factor = 4 / 2 */
+ kPDM_QualityModeVeryLow2KFactor = 8U, /*!< very low2 quality mode K factor = 8 / 2 */
+};
+
+/*! @brief PDM decimation filter output gain */
+typedef enum _pdm_df_output_gain
+{
+ kPDM_DfOutputGain0 = 0U, /*!< Decimation filter output gain 0 */
+ kPDM_DfOutputGain1 = 1U, /*!< Decimation filter output gain 1 */
+ kPDM_DfOutputGain2 = 2U, /*!< Decimation filter output gain 2 */
+ kPDM_DfOutputGain3 = 3U, /*!< Decimation filter output gain 3 */
+ kPDM_DfOutputGain4 = 4U, /*!< Decimation filter output gain 4 */
+ kPDM_DfOutputGain5 = 5U, /*!< Decimation filter output gain 5 */
+ kPDM_DfOutputGain6 = 6U, /*!< Decimation filter output gain 6 */
+ kPDM_DfOutputGain7 = 7U, /*!< Decimation filter output gain 7 */
+ kPDM_DfOutputGain8 = 8U, /*!< Decimation filter output gain 8 */
+ kPDM_DfOutputGain9 = 9U, /*!< Decimation filter output gain 9 */
+ kPDM_DfOutputGain10 = 0xAU, /*!< Decimation filter output gain 10 */
+ kPDM_DfOutputGain11 = 0xBU, /*!< Decimation filter output gain 11 */
+ kPDM_DfOutputGain12 = 0xCU, /*!< Decimation filter output gain 12 */
+ kPDM_DfOutputGain13 = 0xDU, /*!< Decimation filter output gain 13 */
+ kPDM_DfOutputGain14 = 0xEU, /*!< Decimation filter output gain 14 */
+ kPDM_DfOutputGain15 = 0xFU, /*!< Decimation filter output gain 15 */
+} pdm_df_output_gain_t;
+
+/*! @brief PDM data width */
+enum _pdm_data_width
+{
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH != 2U)
+ kPDM_DataWwidth24 = 3U, /*!< PDM data width 24bit */
+ kPDM_DataWwidth32 = 4U, /*!< PDM data width 32bit */
+#else
+ kPDM_DataWdith16 = 2U, /*!< PDM data width 16bit */
+#endif
+};
+
+/*! @brief PDM channel configurations */
+typedef struct _pdm_channel_config
+{
+#if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
+ pdm_dc_remover_t outputCutOffFreq; /*!< PDM output DC remover cut off frequency */
+#endif
+
+#if !(defined(FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED) && (FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED))
+ pdm_dc_remover_t cutOffFreq; /*!< DC remover cut off frequency */
+#endif
+
+ pdm_df_output_gain_t gain; /*!< Decimation Filter Output Gain */
+} pdm_channel_config_t;
+
+/*! @brief PDM user configuration structure */
+typedef struct _pdm_config
+{
+ bool
+ enableDoze; /*!< This module will enter disable/low leakage mode if DOZEN is active with ipg_doze is asserted */
+ uint8_t fifoWatermark; /*!< Watermark value for FIFO */
+ pdm_df_quality_mode_t qualityMode; /*!< Quality mode */
+ uint8_t cicOverSampleRate; /*!< CIC filter over sampling rate */
+} pdm_config_t;
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*! @brief PDM voice activity detector interrupt type */
+enum _pdm_hwvad_interrupt_enable
+{
+ kPDM_HwvadErrorInterruptEnable = PDM_VAD0_CTRL_1_VADERIE_MASK, /*!< PDM channel HWVAD error interrupt enable. */
+ kPDM_HwvadInterruptEnable = PDM_VAD0_CTRL_1_VADIE_MASK, /*!< PDM channel HWVAD interrupt */
+};
+
+/*! @brief The PDM hwvad interrupt status flag */
+enum _pdm_hwvad_int_status
+{
+ kPDM_HwvadStatusInputSaturation = PDM_VAD0_STAT_VADINSATF_MASK, /*!< HWVAD saturation condition */
+ kPDM_HwvadStatusVoiceDetectFlag = PDM_VAD0_STAT_VADIF_MASK, /*!< HWVAD voice detect interrupt triggered */
+};
+
+/*! @brief High pass filter configure cut-off frequency*/
+typedef enum _pdm_hwvad_hpf_config
+{
+ kPDM_HwvadHpfBypassed = 0x0U, /*!< High-pass filter bypass */
+ kPDM_HwvadHpfCutOffFreq1750Hz = 0x1U, /*!< High-pass filter cut off frequency 1750HZ */
+ kPDM_HwvadHpfCutOffFreq215Hz = 0x2U, /*!< High-pass filter cut off frequency 215HZ */
+ kPDM_HwvadHpfCutOffFreq102Hz = 0x3U, /*!< High-pass filter cut off frequency 102HZ */
+} pdm_hwvad_hpf_config_t;
+
+/*! @brief HWVAD internal filter status */
+typedef enum _pdm_hwvad_filter_status
+{
+ kPDM_HwvadInternalFilterNormalOperation = 0U, /*!< internal filter ready for normal operation */
+ kPDM_HwvadInternalFilterInitial = PDM_VAD0_CTRL_1_VADST10_MASK, /*!< interla filter are initial */
+} pdm_hwvad_filter_status_t;
+
+/*! @brief PDM voice activity detector user configuration structure */
+typedef struct _pdm_hwvad_config
+{
+ uint8_t channel; /*!< Which channel uses voice activity detector */
+ uint8_t initializeTime; /*!< Number of frames or samples to initialize voice activity detector. */
+ uint8_t cicOverSampleRate; /*!< CIC filter over sampling rate */
+
+ uint8_t inputGain; /*!< Voice activity detector input gain */
+ uint32_t frameTime; /*!< Voice activity frame time */
+ pdm_hwvad_hpf_config_t cutOffFreq; /*!< High pass filter cut off frequency */
+ bool enableFrameEnergy; /*!< If frame energy enabled, true means enable */
+ bool enablePreFilter; /*!< If pre-filter enabled */
+} pdm_hwvad_config_t;
+
+/*! @brief PDM voice activity detector noise filter user configuration structure */
+typedef struct _pdm_hwvad_noise_filter
+{
+ bool enableAutoNoiseFilter; /*!< If noise fileter automatically activated, true means enable */
+ bool enableNoiseMin; /*!< If Noise minimum block enabled, true means enabled */
+ bool enableNoiseDecimation; /*!< If enable noise input decimation */
+ bool enableNoiseDetectOR; /*!< Enables a OR logic in the output of minimum noise estimator block */
+ uint32_t noiseFilterAdjustment; /*!< The adjustment value of the noise filter */
+ uint32_t noiseGain; /*!< Gain value for the noise energy or envelope estimated */
+} pdm_hwvad_noise_filter_t;
+
+/*! @brief PDM voice activity detector zero cross detector result */
+typedef enum _pdm_hwvad_zcd_result
+{
+ kPDM_HwvadResultOREnergyBasedDetection =
+ 0U, /*!< zero cross detector result will be OR with energy based detection */
+ kPDM_HwvadResultANDEnergyBasedDetection =
+ 1U, /*!< zero cross detector result will be AND with energy based detection */
+} pdm_hwvad_zcd_result_t;
+
+/*! @brief PDM voice activity detector zero cross detector configuration structure */
+typedef struct _pdm_hwvad_zero_cross_detector
+{
+ bool enableAutoThreshold; /*!< If ZCD auto-threshold enabled, true means enabled. */
+ pdm_hwvad_zcd_result_t zcdAnd; /*!< Is ZCD result is AND'ed with energy-based detection, false means OR'ed */
+ uint32_t threshold; /*!< The adjustment value of the noise filter */
+ uint32_t adjustmentThreshold; /*!< Gain value for the noise energy or envelope estimated */
+} pdm_hwvad_zero_cross_detector_t;
+#endif
+
+/*! @brief PDM SDMA transfer structure */
+typedef struct _pdm_transfer
+{
+ volatile uint8_t *data; /*!< Data start address to transfer. */
+ volatile size_t dataSize; /*!< Total Transfer bytes size. */
+} pdm_transfer_t;
+
+/*! @brief PDM handle */
+typedef struct _pdm_handle pdm_handle_t;
+
+/*! @brief PDM transfer callback prototype */
+typedef void (*pdm_transfer_callback_t)(PDM_Type *base, pdm_handle_t *handle, status_t status, void *userData);
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*! @brief PDM HWVAD callback prototype */
+typedef void (*pdm_hwvad_callback_t)(status_t status, void *userData);
+/*! @brief PDM HWVAD notification structure */
+typedef struct _pdm_hwvad_notification
+{
+ pdm_hwvad_callback_t callback;
+ void *userData;
+} pdm_hwvad_notification_t;
+#endif
+
+/*! @brief PDM handle structure */
+struct _pdm_handle
+{
+ uint32_t state; /*!< Transfer status */
+ pdm_transfer_callback_t callback; /*!< Callback function called at transfer event*/
+ void *userData; /*!< Callback parameter passed to callback function*/
+
+ pdm_transfer_t pdmQueue[PDM_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */
+ size_t transferSize[PDM_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+
+ uint32_t format; /*!< data format */
+ uint8_t watermark; /*!< Watermark value */
+ uint8_t startChannel; /*!< end channel */
+ uint8_t channelNums; /*!< Enabled channel number */
+};
+
+/*******************************************************************************
+ * API
+ ******************************************************************************/
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /*_cplusplus*/
+
+/*!
+ * @name Initialization and deinitialization
+ * @{
+ */
+
+/*!
+ * @brief Initializes the PDM peripheral.
+ *
+ * Ungates the PDM clock, resets the module, and configures PDM with a configuration structure.
+ * The configuration structure can be custom filled or set with default values by
+ * PDM_GetDefaultConfig().
+ *
+ * @note This API should be called at the beginning of the application to use
+ * the PDM driver. Otherwise, accessing the PDM module can cause a hard fault
+ * because the clock is not enabled.
+ *
+ * @param base PDM base pointer
+ * @param config PDM configuration structure.
+ */
+void PDM_Init(PDM_Type *base, const pdm_config_t *config);
+
+/*!
+ * @brief De-initializes the PDM peripheral.
+ *
+ * This API gates the PDM clock. The PDM module can't operate unless PDM_Init
+ * is called to enable the clock.
+ *
+ * @param base PDM base pointer
+ */
+void PDM_Deinit(PDM_Type *base);
+
+/*!
+ * @brief Resets the PDM module.
+ *
+ * @param base PDM base pointer
+ */
+static inline void PDM_Reset(PDM_Type *base)
+{
+ base->CTRL_1 |= PDM_CTRL_1_SRES_MASK;
+}
+
+/*!
+ * @brief Enables/disables PDM interface.
+ *
+ * @param base PDM base pointer
+ * @param enable True means PDM interface is enabled, false means PDM interface is disabled.
+ */
+static inline void PDM_Enable(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_PDMIEN_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_PDMIEN_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables DOZE.
+ *
+ * @param base PDM base pointer
+ * @param enable True means the module will enter Disable/Low Leakage mode when ipg_doze is asserted, false means the
+ * module will not enter Disable/Low Leakage mode when ipg_doze is asserted.
+ */
+static inline void PDM_EnableDoze(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_DOZEN_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_DOZEN_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables debug mode for PDM.
+ * The PDM interface cannot enter debug mode once in Disable/Low Leakage or Low Power mode.
+ * @param base PDM base pointer
+ * @param enable True means PDM interface enter debug mode, false means PDM interface in normal mode.
+ */
+static inline void PDM_EnableDebugMode(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_DBG_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_DBG_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables PDM interface in debug mode.
+ *
+ * @param base PDM base pointer
+ * @param enable True means PDM interface is enabled debug mode, false means PDM interface is disabled after
+ * after completing the current frame in debug mode.
+ */
+static inline void PDM_EnableInDebugMode(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_DBGE_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_DBGE_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables PDM interface disable/Low Leakage mode.
+ *
+ * @param base PDM base pointer
+ * @param enable True means PDM interface is in disable/low leakage mode, False means PDM interface is in normal mode.
+ */
+static inline void PDM_EnterLowLeakageMode(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= PDM_CTRL_1_MDIS_MASK;
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_MDIS_MASK;
+ }
+}
+
+/*!
+ * @brief Enables/disables the PDM channel.
+ *
+ * @param base PDM base pointer
+ * @param channel PDM channel number need to enable or disable.
+ * @param enable True means enable PDM channel, false means disable.
+ */
+static inline void PDM_EnableChannel(PDM_Type *base, uint8_t channel, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 |= (1UL << channel);
+ }
+ else
+ {
+ base->CTRL_1 &= ~(1UL << channel);
+ }
+}
+
+/*!
+ * @brief PDM one channel configurations.
+ *
+ * @param base PDM base pointer
+ * @param config PDM channel configurations.
+ * @param channel channel number.
+ * after completing the current frame in debug mode.
+ */
+void PDM_SetChannelConfig(PDM_Type *base, uint32_t channel, const pdm_channel_config_t *config);
+
+/*!
+ * @brief PDM set sample rate.
+ *
+ * @note This function is depend on the configuration of the PDM and PDM channel, so the correct call sequence is
+ * @code
+ * PDM_Init(base, pdmConfig)
+ * PDM_SetChannelConfig(base, channel, &channelConfig)
+ * PDM_SetSampleRateConfig(base, source, sampleRate)
+ * @endcode
+ * @param base PDM base pointer
+ * @param sourceClock_HZ PDM source clock frequency.
+ * @param sampleRate_HZ PDM sample rate.
+ */
+status_t PDM_SetSampleRateConfig(PDM_Type *base, uint32_t sourceClock_HZ, uint32_t sampleRate_HZ);
+
+/*!
+ * @brief PDM set sample rate.
+ *
+ * @deprecated Do not use this function. It has been superceded by @ref PDM_SetSampleRateConfig
+ * @param base PDM base pointer
+ * @param enableChannelMask PDM channel enable mask.
+ * @param qualityMode quality mode.
+ * @param osr cic oversample rate
+ * @param clkDiv clock divider
+ */
+status_t PDM_SetSampleRate(
+ PDM_Type *base, uint32_t enableChannelMask, pdm_df_quality_mode_t qualityMode, uint8_t osr, uint32_t clkDiv);
+
+/*!
+ * @brief Get the instance number for PDM.
+ *
+ * @param base PDM base pointer.
+ */
+uint32_t PDM_GetInstance(PDM_Type *base);
+/*! @} */
+
+/*!
+ * @name Status
+ * @{
+ */
+
+/*!
+ * @brief Gets the PDM internal status flag.
+ * Use the Status Mask in _pdm_internal_status to get the status value needed
+ * @param base PDM base pointer
+ * @return PDM status flag value.
+ */
+static inline uint32_t PDM_GetStatus(PDM_Type *base)
+{
+ return base->STAT;
+}
+
+/*!
+ * @brief Gets the PDM FIFO status flag.
+ * Use the Status Mask in _pdm_fifo_status to get the status value needed
+ * @param base PDM base pointer
+ * @return FIFO status.
+ */
+static inline uint32_t PDM_GetFifoStatus(PDM_Type *base)
+{
+ return base->FIFO_STAT;
+}
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+/*!
+ * @brief Gets the PDM Range status flag.
+ * Use the Status Mask in _pdm_range_status to get the status value needed
+ * @param base PDM base pointer
+ * @return output status.
+ */
+static inline uint32_t PDM_GetRangeStatus(PDM_Type *base)
+{
+ return base->RANGE_STAT;
+}
+#else
+/*!
+ * @brief Gets the PDM output status flag.
+ * Use the Status Mask in _pdm_output_status to get the status value needed
+ * @param base PDM base pointer
+ * @return output status.
+ */
+static inline uint32_t PDM_GetOutputStatus(PDM_Type *base)
+{
+ return base->OUT_STAT;
+}
+#endif
+
+/*!
+ * @brief Clears the PDM Tx status.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask. It can be a combination of the status between kPDM_StatusFrequencyLow and
+ * kPDM_StatusCh7FifoDataAvaliable.
+ */
+static inline void PDM_ClearStatus(PDM_Type *base, uint32_t mask)
+{
+ base->STAT = mask;
+}
+
+/*!
+ * @brief Clears the PDM Tx status.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask.It can be a combination of the status in _pdm_fifo_status.
+ */
+static inline void PDM_ClearFIFOStatus(PDM_Type *base, uint32_t mask)
+{
+ base->FIFO_STAT = mask;
+}
+
+#if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
+/*!
+ * @brief Clears the PDM range status.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask. It can be a combination of the status in _pdm_range_status.
+ */
+static inline void PDM_ClearRangeStatus(PDM_Type *base, uint32_t mask)
+{
+ base->RANGE_STAT = mask;
+}
+#else
+/*!
+ * @brief Clears the PDM output status.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask. It can be a combination of the status in _pdm_output_status.
+ */
+static inline void PDM_ClearOutputStatus(PDM_Type *base, uint32_t mask)
+{
+ base->OUT_STAT = mask;
+}
+#endif
+
+/*! @} */
+
+/*!
+ * @name Interrupts
+ * @{
+ */
+
+/*!
+ * @brief Enables the PDM interrupt requests.
+ *
+ * @param base PDM base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kPDM_ErrorInterruptEnable
+ * @arg kPDM_FIFOInterruptEnable
+ */
+void PDM_EnableInterrupts(PDM_Type *base, uint32_t mask);
+
+/*!
+ * @brief Disables the PDM interrupt requests.
+ *
+ * @param base PDM base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kPDM_ErrorInterruptEnable
+ * @arg kPDM_FIFOInterruptEnable
+ */
+static inline void PDM_DisableInterrupts(PDM_Type *base, uint32_t mask)
+{
+ base->CTRL_1 &= ~mask;
+}
+
+/*! @} */
+
+/*!
+ * @name DMA Control
+ * @{
+ */
+
+/*!
+ * @brief Enables/disables the PDM DMA requests.
+ *
+ * @param base PDM base pointer
+ * @param enable True means enable DMA, false means disable DMA.
+ */
+static inline void PDM_EnableDMA(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DISEL_MASK)) | PDM_CTRL_1_DISEL(0x1U);
+ }
+ else
+ {
+ base->CTRL_1 &= ~PDM_CTRL_1_DISEL_MASK;
+ }
+}
+
+/*!
+ * @brief Gets the PDM data register address.
+ *
+ * This API is used to provide a transfer address for the PDM DMA transfer configuration.
+ *
+ * @param base PDM base pointer.
+ * @param channel Which data channel used.
+ * @return data register address.
+ */
+static inline uint32_t PDM_GetDataRegisterAddress(PDM_Type *base, uint32_t channel)
+{
+ return (uint32_t)(&(base->DATACH)[channel]);
+}
+
+/*! @} */
+
+/*!
+ * @name Bus Operations
+ * @{
+ */
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 2U)
+/*!
+ * @brief Reads data from the PDM FIFO.
+ *
+ * @param base PDM base pointer.
+ * @param channel Data channel used.
+ * @return Data in PDM FIFO.
+ */
+static inline int16_t PDM_ReadData(PDM_Type *base, uint32_t channel)
+{
+ return (int16_t)(base->DATACH[channel]);
+}
+
+/*!
+ * @brief PDM read data non blocking.
+ * So the actually read data byte size in this function is (size * 2 * channelNums).
+ * @param base PDM base pointer.
+ * @param startChannel start channel number.
+ * @param channelNums total enabled channelnums.
+ * @param buffer received buffer address.
+ * @param size number of 16bit data to read.
+ */
+void PDM_ReadNonBlocking(PDM_Type *base, uint32_t startChannel, uint32_t channelNums, int16_t *buffer, size_t size);
+#endif
+
+/*!
+ * @brief PDM read fifo.
+ * @note: This function support 16 bit only for IP version that only supports 16bit.
+ *
+ * @param base PDM base pointer.
+ * @param startChannel start channel number.
+ * @param channelNums total enabled channelnums.
+ * @param buffer received buffer address.
+ * @param size number of samples to read.
+ * @param dataWidth sample width.
+ */
+void PDM_ReadFifo(
+ PDM_Type *base, uint32_t startChannel, uint32_t channelNums, void *buffer, size_t size, uint32_t dataWidth);
+
+#if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 4U)
+/*!
+ * @brief Reads data from the PDM FIFO.
+ *
+ * @param base PDM base pointer.
+ * @param channel Data channel used.
+ * @return Data in PDM FIFO.
+ */
+static inline uint32_t PDM_ReadData(PDM_Type *base, uint32_t channel)
+{
+ return base->DATACH[channel];
+}
+#endif
+
+/*!
+ * @brief Set the PDM channel gain.
+ *
+ * Please note for different quality mode, the valid gain value is different, reference RM for detail.
+ * @param base PDM base pointer.
+ * @param channel PDM channel index.
+ * @param gain channel gain, the register gain value range is 0 - 15.
+ */
+void PDM_SetChannelGain(PDM_Type *base, uint32_t channel, pdm_df_output_gain_t gain);
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
+/*! @} */
+
+/*!
+ * @name Voice Activity Detector
+ * @{
+ */
+
+/*!
+ * @brief Configure voice activity detector.
+ *
+ * @param base PDM base pointer
+ * @param config Voice activity detector configure structure pointer .
+ */
+void PDM_SetHwvadConfig(PDM_Type *base, const pdm_hwvad_config_t *config);
+
+/*!
+ * @brief PDM hwvad force output disable.
+ *
+ * @param base PDM base pointer
+ * @param enable true is output force disable, false is output not force.
+ */
+static inline void PDM_ForceHwvadOutputDisable(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->VAD0_CTRL_2 &= ~PDM_VAD0_CTRL_2_VADFOUTDIS_MASK;
+ }
+ else
+ {
+ base->VAD0_CTRL_2 |= PDM_VAD0_CTRL_2_VADFOUTDIS_MASK;
+ }
+}
+
+/*!
+ * @brief PDM hwvad reset.
+ * It will reset VADNDATA register and will clean all internal buffers, should be called when the PDM isn't running.
+ *
+ * @param base PDM base pointer
+ */
+static inline void PDM_ResetHwvad(PDM_Type *base)
+{
+ base->VAD0_CTRL_1 |= PDM_VAD0_CTRL_1_VADRST_MASK;
+}
+/*!
+ * @brief Enable/Disable Voice activity detector.
+ * Should be called when the PDM isn't running.
+ * @param base PDM base pointer.
+ * @param enable True means enable voice activity detector, false means disable.
+ */
+static inline void PDM_EnableHwvad(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->VAD0_CTRL_1 |= PDM_VAD0_CTRL_1_VADEN_MASK;
+ }
+ else
+ {
+ base->VAD0_CTRL_1 &= ~PDM_VAD0_CTRL_1_VADEN_MASK;
+ }
+}
+
+/*!
+ * @brief Enables the PDM Voice Detector interrupt requests.
+ *
+ * @param base PDM base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kPDM_HWVADErrorInterruptEnable
+ * @arg kPDM_HWVADInterruptEnable
+ */
+static inline void PDM_EnableHwvadInterrupts(PDM_Type *base, uint32_t mask)
+{
+ base->VAD0_CTRL_1 |= mask;
+}
+
+/*!
+ * @brief Disables the PDM Voice Detector interrupt requests.
+ *
+ * @param base PDM base pointer
+ * @param mask interrupt source
+ * The parameter can be a combination of the following sources if defined.
+ * @arg kPDM_HWVADErrorInterruptEnable
+ * @arg kPDM_HWVADInterruptEnable
+ */
+static inline void PDM_DisableHwvadInterrupts(PDM_Type *base, uint32_t mask)
+{
+ base->VAD0_CTRL_1 &= ~mask;
+}
+
+/*!
+ * @brief Clears the PDM voice activity detector status flags.
+ *
+ * @param base PDM base pointer
+ * @param mask State mask,reference _pdm_hwvad_int_status.
+ */
+static inline void PDM_ClearHwvadInterruptStatusFlags(PDM_Type *base, uint32_t mask)
+{
+ base->VAD0_STAT = mask;
+}
+
+/*!
+ * @brief Clears the PDM voice activity detector status flags.
+ *
+ * @param base PDM base pointer
+ * @return status, reference _pdm_hwvad_int_status
+ */
+static inline uint32_t PDM_GetHwvadInterruptStatusFlags(PDM_Type *base)
+{
+ return base->VAD0_STAT & (PDM_VAD0_STAT_VADIF_MASK | PDM_VAD0_STAT_VADINSATF_MASK);
+}
+
+/*!
+ * @brief Get the PDM voice activity detector initial flags.
+ *
+ * @param base PDM base pointer
+ * @return initial flag.
+ */
+static inline uint32_t PDM_GetHwvadInitialFlag(PDM_Type *base)
+{
+ return base->VAD0_STAT & PDM_VAD0_STAT_VADINITF_MASK;
+}
+
+#if !(defined(FSL_FEATURE_PDM_HAS_NO_VADEF) && (FSL_FEATURE_PDM_HAS_NO_VADEF))
+/*!
+ * @brief Get the PDM voice activity detector voice detected flags.
+ * NOte: this flag is auto cleared when voice gone.
+ * @param base PDM base pointer
+ * @return voice detected flag.
+ */
+static inline uint32_t PDM_GetHwvadVoiceDetectedFlag(PDM_Type *base)
+{
+ return base->VAD0_STAT & PDM_VAD0_STAT_VADEF_MASK;
+}
+#endif
+
+/*!
+ * @brief Enables/disables voice activity detector signal filter.
+ *
+ * @param base PDM base pointer
+ * @param enable True means enable signal filter, false means disable.
+ */
+static inline void PDM_EnableHwvadSignalFilter(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->VAD0_SCONFIG |= PDM_VAD0_SCONFIG_VADSFILEN_MASK;
+ }
+ else
+ {
+ base->VAD0_SCONFIG &= ~PDM_VAD0_SCONFIG_VADSFILEN_MASK;
+ }
+}
+
+/*!
+ * @brief Configure voice activity detector signal filter.
+ *
+ * @param base PDM base pointer
+ * @param enableMaxBlock If signal maximum block enabled.
+ * @param signalGain Gain value for the signal energy.
+ */
+void PDM_SetHwvadSignalFilterConfig(PDM_Type *base, bool enableMaxBlock, uint32_t signalGain);
+
+/*!
+ * @brief Configure voice activity detector noise filter.
+ *
+ * @param base PDM base pointer
+ * @param config Voice activity detector noise filter configure structure pointer .
+ */
+void PDM_SetHwvadNoiseFilterConfig(PDM_Type *base, const pdm_hwvad_noise_filter_t *config);
+
+/*!
+ * @brief Enables/disables voice activity detector zero cross detector.
+ *
+ * @param base PDM base pointer
+ * @param enable True means enable zero cross detector, false means disable.
+ */
+static inline void PDM_EnableHwvadZeroCrossDetector(PDM_Type *base, bool enable)
+{
+ if (enable)
+ {
+ base->VAD0_ZCD |= PDM_VAD0_ZCD_VADZCDEN_MASK;
+ }
+ else
+ {
+ base->VAD0_ZCD &= ~PDM_VAD0_ZCD_VADZCDEN_MASK;
+ }
+}
+
+/*!
+ * @brief Configure voice activity detector zero cross detector.
+ *
+ * @param base PDM base pointer
+ * @param config Voice activity detector zero cross detector configure structure pointer .
+ */
+void PDM_SetHwvadZeroCrossDetectorConfig(PDM_Type *base, const pdm_hwvad_zero_cross_detector_t *config);
+
+/*!
+ * @brief Reads noise data.
+ *
+ * @param base PDM base pointer.
+ * @return Data in PDM noise data register.
+ */
+static inline uint16_t PDM_GetNoiseData(PDM_Type *base)
+{
+ return (uint16_t)base->VAD0_NDATA;
+}
+
+/*!
+ * @brief set hwvad internal filter status .
+ * Note: filter initial status should be asserted for two more cycles, then set it to normal operation.
+ * @param base PDM base pointer.
+ * @param status internal filter status.
+ */
+static inline void PDM_SetHwvadInternalFilterStatus(PDM_Type *base, pdm_hwvad_filter_status_t status)
+{
+ base->VAD0_CTRL_1 = (base->VAD0_CTRL_1 & (~PDM_VAD0_CTRL_1_VADST10_MASK)) | (uint32_t)status;
+}
+
+/*!
+ * @brief set HWVAD in envelope based mode .
+ * Recommand configurations,
+ * @code
+ * static const pdm_hwvad_config_t hwvadConfig = {
+ * .channel = 0,
+ * .initializeTime = 10U,
+ * .cicOverSampleRate = 0U,
+ * .inputGain = 0U,
+ * .frameTime = 10U,
+ * .cutOffFreq = kPDM_HwvadHpfBypassed,
+ * .enableFrameEnergy = false,
+ * .enablePreFilter = true,
+};
+
+ * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
+ * .enableAutoNoiseFilter = false,
+ * .enableNoiseMin = true,
+ * .enableNoiseDecimation = true,
+ * .noiseFilterAdjustment = 0U,
+ * .noiseGain = 7U,
+ * .enableNoiseDetectOR = true,
+ * };
+ * @endcode
+ * @param base PDM base pointer.
+ * @param hwvadConfig internal filter status.
+ * @param noiseConfig Voice activity detector noise filter configure structure pointer.
+ * @param zcdConfig Voice activity detector zero cross detector configure structure pointer .
+ * @param signalGain signal gain value.
+ */
+void 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);
+
+/*!
+ * brief set HWVAD in energy based mode .
+ * Recommand configurations,
+ * code
+ * static const pdm_hwvad_config_t hwvadConfig = {
+ * .channel = 0,
+ * .initializeTime = 10U,
+ * .cicOverSampleRate = 0U,
+ * .inputGain = 0U,
+ * .frameTime = 10U,
+ * .cutOffFreq = kPDM_HwvadHpfBypassed,
+ * .enableFrameEnergy = true,
+ * .enablePreFilter = true,
+};
+
+ * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
+ * .enableAutoNoiseFilter = true,
+ * .enableNoiseMin = false,
+ * .enableNoiseDecimation = false,
+ * .noiseFilterAdjustment = 0U,
+ * .noiseGain = 7U,
+ * .enableNoiseDetectOR = false,
+ * };
+ * code
+ * param base PDM base pointer.
+ * param hwvadConfig internal filter status.
+ * param noiseConfig Voice activity detector noise filter configure structure pointer.
+ * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
+ * param signalGain signal gain value, signal gain value should be properly according to application.
+ */
+void 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);
+
+/*!
+ * @brief Enable/Disable hwvad callback.
+
+ * This function enable/disable the hwvad interrupt for the selected PDM peripheral.
+ *
+ * @param base Base address of the PDM peripheral.
+ * @param vadCallback callback Pointer to store callback function, should be NULL when disable.
+ * @param userData user data.
+ * @param enable true is enable, false is disable.
+ * @retval None.
+ */
+void PDM_EnableHwvadInterruptCallback(PDM_Type *base, pdm_hwvad_callback_t vadCallback, void *userData, bool enable);
+/*! @} */
+#endif
+
+/*!
+ * @name Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the PDM handle.
+ *
+ * This function initializes the handle for the PDM transactional APIs. Call
+ * this function once to get the handle initialized.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM handle pointer.
+ * @param callback Pointer to the user callback function.
+ * @param userData User parameter passed to the callback function.
+ */
+void PDM_TransferCreateHandle(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_callback_t callback, void *userData);
+
+/*!
+ * @brief PDM set channel transfer config.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM handle pointer.
+ * @param channel PDM channel.
+ * @param config channel config.
+ * @param format data format, support data width configurations,_pdm_data_width.
+ * @retval kStatus_PDM_ChannelConfig_Failed or kStatus_Success.
+ */
+status_t PDM_TransferSetChannelConfig(
+ PDM_Type *base, pdm_handle_t *handle, uint32_t channel, const pdm_channel_config_t *config, uint32_t format);
+
+/*!
+ * @brief Performs an interrupt non-blocking receive transfer on PDM.
+ *
+ * @note This API returns immediately after the transfer initiates.
+ * Call the PDM_RxGetTransferStatusIRQ to poll the transfer status and check whether
+ * the transfer is finished. If the return status is not kStatus_PDM_Busy, the transfer
+ * is finished.
+ *
+ * @param base PDM base pointer
+ * @param handle Pointer to the pdm_handle_t structure which stores the transfer state.
+ * @param xfer Pointer to the pdm_transfer_t structure.
+ * @retval kStatus_Success Successfully started the data receive.
+ * @retval kStatus_PDM_Busy Previous receive still not finished.
+ */
+status_t PDM_TransferReceiveNonBlocking(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_t *xfer);
+
+/*!
+ * @brief Aborts the current IRQ receive.
+ *
+ * @note This API can be called when an interrupt non-blocking transfer initiates
+ * to abort the transfer early.
+ *
+ * @param base PDM base pointer
+ * @param handle Pointer to the pdm_handle_t structure which stores the transfer state.
+ */
+void PDM_TransferAbortReceive(PDM_Type *base, pdm_handle_t *handle);
+
+/*!
+ * @brief Tx interrupt handler.
+ *
+ * @param base PDM base pointer.
+ * @param handle Pointer to the pdm_handle_t structure.
+ */
+void PDM_TransferHandleIRQ(PDM_Type *base, pdm_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif /*_cplusplus*/
+
+/*! @} */
+
+#endif /* _FSL_PDM_H_ */
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.c b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.c
new file mode 100644
index 0000000000..3c8104b5f3
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.c
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2019 NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "fsl_pdm_edma.h"
+
+/* Component ID definition, used by tools. */
+#ifndef FSL_COMPONENT_ID
+#define FSL_COMPONENT_ID "platform.drivers.pdm_edma"
+#endif
+
+/*******************************************************************************
+ * Definitations
+ ******************************************************************************/
+/* Used for 32byte aligned */
+#define STCD_ADDR(address) (edma_tcd_t *)(((uint32_t)(address) + 32) & ~0x1FU)
+
+/*<! Structure definition for pdm_edma_private_handle_t. The structure is private. */
+typedef struct _pdm_edma_private_handle
+{
+ PDM_Type *base;
+ pdm_edma_handle_t *handle;
+} pdm_edma_private_handle_t;
+
+/*! @brief pdm transfer state */
+enum _pdm_edma_transfer_state
+{
+ kPDM_Busy = 0x0U, /*!< PDM is busy */
+ kPDM_Idle, /*!< Transfer is done. */
+};
+
+/*******************************************************************************
+ * Prototypes
+ ******************************************************************************/
+/*!
+ * @brief PDM EDMA callback for receive.
+ *
+ * @param handle pointer to pdm_edma_handle_t structure which stores the transfer state.
+ * @param userData Parameter for user callback.
+ * @param done If the DMA transfer finished.
+ * @param tcds The TCD index.
+ */
+static void PDM_EDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds);
+
+/*!
+ * @brief Mapping the enabled channel to a number power of 2.
+ *
+ * @param channel PDM channel number.
+ */
+static edma_modulo_t PDM_TransferMappingChannel(uint32_t *channel);
+/*******************************************************************************
+ * Variables
+ ******************************************************************************/
+
+/*! @brief pdm base address pointer */
+static PDM_Type *const s_pdmBases[] = PDM_BASE_PTRS;
+/*<! Private handle only used for internally. */
+static pdm_edma_private_handle_t s_edmaPrivateHandle[ARRAY_SIZE(s_pdmBases)];
+/*******************************************************************************
+ * Code
+ ******************************************************************************/
+static edma_modulo_t PDM_TransferMappingChannel(uint32_t *channel)
+{
+ edma_modulo_t modulo = kEDMA_ModuloDisable;
+#if FSL_FEATURE_PDM_CHANNEL_NUM == 8U
+ if (*channel == 2U)
+ {
+ modulo = kEDMA_Modulo8bytes;
+ }
+ else if ((*channel == 3U) || (*channel == 4U))
+ {
+ *channel = 4U;
+ modulo = kEDMA_Modulo16bytes;
+ }
+ else
+ {
+ modulo = kEDMA_ModuloDisable;
+ }
+#endif
+
+ return modulo;
+}
+
+static void PDM_EDMACallback(edma_handle_t *handle, void *userData, bool done, uint32_t tcds)
+{
+ pdm_edma_private_handle_t *privHandle = (pdm_edma_private_handle_t *)userData;
+ pdm_edma_handle_t *pdmHandle = privHandle->handle;
+
+ if (!(pdmHandle->isLoopTransfer))
+ {
+ (void)memset(&pdmHandle->tcd[pdmHandle->tcdDriver], 0, sizeof(edma_tcd_t));
+ pdmHandle->tcdDriver = (pdmHandle->tcdDriver + 1U) % pdmHandle->tcdNum;
+ }
+
+ pdmHandle->receivedBytes +=
+ pdmHandle->tcd[pdmHandle->tcdDriver].BITER * (pdmHandle->tcd[pdmHandle->tcdDriver].NBYTES & 0x3FFU);
+
+ /* If finished a block, call the callback function */
+ if (pdmHandle->callback != NULL)
+ {
+ (pdmHandle->callback)(privHandle->base, pdmHandle, kStatus_PDM_Idle, pdmHandle->userData);
+ }
+
+ pdmHandle->tcdUsedNum--;
+ /* If all data finished, just stop the transfer */
+ if ((pdmHandle->tcdUsedNum == 0U) && !(pdmHandle->isLoopTransfer))
+ {
+ /* Disable DMA enable bit */
+ PDM_EnableDMA(privHandle->base, false);
+ EDMA_AbortTransfer(handle);
+ }
+}
+
+/*!
+ * brief Initializes the PDM Rx eDMA handle.
+ *
+ * This function initializes the PDM slave DMA handle, which can be used for other PDM master transactional APIs.
+ * Usually, for a specified PDM instance, call this API once to get the initialized handle.
+ *
+ * param base PDM base pointer.
+ * param handle PDM eDMA handle pointer.
+ * param base PDM peripheral base address.
+ * param callback Pointer to user callback function.
+ * param userData User parameter passed to the callback function.
+ * param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void PDM_TransferCreateHandleEDMA(
+ PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle)
+{
+ assert((handle != NULL) && (dmaHandle != NULL));
+
+ uint32_t instance = PDM_GetInstance(base);
+
+ /* Zero the handle */
+ (void)memset(handle, 0, sizeof(*handle));
+
+ /* Set pdm base to handle */
+ handle->dmaHandle = dmaHandle;
+ handle->callback = callback;
+ handle->userData = userData;
+
+ /* Set PDM state to idle */
+ handle->state = (uint32_t)kPDM_Idle;
+
+ s_edmaPrivateHandle[instance].base = base;
+ s_edmaPrivateHandle[instance].handle = handle;
+
+ /* Install callback for Tx dma channel */
+ EDMA_SetCallback(dmaHandle, PDM_EDMACallback, &s_edmaPrivateHandle[instance]);
+}
+
+/*!
+ * brief Initializes the multi PDM channel interleave type.
+ *
+ * This function initializes the PDM DMA handle member interleaveType, it shall be called only when application would
+ * like to use type kPDM_EDMAMultiChannelInterleavePerChannelBlock, since the default interleaveType is
+ * kPDM_EDMAMultiChannelInterleavePerChannelSample always
+ *
+ * param handle PDM eDMA handle pointer.
+ * param multiChannelInterleaveType Multi channel interleave type.
+ */
+void PDM_TransferSetMultiChannelInterleaveType(pdm_edma_handle_t *handle,
+ pdm_edma_multi_channel_interleave_t multiChannelInterleaveType)
+{
+ handle->interleaveType = multiChannelInterleaveType;
+}
+
+/*!
+ * brief Install EDMA descriptor memory.
+ *
+ * param handle Pointer to EDMA channel transfer handle.
+ * param tcdAddr EDMA head descriptor address.
+ * param tcdNum EDMA link descriptor address.
+ */
+void PDM_TransferInstallEDMATCDMemory(pdm_edma_handle_t *handle, void *tcdAddr, size_t tcdNum)
+{
+ assert(handle != NULL);
+
+ handle->tcd = (edma_tcd_t *)tcdAddr;
+ handle->tcdNum = tcdNum;
+}
+
+/*!
+ * brief Configures the PDM channel.
+ *
+ * param base PDM base pointer.
+ * param handle PDM eDMA handle pointer.
+ * param channel channel index.
+ * param pdmConfig pdm channel configurations.
+ */
+void PDM_TransferSetChannelConfigEDMA(PDM_Type *base,
+ pdm_edma_handle_t *handle,
+ uint32_t channel,
+ const pdm_channel_config_t *config)
+{
+ assert((handle != NULL) && (config != NULL));
+ assert(channel < (uint32_t)FSL_FEATURE_PDM_CHANNEL_NUM);
+
+ /* Configure the PDM channel */
+ PDM_SetChannelConfig(base, channel, config);
+
+ /* record end channel number */
+ handle->endChannel = (uint8_t)channel;
+ /* increase totoal enabled channel number */
+ handle->channelNums++;
+ /* increase count pre channel numbers */
+ handle->count = (uint8_t)(base->FIFO_CTRL & PDM_FIFO_CTRL_FIFOWMK_MASK);
+}
+
+/*!
+ * brief Performs a non-blocking PDM receive using eDMA.
+ *
+ * note This interface returns immediately after the transfer initiates. Call
+ * the PDM_GetReceiveRemainingBytes to poll the transfer status and check whether the PDM transfer is finished.
+ *
+ * 1. Scatter gather case:
+ * This functio support dynamic scatter gather and staic scatter gather,
+ * a. for the dynamic scatter gather case:
+ * Application should call PDM_TransferReceiveEDMA function continuously to make sure new receive request is submit
+ *before the previous one finish. b. for the static scatter gather case: Application should use the link transfer
+ *feature and make sure a loop link transfer is provided, such as: code pdm_edma_transfer_t pdmXfer[2] =
+ * {
+ * {
+ * .data = s_buffer,
+ * .dataSize = BUFFER_SIZE,
+ * .linkTransfer = &pdmXfer[1],
+ * },
+ *
+ * {
+ * .data = &s_buffer[BUFFER_SIZE],
+ * .dataSize = BUFFER_SIZE,
+ * .linkTransfer = &pdmXfer[0]
+ * },
+ * };
+ *endcode
+ *
+ * 2. Multi channel case:
+ * This function support receive multi pdm channel data, for example, if two channel is requested,
+ * code
+ * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_0, &channelConfig);
+ * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_1, &channelConfig);
+ * PDM_TransferReceiveEDMA(DEMO_PDM, &s_pdmRxHandle_0, pdmXfer);
+ * endcode
+ * The output data will be formatted as below if handle->interleaveType =
+ *kPDM_EDMAMultiChannelInterleavePerChannelSample :
+ * -------------------------------------------------------------------------
+ * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....|
+ * -------------------------------------------------------------------------
+ *
+ * The output data will be formatted as below if handle->interleaveType = kPDM_EDMAMultiChannelInterleavePerChannelBlock
+ *:
+ * ----------------------------------------------------------------------------------------------------------------------
+ * |CHANNEL3 | CHANNEL3 | CHANNEL3 | .... | CHANNEL4 | CHANNEL 4 | CHANNEL4 |....| CHANNEL5 | CHANNEL 5 | CHANNEL5
+ *|....|
+ * ----------------------------------------------------------------------------------------------------------------------
+ * Note: the dataSize of xfer is the total data size, while application using
+ * kPDM_EDMAMultiChannelInterleavePerChannelBlock, the buffer size for each PDM channel is channelSize = dataSize /
+ * channelNums, there are limitation for this feature,
+ * 1. For 3 DMIC array: the dataSize shall be 4 * (channelSize)
+ * The addtional buffer is mandantory for edma modulo feature.
+ * 2. The kPDM_EDMAMultiChannelInterleavePerChannelBlock feature support below dmic array only,
+ * 2 DMIC array: CHANNEL3, CHANNEL4
+ * 3 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5
+ * 4 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5, CHANNEL6
+ * Any other combinations is not support, that is to SAY, THE FEATURE SUPPORT RECEIVE START FROM CHANNEL3 ONLY AND 4
+ * MAXIMUM DMIC CHANNELS.
+ *
+ * param base PDM base pointer
+ * param handle PDM eDMA handle pointer.
+ * param xfer Pointer to DMA transfer structure.
+ * retval kStatus_Success Start a PDM eDMA receive successfully.
+ * retval kStatus_InvalidArgument The input argument is invalid.
+ * retval kStatus_RxBusy PDM is busy receiving data.
+ */
+status_t PDM_TransferReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_transfer_t *xfer)
+{
+ assert((handle != NULL) && (xfer != NULL));
+
+ edma_transfer_config_t config = {0};
+ uint32_t startAddr = PDM_GetDataRegisterAddress(base, handle->endChannel - (handle->channelNums - 1UL));
+ pdm_edma_transfer_t *currentTransfer = xfer;
+ uint32_t nextTcdIndex = 0U, tcdIndex = handle->tcdUser, destOffset = FSL_FEATURE_PDM_FIFO_WIDTH;
+ uint32_t mappedChannel = handle->channelNums;
+ edma_modulo_t modulo = kEDMA_ModuloDisable;
+ /* minor offset used for channel sample interleave transfer */
+ edma_minor_offset_config_t minorOffset = {
+ .enableSrcMinorOffset = true,
+ .enableDestMinorOffset = false,
+ .minorOffset = 0xFFFFFU - mappedChannel * (uint32_t)FSL_FEATURE_PDM_FIFO_OFFSET + 1U};
+
+ /* Check if input parameter invalid */
+ if ((xfer->data == NULL) || (xfer->dataSize == 0U))
+ {
+ return kStatus_InvalidArgument;
+ }
+
+ if ((handle->interleaveType == kPDM_EDMAMultiChannelInterleavePerChannelBlock) && (mappedChannel > 1U))
+ {
+ /* Limitation of the feature, reference the API comments */
+ if (((startAddr & 0xFU) != 0U) || (mappedChannel > 4U))
+ {
+ return kStatus_InvalidArgument;
+ }
+ modulo = PDM_TransferMappingChannel(&mappedChannel);
+ if ((xfer->dataSize % mappedChannel) != 0U)
+ {
+ return kStatus_InvalidArgument;
+ }
+ destOffset = xfer->dataSize / mappedChannel;
+ /* reconfigure the minor loop offset for channel block interleave */
+ minorOffset.enableSrcMinorOffset = false, minorOffset.enableDestMinorOffset = true,
+ minorOffset.minorOffset =
+ 0xFFFFFU - mappedChannel * (uint32_t)destOffset + (uint32_t)FSL_FEATURE_PDM_FIFO_WIDTH + 1U;
+ }
+
+ while (currentTransfer != NULL)
+ {
+ if (handle->tcdUsedNum >= handle->tcdNum)
+ {
+ return kStatus_PDM_QueueFull;
+ }
+ else
+ {
+ uint32_t primask = DisableGlobalIRQ();
+ handle->tcdUsedNum++;
+ EnableGlobalIRQ(primask);
+ }
+
+ nextTcdIndex = (handle->tcdUser + 1U) % handle->tcdNum;
+
+ if (mappedChannel == 1U)
+ {
+ EDMA_PrepareTransferConfig(&config, (void *)(uint32_t *)startAddr, FSL_FEATURE_PDM_FIFO_WIDTH, 0,
+ (uint8_t *)(uint32_t)currentTransfer->data, FSL_FEATURE_PDM_FIFO_WIDTH,
+ FSL_FEATURE_PDM_FIFO_WIDTH, handle->count * (uint32_t)FSL_FEATURE_PDM_FIFO_WIDTH,
+ currentTransfer->dataSize);
+ }
+ else
+ {
+ EDMA_PrepareTransferConfig(&config, (void *)(uint32_t *)startAddr, FSL_FEATURE_PDM_FIFO_WIDTH,
+ FSL_FEATURE_PDM_FIFO_OFFSET, (uint8_t *)(uint32_t)currentTransfer->data,
+ FSL_FEATURE_PDM_FIFO_WIDTH, (int16_t)destOffset,
+ mappedChannel * (uint32_t)FSL_FEATURE_PDM_FIFO_WIDTH, currentTransfer->dataSize);
+ }
+
+ EDMA_TcdSetTransferConfig((edma_tcd_t *)&handle->tcd[handle->tcdUser], &config,
+ (edma_tcd_t *)&handle->tcd[nextTcdIndex]);
+
+ if (mappedChannel > 1U)
+ {
+ EDMA_TcdSetMinorOffsetConfig((edma_tcd_t *)&handle->tcd[handle->tcdUser], &minorOffset);
+
+ if (handle->interleaveType == kPDM_EDMAMultiChannelInterleavePerChannelBlock)
+ {
+ EDMA_TcdSetModulo((edma_tcd_t *)&handle->tcd[handle->tcdUser], modulo, kEDMA_ModuloDisable);
+ }
+ }
+
+ EDMA_TcdEnableInterrupts((edma_tcd_t *)&handle->tcd[handle->tcdUser], (uint32_t)kEDMA_MajorInterruptEnable);
+
+ handle->tcdUser = nextTcdIndex;
+
+ currentTransfer = currentTransfer->linkTransfer;
+
+ if (currentTransfer == xfer)
+ {
+ handle->isLoopTransfer = true;
+ break;
+ }
+ }
+
+ if (handle->state != (uint32_t)kPDM_Busy)
+ {
+ EDMA_InstallTCD(handle->dmaHandle->base, handle->dmaHandle->channel, (edma_tcd_t *)&handle->tcd[tcdIndex]);
+ /* Start DMA transfer */
+ EDMA_StartTransfer(handle->dmaHandle);
+
+ /* Enable DMA enable bit */
+ PDM_EnableDMA(base, true);
+ /* enable PDM */
+ PDM_Enable(base, true);
+
+ handle->state = (uint32_t)kPDM_Busy;
+ }
+
+ return kStatus_Success;
+}
+
+/*!
+ * brief Aborts a PDM receive using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call PDM_TransferTerminateReceiveEDMA.
+ *
+ * param base PDM base pointer
+ * param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferAbortReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Disable dma */
+ EDMA_AbortTransfer(handle->dmaHandle);
+
+ /* Disable DMA enable bit */
+ PDM_EnableDMA(base, false);
+
+ /* Disable PDM */
+ PDM_Enable(base, false);
+
+ /* Handle the queue index */
+ handle->tcdUsedNum--;
+
+ /* Set the handle state */
+ handle->state = (uint32_t)kPDM_Idle;
+}
+
+/*!
+ * brief Terminate all PDM receive.
+ *
+ * This function will clear all transfer slots buffered in the pdm queue. If users only want to abort the
+ * current transfer slot, please call PDM_TransferAbortReceiveEDMA.
+ *
+ * param base PDM base pointer.
+ * param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferTerminateReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle)
+{
+ assert(handle != NULL);
+
+ /* Abort the current transfer */
+ PDM_TransferAbortReceiveEDMA(base, handle);
+
+ /* Clear all the internal information */
+ (void)memset(handle->tcd, 0, sizeof(edma_tcd_t) * handle->tcdNum);
+ handle->tcdUser = 0U;
+ handle->tcdUsedNum = 0U;
+}
+
+/*!
+ * brief Gets byte count received by PDM.
+ *
+ * param base PDM base pointer
+ * param handle PDM eDMA handle pointer.
+ * param count Bytes count received by PDM.
+ * retval kStatus_Success Succeed get the transfer count.
+ * retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t PDM_TransferGetReceiveCountEDMA(PDM_Type *base, pdm_edma_handle_t *handle, size_t *count)
+{
+ assert(handle != NULL);
+
+ *count = handle->receivedBytes;
+
+ return kStatus_Success;
+}
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.h b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.h
new file mode 100644
index 0000000000..4da78192f9
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_edma.h
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2019 - 2020, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+#ifndef _FSL_PDM_EDMA_H_
+#define _FSL_PDM_EDMA_H_
+
+#include "fsl_edma.h"
+#include "fsl_pdm.h"
+
+/*!
+ * @addtogroup pdm_edma PDM EDMA Driver
+ * @ingroup pdm
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_PDM_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 6, 1)) /*!< Version 2.6.1 */
+/*@}*/
+
+/*! @brief PDM edma handler */
+typedef struct _pdm_edma_handle pdm_edma_handle_t;
+
+/*!@brief pdm multi channel interleave type */
+typedef enum _pdm_edma_multi_channel_interleave
+{
+ kPDM_EDMAMultiChannelInterleavePerChannelSample =
+ 0U, /*!< multi channel PDM data interleave per channel sample
+ * -------------------------------------------------------------------------
+ * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....|
+ * -------------------------------------------------------------------------
+ */
+ kPDM_EDMAMultiChannelInterleavePerChannelBlock =
+ 1U, /*!< multi channel PDM data interleave per channel block
+ * ----------------------------------------------------------------------------------------------------------------------------
+ * |CHANNEL0 | CHANNEL0 | CHANNEL0 | ...... | CHANNEL1 | CHANNEL 1 | CHANNEL 1 | ....| CHANNEL2 | CHANNEL 2
+ * | CHANNEL 2 | ....|
+ * ----------------------------------------------------------------------------------------------------------------------------
+ */
+} pdm_edma_multi_channel_interleave_t;
+
+/*! @brief PDM edma transfer */
+typedef struct _pdm_edma_transfer
+{
+ volatile uint8_t *data; /*!< Data start address to transfer. */
+ volatile size_t dataSize; /*!< Total Transfer bytes size. */
+ struct _pdm_edma_transfer *linkTransfer; /*!< linked transfer configurations */
+} pdm_edma_transfer_t;
+
+/*! @brief PDM eDMA transfer callback function for finish and error */
+typedef void (*pdm_edma_callback_t)(PDM_Type *base, pdm_edma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief PDM DMA transfer handle, users should not touch the content of the handle.*/
+struct _pdm_edma_handle
+{
+ edma_handle_t *dmaHandle; /*!< DMA handler for PDM send */
+ uint8_t count; /*!< The transfer data count in a DMA request */
+ uint32_t receivedBytes; /*!< total transfer count */
+ uint32_t state; /*!< Internal state for PDM eDMA transfer */
+ pdm_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
+ bool isLoopTransfer; /*!< loop transfer */
+ void *userData; /*!< User callback parameter */
+ edma_tcd_t *tcd; /*!< TCD pool for eDMA transfer. */
+ uint32_t tcdNum; /*!< TCD number */
+ uint32_t tcdUser; /*!< Index for user to queue transfer. */
+ uint32_t tcdDriver; /*!< Index for driver to get the transfer data and size */
+ volatile uint32_t tcdUsedNum; /*!< Index for user to queue transfer. */
+
+ pdm_edma_multi_channel_interleave_t interleaveType; /*!< multi channel transfer interleave type */
+
+ uint8_t endChannel; /*!< The last enabled channel */
+ uint8_t channelNums; /*!< total channel numbers */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name PDM eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Install EDMA descriptor memory.
+ *
+ * @param handle Pointer to EDMA channel transfer handle.
+ * @param tcdAddr EDMA head descriptor address.
+ * @param tcdNum EDMA link descriptor address.
+ */
+void PDM_TransferInstallEDMATCDMemory(pdm_edma_handle_t *handle, void *tcdAddr, size_t tcdNum);
+
+/*!
+ * @brief Initializes the PDM Rx eDMA handle.
+ *
+ * This function initializes the PDM slave DMA handle, which can be used for other PDM master transactional APIs.
+ * Usually, for a specified PDM instance, call this API once to get the initialized handle.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ */
+void PDM_TransferCreateHandleEDMA(
+ PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle);
+
+/*!
+ * @brief Initializes the multi PDM channel interleave type.
+ *
+ * This function initializes the PDM DMA handle member interleaveType, it shall be called only when application would
+ * like to use type kPDM_EDMAMultiChannelInterleavePerChannelBlock, since the default interleaveType is
+ * kPDM_EDMAMultiChannelInterleavePerChannelSample always
+ *
+ * @param handle PDM eDMA handle pointer.
+ * @param multiChannelInterleaveType Multi channel interleave type.
+ */
+void PDM_TransferSetMultiChannelInterleaveType(pdm_edma_handle_t *handle,
+ pdm_edma_multi_channel_interleave_t multiChannelInterleaveType);
+
+/*!
+ * @brief Configures the PDM channel.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ * @param channel channel index.
+ * @param config pdm channel configurations.
+ */
+void PDM_TransferSetChannelConfigEDMA(PDM_Type *base,
+ pdm_edma_handle_t *handle,
+ uint32_t channel,
+ const pdm_channel_config_t *config);
+
+/*!
+ * @brief Performs a non-blocking PDM receive using eDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * the PDM_GetReceiveRemainingBytes to poll the transfer status and check whether the PDM transfer is finished.
+ *
+ * 1. Scatter gather case:
+ * This functio support dynamic scatter gather and staic scatter gather,
+ * a. for the dynamic scatter gather case:
+ * Application should call PDM_TransferReceiveEDMA function continuously to make sure new receive request is submit
+ * before the previous one finish. b. for the static scatter gather case: Application should use the link transfer
+ * feature and make sure a loop link transfer is provided, such as:
+ * @code pdm_edma_transfer_t pdmXfer[2] =
+ * {
+ * {
+ * .data = s_buffer,
+ * .dataSize = BUFFER_SIZE,
+ * .linkTransfer = &pdmXfer[1],
+ * },
+ *
+ * {
+ * .data = &s_buffer[BUFFER_SIZE],
+ * .dataSize = BUFFER_SIZE,
+ * .linkTransfer = &pdmXfer[0]
+ * },
+ * };
+ * @endcode
+ *
+ * 2. Multi channel case:
+ * This function support receive multi pdm channel data, for example, if two channel is requested,
+ * @code
+ * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_0, &channelConfig);
+ * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_1, &channelConfig);
+ * PDM_TransferReceiveEDMA(DEMO_PDM, &s_pdmRxHandle_0, pdmXfer);
+ * @endcode
+ * The output data will be formatted as below if handle->interleaveType =
+ * kPDM_EDMAMultiChannelInterleavePerChannelSample :
+ * -------------------------------------------------------------------------
+ * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....|
+ * -------------------------------------------------------------------------
+ *
+ * The output data will be formatted as below if handle->interleaveType = kPDM_EDMAMultiChannelInterleavePerChannelBlock
+ * :
+ * ----------------------------------------------------------------------------------------------------------------------
+ * |CHANNEL3 | CHANNEL3 | CHANNEL3 | .... | CHANNEL4 | CHANNEL 4 | CHANNEL4 |....| CHANNEL5 | CHANNEL 5 | CHANNEL5
+ * |....|
+ * ----------------------------------------------------------------------------------------------------------------------
+ * Note: the dataSize of xfer is the total data size, while application using
+ * kPDM_EDMAMultiChannelInterleavePerChannelBlock, the buffer size for each PDM channel is channelSize = dataSize /
+ * channelNums, then there are limitation for this feature,
+ * 1. 3 DMIC array: the dataSize shall be 4 * (channelSize)
+ * The addtional buffer is mandantory for edma modulo feature.
+ * 2. The kPDM_EDMAMultiChannelInterleavePerChannelBlock feature support below dmic array only,
+ * 2 DMIC array: CHANNEL3, CHANNEL4
+ * 3 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5
+ * 4 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5, CHANNEL6
+ * Any other combinations is not support, that is to SAY, THE FEATURE SUPPORT RECEIVE START FROM CHANNEL3 ONLY AND 4
+ * MAXIMUM DMIC CHANNELS.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a PDM eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_RxBusy PDM is busy receiving data.
+ */
+status_t PDM_TransferReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_transfer_t *xfer);
+
+/*!
+ * @brief Terminate all PDM receive.
+ *
+ * This function will clear all transfer slots buffered in the pdm queue. If users only want to abort the
+ * current transfer slot, please call PDM_TransferAbortReceiveEDMA.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferTerminateReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle);
+
+/*!
+ * @brief Aborts a PDM receive using eDMA.
+ *
+ * This function only aborts the current transfer slots, the other transfer slots' information still kept
+ * in the handler. If users want to terminate all transfer slots, just call PDM_TransferTerminateReceiveEDMA.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferAbortReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle);
+
+/*!
+ * @brief Gets byte count received by PDM.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ * @param count Bytes count received by PDM.
+ * @retval kStatus_Success Succeed get the transfer count.
+ * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress.
+ */
+status_t PDM_TransferGetReceiveCountEDMA(PDM_Type *base, pdm_edma_handle_t *handle, size_t *count);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif
diff --git a/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_sdma.h b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_sdma.h
new file mode 100644
index 0000000000..9237341309
--- /dev/null
+++ b/bsps/arm/imxrt/mcux-sdk/drivers/pdm/fsl_pdm_sdma.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2018, Freescale Semiconductor, Inc.
+ * Copyright 2019 - 2020, NXP
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _FSL_PDM_SDMA_H_
+#define _FSL_PDM_SDMA_H_
+
+#include "fsl_pdm.h"
+#include "fsl_sdma.h"
+
+/*!
+ * @addtogroup pdm_sdma PDM SDMA Driver
+ * @ingroup pdm
+ * @{
+ */
+
+/*******************************************************************************
+ * Definitions
+ ******************************************************************************/
+
+/*! @name Driver version */
+/*@{*/
+#define FSL_PDM_SDMA_DRIVER_VERSION (MAKE_VERSION(2, 7, 0)) /*!< Version 2.7.0 */
+/*@}*/
+
+typedef struct _pdm_sdma_handle pdm_sdma_handle_t;
+
+/*! @brief PDM eDMA transfer callback function for finish and error */
+typedef void (*pdm_sdma_callback_t)(PDM_Type *base, pdm_sdma_handle_t *handle, status_t status, void *userData);
+
+/*! @brief PDM DMA transfer handle, users should not touch the content of the handle.*/
+struct _pdm_sdma_handle
+{
+ sdma_handle_t *dmaHandle; /*!< DMA handler for PDM send */
+ uint8_t nbytes; /*!< eDMA minor byte transfer count initially configured. */
+ uint8_t fifoWidth; /*!< fifo width */
+ uint8_t endChannel; /*!< The last enabled channel */
+ uint8_t channelNums; /*!< total channel numbers */
+ uint32_t count; /*!< The transfer data count in a DMA request */
+ uint32_t state; /*!< Internal state for PDM eDMA transfer */
+ uint32_t eventSource; /*!< PDM event source number */
+ pdm_sdma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */
+ void *userData; /*!< User callback parameter */
+ sdma_buffer_descriptor_t bdPool[PDM_XFER_QUEUE_SIZE]; /*!< BD pool for SDMA transfer. */
+ pdm_transfer_t pdmQueue[PDM_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer. */
+ size_t transferSize[PDM_XFER_QUEUE_SIZE]; /*!< Data bytes need to transfer */
+ volatile uint8_t queueUser; /*!< Index for user to queue transfer. */
+ volatile uint8_t queueDriver; /*!< Index for driver to get the transfer data and size */
+};
+
+/*******************************************************************************
+ * APIs
+ ******************************************************************************/
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/*!
+ * @name eDMA Transactional
+ * @{
+ */
+
+/*!
+ * @brief Initializes the PDM eDMA handle.
+ *
+ * This function initializes the PDM DMA handle, which can be used for other PDM master transactional APIs.
+ * Usually, for a specified PDM instance, call this API once to get the initialized handle.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ * @param callback Pointer to user callback function.
+ * @param userData User parameter passed to the callback function.
+ * @param dmaHandle eDMA handle pointer, this handle shall be static allocated by users.
+ * @param eventSource PDM event source number.
+ */
+void PDM_TransferCreateHandleSDMA(PDM_Type *base,
+ pdm_sdma_handle_t *handle,
+ pdm_sdma_callback_t callback,
+ void *userData,
+ sdma_handle_t *dmaHandle,
+ uint32_t eventSource);
+
+/*!
+ * @brief Performs a non-blocking PDM receive using eDMA.
+ *
+ * @note This interface returns immediately after the transfer initiates. Call
+ * the PDM_GetReceiveRemainingBytes to poll the transfer status and check whether the PDM transfer is finished.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ * @param xfer Pointer to DMA transfer structure.
+ * @retval kStatus_Success Start a PDM eDMA receive successfully.
+ * @retval kStatus_InvalidArgument The input argument is invalid.
+ * @retval kStatus_RxBusy PDM is busy receiving data.
+ */
+status_t PDM_TransferReceiveSDMA(PDM_Type *base, pdm_sdma_handle_t *handle, pdm_transfer_t *xfer);
+
+/*!
+ * @brief Aborts a PDM receive using eDMA.
+ *
+ * @param base PDM base pointer
+ * @param handle PDM eDMA handle pointer.
+ */
+void PDM_TransferAbortReceiveSDMA(PDM_Type *base, pdm_sdma_handle_t *handle);
+
+/*!
+ * @brief PDM channel configurations.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM eDMA handle pointer.
+ * @param channel channel number.
+ * @param config channel configurations.
+ */
+void PDM_SetChannelConfigSDMA(PDM_Type *base,
+ pdm_sdma_handle_t *handle,
+ uint32_t channel,
+ const pdm_channel_config_t *config);
+
+/*!
+ * @brief Terminate all the PDM sdma receive transfer.
+ *
+ * @param base PDM base pointer.
+ * @param handle PDM SDMA handle pointer.
+ */
+void PDM_TransferTerminateReceiveSDMA(PDM_Type *base, pdm_sdma_handle_t *handle);
+
+/*! @} */
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*!
+ * @}
+ */
+#endif