1 /***************************************************************************//** 2 * @file 3 * @brief Pulse Density Modulation (PDM) peripheral API 4 ******************************************************************************* 5 * # License 6 * <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b> 7 ******************************************************************************* 8 * 9 * SPDX-License-Identifier: Zlib 10 * 11 * The licensor of this software is Silicon Laboratories Inc. 12 * 13 * This software is provided 'as-is', without any express or implied 14 * warranty. In no event will the authors be held liable for any damages 15 * arising from the use of this software. 16 * 17 * Permission is granted to anyone to use this software for any purpose, 18 * including commercial applications, and to alter it and redistribute it 19 * freely, subject to the following restrictions: 20 * 21 * 1. The origin of this software must not be misrepresented; you must not 22 * claim that you wrote the original software. If you use this software 23 * in a product, an acknowledgment in the product documentation would be 24 * appreciated but is not required. 25 * 2. Altered source versions must be plainly marked as such, and must not be 26 * misrepresented as being the original software. 27 * 3. This notice may not be removed or altered from any source distribution. 28 * 29 ******************************************************************************/ 30 31 #include "em_pdm.h" 32 #if defined(PDM_PRESENT) && (PDM_COUNT == 1) 33 34 #include "sl_assert.h" 35 36 /***************************************************************************//** 37 * @addtogroup pdm 38 * @{ 39 ******************************************************************************/ 40 41 /***************************************************************************//** 42 * @brief 43 * De-initialize the PDM peripheral. 44 * 45 * @details 46 * This function will stop the PDM filter and set PDM control registers to 47 * their reset values. 48 * 49 * @param[in] pdm 50 * A pointer to the PDM peripheral register block. 51 ******************************************************************************/ PDM_DeInit(PDM_TypeDef * pdm)52void PDM_DeInit(PDM_TypeDef *pdm) 53 { 54 PDM_Stop(pdm); 55 PDM_Clear(pdm); 56 PDM_FifoFlush(pdm); 57 PDM_Reset(pdm); 58 } 59 60 /***************************************************************************//** 61 * @brief 62 * Initialize the PDM peripheral. 63 * 64 * @details 65 * This function will configure basic settings in PDM according to values 66 * in the initialization data structure. 67 * 68 * Notice that enabling of PDM clock, setup of PDM pins and setup of PRS 69 * is not covered by this function. 70 * 71 * @param[in] pdm 72 * A pointer to the PDM peripheral register block. 73 * 74 * @param[in] init 75 * A pointer to the initialization structure used to configure the PDM. 76 ******************************************************************************/ PDM_Init(PDM_TypeDef * pdm,const PDM_Init_TypeDef * init)77void PDM_Init(PDM_TypeDef *pdm, const PDM_Init_TypeDef *init) 78 { 79 EFM_ASSERT(init->dsr <= (_PDM_CTRL_DSR_MASK >> _PDM_CTRL_DSR_SHIFT)); 80 EFM_ASSERT(init->gain <= (_PDM_CTRL_GAIN_MASK >> _PDM_CTRL_GAIN_SHIFT)); 81 EFM_ASSERT(init->prescaler <= (_PDM_CFG1_PRESC_MASK >> _PDM_CFG1_PRESC_SHIFT)); 82 83 while (pdm->SYNCBUSY != 0U) { 84 // Wait for any pending CMD synchronization 85 } 86 87 pdm->EN = PDM_EN_EN_DISABLE; 88 89 #if defined(PDM_CFG0_NUMCH_THREE) 90 pdm->CFG0 = ((uint32_t)init->ch3ClkPolarity << _PDM_CFG0_CH3CLKPOL_SHIFT) 91 | ((uint32_t)init->ch2ClkPolarity << _PDM_CFG0_CH2CLKPOL_SHIFT) 92 | ((uint32_t)init->ch1ClkPolarity << _PDM_CFG0_CH1CLKPOL_SHIFT) 93 | ((uint32_t)init->ch0ClkPolarity << _PDM_CFG0_CH0CLKPOL_SHIFT) 94 | ((uint32_t)init->fifoValidWatermark << _PDM_CFG0_FIFODVL_SHIFT) 95 | ((uint32_t)init->dataFormat << _PDM_CFG0_DATAFORMAT_SHIFT) 96 | ((uint32_t)init->numChannels << _PDM_CFG0_NUMCH_SHIFT) 97 | ((uint32_t)init->filterOrder << _PDM_CFG0_FORDER_SHIFT) 98 | (init->enableCh2Ch3Stereo ? PDM_CFG0_STEREOMODECH23_CH23ENABLE : 0U) 99 | (init->enableCh0Ch1Stereo ? PDM_CFG0_STEREOMODECH01_CH01ENABLE : 0U); 100 #else 101 pdm->CFG0 = ((uint32_t)init->ch1ClkPolarity << _PDM_CFG0_CH1CLKPOL_SHIFT) 102 | ((uint32_t)init->ch0ClkPolarity << _PDM_CFG0_CH0CLKPOL_SHIFT) 103 | ((uint32_t)init->fifoValidWatermark << _PDM_CFG0_FIFODVL_SHIFT) 104 | ((uint32_t)init->dataFormat << _PDM_CFG0_DATAFORMAT_SHIFT) 105 | ((uint32_t)init->numChannels << _PDM_CFG0_NUMCH_SHIFT) 106 | ((uint32_t)init->filterOrder << _PDM_CFG0_FORDER_SHIFT) 107 | (init->enableCh0Ch1Stereo ? PDM_CFG0_STEREOMODECH01_CH01ENABLE : 0U); 108 #endif 109 110 pdm->CFG1 = init->prescaler << _PDM_CFG1_PRESC_SHIFT; 111 112 pdm->EN = PDM_EN_EN_ENABLE; 113 114 pdm->CTRL = (init->dsr << _PDM_CTRL_DSR_SHIFT) 115 #if defined(PDM_CTRL_OUTCLKEN) 116 | (init->outClkEn ? PDM_CTRL_OUTCLKEN : 0U) 117 #endif 118 | (init->gain << _PDM_CTRL_GAIN_SHIFT); 119 120 if (init->start) { 121 PDM_Clear(pdm); 122 PDM_FifoFlush(pdm); 123 PDM_Start(pdm); 124 } 125 } 126 127 /***************************************************************************//** 128 * @brief 129 * Initialize PDM registers with reset values. 130 * 131 * @param[in] pdm 132 * A pointer to the PDM peripheral register block. 133 ******************************************************************************/ PDM_Reset(PDM_TypeDef * pdm)134void PDM_Reset(PDM_TypeDef *pdm) 135 { 136 while (pdm->SYNCBUSY != 0U) { 137 // Wait for any pending CMD synchronization 138 } 139 140 if (pdm->EN != 0U) { 141 pdm->CMD = PDM_CMD_FIFOFL | PDM_CMD_CLEAR | PDM_CMD_STOP; 142 while (pdm->SYNCBUSY != 0U) { 143 } 144 } 145 146 #if defined(PDM_HAS_SET_CLEAR) 147 pdm->EN_SET = PDM_EN_EN; 148 #endif 149 pdm->CTRL = _PDM_CTRL_RESETVALUE; 150 pdm->IEN = _PDM_IEN_RESETVALUE; 151 #if defined(PDM_HAS_SET_CLEAR) 152 pdm->IF_CLR = _PDM_IF_MASK; 153 #else 154 pdm->IFC = _PDM_IFC_MASK; 155 #endif 156 #if defined(_PDM_ROUTEPEN_MASK) 157 pdm->ROUTEPEN = _PDM_ROUTEPEN_RESETVALUE; 158 pdm->ROUTELOC0 = _PDM_ROUTELOC0_RESETVALUE; 159 pdm->ROUTELOC1 = _PDM_ROUTELOC1_RESETVALUE; 160 #endif 161 while (pdm->SYNCBUSY != 0U) { 162 /* Must wait for SYNCBUSY before disabling an enabled pdm. */ 163 } 164 pdm->EN = _PDM_EN_RESETVALUE; 165 pdm->CFG0 = _PDM_CFG0_RESETVALUE; 166 pdm->CFG1 = _PDM_CFG1_RESETVALUE; 167 168 while (pdm->SYNCBUSY != 0U) { 169 // Wait for any pending CMD synchronization 170 } 171 } 172 173 /** @} (end addtogroup pdm) */ 174 175 #endif // defined(PDM_PRESENT) && (PDM_COUNT == 1) 176