数字麦克风PDM信号采集与STM32 I2S接口应用(四)--单片机源码
本文是数字麦克风笔记文章的单片机程序。一些朋友私信我,调试出问题。
我的博客只是总结经验不是教程,所以不是什么都记,想起来当时我也是花了一些时间才发现问题的,可能确实有些坑。
我就把源码贴出来吧,可能主要问题是DMA的配置。尤其双DMA时候,需要手动启动I2S的接收DMA,HAL库没有这个接口,不看datasheet是找不到这个毛病的,这也是HAL库用多了引起的问题,一些特底层的问题大家都不愿意去搞了。
测试代码有点乱没整理。
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2019 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "crc.h" #include "dma.h" #include "i2s.h" //#include "pdm2pcm.h" #include "usb_device.h" #include "gpio.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "usbd_cdc_if.h" #include <stdio.h> #include "pdm_filter.h" #include "arm_math.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* ---- 12khz % Discrete-Time IIR Filter (real) % ------------------------------- % Filter Structure : Direct-Form I, Second-Order Sections % Number of Sections : 3 % Stable : Yes % Linear Phase : No SOS Matrix: 1 -2 1 1 1.195433962890738 0.69059892324149696 1 -2 1 1 0.94280904158206325 0.33333333333333331 1 -2 1 1 0.84028692165132668 0.18834516088404465 Scale Values: 0.12379124008768976 0.097631072937817504 0.087014559808179473 --- 2khz % Generated by MATLAB(R) 8.3 and the Signal Processing Toolbox 6.21. % Generated on: 23-Jul-2019 18:13:58 % Coefficient Format: Decimal % Discrete-Time IIR Filter (real) % ------------------------------- % Filter Structure : Direct-Form I, Second-Order Sections % Number of Sections : 3 % Stable : Yes % Linear Phase : No SOS Matrix: 1 -2 1 1 -1.6812394272942188 0.81976044292731376 1 -2 1 1 -1.454243586251585 0.57406191508395488 1 -2 1 1 -1.349079994888392 0.46023366403769816 Scale Values: 0.8752499675553832 0.75707637533388505 0.70232841473152252 */ #define numStages 3 // 6 order #define FILTER_SAMPLES 2*160 float32_t FilterDataIn[FILTER_SAMPLES]={0}; float32_t FilterDataOut[FILTER_SAMPLES]={0}; static float32_t testInput_f32_50Hz_200Hz[FILTER_SAMPLES]; /* input samping points */ static float32_t testOutput[FILTER_SAMPLES]; /* output */ static float32_t IIRStateF32[4*numStages]; /* tmp buf=numTaps + blockSize - 1*/ #if 1 // 12khz hpf const float32_t IIRCoeffs32HP[5*numStages] = { 1.0f, -2.0f, 1.0f, -1.195433962890738f, -0.69059892324149696f, 1.0f, -2.0f, 1.0f, -0.94280904158206325f, -0.33333333333333331f, 1.0f, -2.0f, 1.0f, -0.84028692165132668f, -0.18834516088404465f }; const float32_t ScaleValue = 0.12379124008768976f * 0.097631072937817504f * 0.087014559808179473f; #else // 2khz hpf, people can hear the sound, just high pitch. const float32_t IIRCoeffs32HP[5*numStages] = { 1.0f, -2.0f, 1.0f, 1.6812394272942188, -0.81976044292731376, 1.0f, -2.0f, 1.0f, 1.454243586251585, -0.57406191508395488, 1.0f, -2.0f, 1.0f, 1.349079994888392, -0.46023366403769816 }; const float32_t ScaleValue = 0.8752499675553832f * 0.75707637533388505f * 0.70232841473152252f; #endif void arm_copy_u162f32( int16_t * pSrc, float32_t * pDst, uint32_t blockSize) { uint32_t blkCnt; /* loop counter */ #ifndef ARM_MATH_CM0 /* Run the below code for Cortex-M4 and Cortex-M3 */ /*loop Unrolling */ blkCnt = blockSize >> 2u; /* First part of the processing with loop unrolling. Compute 4 outputs at a time. ** a second loop below computes the remaining 1 to 3 samples. */ while(blkCnt > 0u) { /* C = A */ /* Copy and then store the results in the destination buffer */ *pDst++ = *pSrc++; *pDst++ = *pSrc++; *pDst++ = *pSrc++; *pDst++ = *pSrc++; /* Decrement the loop counter */ blkCnt--; } /* If the blockSize is not a multiple of 4, compute any remaining output samples here. ** No loop unrolling is used. */ blkCnt = blockSize % 0x4u; #else /* Run the below code for Cortex-M0 */ /* Loop over blockSize number of values */ blkCnt = blockSize; #endif /* #ifndef ARM_MATH_CM0 */ while(blkCnt > 0u) { /* C = A */ /* Copy and then store the results in the destination buffer */ *pDst++ = *pSrc++; /* Decrement the loop counter */ blkCnt--; } } void arm_copy_f322u16( float32_t * pSrc, int16_t * pDst, uint32_t blockSize) { uint32_t blkCnt; /* loop counter */ #ifndef ARM_MATH_CM0 /* Run the below code for Cortex-M4 and Cortex-M3 */ /*loop Unrolling */ blkCnt = blockSize >> 2u; /* First part of the processing with loop unrolling. Compute 4 outputs at a time. ** a second loop below computes the remaining 1 to 3 samples. */ while(blkCnt > 0u) { /* C = A */ /* Copy and then store the results in the destination buffer */ *pDst++ = (int16_t)*pSrc++; *pDst++ = (int16_t)*pSrc++; *pDst++ = (int16_t)*pSrc++; *pDst++ = (int16_t)*pSrc++; /* Decrement the loop counter */ blkCnt--; } /* If the blockSize is not a multiple of 4, compute any remaining output samples here. ** No loop unrolling is used. */ blkCnt = blockSize % 0x4u; #else /* Run the below code for Cortex-M0 */ /* Loop over blockSize number of values */ blkCnt = blockSize; #endif /* #ifndef ARM_MATH_CM0 */ while(blkCnt > 0u) { /* C = A */ /* Copy and then store the results in the destination buffer */ *pDst++ = (int16_t)*pSrc++; /* Decrement the loop counter */ blkCnt--; } } /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ #define PDM_2_PCM_SAM (2*64) #define PDM_SAM_POINTS (2*640) #define PCM_SAM_POINTS (2*160) typedef struct { int pdmIdx; int pcmIdx; uint16_t PDMBuf[2][PDM_SAM_POINTS]; int16_t PCMBuf[PCM_SAM_POINTS]; }MicrophoneBufStruct; MicrophoneBufStruct MicrophoreBuf = {0}; PDMFilter_InitStruct Filter; void HAL_I2S_DMA_RxM0CpltCallback(DMA_HandleTypeDef *hdma); void HAL_I2S_DMA_RxM1CpltCallback(DMA_HandleTypeDef *hdma); void HAL_I2S_DMA_Rx_Error_CpltCallback(DMA_HandleTypeDef *hdma); int UsbTxErr = 0; uint8_t printBuf[PCM_SAM_POINTS*10]={0}; int tests = 0; static int32_t idx = 0; /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_I2S2_Init(); MX_USB_DEVICE_Init(); MX_CRC_Init(); // MX_PDM2PCM_Init(); /* USER CODE BEGIN 2 */ HAL_Delay(3000); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ __HAL_RCC_GPIOB_CLK_ENABLE(); //PB0 : FOR MEAS IIS SAMPING TIME GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); HAL_GPIO_WritePin( GPIOB, GPIO_PIN_0, 0); /* Filter LP & HP Init */ //Õâ¸öÂ˲¨Æ÷Ч¹û±È½Ï²î£¬×Ô¼ºÂ˲¨²ÅÐУ¬³öÏÖÔëÉùºÍÌø±ä¡£ Filter.HP_HZ = 100; Filter.LP_HZ = 15000; Filter.Fs = 32000; Filter.Out_MicChannels = 1; Filter.In_MicChannels = 1; PDM_Filter_Init((PDMFilter_InitStruct *)&Filter); hi2s2.hdmarx->XferCpltCallback = HAL_I2S_DMA_RxM0CpltCallback; hi2s2.hdmarx->XferM1CpltCallback = HAL_I2S_DMA_RxM1CpltCallback; hi2s2.hdmarx->XferErrorCallback = HAL_I2S_DMA_Rx_Error_CpltCallback; HAL_DMAEx_MultiBufferStart_IT(hi2s2.hdmarx, (uint32_t)&hi2s2.Instance->DR, (uint32_t)&MicrophoreBuf.PDMBuf[0], (uint32_t)&MicrophoreBuf.PDMBuf[1], PDM_SAM_POINTS); HAL_I2S_DMAResume(&hi2s2); /* Enable Rx DMA Request */ SET_BIT(hi2s2.Instance->CR2, SPI_CR2_RXDMAEN); // HAL_I2S_Receive_DMA (&hi2s2, MicrophoreBuf.PDMBuf[0], PDM_SAM_POINTS); static char printBuf[100]={0}; static int cur_buf = 0; HAL_GPIO_WritePin( GPIOB, GPIO_PIN_0, 0); arm_biquad_casd_df1_inst_f32 S = {0}; arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32HP[0], (float32_t *)&IIRStateF32[0]); while (1) { uint16_t *srcBuf = 0; int16_t *dstBuf = 0; if(MicrophoreBuf.pdmIdx == -1) continue; dstBuf = MicrophoreBuf.PCMBuf; srcBuf = MicrophoreBuf.PDMBuf[MicrophoreBuf.pdmIdx]; MicrophoreBuf.pdmIdx = -1; for(int i=0; i<PDM_SAM_POINTS; i++) { uint16_t a = srcBuf[i]; srcBuf[i] = HTONS(a); } uint16_t volumeGain = 10; int num = 0; HAL_GPIO_WritePin( GPIOB, GPIO_PIN_0, 1); for(int i=0; i<PDM_SAM_POINTS; i=i+PDM_2_PCM_SAM) { num += PDM_Filter_64_LSB((uint8_t *)&srcBuf[i], (uint16_t *)&dstBuf[i/4], volumeGain , (PDMFilter_InitStruct *)&Filter); } HAL_GPIO_WritePin( GPIOB, GPIO_PIN_0, 0); // USE IIR FILTER HERE #if 1 //HAL_GPIO_WritePin( GPIOB, GPIO_PIN_0, 1); arm_copy_u162f32(dstBuf, FilterDataIn, FILTER_SAMPLES); arm_biquad_cascade_df1_f32(&S, FilterDataIn, FilterDataOut, FILTER_SAMPLES); arm_scale_f32(FilterDataOut, ScaleValue, FilterDataOut, FILTER_SAMPLES); arm_copy_f322u16(FilterDataOut, dstBuf, FILTER_SAMPLES); //HAL_GPIO_WritePin( GPIOB, GPIO_PIN_0, 0); #endif #if 0 // send raw data to pc if(USBD_OK != CDC_Transmit_FS((uint8_t *)dstBuf, 2*PCM_SAM_POINTS) ) { UsbTxErr++; // HAL_Delay(1); // CDC_Transmit_FS((uint8_t *)dstBuf, PCM_SAM_POINTS); } #endif #if 1 // calc fire trigger. float32_t calcRst = 0.0f; uint8_t triggerFired = 0; HAL_GPIO_WritePin( GPIOB, GPIO_PIN_0, 1); for(int i=0; i<2; i++) { int offset = i*FILTER_SAMPLES/2; arm_abs_f32(FilterDataOut + offset, FilterDataOut + offset, FILTER_SAMPLES/2); arm_mean_f32(FilterDataOut+ offset, FILTER_SAMPLES/2, &calcRst); if(((int)calcRst >1700) && (triggerFired == 0)) { triggerFired = 1; break; } } HAL_GPIO_WritePin( GPIOB, GPIO_PIN_0, 0); uint8_t cmd[] = { 2,0,0,0, 0,0,0,0, 3,0,0,0, 1, 6,7}; cmd[12] = triggerFired<<7; // 0x80 null, 0x81 sound, 0x82 acc, 0x83 all. cmd[13] = (uint8_t)(((int)calcRst) & 0xff); cmd[14] = (uint8_t)(((int)calcRst) >> 8); if(USBD_OK != CDC_Transmit_FS((uint8_t *)cmd, sizeof(cmd) ) ) { UsbTxErr++; } #endif } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 8; RCC_OscInitStruct.PLL.PLLN = 336; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 7; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) { Error_Handler(); } PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S; PeriphClkInitStruct.PLLI2S.PLLI2SN = 369; PeriphClkInitStruct.PLLI2S.PLLI2SR = 6; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { Error_Handler(); } } /* USER CODE BEGIN 4 */ static void DMA_SetConfig(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength) { /* Clear DBM bit */ hdma->Instance->CR &= (uint32_t)(~DMA_SxCR_DBM); /* Configure DMA Stream data length */ hdma->Instance->NDTR = DataLength; /* Memory to Peripheral */ if((hdma->Init.Direction) == DMA_MEMORY_TO_PERIPH) { /* Configure DMA Stream destination address */ hdma->Instance->PAR = DstAddress; /* Configure DMA Stream source address */ hdma->Instance->M0AR = SrcAddress; } /* Peripheral to Memory */ else { /* Configure DMA Stream source address */ hdma->Instance->PAR = SrcAddress; /* Configure DMA Stream destination address */ hdma->Instance->M0AR = DstAddress; } } void HAL_I2S_RxCpltCallback(I2S_HandleTypeDef *hi2s) { uint16_t *srcBuf = MicrophoreBuf.PDMBuf[0]; int16_t *dstBuf = MicrophoreBuf.PCMBuf; // HAL_I2S_Receive_DMA (&hi2s2, MicrophoreBuf.PDMBuf[0], PDM_SAM_POINTS); // if(idx == 0){ // MicrophoreBuf.pdmIdx = 0; // //HAL_I2S_Receive_DMA (&hi2s2, (uint16_t*)MicrophoreBuf.PDMBuf[1], PDM_SAM_POINTS); // } // else if(idx % 2 == 1){ // MicrophoreBuf.pdmIdx = 1; // // HAL_I2S_Receive_DMA (&hi2s2, (uint16_t*)MicrophoreBuf.PDMBuf[0], PDM_SAM_POINTS); // } // else{ // MicrophoreBuf.pdmIdx = 0; // // HAL_I2S_Receive_DMA (&hi2s2, (uint16_t*)MicrophoreBuf.PDMBuf[1], PDM_SAM_POINTS); // } // idx++; } void HAL_I2S_DMA_RxM0CpltCallback(DMA_HandleTypeDef *hdma) { MicrophoreBuf.pdmIdx = 0; } void HAL_I2S_DMA_RxM1CpltCallback(DMA_HandleTypeDef *hdma) { MicrophoreBuf.pdmIdx = 1; } void HAL_I2S_DMA_Rx_Error_CpltCallback(DMA_HandleTypeDef *hdma) { } /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/** ****************************************************************************** * File Name : I2S.c * Description : This file provides code for the configuration * of the I2S instances. ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2019 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under Ultimate Liberty license * SLA0044, the "License"; You may not use this file except in compliance with * the License. You may obtain a copy of the License at: * www.st.com/SLA0044 * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "i2s.h" /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ I2S_HandleTypeDef hi2s2; DMA_HandleTypeDef hdma_spi2_rx; /* I2S2 init function */ void MX_I2S2_Init(void) { hi2s2.Instance = SPI2; hi2s2.Init.Mode = I2S_MODE_MASTER_RX; hi2s2.Init.Standard = I2S_STANDARD_PHILIPS; hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B; hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_DISABLE; hi2s2.Init.AudioFreq = 64000;//I2S_AUDIOFREQ_32K; hi2s2.Init.CPOL = I2S_CPOL_HIGH;//I2S_CPOL_LOW; hi2s2.Init.ClockSource = I2S_CLOCK_PLL; hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE; if (HAL_I2S_Init(&hi2s2) != HAL_OK) { Error_Handler(); } } void HAL_I2S_MspInit(I2S_HandleTypeDef* i2sHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(i2sHandle->Instance==SPI2) { /* USER CODE BEGIN SPI2_MspInit 0 */ /* USER CODE END SPI2_MspInit 0 */ /* I2S2 clock enable */ __HAL_RCC_SPI2_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /**I2S2 GPIO Configuration PC3 ------> I2S2_SD PB10 ------> I2S2_CK PB12 ------> I2S2_WS */ GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF5_SPI2; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* I2S2 DMA Init */ /* SPI2_RX Init */ hdma_spi2_rx.Instance = DMA1_Stream3; hdma_spi2_rx.Init.Channel = DMA_CHANNEL_0; hdma_spi2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_spi2_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_spi2_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_spi2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_spi2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;//DMA_PDATAALIGN_HALFWORD; hdma_spi2_rx.Init.Mode = DMA_CIRCULAR; //hdma_spi2_rx.Init.Mode = DMA_NORMAL; hdma_spi2_rx.Init.Priority = DMA_PRIORITY_HIGH; hdma_spi2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; if (HAL_DMA_Init(&hdma_spi2_rx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(i2sHandle,hdmarx,hdma_spi2_rx); /* USER CODE BEGIN SPI2_MspInit 1 */ /* USER CODE END SPI2_MspInit 1 */ } } void HAL_I2S_MspDeInit(I2S_HandleTypeDef* i2sHandle) { if(i2sHandle->Instance==SPI2) { /* USER CODE BEGIN SPI2_MspDeInit 0 */ /* USER CODE END SPI2_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_SPI2_CLK_DISABLE(); /**I2S2 GPIO Configuration PC3 ------> I2S2_SD PB10 ------> I2S2_CK PB12 ------> I2S2_WS */ HAL_GPIO_DeInit(GPIOC, GPIO_PIN_3); HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_12); /* I2S2 DMA DeInit */ HAL_DMA_DeInit(i2sHandle->hdmarx); /* USER CODE BEGIN SPI2_MspDeInit 1 */ /* USER CODE END SPI2_MspDeInit 1 */ } } /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
数字麦克风PDM信号采集与STM32 I2S接口应用--笔记目录:
数字麦克风PDM信号采集与STM32 I2S接口应用(一)
https://www.cnblogs.com/pingwen/p/11298675.html
数字麦克风PDM信号采集与STM32 I2S接口应用(二)
https://www.cnblogs.com/pingwen/p/11301935.html
数字麦克风PDM信号采集与STM32 I2S接口应用(三)
https://www.cnblogs.com/pingwen/p/11794081.html
数字麦克风PDM转PCM与STM32 I2S接口应用----重要文档列表
https://www.cnblogs.com/pingwen/p/11302452.html