DISCOVERY BOARD AUDIO RECORD AND PLAYBACK. Errors are currently with LCD and QSPI definitions.
Dependencies: BSP
main.c
- Committer:
- EricLew
- Date:
- 2015-11-22
- Revision:
- 3:233580d5c68e
- Parent:
- 0:c8cd09e8b137
File content as of revision 3:233580d5c68e:
/** ****************************************************************************** * @file DFSDM/DFSDM_AudioRecord/Src/main.c * @author MCD Application Team * @version V1.1.0 * @date 16-September-2015 * @brief This example describes how to use DFSDM HAL API to realize * audio recording. ****************************************************************************** * @attention * * <h2><center>© COPYRIGHT(c) 2015 STMicroelectronics</center></h2> * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /** @addtogroup STM32L4xx_HAL_Examples * @{ */ /** @addtogroup DFSDM_AudioRecord * @{ */ /* Private typedef -----------------------------------------------------------*/ /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ #define SaturaLH(N, L, H) (((N)<(L))?(L):(((N)>(H))?(H):(N))) /* Private variables ---------------------------------------------------------*/ DFSDM_Channel_HandleTypeDef DfsdmChannelHandle; DFSDM_Filter_HandleTypeDef DfsdmFilterHandle; DMA_HandleTypeDef hDfsdmDma; SAI_HandleTypeDef SaiHandle; DMA_HandleTypeDef hSaiDma; AUDIO_DrvTypeDef *audio_drv; int32_t RecBuff[2048]; int16_t PlayBuff[4096]; uint32_t DmaRecHalfBuffCplt = 0; uint32_t DmaRecBuffCplt = 0; uint32_t PlaybackStarted = 0; /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void DFSDM_Init(void); static void Playback_Init(void); /* Private functions ---------------------------------------------------------*/ /** * @brief Main program * @param None * @retval None */ int main(void) { uint32_t i; /* STM32L4xx HAL library initialization: - Configure the Flash prefetch - Systick timer is configured by default as source of time base, but user can eventually implement his proper time base source (a general purpose timer for example or other time source), keeping in mind that Time base duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and handled in milliseconds basis. - Set NVIC Group Priority to 4 - Low Level Initialization */ HAL_Init(); /* Configure the system clock to have a frequency of 80 MHz */ SystemClock_Config(); /* Configure LED4 */ BSP_LED_Init(LED4); /* Initialize DFSDM channels and filter for record */ DFSDM_Init(); /* Initialize playback */ Playback_Init(); /* Start DFSDM conversions */ if(HAL_OK != HAL_DFSDM_FilterRegularStart_DMA(&DfsdmFilterHandle, RecBuff, 2048)) { Error_Handler(); } /* Start loopback */ while(1) { if(DmaRecHalfBuffCplt == 1) { /* Store values on Play buff */ for(i = 0; i < 1024; i++) { PlayBuff[2*i] = SaturaLH((RecBuff[i] >> 8), -32768, 32767); PlayBuff[(2*i)+1] = PlayBuff[2*i]; } if(PlaybackStarted == 0) { if(0 != audio_drv->Play(AUDIO_I2C_ADDRESS, (uint16_t *) &PlayBuff[0], 4096)) { Error_Handler(); } if(HAL_OK != HAL_SAI_Transmit_DMA(&SaiHandle, (uint8_t *) &PlayBuff[0], 4096)) { Error_Handler(); } PlaybackStarted = 1; } DmaRecHalfBuffCplt = 0; } if(DmaRecBuffCplt == 1) { /* Store values on Play buff */ for(i = 1024; i < 2048; i++) { PlayBuff[2*i] = SaturaLH((RecBuff[i] >> 8), -32768, 32767); PlayBuff[(2*i)+1] = PlayBuff[2*i]; } DmaRecBuffCplt = 0; } } } /** * @brief System Clock Configuration * The system Clock is configured as follows : * System Clock source = PLL (MSI) * SYSCLK(Hz) = 80000000 * HCLK(Hz) = 80000000 * AHB Prescaler = 1 * APB1 Prescaler = 1 * APB2 Prescaler = 1 * MSI Frequency(Hz) = 4000000 * PLL_M = 1 * PLL_N = 40 * PLL_R = 2 * PLL_P = 7 * PLL_Q = 4 * Flash Latency(WS) = 4 * @param None * @retval None */ void SystemClock_Config(void) { RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_OscInitTypeDef RCC_OscInitStruct = {0}; /* MSI is enabled after System reset, activate PLL with MSI as source */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6; RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_MSI; RCC_OscInitStruct.PLL.PLLM = 1; RCC_OscInitStruct.PLL.PLLN = 40; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLP = 7; RCC_OscInitStruct.PLL.PLLQ = 4; if(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { /* Initialization Error */ while(1); } /* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2 clocks dividers */ RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2); RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { /* Initialization Error */ while(1); } } /** * @brief DFSDM channels and filter initialization * @param None * @retval None */ static void DFSDM_Init(void) { /* Initialize channel 2 */ __HAL_DFSDM_CHANNEL_RESET_HANDLE_STATE(&DfsdmChannelHandle); DfsdmChannelHandle.Instance = DFSDM_Channel2; DfsdmChannelHandle.Init.OutputClock.Activation = ENABLE; DfsdmChannelHandle.Init.OutputClock.Selection = DFSDM_CHANNEL_OUTPUT_CLOCK_AUDIO; DfsdmChannelHandle.Init.OutputClock.Divider = 4; /* 11.294MHz/4 = 2.82MHz */ DfsdmChannelHandle.Init.Input.Multiplexer = DFSDM_CHANNEL_EXTERNAL_INPUTS; DfsdmChannelHandle.Init.Input.DataPacking = DFSDM_CHANNEL_STANDARD_MODE; /* N.U. */ DfsdmChannelHandle.Init.Input.Pins = DFSDM_CHANNEL_SAME_CHANNEL_PINS; DfsdmChannelHandle.Init.SerialInterface.Type = DFSDM_CHANNEL_SPI_RISING; DfsdmChannelHandle.Init.SerialInterface.SpiClock = DFSDM_CHANNEL_SPI_CLOCK_INTERNAL; DfsdmChannelHandle.Init.Awd.FilterOrder = DFSDM_CHANNEL_FASTSINC_ORDER; /* N.U. */ DfsdmChannelHandle.Init.Awd.Oversampling = 10; /* N.U. */ DfsdmChannelHandle.Init.Offset = 0; DfsdmChannelHandle.Init.RightBitShift = 2; if(HAL_OK != HAL_DFSDM_ChannelInit(&DfsdmChannelHandle)) { Error_Handler(); } /* Initialize filter 0 */ __HAL_DFSDM_FILTER_RESET_HANDLE_STATE(&DfsdmFilterHandle); DfsdmFilterHandle.Instance = DFSDM_Filter0; DfsdmFilterHandle.Init.RegularParam.Trigger = DFSDM_FILTER_SW_TRIGGER; DfsdmFilterHandle.Init.RegularParam.FastMode = ENABLE; DfsdmFilterHandle.Init.RegularParam.DmaMode = ENABLE; DfsdmFilterHandle.Init.InjectedParam.Trigger = DFSDM_FILTER_SW_TRIGGER; /* N.U. */ DfsdmFilterHandle.Init.InjectedParam.ScanMode = ENABLE; /* N.U. */ DfsdmFilterHandle.Init.InjectedParam.DmaMode = DISABLE; /* N.U. */ DfsdmFilterHandle.Init.InjectedParam.ExtTrigger = DFSDM_FILTER_EXT_TRIG_TIM1_TRGO; /* N.U. */ DfsdmFilterHandle.Init.InjectedParam.ExtTriggerEdge = DFSDM_FILTER_EXT_TRIG_RISING_EDGE; /* N.U. */ DfsdmFilterHandle.Init.FilterParam.SincOrder = DFSDM_FILTER_SINC3_ORDER; DfsdmFilterHandle.Init.FilterParam.Oversampling = 64; /* 11.294MHz/(4*64) = 44.1KHz */ DfsdmFilterHandle.Init.FilterParam.IntOversampling = 1; if(HAL_OK != HAL_DFSDM_FilterInit(&DfsdmFilterHandle)) { Error_Handler(); } /* Configure regular channel and continuous mode for filter 0 */ if(HAL_OK != HAL_DFSDM_FilterConfigRegChannel(&DfsdmFilterHandle, DFSDM_CHANNEL_2, DFSDM_CONTINUOUS_CONV_ON)) { Error_Handler(); } } /** * @brief Playback initialization * @param None * @retval None */ static void Playback_Init(void) { /* Initialize SAI */ __HAL_SAI_RESET_HANDLE_STATE(&SaiHandle); SaiHandle.Instance = SAI1_Block_A; SaiHandle.Init.AudioMode = SAI_MODEMASTER_TX; SaiHandle.Init.Synchro = SAI_ASYNCHRONOUS; SaiHandle.Init.SynchroExt = SAI_SYNCEXT_DISABLE; SaiHandle.Init.OutputDrive = SAI_OUTPUTDRIVE_ENABLE; SaiHandle.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; SaiHandle.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; SaiHandle.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_44K; SaiHandle.Init.Mckdiv = 0; /* N.U */ SaiHandle.Init.MonoStereoMode = SAI_STEREOMODE; SaiHandle.Init.CompandingMode = SAI_NOCOMPANDING; SaiHandle.Init.TriState = SAI_OUTPUT_NOTRELEASED; SaiHandle.Init.Protocol = SAI_FREE_PROTOCOL; SaiHandle.Init.DataSize = SAI_DATASIZE_16; SaiHandle.Init.FirstBit = SAI_FIRSTBIT_MSB; SaiHandle.Init.ClockStrobing = SAI_CLOCKSTROBING_RISINGEDGE; SaiHandle.FrameInit.FrameLength = 32; SaiHandle.FrameInit.ActiveFrameLength = 16; SaiHandle.FrameInit.FSDefinition = SAI_FS_CHANNEL_IDENTIFICATION; SaiHandle.FrameInit.FSPolarity = SAI_FS_ACTIVE_LOW; SaiHandle.FrameInit.FSOffset = SAI_FS_BEFOREFIRSTBIT; SaiHandle.SlotInit.FirstBitOffset = 0; SaiHandle.SlotInit.SlotSize = SAI_SLOTSIZE_DATASIZE; SaiHandle.SlotInit.SlotNumber = 2; SaiHandle.SlotInit.SlotActive = (SAI_SLOTACTIVE_0 | SAI_SLOTACTIVE_1); if(HAL_OK != HAL_SAI_Init(&SaiHandle)) { Error_Handler(); } /* Enable SAI to generate clock used by audio driver */ __HAL_SAI_ENABLE(&SaiHandle); /* Initialize audio driver */ if(CS43L22_ID != cs43l22_drv.ReadID(AUDIO_I2C_ADDRESS)) { Error_Handler(); } audio_drv = &cs43l22_drv; audio_drv->Reset(AUDIO_I2C_ADDRESS); if(0 != audio_drv->Init(AUDIO_I2C_ADDRESS, OUTPUT_DEVICE_HEADPHONE, 90, AUDIO_FREQUENCY_44K)) { Error_Handler(); } } /** * @brief This function is executed in case of error occurrence. * @param None * @retval None */ void Error_Handler(void) { while (1) { /* Toggle LED4 with a period of one second */ BSP_LED_Toggle(LED4); HAL_Delay(1000); } } /** * @brief Initializes the DFSDM channel MSP. * @param hdfsdm_channel : DFSDM channel handle. * @retval None */ void HAL_DFSDM_ChannelMspInit(DFSDM_Channel_HandleTypeDef *hdfsdm_channel) { /* Init of clock, gpio and PLLSAI1 clock */ GPIO_InitTypeDef GPIO_Init; RCC_PeriphCLKInitTypeDef RCC_PeriphCLKInitStruct; /* Enable DFSDM clock */ __HAL_RCC_DFSDM_CLK_ENABLE(); /* Configure PE9 for DFSDM_CKOUT and PE7 for DFSDM_DATIN2 */ __HAL_RCC_GPIOE_CLK_ENABLE(); GPIO_Init.Mode = GPIO_MODE_AF_PP; GPIO_Init.Pull = GPIO_PULLDOWN; GPIO_Init.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_Init.Alternate = GPIO_AF6_DFSDM; GPIO_Init.Pin = GPIO_PIN_9; HAL_GPIO_Init(GPIOE, &GPIO_Init); GPIO_Init.Pin = GPIO_PIN_7; HAL_GPIO_Init(GPIOE, &GPIO_Init); /* Configure and enable PLLSAI1 clock to generate 11.294MHz */ RCC_PeriphCLKInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SAI1; RCC_PeriphCLKInitStruct.PLLSAI1.PLLSAI1N = 48; RCC_PeriphCLKInitStruct.PLLSAI1.PLLSAI1P = 17; RCC_PeriphCLKInitStruct.PLLSAI1.PLLSAI1ClockOut = RCC_PLLSAI1_SAI1CLK; RCC_PeriphCLKInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI1; if(HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphCLKInitStruct) != HAL_OK) { Error_Handler(); } } /** * @brief Initializes the DFSDM filter MSP. * @param hdfsdm_filter : DFSDM filter handle. * @retval None */ void HAL_DFSDM_FilterMspInit(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) { /* Configure DMA1_Channel4 */ __HAL_RCC_DMA1_CLK_ENABLE(); hDfsdmDma.Init.Request = DMA_REQUEST_0; hDfsdmDma.Init.Direction = DMA_PERIPH_TO_MEMORY; hDfsdmDma.Init.PeriphInc = DMA_PINC_DISABLE; hDfsdmDma.Init.MemInc = DMA_MINC_ENABLE; hDfsdmDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hDfsdmDma.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hDfsdmDma.Init.Mode = DMA_CIRCULAR; hDfsdmDma.Init.Priority = DMA_PRIORITY_HIGH; hDfsdmDma.Instance = DMA1_Channel4; __HAL_LINKDMA(hdfsdm_filter, hdmaReg, hDfsdmDma); if (HAL_OK != HAL_DMA_Init(&hDfsdmDma)) { Error_Handler(); } HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0x01, 0); HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn); } /** * @brief SAI MSP Init. * @param hsai : pointer to a SAI_HandleTypeDef structure that contains * the configuration information for SAI module. * @retval None */ void HAL_SAI_MspInit(SAI_HandleTypeDef *hsai) { GPIO_InitTypeDef GPIO_Init; /* Enable SAI1 clock */ __HAL_RCC_SAI1_CLK_ENABLE(); /* Configure GPIOs used for SAI1 */ __HAL_RCC_GPIOE_CLK_ENABLE(); GPIO_Init.Mode = GPIO_MODE_AF_PP; GPIO_Init.Pull = GPIO_NOPULL; GPIO_Init.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_Init.Alternate = GPIO_AF13_SAI1; GPIO_Init.Pin = (GPIO_PIN_2 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6); HAL_GPIO_Init(GPIOE, &GPIO_Init); /* Configure DMA used for SAI1 */ __HAL_RCC_DMA2_CLK_ENABLE(); hSaiDma.Init.Request = DMA_REQUEST_1; hSaiDma.Init.Direction = DMA_MEMORY_TO_PERIPH; hSaiDma.Init.PeriphInc = DMA_PINC_DISABLE; hSaiDma.Init.MemInc = DMA_MINC_ENABLE; hSaiDma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hSaiDma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hSaiDma.Init.Mode = DMA_CIRCULAR; hSaiDma.Init.Priority = DMA_PRIORITY_HIGH; hSaiDma.Instance = DMA2_Channel1; __HAL_LINKDMA(hsai, hdmatx, hSaiDma); if (HAL_OK != HAL_DMA_Init(&hSaiDma)) { Error_Handler(); } HAL_NVIC_SetPriority(DMA2_Channel1_IRQn, 0x01, 0); HAL_NVIC_EnableIRQ(DMA2_Channel1_IRQn); } /** * @brief Half regular conversion complete callback. * @param hdfsdm_filter : DFSDM filter handle. * @retval None */ void HAL_DFSDM_FilterRegConvHalfCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) { DmaRecHalfBuffCplt = 1; } /** * @brief Regular conversion complete callback. * @note In interrupt mode, user has to read conversion value in this function using HAL_DFSDM_FilterGetRegularValue. * @param hdfsdm_filter : DFSDM filter handle. * @retval None */ void HAL_DFSDM_FilterRegConvCpltCallback(DFSDM_Filter_HandleTypeDef *hdfsdm_filter) { DmaRecBuffCplt = 1; } #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 can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* Infinite loop */ while (1) { } } #endif /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/