1 /* 2 * Copyright 2019 - 2020, NXP 3 * All rights reserved. 4 * 5 * SPDX-License-Identifier: BSD-3-Clause 6 */ 7 #ifndef FSL_PDM_EDMA_H_ 8 #define FSL_PDM_EDMA_H_ 9 10 #include "fsl_edma.h" 11 #include "fsl_pdm.h" 12 13 /*! 14 * @addtogroup pdm_edma PDM EDMA Driver 15 * @ingroup pdm 16 * @{ 17 */ 18 19 /******************************************************************************* 20 * Definitions 21 ******************************************************************************/ 22 23 /*! @name Driver version */ 24 /*! @{ */ 25 #define FSL_PDM_EDMA_DRIVER_VERSION (MAKE_VERSION(2, 6, 3)) /*!< Version 2.6.3 */ 26 /*! @} */ 27 28 /*! @brief the PDM enable position When calling PDM_TransferReceiveEDMA */ 29 #ifndef MCUX_SDK_PDM_EDMA_PDM_ENABLE_INTERNAL 30 #define MCUX_SDK_PDM_EDMA_PDM_ENABLE_INTERNAL 1U 31 #endif 32 33 /*! @brief PDM edma handler */ 34 typedef struct _pdm_edma_handle pdm_edma_handle_t; 35 36 /*!@brief pdm multi channel interleave type */ 37 typedef enum _pdm_edma_multi_channel_interleave 38 { 39 kPDM_EDMAMultiChannelInterleavePerChannelSample = 40 0U, /*!< multi channel PDM data interleave per channel sample 41 * ------------------------------------------------------------------------- 42 * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....| 43 * ------------------------------------------------------------------------- 44 */ 45 kPDM_EDMAMultiChannelInterleavePerChannelBlock = 46 1U, /*!< multi channel PDM data interleave per channel block 47 * ---------------------------------------------------------------------------------------------------------------------------- 48 * |CHANNEL0 | CHANNEL0 | CHANNEL0 | ...... | CHANNEL1 | CHANNEL 1 | CHANNEL 1 | ....| CHANNEL2 | CHANNEL 2 49 * | CHANNEL 2 | ....| 50 * ---------------------------------------------------------------------------------------------------------------------------- 51 */ 52 } pdm_edma_multi_channel_interleave_t; 53 54 /*! @brief PDM edma transfer */ 55 typedef struct _pdm_edma_transfer 56 { 57 volatile uint8_t *data; /*!< Data start address to transfer. */ 58 volatile size_t dataSize; /*!< Total Transfer bytes size. */ 59 struct _pdm_edma_transfer *linkTransfer; /*!< linked transfer configurations */ 60 } pdm_edma_transfer_t; 61 62 /*! @brief PDM eDMA transfer callback function for finish and error */ 63 typedef void (*pdm_edma_callback_t)(PDM_Type *base, pdm_edma_handle_t *handle, status_t status, void *userData); 64 65 /*! @brief PDM DMA transfer handle, users should not touch the content of the handle.*/ 66 struct _pdm_edma_handle 67 { 68 edma_handle_t *dmaHandle; /*!< DMA handler for PDM send */ 69 uint8_t count; /*!< The transfer data count in a DMA request */ 70 uint32_t receivedBytes; /*!< total transfer count */ 71 uint32_t state; /*!< Internal state for PDM eDMA transfer */ 72 pdm_edma_callback_t callback; /*!< Callback for users while transfer finish or error occurs */ 73 bool isLoopTransfer; /*!< loop transfer */ 74 void *userData; /*!< User callback parameter */ 75 edma_tcd_t *tcd; /*!< TCD pool for eDMA transfer. */ 76 uint32_t tcdNum; /*!< TCD number */ 77 uint32_t tcdUser; /*!< Index for user to queue transfer. */ 78 uint32_t tcdDriver; /*!< Index for driver to get the transfer data and size */ 79 volatile uint32_t tcdUsedNum; /*!< Index for user to queue transfer. */ 80 81 pdm_edma_multi_channel_interleave_t interleaveType; /*!< multi channel transfer interleave type */ 82 83 uint8_t endChannel; /*!< The last enabled channel */ 84 uint8_t channelNums; /*!< total channel numbers */ 85 }; 86 87 /******************************************************************************* 88 * APIs 89 ******************************************************************************/ 90 #if defined(__cplusplus) 91 extern "C" { 92 #endif 93 94 /*! 95 * @name PDM eDMA Transactional 96 * @{ 97 */ 98 99 /*! 100 * @brief Install EDMA descriptor memory. 101 * 102 * @param handle Pointer to EDMA channel transfer handle. 103 * @param tcdAddr EDMA head descriptor address. 104 * @param tcdNum EDMA link descriptor address. 105 */ 106 void PDM_TransferInstallEDMATCDMemory(pdm_edma_handle_t *handle, void *tcdAddr, size_t tcdNum); 107 108 /*! 109 * @brief Initializes the PDM Rx eDMA handle. 110 * 111 * This function initializes the PDM slave DMA handle, which can be used for other PDM master transactional APIs. 112 * Usually, for a specified PDM instance, call this API once to get the initialized handle. 113 * 114 * @param base PDM base pointer. 115 * @param handle PDM eDMA handle pointer. 116 * @param callback Pointer to user callback function. 117 * @param userData User parameter passed to the callback function. 118 * @param dmaHandle eDMA handle pointer, this handle shall be static allocated by users. 119 */ 120 void PDM_TransferCreateHandleEDMA( 121 PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_callback_t callback, void *userData, edma_handle_t *dmaHandle); 122 123 /*! 124 * @brief Initializes the multi PDM channel interleave type. 125 * 126 * This function initializes the PDM DMA handle member interleaveType, it shall be called only when application would 127 * like to use type kPDM_EDMAMultiChannelInterleavePerChannelBlock, since the default interleaveType is 128 * kPDM_EDMAMultiChannelInterleavePerChannelSample always 129 * 130 * @param handle PDM eDMA handle pointer. 131 * @param multiChannelInterleaveType Multi channel interleave type. 132 */ 133 void PDM_TransferSetMultiChannelInterleaveType(pdm_edma_handle_t *handle, 134 pdm_edma_multi_channel_interleave_t multiChannelInterleaveType); 135 136 /*! 137 * @brief Configures the PDM channel. 138 * 139 * @param base PDM base pointer. 140 * @param handle PDM eDMA handle pointer. 141 * @param channel channel index. 142 * @param config pdm channel configurations. 143 */ 144 void PDM_TransferSetChannelConfigEDMA(PDM_Type *base, 145 pdm_edma_handle_t *handle, 146 uint32_t channel, 147 const pdm_channel_config_t *config); 148 149 /*! 150 * @brief Performs a non-blocking PDM receive using eDMA. 151 * 152 * @note This interface returns immediately after the transfer initiates. Call 153 * the PDM_GetReceiveRemainingBytes to poll the transfer status and check whether the PDM transfer is finished. 154 * 155 * Mcaro MCUX_SDK_PDM_EDMA_PDM_ENABLE_INTERNAL can control whether PDM is enabled internally or externally. 156 * 157 * 1. Scatter gather case: 158 * This functio support dynamic scatter gather and staic scatter gather, 159 * a. for the dynamic scatter gather case: 160 * Application should call PDM_TransferReceiveEDMA function continuously to make sure new receive request is submit 161 * before the previous one finish. b. for the static scatter gather case: Application should use the link transfer 162 * feature and make sure a loop link transfer is provided, such as: 163 * @code pdm_edma_transfer_t pdmXfer[2] = 164 * { 165 * { 166 * .data = s_buffer, 167 * .dataSize = BUFFER_SIZE, 168 * .linkTransfer = &pdmXfer[1], 169 * }, 170 * 171 * { 172 * .data = &s_buffer[BUFFER_SIZE], 173 * .dataSize = BUFFER_SIZE, 174 * .linkTransfer = &pdmXfer[0] 175 * }, 176 * }; 177 * @endcode 178 * 179 * 2. Multi channel case: 180 * This function support receive multi pdm channel data, for example, if two channel is requested, 181 * @code 182 * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_0, &channelConfig); 183 * PDM_TransferSetChannelConfigEDMA(DEMO_PDM, &s_pdmRxHandle_0, DEMO_PDM_ENABLE_CHANNEL_1, &channelConfig); 184 * PDM_TransferReceiveEDMA(DEMO_PDM, &s_pdmRxHandle_0, pdmXfer); 185 * @endcode 186 * The output data will be formatted as below if handle->interleaveType = 187 * kPDM_EDMAMultiChannelInterleavePerChannelSample : 188 * ------------------------------------------------------------------------- 189 * |CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL1 | CHANNEL0 | CHANNEL 1 | ....| 190 * ------------------------------------------------------------------------- 191 * 192 * The output data will be formatted as below if handle->interleaveType = kPDM_EDMAMultiChannelInterleavePerChannelBlock 193 * : 194 * ---------------------------------------------------------------------------------------------------------------------- 195 * |CHANNEL3 | CHANNEL3 | CHANNEL3 | .... | CHANNEL4 | CHANNEL 4 | CHANNEL4 |....| CHANNEL5 | CHANNEL 5 | CHANNEL5 196 * |....| 197 * ---------------------------------------------------------------------------------------------------------------------- 198 * Note: the dataSize of xfer is the total data size, while application using 199 * kPDM_EDMAMultiChannelInterleavePerChannelBlock, the buffer size for each PDM channel is channelSize = dataSize / 200 * channelNums, then there are limitation for this feature, 201 * 1. 3 DMIC array: the dataSize shall be 4 * (channelSize) 202 * The addtional buffer is mandantory for edma modulo feature. 203 * 2. The kPDM_EDMAMultiChannelInterleavePerChannelBlock feature support below dmic array only, 204 * 2 DMIC array: CHANNEL3, CHANNEL4 205 * 3 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5 206 * 4 DMIC array: CHANNEL3, CHANNEL4, CHANNEL5, CHANNEL6 207 * Any other combinations is not support, that is to SAY, THE FEATURE SUPPORT RECEIVE START FROM CHANNEL3 ONLY AND 4 208 * MAXIMUM DMIC CHANNELS. 209 * 210 * @param base PDM base pointer 211 * @param handle PDM eDMA handle pointer. 212 * @param xfer Pointer to DMA transfer structure. 213 * @retval kStatus_Success Start a PDM eDMA receive successfully. 214 * @retval kStatus_InvalidArgument The input argument is invalid. 215 * @retval kStatus_RxBusy PDM is busy receiving data. 216 */ 217 status_t PDM_TransferReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle, pdm_edma_transfer_t *xfer); 218 219 /*! 220 * @brief Terminate all PDM receive. 221 * 222 * This function will clear all transfer slots buffered in the pdm queue. If users only want to abort the 223 * current transfer slot, please call PDM_TransferAbortReceiveEDMA. 224 * 225 * @param base PDM base pointer. 226 * @param handle PDM eDMA handle pointer. 227 */ 228 void PDM_TransferTerminateReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle); 229 230 /*! 231 * @brief Aborts a PDM receive using eDMA. 232 * 233 * This function only aborts the current transfer slots, the other transfer slots' information still kept 234 * in the handler. If users want to terminate all transfer slots, just call PDM_TransferTerminateReceiveEDMA. 235 * 236 * @param base PDM base pointer 237 * @param handle PDM eDMA handle pointer. 238 */ 239 void PDM_TransferAbortReceiveEDMA(PDM_Type *base, pdm_edma_handle_t *handle); 240 241 /*! 242 * @brief Gets byte count received by PDM. 243 * 244 * @param base PDM base pointer 245 * @param handle PDM eDMA handle pointer. 246 * @param count Bytes count received by PDM. 247 * @retval kStatus_Success Succeed get the transfer count. 248 * @retval kStatus_NoTransferInProgress There is no non-blocking transaction in progress. 249 */ 250 status_t PDM_TransferGetReceiveCountEDMA(PDM_Type *base, pdm_edma_handle_t *handle, size_t *count); 251 252 /*! @} */ 253 254 #if defined(__cplusplus) 255 } 256 #endif 257 258 /*! 259 * @} 260 */ 261 #endif 262