1 /*
2  * Copyright (c) 2018, Freescale Semiconductor, Inc.
3  * Copyright 2019-2020 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #ifndef FSL_PDM_H_
10 #define FSL_PDM_H_
11 
12 #include "fsl_common.h"
13 
14 /*!
15  * @addtogroup pdm_driver PDM Driver
16  * @{
17  */
18 
19 /*******************************************************************************
20  * Definitions
21  ******************************************************************************/
22 
23 /*! @name Driver version */
24 /*! @{ */
25 #define FSL_PDM_DRIVER_VERSION (MAKE_VERSION(2, 9, 1)) /*!< Version 2.9.1 */
26 /*! @} */
27 
28 /*! @brief PDM XFER QUEUE SIZE */
29 #define PDM_XFER_QUEUE_SIZE (4U)
30 
31 /*! @brief PDM return status*/
32 enum
33 {
34     kStatus_PDM_Busy = MAKE_STATUS(kStatusGroup_PDM, 0),                 /*!< PDM is busy. */
35 #if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
36     kStatus_PDM_CLK_LOW = MAKE_STATUS(kStatusGroup_PDM, 1),              /*!< PDM clock frequency low */
37 #endif
38     kStatus_PDM_FIFO_ERROR           = MAKE_STATUS(kStatusGroup_PDM, 2), /*!< PDM FIFO underrun or overflow */
39     kStatus_PDM_QueueFull            = MAKE_STATUS(kStatusGroup_PDM, 3), /*!< PDM FIFO underrun or overflow */
40     kStatus_PDM_Idle                 = MAKE_STATUS(kStatusGroup_PDM, 4), /*!< PDM is idle */
41     kStatus_PDM_Output_ERROR         = MAKE_STATUS(kStatusGroup_PDM, 5), /*!< PDM is output error */
42     kStatus_PDM_ChannelConfig_Failed = MAKE_STATUS(kStatusGroup_PDM, 6), /*!< PDM channel config failed */
43 #if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
44     kStatus_PDM_HWVAD_VoiceDetected = MAKE_STATUS(kStatusGroup_PDM, 7),  /*!< PDM hwvad voice detected */
45     kStatus_PDM_HWVAD_Error         = MAKE_STATUS(kStatusGroup_PDM, 8),  /*!< PDM hwvad error */
46 #endif
47 };
48 
49 /*! @brief The PDM interrupt enable flag */
50 enum _pdm_interrupt_enable
51 {
52     kPDM_ErrorInterruptEnable = PDM_CTRL_1_ERREN_MASK, /*!< PDM channel error interrupt enable. */
53     kPDM_FIFOInterruptEnable  = PDM_CTRL_1_DISEL(2U),  /*!< PDM channel FIFO interrupt */
54 };
55 
56 /*! @brief The PDM status */
57 enum _pdm_internal_status
58 {
59     kPDM_StatusDfBusyFlag = (int)PDM_STAT_BSY_FIL_MASK, /*!< Decimation filter is busy processing data */
60 #if !(defined(FSL_FEATURE_PDM_HAS_NO_FIR_RDY) && FSL_FEATURE_PDM_HAS_NO_FIR_RDY)
61     kPDM_StatusFIRFilterReady = PDM_STAT_FIR_RDY_MASK,  /*!< FIR filter data is ready */
62 #endif
63 #if (defined(FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ) && (FSL_FEATURE_PDM_HAS_STATUS_LOW_FREQ == 1U))
64     kPDM_StatusFrequencyLow = PDM_STAT_LOWFREQF_MASK,     /*!< Mic app clock frequency not high enough */
65 #endif
66     kPDM_StatusCh0FifoDataAvaliable = PDM_STAT_CH0F_MASK, /*!< channel 0 fifo data reached watermark level */
67     kPDM_StatusCh1FifoDataAvaliable = PDM_STAT_CH1F_MASK, /*!< channel 1 fifo data reached watermark level */
68     kPDM_StatusCh2FifoDataAvaliable = PDM_STAT_CH2F_MASK, /*!< channel 2 fifo data reached watermark level */
69     kPDM_StatusCh3FifoDataAvaliable = PDM_STAT_CH3F_MASK, /*!< channel 3 fifo data reached watermark level */
70 #if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
71     kPDM_StatusCh4FifoDataAvaliable = PDM_STAT_CH4F_MASK, /*!< channel 4 fifo data reached watermark level */
72     kPDM_StatusCh5FifoDataAvaliable = PDM_STAT_CH5F_MASK, /*!< channel 5 fifo data reached watermark level */
73     kPDM_StatusCh6FifoDataAvaliable = PDM_STAT_CH6F_MASK, /*!< channel 6 fifo data reached watermark level */
74     kPDM_StatusCh7FifoDataAvaliable = PDM_STAT_CH7F_MASK, /*!< channel 7 fifo data reached watermark level */
75 #endif
76 };
77 
78 /*! @brief PDM channel enable mask */
79 enum _pdm_channel_enable_mask
80 {
81     kPDM_EnableChannel0 = PDM_STAT_CH0F_MASK, /*!< channgel 0 enable mask */
82     kPDM_EnableChannel1 = PDM_STAT_CH1F_MASK, /*!< channgel 1 enable mask */
83     kPDM_EnableChannel2 = PDM_STAT_CH2F_MASK, /*!< channgel 2 enable mask */
84     kPDM_EnableChannel3 = PDM_STAT_CH3F_MASK, /*!< channgel 3 enable mask */
85 #if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
86     kPDM_EnableChannel4 = PDM_STAT_CH4F_MASK, /*!< channgel 4 enable mask */
87     kPDM_EnableChannel5 = PDM_STAT_CH5F_MASK, /*!< channgel 5 enable mask */
88     kPDM_EnableChannel6 = PDM_STAT_CH6F_MASK, /*!< channgel 6 enable mask */
89     kPDM_EnableChannel7 = PDM_STAT_CH7F_MASK, /*!< channgel 7 enable mask */
90 
91     kPDM_EnableChannelAll = kPDM_EnableChannel0 | kPDM_EnableChannel1 | kPDM_EnableChannel2 | kPDM_EnableChannel3 |
92                             kPDM_EnableChannel4 | kPDM_EnableChannel5 | kPDM_EnableChannel6 | kPDM_EnableChannel7,
93 #else
94     kPDM_EnableChannelAll = kPDM_EnableChannel0 | kPDM_EnableChannel1 | kPDM_EnableChannel2 | kPDM_EnableChannel3,
95 #endif
96 };
97 
98 /*! @brief The PDM fifo status */
99 enum _pdm_fifo_status
100 {
101     kPDM_FifoStatusUnderflowCh0 = PDM_FIFO_STAT_FIFOUND0_MASK, /*!< channel0 fifo status underflow */
102     kPDM_FifoStatusUnderflowCh1 = PDM_FIFO_STAT_FIFOUND1_MASK, /*!< channel1 fifo status underflow */
103     kPDM_FifoStatusUnderflowCh2 = PDM_FIFO_STAT_FIFOUND2_MASK, /*!< channel2 fifo status underflow */
104     kPDM_FifoStatusUnderflowCh3 = PDM_FIFO_STAT_FIFOUND3_MASK, /*!< channel3 fifo status underflow */
105 #if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
106     kPDM_FifoStatusUnderflowCh4 = PDM_FIFO_STAT_FIFOUND4_MASK, /*!< channel4 fifo status underflow */
107     kPDM_FifoStatusUnderflowCh5 = PDM_FIFO_STAT_FIFOUND5_MASK, /*!< channel5 fifo status underflow */
108     kPDM_FifoStatusUnderflowCh6 = PDM_FIFO_STAT_FIFOUND6_MASK, /*!< channel6 fifo status underflow */
109     kPDM_FifoStatusUnderflowCh7 = PDM_FIFO_STAT_FIFOUND6_MASK, /*!< channel7 fifo status underflow */
110 #endif
111 
112     kPDM_FifoStatusOverflowCh0 = PDM_FIFO_STAT_FIFOOVF0_MASK, /*!< channel0 fifo status overflow */
113     kPDM_FifoStatusOverflowCh1 = PDM_FIFO_STAT_FIFOOVF1_MASK, /*!< channel1 fifo status overflow */
114     kPDM_FifoStatusOverflowCh2 = PDM_FIFO_STAT_FIFOOVF2_MASK, /*!< channel2 fifo status overflow */
115     kPDM_FifoStatusOverflowCh3 = PDM_FIFO_STAT_FIFOOVF3_MASK, /*!< channel3 fifo status overflow */
116 #if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
117     kPDM_FifoStatusOverflowCh4 = PDM_FIFO_STAT_FIFOOVF4_MASK, /*!< channel4 fifo status overflow */
118     kPDM_FifoStatusOverflowCh5 = PDM_FIFO_STAT_FIFOOVF5_MASK, /*!< channel5 fifo status overflow */
119     kPDM_FifoStatusOverflowCh6 = PDM_FIFO_STAT_FIFOOVF6_MASK, /*!< channel6 fifo status overflow */
120     kPDM_FifoStatusOverflowCh7 = PDM_FIFO_STAT_FIFOOVF7_MASK, /*!< channel7 fifo status overflow */
121 #endif
122 };
123 
124 #if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
125 /*! @brief The PDM output status */
126 enum _pdm_range_status
127 {
128     kPDM_RangeStatusUnderFlowCh0 = PDM_RANGE_STAT_RANGEUNF0_MASK, /*!< channel0 range status underflow */
129     kPDM_RangeStatusUnderFlowCh1 = PDM_RANGE_STAT_RANGEUNF1_MASK, /*!< channel1 range status underflow */
130     kPDM_RangeStatusUnderFlowCh2 = PDM_RANGE_STAT_RANGEUNF2_MASK, /*!< channel2 range status underflow */
131     kPDM_RangeStatusUnderFlowCh3 = PDM_RANGE_STAT_RANGEUNF3_MASK, /*!< channel3 range status underflow */
132 #if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
133     kPDM_RangeStatusUnderFlowCh4 = PDM_RANGE_STAT_RANGEUNF4_MASK, /*!< channel4 range status underflow */
134     kPDM_RangeStatusUnderFlowCh5 = PDM_RANGE_STAT_RANGEUNF5_MASK, /*!< channel5 range status underflow */
135     kPDM_RangeStatusUnderFlowCh6 = PDM_RANGE_STAT_RANGEUNF6_MASK, /*!< channel6 range status underflow */
136     kPDM_RangeStatusUnderFlowCh7 = PDM_RANGE_STAT_RANGEUNF7_MASK, /*!< channel7 range status underflow */
137 #endif
138     kPDM_RangeStatusOverFlowCh0 = PDM_RANGE_STAT_RANGEOVF0_MASK,  /*!< channel0 range status overflow */
139     kPDM_RangeStatusOverFlowCh1 = PDM_RANGE_STAT_RANGEOVF1_MASK,  /*!< channel1 range status overflow */
140     kPDM_RangeStatusOverFlowCh2 = PDM_RANGE_STAT_RANGEOVF2_MASK,  /*!< channel2 range status overflow */
141     kPDM_RangeStatusOverFlowCh3 = PDM_RANGE_STAT_RANGEOVF3_MASK,  /*!< channel3 range status overflow */
142 #if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
143     kPDM_RangeStatusOverFlowCh4 = PDM_RANGE_STAT_RANGEOVF4_MASK,  /*!< channel4 range status overflow */
144     kPDM_RangeStatusOverFlowCh5 = PDM_RANGE_STAT_RANGEOVF5_MASK,  /*!< channel5 range status overflow */
145     kPDM_RangeStatusOverFlowCh6 = PDM_RANGE_STAT_RANGEOVF6_MASK,  /*!< channel6 range status overflow */
146     kPDM_RangeStatusOverFlowCh7 = PDM_RANGE_STAT_RANGEOVF7_MASK,  /*!< channel7 range status overflow */
147 #endif
148 };
149 #else
150 /*! @brief The PDM output status */
151 enum _pdm_output_status
152 {
153     kPDM_OutputStatusUnderFlowCh0 = PDM_OUT_STAT_OUTUNF0_MASK, /*!< channel0 output status underflow */
154     kPDM_OutputStatusUnderFlowCh1 = PDM_OUT_STAT_OUTUNF1_MASK, /*!< channel1 output status underflow */
155     kPDM_OutputStatusUnderFlowCh2 = PDM_OUT_STAT_OUTUNF2_MASK, /*!< channel2 output status underflow */
156     kPDM_OutputStatusUnderFlowCh3 = PDM_OUT_STAT_OUTUNF3_MASK, /*!< channel3 output status underflow */
157 #if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
158     kPDM_OutputStatusUnderFlowCh4 = PDM_OUT_STAT_OUTUNF4_MASK, /*!< channel4 output status underflow */
159     kPDM_OutputStatusUnderFlowCh5 = PDM_OUT_STAT_OUTUNF5_MASK, /*!< channel5 output status underflow */
160     kPDM_OutputStatusUnderFlowCh6 = PDM_OUT_STAT_OUTUNF6_MASK, /*!< channel6 output status underflow */
161     kPDM_OutputStatusUnderFlowCh7 = PDM_OUT_STAT_OUTUNF7_MASK, /*!< channel7 output status underflow */
162 #endif
163     kPDM_OutputStatusOverFlowCh0  = PDM_OUT_STAT_OUTOVF0_MASK, /*!< channel0 output status overflow */
164     kPDM_OutputStatusOverFlowCh1  = PDM_OUT_STAT_OUTOVF1_MASK, /*!< channel1 output status overflow */
165     kPDM_OutputStatusOverFlowCh2  = PDM_OUT_STAT_OUTOVF2_MASK, /*!< channel2 output status overflow */
166     kPDM_OutputStatusOverFlowCh3  = PDM_OUT_STAT_OUTOVF3_MASK, /*!< channel3 output status overflow */
167 #if !defined(FSL_FEATURE_PDM_CHANNEL_NUM) || (FSL_FEATURE_PDM_CHANNEL_NUM == 8U)
168     kPDM_OutputStatusOverFlowCh4  = PDM_OUT_STAT_OUTOVF4_MASK, /*!< channel4 output status overflow */
169     kPDM_OutputStatusOverFlowCh5  = PDM_OUT_STAT_OUTOVF5_MASK, /*!< channel5 output status overflow */
170     kPDM_OutputStatusOverFlowCh6  = PDM_OUT_STAT_OUTOVF6_MASK, /*!< channel6 output status overflow */
171     kPDM_OutputStatusOverFlowCh7  = PDM_OUT_STAT_OUTOVF7_MASK, /*!< channel7 output status overflow */
172 #endif
173 };
174 #endif
175 
176 #if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
177 /*! @brief PDM DC remover configurations */
178 typedef enum _pdm_dc_remover
179 {
180     kPDM_DcRemoverCutOff20Hz = 0U, /*!< DC remover cut off 20HZ */
181     kPDM_DcRemoverCutOff13Hz = 1U, /*!< DC remover cut off 13.3HZ */
182     kPDM_DcRemoverCutOff40Hz = 2U, /*!< DC remover cut off 40HZ */
183     kPDM_DcRemoverBypass     = 3U, /*!< DC remover bypass */
184 } pdm_dc_remover_t;
185 #else
186 /*! @brief PDM DC remover configurations */
187 typedef enum _pdm_dc_remover
188 {
189     kPDM_DcRemoverCutOff21Hz  = 0U, /*!< DC remover cut off 21HZ */
190     kPDM_DcRemoverCutOff83Hz  = 1U, /*!< DC remover cut off 83HZ */
191     kPDM_DcRemoverCutOff152Hz = 2U, /*!< DC remover cut off 152HZ */
192     kPDM_DcRemoverBypass      = 3U, /*!< DC remover bypass */
193 } pdm_dc_remover_t;
194 #endif
195 
196 /*! @brief PDM decimation filter quality mode */
197 typedef enum _pdm_df_quality_mode
198 {
199     kPDM_QualityModeMedium   = 0U, /*!< quality mode memdium */
200     kPDM_QualityModeHigh     = 1U, /*!< quality mode high */
201     kPDM_QualityModeLow      = 7U, /*!< quality mode low */
202     kPDM_QualityModeVeryLow0 = 6U, /*!< quality mode very low0 */
203     kPDM_QualityModeVeryLow1 = 5U, /*!< quality mode very low1 */
204     kPDM_QualityModeVeryLow2 = 4U, /*!< quality mode very low2 */
205 } pdm_df_quality_mode_t;
206 
207 /*! @brief PDM  quality mode K factor */
208 enum _pdm_qulaity_mode_k_factor
209 {
210     kPDM_QualityModeHighKFactor     = 1U, /*!< high quality mode K factor = 1 / 2 */
211     kPDM_QualityModeMediumKFactor   = 2U, /*!< medium/very low0 quality mode K factor = 2 / 2 */
212     kPDM_QualityModeLowKFactor      = 4U, /*!< low/very low1 quality mode K factor = 4 / 2 */
213     kPDM_QualityModeVeryLow2KFactor = 8U, /*!< very low2 quality mode K factor = 8 / 2 */
214 };
215 
216 /*! @brief PDM decimation filter output gain */
217 typedef enum _pdm_df_output_gain
218 {
219     kPDM_DfOutputGain0  = 0U,   /*!< Decimation filter output gain 0 */
220     kPDM_DfOutputGain1  = 1U,   /*!< Decimation filter output gain 1 */
221     kPDM_DfOutputGain2  = 2U,   /*!< Decimation filter output gain 2 */
222     kPDM_DfOutputGain3  = 3U,   /*!< Decimation filter output gain 3 */
223     kPDM_DfOutputGain4  = 4U,   /*!< Decimation filter output gain 4 */
224     kPDM_DfOutputGain5  = 5U,   /*!< Decimation filter output gain 5 */
225     kPDM_DfOutputGain6  = 6U,   /*!< Decimation filter output gain 6 */
226     kPDM_DfOutputGain7  = 7U,   /*!< Decimation filter output gain 7 */
227     kPDM_DfOutputGain8  = 8U,   /*!< Decimation filter output gain 8 */
228     kPDM_DfOutputGain9  = 9U,   /*!< Decimation filter output gain 9 */
229     kPDM_DfOutputGain10 = 0xAU, /*!< Decimation filter output gain 10 */
230     kPDM_DfOutputGain11 = 0xBU, /*!< Decimation filter output gain 11 */
231     kPDM_DfOutputGain12 = 0xCU, /*!< Decimation filter output gain 12 */
232     kPDM_DfOutputGain13 = 0xDU, /*!< Decimation filter output gain 13 */
233     kPDM_DfOutputGain14 = 0xEU, /*!< Decimation filter output gain 14 */
234     kPDM_DfOutputGain15 = 0xFU, /*!< Decimation filter output gain 15 */
235 } pdm_df_output_gain_t;
236 
237 /*! @brief PDM data width */
238 enum _pdm_data_width
239 {
240 #if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH != 2U)
241     kPDM_DataWwidth24 = 3U, /*!< PDM data width 24bit */
242     kPDM_DataWwidth32 = 4U, /*!< PDM data width 32bit */
243 #else
244     kPDM_DataWdith16 = 2U,          /*!< PDM data width 16bit */
245 #endif
246 };
247 
248 /*! @brief PDM channel configurations */
249 typedef struct _pdm_channel_config
250 {
251 #if (defined(FSL_FEATURE_PDM_HAS_DC_OUT_CTRL) && (FSL_FEATURE_PDM_HAS_DC_OUT_CTRL))
252     pdm_dc_remover_t outputCutOffFreq; /*!< PDM output DC remover cut off frequency */
253 #endif
254 
255 #if !(defined(FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED) && (FSL_FEATURE_PDM_DC_CTRL_VALUE_FIXED))
256     pdm_dc_remover_t cutOffFreq; /*!< DC remover cut off frequency */
257 #endif
258 
259     pdm_df_output_gain_t gain; /*!< Decimation Filter Output Gain */
260 } pdm_channel_config_t;
261 
262 /*! @brief PDM user configuration structure */
263 typedef struct _pdm_config
264 {
265     bool
266         enableDoze; /*!< This module will enter disable/low leakage mode if DOZEN is active with ipg_doze is asserted */
267 #if defined(FSL_FEATURE_PDM_HAS_DECIMATION_FILTER_BYPASS) && FSL_FEATURE_PDM_HAS_DECIMATION_FILTER_BYPASS
268     bool enableFilterBypass;           /*!< Switchable bypass path for the decimation filter */
269 #endif
270     uint8_t fifoWatermark;             /*!< Watermark value for FIFO */
271     pdm_df_quality_mode_t qualityMode; /*!< Quality mode */
272     uint8_t cicOverSampleRate;         /*!< CIC filter over sampling rate */
273 } pdm_config_t;
274 
275 #if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
276 /*! @brief PDM voice activity detector interrupt type */
277 enum _pdm_hwvad_interrupt_enable
278 {
279     kPDM_HwvadErrorInterruptEnable = PDM_VAD0_CTRL_1_VADERIE_MASK, /*!< PDM channel HWVAD error interrupt enable. */
280     kPDM_HwvadInterruptEnable      = PDM_VAD0_CTRL_1_VADIE_MASK,   /*!< PDM channel HWVAD interrupt */
281 };
282 
283 /*! @brief The PDM hwvad interrupt status flag */
284 enum _pdm_hwvad_int_status
285 {
286     kPDM_HwvadStatusInputSaturation = PDM_VAD0_STAT_VADINSATF_MASK, /*!< HWVAD saturation condition */
287     kPDM_HwvadStatusVoiceDetectFlag = PDM_VAD0_STAT_VADIF_MASK,     /*!< HWVAD voice detect interrupt triggered */
288 };
289 
290 /*! @brief High pass filter configure cut-off frequency*/
291 typedef enum _pdm_hwvad_hpf_config
292 {
293     kPDM_HwvadHpfBypassed         = 0x0U, /*!< High-pass filter bypass */
294     kPDM_HwvadHpfCutOffFreq1750Hz = 0x1U, /*!< High-pass filter cut off frequency 1750HZ */
295     kPDM_HwvadHpfCutOffFreq215Hz  = 0x2U, /*!< High-pass filter cut off frequency 215HZ */
296     kPDM_HwvadHpfCutOffFreq102Hz  = 0x3U, /*!< High-pass filter cut off frequency 102HZ */
297 } pdm_hwvad_hpf_config_t;
298 
299 /*! @brief HWVAD internal filter status */
300 typedef enum _pdm_hwvad_filter_status
301 {
302     kPDM_HwvadInternalFilterNormalOperation = 0U, /*!< internal filter ready for normal operation */
303     kPDM_HwvadInternalFilterInitial         = PDM_VAD0_CTRL_1_VADST10_MASK, /*!< interla filter are initial */
304 } pdm_hwvad_filter_status_t;
305 
306 /*! @brief PDM voice activity detector user configuration structure */
307 typedef struct _pdm_hwvad_config
308 {
309     uint8_t channel;                   /*!< Which channel uses voice activity detector */
310     uint8_t initializeTime;            /*!< Number of frames or samples to initialize voice activity detector. */
311     uint8_t cicOverSampleRate;         /*!< CIC filter over sampling rate */
312 
313     uint8_t inputGain;                 /*!< Voice activity detector input gain */
314     uint32_t frameTime;                /*!< Voice activity frame time */
315     pdm_hwvad_hpf_config_t cutOffFreq; /*!< High pass filter cut off frequency */
316     bool enableFrameEnergy;            /*!< If frame energy enabled, true means enable */
317     bool enablePreFilter;              /*!< If pre-filter enabled */
318 } pdm_hwvad_config_t;
319 
320 /*! @brief PDM voice activity detector noise filter user configuration structure */
321 typedef struct _pdm_hwvad_noise_filter
322 {
323     bool enableAutoNoiseFilter;     /*!< If noise fileter automatically activated, true means enable */
324     bool enableNoiseMin;            /*!< If Noise minimum block enabled, true means enabled */
325     bool enableNoiseDecimation;     /*!< If enable noise input decimation */
326     bool enableNoiseDetectOR;       /*!< Enables a OR logic in the output of minimum noise estimator block */
327     uint32_t noiseFilterAdjustment; /*!< The adjustment value of the noise filter */
328     uint32_t noiseGain;             /*!< Gain value for the noise energy or envelope estimated */
329 } pdm_hwvad_noise_filter_t;
330 
331 /*! @brief PDM voice activity detector zero cross detector result */
332 typedef enum _pdm_hwvad_zcd_result
333 {
334     kPDM_HwvadResultOREnergyBasedDetection =
335         0U, /*!< zero cross detector result will be OR with energy based detection */
336     kPDM_HwvadResultANDEnergyBasedDetection =
337         1U, /*!< zero cross detector result will be AND with energy based detection */
338 } pdm_hwvad_zcd_result_t;
339 
340 /*! @brief PDM voice activity detector zero cross detector configuration structure */
341 typedef struct _pdm_hwvad_zero_cross_detector
342 {
343     bool enableAutoThreshold;      /*!< If ZCD auto-threshold enabled, true means enabled. */
344     pdm_hwvad_zcd_result_t zcdAnd; /*!< Is ZCD result is AND'ed with energy-based detection, false means OR'ed */
345     uint32_t threshold;            /*!< The adjustment value of the noise filter */
346     uint32_t adjustmentThreshold;  /*!< Gain value for the noise energy or envelope estimated */
347 } pdm_hwvad_zero_cross_detector_t;
348 #endif
349 
350 /*! @brief PDM SDMA transfer structure */
351 typedef struct _pdm_transfer
352 {
353     volatile uint8_t *data;   /*!< Data start address to transfer. */
354     volatile size_t dataSize; /*!< Total Transfer bytes size. */
355 } pdm_transfer_t;
356 
357 /*! @brief PDM handle */
358 typedef struct _pdm_handle pdm_handle_t;
359 
360 /*! @brief PDM transfer callback prototype */
361 typedef void (*pdm_transfer_callback_t)(PDM_Type *base, pdm_handle_t *handle, status_t status, void *userData);
362 
363 #if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
364 /*! @brief PDM HWVAD callback prototype */
365 typedef void (*pdm_hwvad_callback_t)(status_t status, void *userData);
366 /*! @brief PDM HWVAD notification structure */
367 typedef struct _pdm_hwvad_notification
368 {
369     pdm_hwvad_callback_t callback;
370     void *userData;
371 } pdm_hwvad_notification_t;
372 #endif
373 
374 /*! @brief PDM handle structure */
375 struct _pdm_handle
376 {
377     uint32_t state;                               /*!< Transfer status */
378     pdm_transfer_callback_t callback;             /*!< Callback function called at transfer event*/
379     void *userData;                               /*!< Callback parameter passed to callback function*/
380 
381     pdm_transfer_t pdmQueue[PDM_XFER_QUEUE_SIZE]; /*!< Transfer queue storing queued transfer */
382     size_t transferSize[PDM_XFER_QUEUE_SIZE];     /*!< Data bytes need to transfer */
383     volatile uint8_t queueUser;                   /*!< Index for user to queue transfer */
384     volatile uint8_t queueDriver;                 /*!< Index for driver to get the transfer data and size */
385 
386     uint32_t format;                              /*!< data format */
387     uint8_t watermark;                            /*!< Watermark value */
388     uint8_t startChannel;                         /*!< end channel */
389     uint8_t channelNums;                          /*!< Enabled channel number */
390 };
391 
392 /*******************************************************************************
393  * API
394  ******************************************************************************/
395 
396 #if defined(__cplusplus)
397 extern "C" {
398 #endif /*_cplusplus*/
399 
400 /*!
401  * @name Initialization and deinitialization
402  * @{
403  */
404 
405 /*!
406  * @brief Initializes the PDM peripheral.
407  *
408  * Ungates the PDM clock, resets the module, and configures PDM with a configuration structure.
409  * The configuration structure can be custom filled or set with default values by
410  * PDM_GetDefaultConfig().
411  *
412  * @note  This API should be called at the beginning of the application to use
413  * the PDM driver. Otherwise, accessing the PDM module can cause a hard fault
414  * because the clock is not enabled.
415  *
416  * @param base PDM base pointer
417  * @param config PDM configuration structure.
418  */
419 void PDM_Init(PDM_Type *base, const pdm_config_t *config);
420 
421 /*!
422  * @brief De-initializes the PDM peripheral.
423  *
424  * This API gates the PDM clock. The PDM module can't operate unless PDM_Init
425  * is called to enable the clock.
426  *
427  * @param base PDM base pointer
428  */
429 void PDM_Deinit(PDM_Type *base);
430 
431 /*!
432  * @brief Resets the PDM module.
433  *
434  * @param base PDM base pointer
435  */
PDM_Reset(PDM_Type * base)436 static inline void PDM_Reset(PDM_Type *base)
437 {
438     base->CTRL_1 |= PDM_CTRL_1_SRES_MASK;
439 }
440 
441 /*!
442  * @brief Enables/disables PDM interface.
443  *
444  * @param base PDM base pointer
445  * @param enable True means PDM interface is enabled, false means PDM interface is disabled.
446  */
PDM_Enable(PDM_Type * base,bool enable)447 static inline void PDM_Enable(PDM_Type *base, bool enable)
448 {
449     if (enable)
450     {
451         base->CTRL_1 |= PDM_CTRL_1_PDMIEN_MASK;
452     }
453     else
454     {
455         base->CTRL_1 &= ~PDM_CTRL_1_PDMIEN_MASK;
456     }
457 }
458 
459 #if !(defined(FSL_FEATURE_PDM_HAS_NO_DOZEN) && FSL_FEATURE_PDM_HAS_NO_DOZEN)
460 /*!
461  * @brief Enables/disables DOZE.
462  *
463  * @param base PDM base pointer
464  * @param enable True means the module will enter Disable/Low Leakage mode when ipg_doze is asserted, false means the
465  * module will not enter Disable/Low Leakage mode when ipg_doze is asserted.
466  */
PDM_EnableDoze(PDM_Type * base,bool enable)467 static inline void PDM_EnableDoze(PDM_Type *base, bool enable)
468 {
469     if (enable)
470     {
471         base->CTRL_1 |= PDM_CTRL_1_DOZEN_MASK;
472     }
473     else
474     {
475         base->CTRL_1 &= ~PDM_CTRL_1_DOZEN_MASK;
476     }
477 }
478 #endif
479 /*!
480  * @brief Enables/disables debug mode for PDM.
481  * The PDM interface cannot enter debug mode once in Disable/Low Leakage or Low Power mode.
482  * @param base PDM base pointer
483  * @param enable True means PDM interface enter debug mode, false means PDM interface in normal mode.
484  */
PDM_EnableDebugMode(PDM_Type * base,bool enable)485 static inline void PDM_EnableDebugMode(PDM_Type *base, bool enable)
486 {
487     if (enable)
488     {
489         base->CTRL_1 |= PDM_CTRL_1_DBG_MASK;
490     }
491     else
492     {
493         base->CTRL_1 &= ~PDM_CTRL_1_DBG_MASK;
494     }
495 }
496 
497 /*!
498  * @brief Enables/disables PDM interface in debug mode.
499  *
500  * @param base PDM base pointer
501  * @param enable True means PDM interface is enabled debug mode, false means PDM interface is disabled after
502  * after completing the current frame in debug mode.
503  */
PDM_EnableInDebugMode(PDM_Type * base,bool enable)504 static inline void PDM_EnableInDebugMode(PDM_Type *base, bool enable)
505 {
506     if (enable)
507     {
508         base->CTRL_1 |= PDM_CTRL_1_DBGE_MASK;
509     }
510     else
511     {
512         base->CTRL_1 &= ~PDM_CTRL_1_DBGE_MASK;
513     }
514 }
515 
516 /*!
517  * @brief Enables/disables PDM interface disable/Low Leakage mode.
518  *
519  * @param base PDM base pointer
520  * @param enable True means PDM interface is in disable/low leakage mode, False means PDM interface is in normal mode.
521  */
PDM_EnterLowLeakageMode(PDM_Type * base,bool enable)522 static inline void PDM_EnterLowLeakageMode(PDM_Type *base, bool enable)
523 {
524     if (enable)
525     {
526         base->CTRL_1 |= PDM_CTRL_1_MDIS_MASK;
527     }
528     else
529     {
530         base->CTRL_1 &= ~PDM_CTRL_1_MDIS_MASK;
531     }
532 }
533 
534 /*!
535  * @brief Enables/disables the PDM channel.
536  *
537  * @param base PDM base pointer
538  * @param channel PDM channel number need to enable or disable.
539  * @param enable True means enable PDM channel, false means disable.
540  */
PDM_EnableChannel(PDM_Type * base,uint8_t channel,bool enable)541 static inline void PDM_EnableChannel(PDM_Type *base, uint8_t channel, bool enable)
542 {
543     if (enable)
544     {
545         base->CTRL_1 |= (1UL << channel);
546     }
547     else
548     {
549         base->CTRL_1 &= ~(1UL << channel);
550     }
551 }
552 
553 /*!
554  * @brief PDM one channel configurations.
555  *
556  * @param base PDM base pointer
557  * @param config PDM channel configurations.
558  * @param channel channel number.
559  * after completing the current frame in debug mode.
560  */
561 void PDM_SetChannelConfig(PDM_Type *base, uint32_t channel, const pdm_channel_config_t *config);
562 
563 /*!
564  * @brief PDM set sample rate.
565  *
566  * @note This function is depend on the configuration of the PDM and PDM channel, so the correct call sequence is
567  * @code
568  * PDM_Init(base, pdmConfig)
569  * PDM_SetChannelConfig(base, channel, &channelConfig)
570  * PDM_SetSampleRateConfig(base, source, sampleRate)
571  * @endcode
572  * @param base PDM base pointer
573  * @param sourceClock_HZ PDM source clock frequency.
574  * @param sampleRate_HZ PDM sample rate.
575  */
576 status_t PDM_SetSampleRateConfig(PDM_Type *base, uint32_t sourceClock_HZ, uint32_t sampleRate_HZ);
577 
578 /*!
579  * @brief PDM set sample rate.
580  *
581  * @deprecated Do not use this function.  It has been superceded by @ref PDM_SetSampleRateConfig
582  * @param base PDM base pointer
583  * @param enableChannelMask PDM channel enable mask.
584  * @param qualityMode quality mode.
585  * @param osr cic oversample rate
586  * @param clkDiv clock divider
587  */
588 status_t PDM_SetSampleRate(
589     PDM_Type *base, uint32_t enableChannelMask, pdm_df_quality_mode_t qualityMode, uint8_t osr, uint32_t clkDiv);
590 
591 /*!
592  * @brief Get the instance number for PDM.
593  *
594  * @param base PDM base pointer.
595  */
596 uint32_t PDM_GetInstance(PDM_Type *base);
597 /*! @} */
598 
599 /*!
600  * @name Status
601  * @{
602  */
603 
604 /*!
605  * @brief Gets the PDM internal status flag.
606  * Use the Status Mask in _pdm_internal_status to get the status value needed
607  * @param base PDM base pointer
608  * @return PDM status flag value.
609  */
PDM_GetStatus(PDM_Type * base)610 static inline uint32_t PDM_GetStatus(PDM_Type *base)
611 {
612     return base->STAT;
613 }
614 
615 /*!
616  * @brief Gets the PDM FIFO status flag.
617  * Use the Status Mask in _pdm_fifo_status to get the status value needed
618  * @param base PDM base pointer
619  * @return FIFO status.
620  */
PDM_GetFifoStatus(PDM_Type * base)621 static inline uint32_t PDM_GetFifoStatus(PDM_Type *base)
622 {
623     return base->FIFO_STAT;
624 }
625 
626 #if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
627 /*!
628  * @brief Gets the PDM Range status flag.
629  * Use the Status Mask in _pdm_range_status to get the status value needed
630  * @param base PDM base pointer
631  * @return output status.
632  */
PDM_GetRangeStatus(PDM_Type * base)633 static inline uint32_t PDM_GetRangeStatus(PDM_Type *base)
634 {
635     return base->RANGE_STAT;
636 }
637 #else
638 /*!
639  * @brief Gets the PDM output status flag.
640  * Use the Status Mask in _pdm_output_status to get the status value needed
641  * @param base PDM base pointer
642  * @return output status.
643  */
PDM_GetOutputStatus(PDM_Type * base)644 static inline uint32_t PDM_GetOutputStatus(PDM_Type *base)
645 {
646     return base->OUT_STAT;
647 }
648 #endif
649 
650 /*!
651  * @brief Clears the PDM Tx status.
652  *
653  * @param base PDM base pointer
654  * @param mask State mask. It can be a combination of the status between kPDM_StatusFrequencyLow and
655  * kPDM_StatusCh7FifoDataAvaliable.
656  */
PDM_ClearStatus(PDM_Type * base,uint32_t mask)657 static inline void PDM_ClearStatus(PDM_Type *base, uint32_t mask)
658 {
659     base->STAT = mask;
660 }
661 
662 /*!
663  * @brief Clears the PDM Tx status.
664  *
665  * @param base PDM base pointer
666  * @param mask State mask.It can be a combination of the status in _pdm_fifo_status.
667  */
PDM_ClearFIFOStatus(PDM_Type * base,uint32_t mask)668 static inline void PDM_ClearFIFOStatus(PDM_Type *base, uint32_t mask)
669 {
670     base->FIFO_STAT = mask;
671 }
672 
673 #if defined(FSL_FEATURE_PDM_HAS_RANGE_CTRL) && FSL_FEATURE_PDM_HAS_RANGE_CTRL
674 /*!
675  * @brief Clears the PDM range status.
676  *
677  * @param base PDM base pointer
678  * @param mask State mask. It can be a combination of the status in _pdm_range_status.
679  */
PDM_ClearRangeStatus(PDM_Type * base,uint32_t mask)680 static inline void PDM_ClearRangeStatus(PDM_Type *base, uint32_t mask)
681 {
682     base->RANGE_STAT = mask;
683 }
684 #else
685 /*!
686  * @brief Clears the PDM output status.
687  *
688  * @param base PDM base pointer
689  * @param mask State mask. It can be a combination of the status in _pdm_output_status.
690  */
PDM_ClearOutputStatus(PDM_Type * base,uint32_t mask)691 static inline void PDM_ClearOutputStatus(PDM_Type *base, uint32_t mask)
692 {
693     base->OUT_STAT = mask;
694 }
695 #endif
696 
697 /*! @} */
698 
699 /*!
700  * @name Interrupts
701  * @{
702  */
703 
704 /*!
705  * @brief Enables the PDM interrupt requests.
706  *
707  * @param base PDM base pointer
708  * @param mask interrupt source
709  *     The parameter can be a combination of the following sources if defined.
710  *     @arg kPDM_ErrorInterruptEnable
711  *     @arg kPDM_FIFOInterruptEnable
712  */
713 void PDM_EnableInterrupts(PDM_Type *base, uint32_t mask);
714 
715 /*!
716  * @brief Disables the PDM interrupt requests.
717  *
718  * @param base PDM base pointer
719  * @param mask interrupt source
720  *     The parameter can be a combination of the following sources if defined.
721  *     @arg kPDM_ErrorInterruptEnable
722  *     @arg kPDM_FIFOInterruptEnable
723  */
PDM_DisableInterrupts(PDM_Type * base,uint32_t mask)724 static inline void PDM_DisableInterrupts(PDM_Type *base, uint32_t mask)
725 {
726     base->CTRL_1 &= ~mask;
727 }
728 
729 /*! @} */
730 
731 /*!
732  * @name DMA Control
733  * @{
734  */
735 
736 /*!
737  * @brief Enables/disables the PDM DMA requests.
738  *
739  * @param base PDM base pointer
740  * @param enable True means enable DMA, false means disable DMA.
741  */
PDM_EnableDMA(PDM_Type * base,bool enable)742 static inline void PDM_EnableDMA(PDM_Type *base, bool enable)
743 {
744     if (enable)
745     {
746         base->CTRL_1 = (base->CTRL_1 & (~PDM_CTRL_1_DISEL_MASK)) | PDM_CTRL_1_DISEL(0x1U);
747     }
748     else
749     {
750         base->CTRL_1 &= ~PDM_CTRL_1_DISEL_MASK;
751     }
752 }
753 
754 /*!
755  * @brief  Gets the PDM data register address.
756  *
757  * This API is used to provide a transfer address for the PDM DMA transfer configuration.
758  *
759  * @param base PDM base pointer.
760  * @param channel Which data channel used.
761  * @return data register address.
762  */
PDM_GetDataRegisterAddress(PDM_Type * base,uint32_t channel)763 static inline uint32_t PDM_GetDataRegisterAddress(PDM_Type *base, uint32_t channel)
764 {
765     return (uint32_t)(&(base->DATACH)[channel]);
766 }
767 
768 /*! @} */
769 
770 /*!
771  * @name Bus Operations
772  * @{
773  */
774 #if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 2U)
775 /*!
776  * @brief Reads data from the PDM FIFO.
777  *
778  * @param base PDM base pointer.
779  * @param channel Data channel used.
780  * @return Data in PDM FIFO.
781  */
PDM_ReadData(PDM_Type * base,uint32_t channel)782 static inline int16_t PDM_ReadData(PDM_Type *base, uint32_t channel)
783 {
784     return (int16_t)(base->DATACH[channel]);
785 }
786 
787 /*!
788  * @brief PDM read data non blocking.
789  * So the actually read data byte size in this function is (size * 2 * channelNums).
790  * @param base PDM base pointer.
791  * @param startChannel start channel number.
792  * @param channelNums total enabled channelnums.
793  * @param buffer received buffer address.
794  * @param size number of 16bit data to read.
795  */
796 void PDM_ReadNonBlocking(PDM_Type *base, uint32_t startChannel, uint32_t channelNums, int16_t *buffer, size_t size);
797 #endif
798 
799 /*!
800  * @brief PDM read fifo.
801  * @note: This function support 16 bit only for IP version that only supports 16bit.
802  *
803  * @param base PDM base pointer.
804  * @param startChannel start channel number.
805  * @param channelNums total enabled channelnums.
806  * @param buffer received buffer address.
807  * @param size number of samples to read.
808  * @param dataWidth sample width.
809  */
810 void PDM_ReadFifo(
811     PDM_Type *base, uint32_t startChannel, uint32_t channelNums, void *buffer, size_t size, uint32_t dataWidth);
812 
813 #if defined(FSL_FEATURE_PDM_FIFO_WIDTH) && (FSL_FEATURE_PDM_FIFO_WIDTH == 4U)
814 /*!
815  * @brief Reads data from the PDM FIFO.
816  *
817  * @param base PDM base pointer.
818  * @param channel Data channel used.
819  * @return Data in PDM FIFO.
820  */
PDM_ReadData(PDM_Type * base,uint32_t channel)821 static inline uint32_t PDM_ReadData(PDM_Type *base, uint32_t channel)
822 {
823     return base->DATACH[channel];
824 }
825 #endif
826 
827 /*!
828  * @brief Set the PDM channel gain.
829  *
830  * Please note for different quality mode, the valid gain value is different, reference RM for detail.
831  * @param base PDM base pointer.
832  * @param channel PDM channel index.
833  * @param gain channel gain, the register gain value range is 0 - 15.
834  */
835 void PDM_SetChannelGain(PDM_Type *base, uint32_t channel, pdm_df_output_gain_t gain);
836 
837 #if !(defined(FSL_FEATURE_PDM_HAS_NO_HWVAD) && FSL_FEATURE_PDM_HAS_NO_HWVAD)
838 /*! @} */
839 
840 /*!
841  * @name Voice Activity Detector
842  * @{
843  */
844 
845 /*!
846  * @brief Configure voice activity detector.
847  *
848  * @param base PDM base pointer
849  * @param config Voice activity detector configure structure pointer .
850  */
851 void PDM_SetHwvadConfig(PDM_Type *base, const pdm_hwvad_config_t *config);
852 
853 /*!
854  * @brief PDM hwvad force output disable.
855  *
856  * @param base PDM base pointer
857  * @param enable true is output force disable, false is output not force.
858  */
PDM_ForceHwvadOutputDisable(PDM_Type * base,bool enable)859 static inline void PDM_ForceHwvadOutputDisable(PDM_Type *base, bool enable)
860 {
861     if (enable)
862     {
863         base->VAD0_CTRL_2 &= ~PDM_VAD0_CTRL_2_VADFOUTDIS_MASK;
864     }
865     else
866     {
867         base->VAD0_CTRL_2 |= PDM_VAD0_CTRL_2_VADFOUTDIS_MASK;
868     }
869 }
870 
871 /*!
872  * @brief PDM hwvad reset.
873  * It will reset VADNDATA register and will clean all internal buffers, should be called when the PDM isn't running.
874  *
875  * @param base PDM base pointer
876  */
PDM_ResetHwvad(PDM_Type * base)877 static inline void PDM_ResetHwvad(PDM_Type *base)
878 {
879     base->VAD0_CTRL_1 |= PDM_VAD0_CTRL_1_VADRST_MASK;
880 }
881 /*!
882  * @brief Enable/Disable Voice activity detector.
883  * Should be called when the PDM isn't running.
884  * @param base PDM base pointer.
885  * @param enable True means enable voice activity detector, false means disable.
886  */
PDM_EnableHwvad(PDM_Type * base,bool enable)887 static inline void PDM_EnableHwvad(PDM_Type *base, bool enable)
888 {
889     if (enable)
890     {
891         base->VAD0_CTRL_1 |= PDM_VAD0_CTRL_1_VADEN_MASK;
892     }
893     else
894     {
895         base->VAD0_CTRL_1 &= ~PDM_VAD0_CTRL_1_VADEN_MASK;
896     }
897 }
898 
899 /*!
900  * @brief Enables the PDM Voice Detector interrupt requests.
901  *
902  * @param base PDM base pointer
903  * @param mask interrupt source
904  *     The parameter can be a combination of the following sources if defined.
905  *     @arg kPDM_HWVADErrorInterruptEnable
906  *     @arg kPDM_HWVADInterruptEnable
907  */
PDM_EnableHwvadInterrupts(PDM_Type * base,uint32_t mask)908 static inline void PDM_EnableHwvadInterrupts(PDM_Type *base, uint32_t mask)
909 {
910     base->VAD0_CTRL_1 |= mask;
911 }
912 
913 /*!
914  * @brief Disables the PDM Voice Detector interrupt requests.
915  *
916  * @param base PDM base pointer
917  * @param mask interrupt source
918  *     The parameter can be a combination of the following sources if defined.
919  *     @arg kPDM_HWVADErrorInterruptEnable
920  *     @arg kPDM_HWVADInterruptEnable
921  */
PDM_DisableHwvadInterrupts(PDM_Type * base,uint32_t mask)922 static inline void PDM_DisableHwvadInterrupts(PDM_Type *base, uint32_t mask)
923 {
924     base->VAD0_CTRL_1 &= ~mask;
925 }
926 
927 /*!
928  * @brief Clears the PDM voice activity detector status flags.
929  *
930  * @param base PDM base pointer
931  * @param mask State mask,reference _pdm_hwvad_int_status.
932  */
PDM_ClearHwvadInterruptStatusFlags(PDM_Type * base,uint32_t mask)933 static inline void PDM_ClearHwvadInterruptStatusFlags(PDM_Type *base, uint32_t mask)
934 {
935     base->VAD0_STAT = mask;
936 }
937 
938 /*!
939  * @brief Clears the PDM voice activity detector status flags.
940  *
941  * @param base PDM base pointer
942  * @return status, reference _pdm_hwvad_int_status
943  */
PDM_GetHwvadInterruptStatusFlags(PDM_Type * base)944 static inline uint32_t PDM_GetHwvadInterruptStatusFlags(PDM_Type *base)
945 {
946     return base->VAD0_STAT & (PDM_VAD0_STAT_VADIF_MASK | PDM_VAD0_STAT_VADINSATF_MASK);
947 }
948 
949 /*!
950  * @brief Get the PDM voice activity detector initial flags.
951  *
952  * @param base PDM base pointer
953  * @return initial flag.
954  */
PDM_GetHwvadInitialFlag(PDM_Type * base)955 static inline uint32_t PDM_GetHwvadInitialFlag(PDM_Type *base)
956 {
957     return base->VAD0_STAT & PDM_VAD0_STAT_VADINITF_MASK;
958 }
959 
960 #if !(defined(FSL_FEATURE_PDM_HAS_NO_VADEF) && (FSL_FEATURE_PDM_HAS_NO_VADEF))
961 /*!
962  * @brief Get the PDM voice activity detector voice detected flags.
963  * NOte: this flag is auto cleared when voice gone.
964  * @param base PDM base pointer
965  * @return voice detected flag.
966  */
PDM_GetHwvadVoiceDetectedFlag(PDM_Type * base)967 static inline uint32_t PDM_GetHwvadVoiceDetectedFlag(PDM_Type *base)
968 {
969     return base->VAD0_STAT & PDM_VAD0_STAT_VADEF_MASK;
970 }
971 #endif
972 
973 /*!
974  * @brief Enables/disables voice activity detector signal filter.
975  *
976  * @param base PDM base pointer
977  * @param enable True means enable signal filter, false means disable.
978  */
PDM_EnableHwvadSignalFilter(PDM_Type * base,bool enable)979 static inline void PDM_EnableHwvadSignalFilter(PDM_Type *base, bool enable)
980 {
981     if (enable)
982     {
983         base->VAD0_SCONFIG |= PDM_VAD0_SCONFIG_VADSFILEN_MASK;
984     }
985     else
986     {
987         base->VAD0_SCONFIG &= ~PDM_VAD0_SCONFIG_VADSFILEN_MASK;
988     }
989 }
990 
991 /*!
992  * @brief Configure voice activity detector signal filter.
993  *
994  * @param base PDM base pointer
995  * @param enableMaxBlock If signal maximum block enabled.
996  * @param signalGain Gain value for the signal energy.
997  */
998 void PDM_SetHwvadSignalFilterConfig(PDM_Type *base, bool enableMaxBlock, uint32_t signalGain);
999 
1000 /*!
1001  * @brief Configure voice activity detector noise filter.
1002  *
1003  * @param base PDM base pointer
1004  * @param config Voice activity detector noise filter configure structure pointer .
1005  */
1006 void PDM_SetHwvadNoiseFilterConfig(PDM_Type *base, const pdm_hwvad_noise_filter_t *config);
1007 
1008 /*!
1009  * @brief Enables/disables voice activity detector zero cross detector.
1010  *
1011  * @param base PDM base pointer
1012  * @param enable True means enable zero cross detector, false means disable.
1013  */
PDM_EnableHwvadZeroCrossDetector(PDM_Type * base,bool enable)1014 static inline void PDM_EnableHwvadZeroCrossDetector(PDM_Type *base, bool enable)
1015 {
1016     if (enable)
1017     {
1018         base->VAD0_ZCD |= PDM_VAD0_ZCD_VADZCDEN_MASK;
1019     }
1020     else
1021     {
1022         base->VAD0_ZCD &= ~PDM_VAD0_ZCD_VADZCDEN_MASK;
1023     }
1024 }
1025 
1026 /*!
1027  * @brief Configure voice activity detector zero cross detector.
1028  *
1029  * @param base PDM base pointer
1030  * @param config Voice activity detector zero cross detector configure structure pointer .
1031  */
1032 void PDM_SetHwvadZeroCrossDetectorConfig(PDM_Type *base, const pdm_hwvad_zero_cross_detector_t *config);
1033 
1034 /*!
1035  * @brief Reads noise data.
1036  *
1037  * @param base PDM base pointer.
1038  * @return Data in PDM noise data register.
1039  */
PDM_GetNoiseData(PDM_Type * base)1040 static inline uint16_t PDM_GetNoiseData(PDM_Type *base)
1041 {
1042     return (uint16_t)base->VAD0_NDATA;
1043 }
1044 
1045 /*!
1046  * @brief set hwvad internal filter status .
1047  * Note: filter initial status should be asserted for two more cycles, then set it to normal operation.
1048  * @param base PDM base pointer.
1049  * @param status internal filter status.
1050  */
PDM_SetHwvadInternalFilterStatus(PDM_Type * base,pdm_hwvad_filter_status_t status)1051 static inline void PDM_SetHwvadInternalFilterStatus(PDM_Type *base, pdm_hwvad_filter_status_t status)
1052 {
1053     base->VAD0_CTRL_1 = (base->VAD0_CTRL_1 & (~PDM_VAD0_CTRL_1_VADST10_MASK)) | (uint32_t)status;
1054 }
1055 
1056 /*!
1057  * @brief set HWVAD in envelope based mode .
1058  * Recommand configurations,
1059  * @code
1060  * static const pdm_hwvad_config_t hwvadConfig = {
1061  *   .channel           = 0,
1062  *   .initializeTime    = 10U,
1063  *   .cicOverSampleRate = 0U,
1064  *   .inputGain         = 0U,
1065  *   .frameTime         = 10U,
1066  *   .cutOffFreq        = kPDM_HwvadHpfBypassed,
1067  *   .enableFrameEnergy = false,
1068  *   .enablePreFilter   = true,
1069 };
1070 
1071  * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
1072  *   .enableAutoNoiseFilter = false,
1073  *   .enableNoiseMin        = true,
1074  *   .enableNoiseDecimation = true,
1075  *   .noiseFilterAdjustment = 0U,
1076  *   .noiseGain             = 7U,
1077  *   .enableNoiseDetectOR   = true,
1078  * };
1079  * @endcode
1080  * @param base PDM base pointer.
1081  * @param hwvadConfig internal filter status.
1082  * @param noiseConfig Voice activity detector noise filter configure structure pointer.
1083  * @param zcdConfig Voice activity detector zero cross detector configure structure pointer .
1084  * @param signalGain signal gain value.
1085  */
1086 void PDM_SetHwvadInEnvelopeBasedMode(PDM_Type *base,
1087                                      const pdm_hwvad_config_t *hwvadConfig,
1088                                      const pdm_hwvad_noise_filter_t *noiseConfig,
1089                                      const pdm_hwvad_zero_cross_detector_t *zcdConfig,
1090                                      uint32_t signalGain);
1091 
1092 /*!
1093  * brief set HWVAD in energy based mode .
1094  * Recommand configurations,
1095  * code
1096  * static const pdm_hwvad_config_t hwvadConfig = {
1097  *   .channel           = 0,
1098  *   .initializeTime    = 10U,
1099  *   .cicOverSampleRate = 0U,
1100  *   .inputGain         = 0U,
1101  *   .frameTime         = 10U,
1102  *   .cutOffFreq        = kPDM_HwvadHpfBypassed,
1103  *   .enableFrameEnergy = true,
1104  *   .enablePreFilter   = true,
1105 };
1106 
1107  * static const pdm_hwvad_noise_filter_t noiseFilterConfig = {
1108  *   .enableAutoNoiseFilter = true,
1109  *   .enableNoiseMin        = false,
1110  *   .enableNoiseDecimation = false,
1111  *   .noiseFilterAdjustment = 0U,
1112  *   .noiseGain             = 7U,
1113  *   .enableNoiseDetectOR   = false,
1114  * };
1115  * code
1116  * param base PDM base pointer.
1117  * param hwvadConfig internal filter status.
1118  * param noiseConfig Voice activity detector noise filter configure structure pointer.
1119  * param zcdConfig Voice activity detector zero cross detector configure structure pointer .
1120  * param signalGain signal gain value, signal gain value should be properly according to application.
1121  */
1122 void PDM_SetHwvadInEnergyBasedMode(PDM_Type *base,
1123                                    const pdm_hwvad_config_t *hwvadConfig,
1124                                    const pdm_hwvad_noise_filter_t *noiseConfig,
1125                                    const pdm_hwvad_zero_cross_detector_t *zcdConfig,
1126                                    uint32_t signalGain);
1127 
1128 /*!
1129  * @brief   Enable/Disable  hwvad callback.
1130 
1131  * This function enable/disable the hwvad interrupt for the selected PDM peripheral.
1132  *
1133  * @param base Base address of the PDM peripheral.
1134  * @param vadCallback callback Pointer to store callback function, should be NULL when disable.
1135  * @param userData user data.
1136  * @param enable true is enable, false is disable.
1137  * @retval None.
1138  */
1139 void PDM_EnableHwvadInterruptCallback(PDM_Type *base, pdm_hwvad_callback_t vadCallback, void *userData, bool enable);
1140 /*! @} */
1141 #endif
1142 
1143 /*!
1144  * @name Transactional
1145  * @{
1146  */
1147 
1148 /*!
1149  * @brief Initializes the PDM handle.
1150  *
1151  * This function initializes the handle for the PDM transactional APIs. Call
1152  * this function once to get the handle initialized.
1153  *
1154  * @param base PDM base pointer.
1155  * @param handle PDM handle pointer.
1156  * @param callback Pointer to the user callback function.
1157  * @param userData User parameter passed to the callback function.
1158  */
1159 void PDM_TransferCreateHandle(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_callback_t callback, void *userData);
1160 
1161 /*!
1162  * @brief PDM set channel transfer config.
1163  *
1164  * @param base PDM base pointer.
1165  * @param handle PDM handle pointer.
1166  * @param channel PDM channel.
1167  * @param config channel config.
1168  * @param format data format, support data width configurations,_pdm_data_width.
1169  * @retval kStatus_PDM_ChannelConfig_Failed or kStatus_Success.
1170  */
1171 status_t PDM_TransferSetChannelConfig(
1172     PDM_Type *base, pdm_handle_t *handle, uint32_t channel, const pdm_channel_config_t *config, uint32_t format);
1173 
1174 /*!
1175  * @brief Performs an interrupt non-blocking receive transfer on PDM.
1176  *
1177  * @note This API returns immediately after the transfer initiates.
1178  * Call the PDM_RxGetTransferStatusIRQ to poll the transfer status and check whether
1179  * the transfer is finished. If the return status is not kStatus_PDM_Busy, the transfer
1180  * is finished.
1181  *
1182  * @param base PDM base pointer
1183  * @param handle Pointer to the pdm_handle_t structure which stores the transfer state.
1184  * @param xfer Pointer to the pdm_transfer_t structure.
1185  * @retval kStatus_Success Successfully started the data receive.
1186  * @retval kStatus_PDM_Busy Previous receive still not finished.
1187  */
1188 status_t PDM_TransferReceiveNonBlocking(PDM_Type *base, pdm_handle_t *handle, pdm_transfer_t *xfer);
1189 
1190 /*!
1191  * @brief Aborts the current IRQ receive.
1192  *
1193  * @note This API can be called when an interrupt non-blocking transfer initiates
1194  * to abort the transfer early.
1195  *
1196  * @param base PDM base pointer
1197  * @param handle Pointer to the pdm_handle_t structure which stores the transfer state.
1198  */
1199 void PDM_TransferAbortReceive(PDM_Type *base, pdm_handle_t *handle);
1200 
1201 /*!
1202  * @brief Tx interrupt handler.
1203  *
1204  * @param base PDM base pointer.
1205  * @param handle Pointer to the pdm_handle_t structure.
1206  */
1207 void PDM_TransferHandleIRQ(PDM_Type *base, pdm_handle_t *handle);
1208 
1209 /*! @} */
1210 
1211 #if defined(__cplusplus)
1212 }
1213 #endif /*_cplusplus*/
1214 
1215 /*! @} */
1216 
1217 #endif /* FSL_PDM_H_ */
1218