赞
踩
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2021 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "delay.h" #include "bsp_printf.h" #include "bsp_key.h" #include "string.h" #include "bsp_sdram.h" #include "bsp_malloc.h" #include "bsp_sdmmc.h" #include "ff.h" /* Obtains integer types */ #include "bsp_exfuns.h" #include "bsp_audioplay.h" #include "bsp_recorder.h" //#include "bsp_w25qxx.h" //#include "bsp_ftl.h" //#include "bsp_nand.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* 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 ---------------------------------------------------------*/ SAI_HandleTypeDef hsai_BlockA1; SAI_HandleTypeDef hsai_BlockB1; DMA_HandleTypeDef hdma_sai1_a; DMA_HandleTypeDef hdma_sai1_b; SD_HandleTypeDef hsd1; DMA_HandleTypeDef hdma_sdmmc1_rx; DMA_HandleTypeDef hdma_sdmmc1_tx; UART_HandleTypeDef huart1; SDRAM_HandleTypeDef hsdram1; /* USER CODE BEGIN PV */ volatile uint8_t rx_done, tx_done; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); static void MX_FMC_Init(void); static void MX_DMA_Init(void); static void MX_SDMMC1_SD_Init(void); static void MX_SAI1_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ static void Sdram_SendCommand(uint32_t CommandMode, uint32_t CommandTarget, uint32_t AutoRefreshNumber, uint32_t ModeRegisterDefinition) { FMC_SDRAM_CommandTypeDef Command; Command.AutoRefreshNumber = AutoRefreshNumber; Command.CommandMode = CommandMode; Command.CommandTarget = CommandTarget; Command.ModeRegisterDefinition = ModeRegisterDefinition; HAL_SDRAM_SendCommand(&hsdram1, &Command, 0); } static void Sdram_Init_Sequence(void) { uint32_t ModeRegisterDefinition; Sdram_SendCommand(FMC_SDRAM_CMD_CLK_ENABLE, FMC_SDRAM_CMD_TARGET_BANK1, 1, 0);//时钟配置使能 delay_us(500);//至少延时200us Sdram_SendCommand(FMC_SDRAM_CMD_PALL, FMC_SDRAM_CMD_TARGET_BANK1, 1, 0);//对所有存储区预充电 Sdram_SendCommand(FMC_SDRAM_CMD_AUTOREFRESH_MODE, FMC_SDRAM_CMD_TARGET_BANK1, 8, 0);//设置自刷新次数 // #define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000) #define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001) #define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002) #define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004) #define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000) #define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008) #define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020) #define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030) #define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000) #define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000) #define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200) ModeRegisterDefinition=(uint32_t)SDRAM_MODEREG_BURST_LENGTH_1 | //设置突发长度:1(可以是1/2/4/8) SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL | //设置突发类型:连续(可以是连续/交错) SDRAM_MODEREG_CAS_LATENCY_3 | //设置CAS值:3(可以是2/3) SDRAM_MODEREG_OPERATING_MODE_STANDARD | //设置操作模式:0,标准模式 SDRAM_MODEREG_WRITEBURST_MODE_SINGLE; //设置突发写模式:1,单点访问 Sdram_SendCommand(FMC_SDRAM_CMD_LOAD_MODE, FMC_SDRAM_CMD_TARGET_BANK1, 1, ModeRegisterDefinition); HAL_SDRAM_ProgramRefreshRate(&hsdram1, 823); } //通过串口打印SD卡相关信息 void show_sdcard_info(void) { HAL_SD_CardCIDTypeDef cid; switch(hsd1.SdCard.CardVersion) { case CARD_V1_X:printf("Card Version:CARD_V1_X\r\n");break; case CARD_V2_X:printf("Card Version:CARD_V2_X\r\n");break; } switch(hsd1.SdCard.CardType) { case CARD_SDSC:printf("Card Type:CARD_SDSC\r\n");break; case CARD_SDHC_SDXC:printf("Card Type:CARD_SDHC_SDXC\r\n");break; case CARD_SECURED:printf("Card Type:CARD_SECURED\r\n");break; } if(HAL_OK != HAL_SD_GetCardCID(&hsd1, &cid)) { Error_Handler(); } printf("Card ManufacturerID:%d\r\n",cid.ManufacturerID); //制造商ID printf("Card RCA:%d\r\n",hsd1.SdCard.RelCardAdd ); //卡相对地址 printf("Card Capacity:%d MB\r\n",(uint32_t)(((uint64_t)hsd1.SdCard.BlockNbr*hsd1.SdCard.BlockSize)>>20)); //显示容量 printf("Card BlockSize:%d\r\n\r\n",hsd1.SdCard.BlockSize); //显示块大小 printf("Card LogBlockNbr:%d\r\n\r\n",hsd1.SdCard.LogBlockNbr); printf("Card LogBlockSize:%d\r\n\r\n",hsd1.SdCard.LogBlockSize); } /* 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_USART1_UART_Init(); MX_FMC_Init(); MX_DMA_Init(); MX_SDMMC1_SD_Init(); MX_SAI1_Init(); /* USER CODE BEGIN 2 */ delay_init(216); delay_ms(5000); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); Sdram_Init_Sequence(); my_mem_init(SRAMIN); //初始化内部内存池 my_mem_init(SRAMEX); //初始化外部SDRAM内存池 exfuns_init(); //为fatfs相关变量申请内存 f_mount(fs[0],"0:",1); //挂载SD卡 /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { //audio_play(); wav_recorder(); /* 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 LSE Drive Capability */ HAL_PWR_EnableBkUpAccess(); /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ 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 = 25; RCC_OscInitStruct.PLL.PLLN = 432; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; RCC_OscInitStruct.PLL.PLLQ = 9; RCC_OscInitStruct.PLL.PLLR = 2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Activate the Over-Drive mode */ if (HAL_PWREx_EnableOverDrive() != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses 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_7) != HAL_OK) { Error_Handler(); } PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_USART1|RCC_PERIPHCLK_SAI1 |RCC_PERIPHCLK_SDMMC1|RCC_PERIPHCLK_CLK48; PeriphClkInitStruct.PLLSAI.PLLSAIN = 288; PeriphClkInitStruct.PLLSAI.PLLSAIR = 4; PeriphClkInitStruct.PLLSAI.PLLSAIQ = 4; PeriphClkInitStruct.PLLSAI.PLLSAIP = RCC_PLLSAIP_DIV2; PeriphClkInitStruct.PLLSAIDivQ = 1; PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_8; PeriphClkInitStruct.Sai1ClockSelection = RCC_SAI1CLKSOURCE_PLLSAI; PeriphClkInitStruct.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2; PeriphClkInitStruct.Clk48ClockSelection = RCC_CLK48SOURCE_PLL; PeriphClkInitStruct.Sdmmc1ClockSelection = RCC_SDMMC1CLKSOURCE_CLK48; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { Error_Handler(); } /** Enables the Clock Security System */ HAL_RCC_EnableCSS(); } /** * @brief SAI1 Initialization Function * @param None * @retval None */ static void MX_SAI1_Init(void) { /* USER CODE BEGIN SAI1_Init 0 */ /* USER CODE END SAI1_Init 0 */ /* USER CODE BEGIN SAI1_Init 1 */ /* USER CODE END SAI1_Init 1 */ hsai_BlockA1.Instance = SAI1_Block_A; hsai_BlockA1.Init.AudioMode = SAI_MODEMASTER_TX; hsai_BlockA1.Init.Synchro = SAI_ASYNCHRONOUS; hsai_BlockA1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; hsai_BlockA1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; hsai_BlockA1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; hsai_BlockA1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_192K; hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE; hsai_BlockA1.Init.MonoStereoMode = SAI_STEREOMODE; hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING; hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED; if (HAL_SAI_InitProtocol(&hsai_BlockA1, SAI_I2S_STANDARD, SAI_PROTOCOL_DATASIZE_16BIT, 2) != HAL_OK) { Error_Handler(); } hsai_BlockB1.Instance = SAI1_Block_B; hsai_BlockB1.Init.AudioMode = SAI_MODESLAVE_RX; hsai_BlockB1.Init.Synchro = SAI_SYNCHRONOUS; hsai_BlockB1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; hsai_BlockB1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; hsai_BlockB1.Init.SynchroExt = SAI_SYNCEXT_DISABLE; hsai_BlockB1.Init.MonoStereoMode = SAI_STEREOMODE; hsai_BlockB1.Init.CompandingMode = SAI_NOCOMPANDING; hsai_BlockB1.Init.TriState = SAI_OUTPUT_NOTRELEASED; if (HAL_SAI_InitProtocol(&hsai_BlockB1, SAI_I2S_STANDARD, SAI_PROTOCOL_DATASIZE_16BIT, 2) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN SAI1_Init 2 */ /* USER CODE END SAI1_Init 2 */ } /** * @brief SDMMC1 Initialization Function * @param None * @retval None */ static void MX_SDMMC1_SD_Init(void) { /* USER CODE BEGIN SDMMC1_Init 0 */ /* USER CODE END SDMMC1_Init 0 */ /* USER CODE BEGIN SDMMC1_Init 1 */ /* USER CODE END SDMMC1_Init 1 */ hsd1.Instance = SDMMC1; hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; hsd1.Init.ClockBypass = SDMMC_CLOCK_BYPASS_DISABLE; hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; hsd1.Init.BusWide = SDMMC_BUS_WIDE_1B; hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; hsd1.Init.ClockDiv = 0; if (HAL_SD_Init(&hsd1) != HAL_OK) { Error_Handler(); } if (HAL_SD_ConfigWideBusOperation(&hsd1, SDMMC_BUS_WIDE_4B) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN SDMMC1_Init 2 */ /* USER CODE END SDMMC1_Init 2 */ } /** * @brief USART1 Initialization Function * @param None * @retval None */ static void MX_USART1_UART_Init(void) { /* USER CODE BEGIN USART1_Init 0 */ /* USER CODE END USART1_Init 0 */ /* USER CODE BEGIN USART1_Init 1 */ /* USER CODE END USART1_Init 1 */ huart1.Instance = USART1; huart1.Init.BaudRate = 115200; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(&huart1) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN USART1_Init 2 */ /* USER CODE END USART1_Init 2 */ } /** * Enable DMA controller clock */ static void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA2_CLK_ENABLE(); /* DMA interrupt init */ /* DMA2_Stream0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 0); HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); /* DMA2_Stream1_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 1, 0); HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn); /* DMA2_Stream3_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream3_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream3_IRQn); /* DMA2_Stream6_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream6_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream6_IRQn); } /* FMC initialization function */ static void MX_FMC_Init(void) { /* USER CODE BEGIN FMC_Init 0 */ /* USER CODE END FMC_Init 0 */ FMC_SDRAM_TimingTypeDef SdramTiming = {0}; /* USER CODE BEGIN FMC_Init 1 */ /* USER CODE END FMC_Init 1 */ /** Perform the SDRAM1 memory initialization sequence */ hsdram1.Instance = FMC_SDRAM_DEVICE; /* hsdram1.Init */ hsdram1.Init.SDBank = FMC_SDRAM_BANK1; hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9; hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13; hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16; hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4; hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3; hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE; hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2; hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE; hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_0; /* SdramTiming */ SdramTiming.LoadToActiveDelay = 2; SdramTiming.ExitSelfRefreshDelay = 8; SdramTiming.SelfRefreshTime = 4; SdramTiming.RowCycleDelay = 7; SdramTiming.WriteRecoveryTime = 3; SdramTiming.RPDelay = 2; SdramTiming.RCDDelay = 2; if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK) { Error_Handler( ); } /* USER CODE BEGIN FMC_Init 2 */ /* USER CODE END FMC_Init 2 */ } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_5, GPIO_PIN_RESET); /*Configure GPIO pin : PC13 */ GPIO_InitStruct.Pin = GPIO_PIN_13; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /*Configure GPIO pin : PA0 */ GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLDOWN; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /*Configure GPIO pins : PH2 PH3 */ GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOH, &GPIO_InitStruct); /*Configure GPIO pins : PB0 PB5 */ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_5; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /*Configure GPIO pin : PB1 */ GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } /* USER CODE BEGIN 4 */ /* 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 */ __disable_irq(); while (1) { } /* 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, ex: 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****/
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.h * @brief : Header for main.c file. * This file contains the common defines of the application. ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2021 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef __MAIN_H #define __MAIN_H #ifdef __cplusplus extern "C" { #endif /* Includes ------------------------------------------------------------------*/ #include "stm32f7xx_hal.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ //extern SDRAM_HandleTypeDef hsdram1; extern SD_HandleTypeDef hsd1; //extern QSPI_HandleTypeDef hqspi; //extern NAND_HandleTypeDef hnand1; extern SAI_HandleTypeDef hsai_BlockA1; extern SAI_HandleTypeDef hsai_BlockB1; extern DMA_HandleTypeDef hdma_sai1_a; extern DMA_HandleTypeDef hdma_sai1_b; /* USER CODE END Includes */ /* Exported types ------------------------------------------------------------*/ /* USER CODE BEGIN ET */ extern volatile uint8_t rx_done, tx_done; /* USER CODE END ET */ /* Exported constants --------------------------------------------------------*/ /* USER CODE BEGIN EC */ /* USER CODE END EC */ /* Exported macro ------------------------------------------------------------*/ /* USER CODE BEGIN EM */ /* USER CODE END EM */ /* Exported functions prototypes ---------------------------------------------*/ void Error_Handler(void); /* USER CODE BEGIN EFP */ /* USER CODE END EFP */ /* Private defines -----------------------------------------------------------*/ /* USER CODE BEGIN Private defines */ 定义一些常用的数据类型短关键字 //typedef int32_t s32; //typedef int16_t s16; //typedef int8_t s8; //typedef const int32_t sc32; //typedef const int16_t sc16; //typedef const int8_t sc8; //typedef __IO int32_t vs32; //typedef __IO int16_t vs16; //typedef __IO int8_t vs8; //typedef __I int32_t vsc32; //typedef __I int16_t vsc16; //typedef __I int8_t vsc8; //typedef uint32_t u32; //typedef uint16_t u16; //typedef uint8_t u8; //typedef const uint32_t uc32; //typedef const uint16_t uc16; //typedef const uint8_t uc8; //typedef __IO uint32_t vu32; //typedef __IO uint16_t vu16; //typedef __IO uint8_t vu8; //typedef __I uint32_t vuc32; //typedef __I uint16_t vuc16; //typedef __I uint8_t vuc8; /* USER CODE END Private defines */ #ifdef __cplusplus } #endif #endif /* __MAIN_H */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file stm32f7xx_hal_msp.c * @brief This file provides code for the MSP Initialization * and de-Initialization codes. ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2021 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ extern DMA_HandleTypeDef hdma_sdmmc1_rx; extern DMA_HandleTypeDef hdma_sdmmc1_tx; /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN TD */ /* USER CODE END TD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN Define */ /* USER CODE END Define */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN Macro */ /* USER CODE END Macro */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* External functions --------------------------------------------------------*/ /* USER CODE BEGIN ExternalFunctions */ /* USER CODE END ExternalFunctions */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * Initializes the Global MSP. */ void HAL_MspInit(void) { /* USER CODE BEGIN MspInit 0 */ /* USER CODE END MspInit 0 */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_RCC_SYSCFG_CLK_ENABLE(); /* System interrupt init*/ /* USER CODE BEGIN MspInit 1 */ /* USER CODE END MspInit 1 */ } /** * @brief SD MSP Initialization * This function configures the hardware resources used in this example * @param hsd: SD handle pointer * @retval None */ void HAL_SD_MspInit(SD_HandleTypeDef* hsd) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(hsd->Instance==SDMMC1) { /* USER CODE BEGIN SDMMC1_MspInit 0 */ /* USER CODE END SDMMC1_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_SDMMC1_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); /**SDMMC1 GPIO Configuration PC8 ------> SDMMC1_D0 PC9 ------> SDMMC1_D1 PC10 ------> SDMMC1_D2 PC11 ------> SDMMC1_D3 PC12 ------> SDMMC1_CK PD2 ------> SDMMC1_CMD */ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 |GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_SDMMC1; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /* SDMMC1 DMA Init */ /* SDMMC1_RX Init */ hdma_sdmmc1_rx.Instance = DMA2_Stream3; hdma_sdmmc1_rx.Init.Channel = DMA_CHANNEL_4; hdma_sdmmc1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_sdmmc1_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_sdmmc1_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_sdmmc1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_sdmmc1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hdma_sdmmc1_rx.Init.Mode = DMA_PFCTRL; hdma_sdmmc1_rx.Init.Priority = DMA_PRIORITY_LOW; hdma_sdmmc1_rx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; hdma_sdmmc1_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_sdmmc1_rx.Init.MemBurst = DMA_MBURST_INC4; hdma_sdmmc1_rx.Init.PeriphBurst = DMA_PBURST_INC4; if (HAL_DMA_Init(&hdma_sdmmc1_rx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(hsd,hdmarx,hdma_sdmmc1_rx); /* SDMMC1_TX Init */ hdma_sdmmc1_tx.Instance = DMA2_Stream6; hdma_sdmmc1_tx.Init.Channel = DMA_CHANNEL_4; hdma_sdmmc1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_sdmmc1_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_sdmmc1_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_sdmmc1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_sdmmc1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; hdma_sdmmc1_tx.Init.Mode = DMA_PFCTRL; hdma_sdmmc1_tx.Init.Priority = DMA_PRIORITY_LOW; hdma_sdmmc1_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE; hdma_sdmmc1_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; hdma_sdmmc1_tx.Init.MemBurst = DMA_MBURST_INC4; hdma_sdmmc1_tx.Init.PeriphBurst = DMA_PBURST_INC4; if (HAL_DMA_Init(&hdma_sdmmc1_tx) != HAL_OK) { Error_Handler(); } __HAL_LINKDMA(hsd,hdmatx,hdma_sdmmc1_tx); /* SDMMC1 interrupt Init */ HAL_NVIC_SetPriority(SDMMC1_IRQn, 3, 0); HAL_NVIC_EnableIRQ(SDMMC1_IRQn); /* USER CODE BEGIN SDMMC1_MspInit 1 */ /* USER CODE END SDMMC1_MspInit 1 */ } } /** * @brief SD MSP De-Initialization * This function freeze the hardware resources used in this example * @param hsd: SD handle pointer * @retval None */ void HAL_SD_MspDeInit(SD_HandleTypeDef* hsd) { if(hsd->Instance==SDMMC1) { /* USER CODE BEGIN SDMMC1_MspDeInit 0 */ /* USER CODE END SDMMC1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_SDMMC1_CLK_DISABLE(); /**SDMMC1 GPIO Configuration PC8 ------> SDMMC1_D0 PC9 ------> SDMMC1_D1 PC10 ------> SDMMC1_D2 PC11 ------> SDMMC1_D3 PC12 ------> SDMMC1_CK PD2 ------> SDMMC1_CMD */ HAL_GPIO_DeInit(GPIOC, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11 |GPIO_PIN_12); HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2); /* SDMMC1 DMA DeInit */ HAL_DMA_DeInit(hsd->hdmarx); HAL_DMA_DeInit(hsd->hdmatx); /* SDMMC1 interrupt DeInit */ HAL_NVIC_DisableIRQ(SDMMC1_IRQn); /* USER CODE BEGIN SDMMC1_MspDeInit 1 */ /* USER CODE END SDMMC1_MspDeInit 1 */ } } /** * @brief UART MSP Initialization * This function configures the hardware resources used in this example * @param huart: UART handle pointer * @retval None */ void HAL_UART_MspInit(UART_HandleTypeDef* huart) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(huart->Instance==USART1) { /* USER CODE BEGIN USART1_MspInit 0 */ /* USER CODE END USART1_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_USART1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USER CODE BEGIN USART1_MspInit 1 */ /* USER CODE END USART1_MspInit 1 */ } } /** * @brief UART MSP De-Initialization * This function freeze the hardware resources used in this example * @param huart: UART handle pointer * @retval None */ void HAL_UART_MspDeInit(UART_HandleTypeDef* huart) { if(huart->Instance==USART1) { /* USER CODE BEGIN USART1_MspDeInit 0 */ /* USER CODE END USART1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_USART1_CLK_DISABLE(); /**USART1 GPIO Configuration PA9 ------> USART1_TX PA10 ------> USART1_RX */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10); /* USER CODE BEGIN USART1_MspDeInit 1 */ /* USER CODE END USART1_MspDeInit 1 */ } } static uint32_t FMC_Initialized = 0; static void HAL_FMC_MspInit(void){ /* USER CODE BEGIN FMC_MspInit 0 */ /* USER CODE END FMC_MspInit 0 */ GPIO_InitTypeDef GPIO_InitStruct ={0}; if (FMC_Initialized) { return; } FMC_Initialized = 1; /* Peripheral clock enable */ __HAL_RCC_FMC_CLK_ENABLE(); /** FMC GPIO Configuration PF0 ------> FMC_A0 PF1 ------> FMC_A1 PF2 ------> FMC_A2 PF3 ------> FMC_A3 PF4 ------> FMC_A4 PF5 ------> FMC_A5 PC0 ------> FMC_SDNWE PC2 ------> FMC_SDNE0 PC3 ------> FMC_SDCKE0 PF11 ------> FMC_SDNRAS PF12 ------> FMC_A6 PF13 ------> FMC_A7 PF14 ------> FMC_A8 PF15 ------> FMC_A9 PG0 ------> FMC_A10 PG1 ------> FMC_A11 PE7 ------> FMC_D4 PE8 ------> FMC_D5 PE9 ------> FMC_D6 PE10 ------> FMC_D7 PE11 ------> FMC_D8 PE12 ------> FMC_D9 PE13 ------> FMC_D10 PE14 ------> FMC_D11 PE15 ------> FMC_D12 PD8 ------> FMC_D13 PD9 ------> FMC_D14 PD10 ------> FMC_D15 PD14 ------> FMC_D0 PD15 ------> FMC_D1 PG2 ------> FMC_A12 PG4 ------> FMC_BA0 PG5 ------> FMC_BA1 PG8 ------> FMC_SDCLK PD0 ------> FMC_D2 PD1 ------> FMC_D3 PG15 ------> FMC_SDNCAS PE0 ------> FMC_NBL0 PE1 ------> FMC_NBL1 */ GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12 |GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FMC; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FMC; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4 |GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FMC; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10 |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FMC; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14 |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_FMC; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /* USER CODE BEGIN FMC_MspInit 1 */ /* USER CODE END FMC_MspInit 1 */ } void HAL_SDRAM_MspInit(SDRAM_HandleTypeDef* hsdram){ /* USER CODE BEGIN SDRAM_MspInit 0 */ /* USER CODE END SDRAM_MspInit 0 */ HAL_FMC_MspInit(); /* USER CODE BEGIN SDRAM_MspInit 1 */ /* USER CODE END SDRAM_MspInit 1 */ } static uint32_t FMC_DeInitialized = 0; static void HAL_FMC_MspDeInit(void){ /* USER CODE BEGIN FMC_MspDeInit 0 */ /* USER CODE END FMC_MspDeInit 0 */ if (FMC_DeInitialized) { return; } FMC_DeInitialized = 1; /* Peripheral clock enable */ __HAL_RCC_FMC_CLK_DISABLE(); /** FMC GPIO Configuration PF0 ------> FMC_A0 PF1 ------> FMC_A1 PF2 ------> FMC_A2 PF3 ------> FMC_A3 PF4 ------> FMC_A4 PF5 ------> FMC_A5 PC0 ------> FMC_SDNWE PC2 ------> FMC_SDNE0 PC3 ------> FMC_SDCKE0 PF11 ------> FMC_SDNRAS PF12 ------> FMC_A6 PF13 ------> FMC_A7 PF14 ------> FMC_A8 PF15 ------> FMC_A9 PG0 ------> FMC_A10 PG1 ------> FMC_A11 PE7 ------> FMC_D4 PE8 ------> FMC_D5 PE9 ------> FMC_D6 PE10 ------> FMC_D7 PE11 ------> FMC_D8 PE12 ------> FMC_D9 PE13 ------> FMC_D10 PE14 ------> FMC_D11 PE15 ------> FMC_D12 PD8 ------> FMC_D13 PD9 ------> FMC_D14 PD10 ------> FMC_D15 PD14 ------> FMC_D0 PD15 ------> FMC_D1 PG2 ------> FMC_A12 PG4 ------> FMC_BA0 PG5 ------> FMC_BA1 PG8 ------> FMC_SDCLK PD0 ------> FMC_D2 PD1 ------> FMC_D3 PG15 ------> FMC_SDNCAS PE0 ------> FMC_NBL0 PE1 ------> FMC_NBL1 */ HAL_GPIO_DeInit(GPIOF, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_11|GPIO_PIN_12 |GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15); HAL_GPIO_DeInit(GPIOC, GPIO_PIN_0|GPIO_PIN_2|GPIO_PIN_3); HAL_GPIO_DeInit(GPIOG, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4 |GPIO_PIN_5|GPIO_PIN_8|GPIO_PIN_15); HAL_GPIO_DeInit(GPIOE, GPIO_PIN_7|GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10 |GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14 |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1); HAL_GPIO_DeInit(GPIOD, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_14 |GPIO_PIN_15|GPIO_PIN_0|GPIO_PIN_1); /* USER CODE BEGIN FMC_MspDeInit 1 */ /* USER CODE END FMC_MspDeInit 1 */ } void HAL_SDRAM_MspDeInit(SDRAM_HandleTypeDef* hsdram){ /* USER CODE BEGIN SDRAM_MspDeInit 0 */ /* USER CODE END SDRAM_MspDeInit 0 */ HAL_FMC_MspDeInit(); /* USER CODE BEGIN SDRAM_MspDeInit 1 */ /* USER CODE END SDRAM_MspDeInit 1 */ } //extern DMA_HandleTypeDef hdma_sai1_a; //extern DMA_HandleTypeDef hdma_sai1_b; //static uint32_t SAI1_client =0; //void HAL_SAI_MspInit(SAI_HandleTypeDef* hsai) //{ // GPIO_InitTypeDef GPIO_InitStruct; ///* SAI1 */ // if(hsai->Instance==SAI1_Block_A) // { // /* Peripheral clock enable */ // if (SAI1_client == 0) // { // __HAL_RCC_SAI1_CLK_ENABLE(); // } // SAI1_client ++; // /**SAI1_A_Block_A GPIO Configuration // PE2 ------> SAI1_MCLK_A // PE4 ------> SAI1_FS_A // PE5 ------> SAI1_SCK_A // PE6 ------> SAI1_SD_A // */ // GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6; // GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // GPIO_InitStruct.Pull = GPIO_NOPULL; // GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // GPIO_InitStruct.Alternate = GPIO_AF6_SAI1; // HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); // /* Peripheral DMA init*/ // hdma_sai1_a.Instance = DMA2_Stream1; // hdma_sai1_a.Init.Channel = DMA_CHANNEL_0; // hdma_sai1_a.Init.Direction = DMA_MEMORY_TO_PERIPH; // hdma_sai1_a.Init.PeriphInc = DMA_PINC_DISABLE; // hdma_sai1_a.Init.MemInc = DMA_MINC_ENABLE; // hdma_sai1_a.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; // hdma_sai1_a.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; // hdma_sai1_a.Init.Mode = DMA_CIRCULAR; // hdma_sai1_a.Init.Priority = DMA_PRIORITY_LOW; // hdma_sai1_a.Init.FIFOMode = DMA_FIFOMODE_ENABLE; // hdma_sai1_a.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; // hdma_sai1_a.Init.MemBurst = DMA_MBURST_SINGLE; // hdma_sai1_a.Init.PeriphBurst = DMA_PBURST_SINGLE; // if (HAL_DMA_Init(&hdma_sai1_a) != HAL_OK) // { // Error_Handler(); // } // /* Several peripheral DMA handle pointers point to the same DMA handle. // Be aware that there is only one stream to perform all the requested DMAs. */ // __HAL_LINKDMA(hsai,hdmarx,hdma_sai1_a); // __HAL_LINKDMA(hsai,hdmatx,hdma_sai1_a); // } // if(hsai->Instance==SAI1_Block_B) // { // /* Peripheral clock enable */ // if (SAI1_client == 0) // { // __HAL_RCC_SAI1_CLK_ENABLE(); // } // SAI1_client ++; // /**SAI1_B_Block_B GPIO Configuration // PE3 ------> SAI1_SD_B // */ // GPIO_InitStruct.Pin = GPIO_PIN_3; // GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // GPIO_InitStruct.Pull = GPIO_NOPULL; // GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; // GPIO_InitStruct.Alternate = GPIO_AF6_SAI1; // HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); // /* Peripheral DMA init*/ // hdma_sai1_b.Instance = DMA2_Stream0; // hdma_sai1_b.Init.Channel = DMA_CHANNEL_10; // hdma_sai1_b.Init.Direction = DMA_PERIPH_TO_MEMORY; // hdma_sai1_b.Init.PeriphInc = DMA_PINC_DISABLE; // hdma_sai1_b.Init.MemInc = DMA_MINC_ENABLE; // hdma_sai1_b.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; // hdma_sai1_b.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; // hdma_sai1_b.Init.Mode = DMA_CIRCULAR; // hdma_sai1_b.Init.Priority = DMA_PRIORITY_LOW; // hdma_sai1_b.Init.FIFOMode = DMA_FIFOMODE_ENABLE; // hdma_sai1_b.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; // hdma_sai1_b.Init.MemBurst = DMA_MBURST_SINGLE; // hdma_sai1_b.Init.PeriphBurst = DMA_PBURST_SINGLE; // if (HAL_DMA_Init(&hdma_sai1_b) != HAL_OK) // { // Error_Handler(); // } // /* Several peripheral DMA handle pointers point to the same DMA handle. // Be aware that there is only one stream to perform all the requested DMAs. */ // __HAL_LINKDMA(hsai,hdmarx,hdma_sai1_b); // __HAL_LINKDMA(hsai,hdmatx,hdma_sai1_b); // } //} //void HAL_SAI_MspDeInit(SAI_HandleTypeDef* hsai) //{ ///* SAI1 */ // if(hsai->Instance==SAI1_Block_A) // { // SAI1_client --; // if (SAI1_client == 0) // { // /* Peripheral clock disable */ // __HAL_RCC_SAI1_CLK_DISABLE(); // } // /**SAI1_A_Block_A GPIO Configuration // PE2 ------> SAI1_MCLK_A // PE4 ------> SAI1_FS_A // PE5 ------> SAI1_SCK_A // PE6 ------> SAI1_SD_A // */ // HAL_GPIO_DeInit(GPIOE, GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6); // /* SAI1 DMA Deinit */ // HAL_DMA_DeInit(hsai->hdmarx); // HAL_DMA_DeInit(hsai->hdmatx); // } // if(hsai->Instance==SAI1_Block_B) // { // SAI1_client --; // if (SAI1_client == 0) // { // /* Peripheral clock disable */ // __HAL_RCC_SAI1_CLK_DISABLE(); // } // /**SAI1_B_Block_B GPIO Configuration // PE3 ------> SAI1_SD_B // */ // HAL_GPIO_DeInit(GPIOE, GPIO_PIN_3); // /* SAI1 DMA Deinit */ // HAL_DMA_DeInit(hsai->hdmarx); // HAL_DMA_DeInit(hsai->hdmatx); // } //} /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file stm32f7xx_it.c * @brief Interrupt Service Routines. ****************************************************************************** * @attention * * <h2><center>© Copyright (c) 2021 STMicroelectronics. * All rights reserved.</center></h2> * * This software component is licensed by ST under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f7xx_it.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "fifo.h" #include "bsp_wavplay.h" #include "bsp_mp3play.h" #include "bsp_flacplay.h" #include "bsp_sai.h" /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN TD */ /* USER CODE END TD */ /* 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 -----------------------------------------------*/ /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ extern DMA_HandleTypeDef hdma_sai1_a; extern DMA_HandleTypeDef hdma_sai1_b; extern DMA_HandleTypeDef hdma_sdmmc1_rx; extern DMA_HandleTypeDef hdma_sdmmc1_tx; extern SD_HandleTypeDef hsd1; /* USER CODE BEGIN EV */ /* USER CODE END EV */ /******************************************************************************/ /* Cortex-M7 Processor Interruption and Exception Handlers */ /******************************************************************************/ /** * @brief This function handles Non maskable interrupt. */ void NMI_Handler(void) { /* USER CODE BEGIN NonMaskableInt_IRQn 0 */ /* USER CODE END NonMaskableInt_IRQn 0 */ HAL_RCC_NMI_IRQHandler(); /* USER CODE BEGIN NonMaskableInt_IRQn 1 */ while (1) { } /* USER CODE END NonMaskableInt_IRQn 1 */ } /** * @brief This function handles Hard fault interrupt. */ void HardFault_Handler(void) { /* USER CODE BEGIN HardFault_IRQn 0 */ /* USER CODE END HardFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_HardFault_IRQn 0 */ /* USER CODE END W1_HardFault_IRQn 0 */ } } /** * @brief This function handles Memory management fault. */ void MemManage_Handler(void) { /* USER CODE BEGIN MemoryManagement_IRQn 0 */ /* USER CODE END MemoryManagement_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_MemoryManagement_IRQn 0 */ /* USER CODE END W1_MemoryManagement_IRQn 0 */ } } /** * @brief This function handles Pre-fetch fault, memory access fault. */ void BusFault_Handler(void) { /* USER CODE BEGIN BusFault_IRQn 0 */ /* USER CODE END BusFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_BusFault_IRQn 0 */ /* USER CODE END W1_BusFault_IRQn 0 */ } } /** * @brief This function handles Undefined instruction or illegal state. */ void UsageFault_Handler(void) { /* USER CODE BEGIN UsageFault_IRQn 0 */ /* USER CODE END UsageFault_IRQn 0 */ while (1) { /* USER CODE BEGIN W1_UsageFault_IRQn 0 */ /* USER CODE END W1_UsageFault_IRQn 0 */ } } /** * @brief This function handles System service call via SWI instruction. */ void SVC_Handler(void) { /* USER CODE BEGIN SVCall_IRQn 0 */ /* USER CODE END SVCall_IRQn 0 */ /* USER CODE BEGIN SVCall_IRQn 1 */ /* USER CODE END SVCall_IRQn 1 */ } /** * @brief This function handles Debug monitor. */ void DebugMon_Handler(void) { /* USER CODE BEGIN DebugMonitor_IRQn 0 */ /* USER CODE END DebugMonitor_IRQn 0 */ /* USER CODE BEGIN DebugMonitor_IRQn 1 */ /* USER CODE END DebugMonitor_IRQn 1 */ } /** * @brief This function handles Pendable request for system service. */ void PendSV_Handler(void) { /* USER CODE BEGIN PendSV_IRQn 0 */ /* USER CODE END PendSV_IRQn 0 */ /* USER CODE BEGIN PendSV_IRQn 1 */ /* USER CODE END PendSV_IRQn 1 */ } /** * @brief This function handles System tick timer. */ void SysTick_Handler(void) { /* USER CODE BEGIN SysTick_IRQn 0 */ /* USER CODE END SysTick_IRQn 0 */ HAL_IncTick(); /* USER CODE BEGIN SysTick_IRQn 1 */ /* USER CODE END SysTick_IRQn 1 */ } /******************************************************************************/ /* STM32F7xx Peripheral Interrupt Handlers */ /* Add here the Interrupt Handlers for the used peripherals. */ /* For the available peripheral interrupt handler names, */ /* please refer to the startup file (startup_stm32f7xx.s). */ /******************************************************************************/ /** * @brief This function handles SDMMC1 global interrupt. */ void SDMMC1_IRQHandler(void) { /* USER CODE BEGIN SDMMC1_IRQn 0 */ /* USER CODE END SDMMC1_IRQn 0 */ HAL_SD_IRQHandler(&hsd1); /* USER CODE BEGIN SDMMC1_IRQn 1 */ /* USER CODE END SDMMC1_IRQn 1 */ } /** * @brief This function handles DMA2 stream0 global interrupt. */ void DMA2_Stream0_IRQHandler(void) { /* USER CODE BEGIN DMA2_Stream0_IRQn 0 */ /* USER CODE END DMA2_Stream0_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_sai1_b); /* USER CODE BEGIN DMA2_Stream0_IRQn 1 */ /* USER CODE END DMA2_Stream0_IRQn 1 */ } /** * @brief This function handles DMA2 stream1 global interrupt. */ void DMA2_Stream1_IRQHandler(void) { /* USER CODE BEGIN DMA2_Stream1_IRQn 0 */ /* USER CODE END DMA2_Stream1_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_sai1_a); /* USER CODE BEGIN DMA2_Stream1_IRQn 1 */ /* USER CODE END DMA2_Stream1_IRQn 1 */ } /** * @brief This function handles DMA2 stream3 global interrupt. */ void DMA2_Stream3_IRQHandler(void) { /* USER CODE BEGIN DMA2_Stream3_IRQn 0 */ /* USER CODE END DMA2_Stream3_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_sdmmc1_rx); /* USER CODE BEGIN DMA2_Stream3_IRQn 1 */ /* USER CODE END DMA2_Stream3_IRQn 1 */ } /** * @brief This function handles DMA2 stream6 global interrupt. */ void DMA2_Stream6_IRQHandler(void) { /* USER CODE BEGIN DMA2_Stream6_IRQn 0 */ /* USER CODE END DMA2_Stream6_IRQn 0 */ HAL_DMA_IRQHandler(&hdma_sdmmc1_tx); /* USER CODE BEGIN DMA2_Stream6_IRQn 1 */ /* USER CODE END DMA2_Stream6_IRQn 1 */ } /* USER CODE BEGIN 1 */ /** * @brief Rx Transfer completed callbacks * @param hsd: Pointer SD handle * @retval None */ void HAL_SD_RxCpltCallback(SD_HandleTypeDef *hsd) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1); rx_done = 1; } /** * @brief Tx Transfer completed callbacks * @param hsd: Pointer to SD handle * @retval None */ void HAL_SD_TxCpltCallback(SD_HandleTypeDef *hsd) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_1); tx_done = 1; } /** * @brief SD error callbacks * @param hsd: Pointer SD handle * @retval None */ void HAL_SD_ErrorCallback(SD_HandleTypeDef *hsd) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); } /* USER CODE END 1 */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
#ifndef __BSP_SAI_H #define __BSP_SAI_H #ifdef __cplusplus extern "C" { #endif #include "main.h" void BSP_SAI1_Init(uint32_t datasize, uint32_t AudioFrequency); void BSP_SAIA1_Init(uint32_t datasize, uint32_t AudioFrequency); void BSP_SAIB1_Init(uint32_t datasize, uint32_t AudioFrequency); uint8_t SAIA_SampleRate_Set(uint32_t samplerate); void SAIA_TX_DMA_Init(uint8_t width); void SAIA1_TX_DMA_Init(uint8_t width); void SAIB1_RX_DMA_Init(uint8_t width); #ifdef __cplusplus } #endif #endif /* __BSP_SAI_H */
#include "bsp_sai.h" #include "bsp_wavplay.h" #include "delay.h" void (*sai_rx_callback)(void); //RX回调函数 /** * @brief SAI1 Initialization Function * @param None * @retval None */ void BSP_SAI1_Init(uint32_t datasize, uint32_t AudioFrequency) { HAL_SAI_DeInit(&hsai_BlockA1); hsai_BlockA1.Instance = SAI1_Block_A; hsai_BlockA1.Init.AudioMode = SAI_MODEMASTER_TX; hsai_BlockA1.Init.Synchro = SAI_ASYNCHRONOUS; hsai_BlockA1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; hsai_BlockA1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; hsai_BlockA1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; hsai_BlockA1.Init.AudioFrequency = AudioFrequency; hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE; hsai_BlockA1.Init.MonoStereoMode = SAI_STEREOMODE; hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING; hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED; if (HAL_SAI_InitProtocol(&hsai_BlockA1, SAI_I2S_STANDARD, datasize, 2) != HAL_OK) { Error_Handler(); } } /** * @brief SAI1 Initialization Function * @param None * @retval None */ void BSP_SAIA1_Init(uint32_t datasize, uint32_t AudioFrequency) { HAL_SAI_DeInit(&hsai_BlockA1); hsai_BlockA1.Instance = SAI1_Block_A; hsai_BlockA1.Init.AudioMode = SAI_MODEMASTER_TX; hsai_BlockA1.Init.Synchro = SAI_ASYNCHRONOUS; hsai_BlockA1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; hsai_BlockA1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE; hsai_BlockA1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; hsai_BlockA1.Init.AudioFrequency = AudioFrequency; hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE; hsai_BlockA1.Init.MonoStereoMode = SAI_STEREOMODE; hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING; hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED; if (HAL_SAI_InitProtocol(&hsai_BlockA1, SAI_I2S_STANDARD, datasize, 2) != HAL_OK) { Error_Handler(); } } /** * @brief SAI1 Initialization Function * @param None * @retval None */ void BSP_SAIB1_Init(uint32_t datasize, uint32_t AudioFrequency) { HAL_SAI_DeInit(&hsai_BlockB1); hsai_BlockB1.Instance = SAI1_Block_B; hsai_BlockB1.Init.AudioMode = SAI_MODESLAVE_RX; hsai_BlockB1.Init.Synchro = SAI_SYNCHRONOUS; hsai_BlockB1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE; hsai_BlockB1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_1QF; hsai_BlockB1.Init.SynchroExt = SAI_SYNCEXT_DISABLE; hsai_BlockB1.Init.MonoStereoMode = SAI_STEREOMODE; hsai_BlockB1.Init.CompandingMode = SAI_NOCOMPANDING; hsai_BlockB1.Init.TriState = SAI_OUTPUT_NOTRELEASED; if (HAL_SAI_InitProtocol(&hsai_BlockB1, SAI_I2S_STANDARD, datasize, 2) != HAL_OK) { Error_Handler(); } hsai_BlockB1.Instance->CR1 |= SAI_xCR1_DMAEN; __HAL_SAI_ENABLE(&hsai_BlockB1); } //SAI Block A采样率设置 //采样率计算公式: //MCKDIV!=0: Fs=SAI_CK_x/[512*MCKDIV] //MCKDIV==0: Fs=SAI_CK_x/256 //SAI_CK_x=(HSE/pllm)*PLLI2SN/PLLI2SQ/(PLLI2SDIVQ+1) //一般HSE=25Mhz //pllm:在Stm32_Clock_Init设置的时候确定,一般是25 //PLLI2SN:一般是192~432 //PLLI2SQ:2~15 //PLLI2SDIVQ:0~31 //MCKDIV:0~15 //SAI A分频系数表@pllm=8,HSE=25Mhz,即vco输入频率为1Mhz const uint16_t SAI_PSC_TBL[][5]= { {800 ,344,7,0,12}, //8Khz采样率 {1102,429,2,18,2}, //11.025Khz采样率 {1600,344,7, 0,6}, //16Khz采样率 {2205,429,2,18,1}, //22.05Khz采样率 {3200,344,7, 0,3}, //32Khz采样率 {4410,429,2,18,0}, //44.1Khz采样率 {4800,344,7, 0,2}, //48Khz采样率 {8820,271,2, 2,1}, //88.2Khz采样率 {9600,344,7, 0,1}, //96Khz采样率 {17640,271,6,0,0}, //176.4Khz采样率 {19200,295,6,0,0}, //192Khz采样率 }; //设置SAIA的采样率(@MCKEN) //samplerate:采样率,单位:Hz //返回值:0,设置成功;1,无法设置. uint8_t SAIA_SampleRate_Set(uint32_t samplerate) { uint8_t i=0; uint32_t tempreg=0; samplerate/=10;//缩小10倍 for(i=0;i<(sizeof(SAI_PSC_TBL)/10);i++)//看看改采样率是否可以支持 { if(samplerate==SAI_PSC_TBL[i][0])break; } RCC->CR&=~(1<<26); //先关闭PLLI2S if(i==(sizeof(SAI_PSC_TBL)/10))return 1;//搜遍了也找不到 tempreg|=(uint32_t)SAI_PSC_TBL[i][1]<<6; //设置PLLI2SN tempreg|=(uint32_t)SAI_PSC_TBL[i][2]<<24; //设置PLLI2SQ RCC->PLLI2SCFGR=tempreg; //设置I2SxCLK的频率 tempreg=RCC->DCKCFGR1; tempreg&=~(0X1F); //清空PLLI2SDIVQ设置. tempreg&=~(0X03<<20); //清空SAI1ASRC设置. tempreg|=SAI_PSC_TBL[i][3]<<0; //设置PLLI2SDIVQ tempreg|=1<<20; //设置SAI1A时钟来源为PLLI2SQ RCC->DCKCFGR1=tempreg; //设置DCKCFGR寄存器 RCC->CR|=1<<26; //开启I2S时钟 while((RCC->CR&1<<27)==0); //等待I2S时钟开启成功. tempreg=SAI1_Block_A->CR1; tempreg&=~(0X0F<<20); //清除MCKDIV设置 tempreg|=(uint32_t)SAI_PSC_TBL[i][4]<<20; //设置MCKDIV tempreg|=1<<16; //使能SAI1 Block A tempreg|=1<<17; //使能DMA SAI1_Block_A->CR1=tempreg; //配置MCKDIV,同时使能SAI1 Block A return 0; } void SAIA_TX_DMA_Init(uint8_t width) { /* Peripheral DMA init*/ //HAL_DMA_DeInit(&hdma_sai1_a); if(width==16) { hdma_sai1_a.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_sai1_a.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; } else if(width==24) { hdma_sai1_a.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_sai1_a.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; } hdma_sai1_a.Instance = DMA2_Stream1; hdma_sai1_a.Init.Channel = DMA_CHANNEL_0; hdma_sai1_a.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_sai1_a.Init.PeriphInc = DMA_PINC_DISABLE; hdma_sai1_a.Init.MemInc = DMA_MINC_ENABLE; hdma_sai1_a.Init.Mode = DMA_CIRCULAR; hdma_sai1_a.Init.Priority = DMA_PRIORITY_LOW; hdma_sai1_a.Init.FIFOMode = DMA_FIFOMODE_ENABLE; hdma_sai1_a.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; hdma_sai1_a.Init.MemBurst = DMA_MBURST_SINGLE; hdma_sai1_a.Init.PeriphBurst = DMA_PBURST_SINGLE; if (HAL_DMA_Init(&hdma_sai1_a) != HAL_OK) { Error_Handler(); } /* Several peripheral DMA handle pointers point to the same DMA handle. Be aware that there is only one stream to perform all the requested DMAs. */ __HAL_LINKDMA(&hsai_BlockA1,hdmarx,hdma_sai1_a); __HAL_LINKDMA(&hsai_BlockA1,hdmatx,hdma_sai1_a); } void SAIA1_TX_DMA_Init(uint8_t width) { /* Peripheral DMA init*/ //HAL_DMA_DeInit(&hdma_sai1_a); if(width==16) { hdma_sai1_a.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_sai1_a.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; } else if(width==24) { hdma_sai1_a.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_sai1_a.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; } hdma_sai1_a.Instance = DMA2_Stream1; hdma_sai1_a.Init.Channel = DMA_CHANNEL_0; hdma_sai1_a.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_sai1_a.Init.PeriphInc = DMA_PINC_DISABLE; hdma_sai1_a.Init.MemInc = DMA_MINC_ENABLE; hdma_sai1_a.Init.Mode = DMA_CIRCULAR; hdma_sai1_a.Init.Priority = DMA_PRIORITY_LOW; hdma_sai1_a.Init.FIFOMode = DMA_FIFOMODE_ENABLE; hdma_sai1_a.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; hdma_sai1_a.Init.MemBurst = DMA_MBURST_SINGLE; hdma_sai1_a.Init.PeriphBurst = DMA_PBURST_SINGLE; if (HAL_DMA_Init(&hdma_sai1_a) != HAL_OK) { Error_Handler(); } /* Several peripheral DMA handle pointers point to the same DMA handle. Be aware that there is only one stream to perform all the requested DMAs. */ __HAL_LINKDMA(&hsai_BlockA1,hdmarx,hdma_sai1_a); __HAL_LINKDMA(&hsai_BlockA1,hdmatx,hdma_sai1_a); } void SAIB1_RX_DMA_Init(uint8_t width) { /* Peripheral DMA init*/ if(width==16) { hdma_sai1_b.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_sai1_b.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; } else if(width==24) { hdma_sai1_b.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD; hdma_sai1_b.Init.MemDataAlignment = DMA_MDATAALIGN_WORD; } hdma_sai1_b.Instance = DMA2_Stream0; hdma_sai1_b.Init.Channel = DMA_CHANNEL_10; hdma_sai1_b.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_sai1_b.Init.PeriphInc = DMA_PINC_DISABLE; hdma_sai1_b.Init.MemInc = DMA_MINC_ENABLE; hdma_sai1_b.Init.Mode = DMA_CIRCULAR; hdma_sai1_b.Init.Priority = DMA_PRIORITY_LOW; hdma_sai1_b.Init.FIFOMode = DMA_FIFOMODE_ENABLE; hdma_sai1_b.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL; hdma_sai1_b.Init.MemBurst = DMA_MBURST_SINGLE; hdma_sai1_b.Init.PeriphBurst = DMA_PBURST_SINGLE; if (HAL_DMA_Init(&hdma_sai1_b) != HAL_OK) { Error_Handler(); } /* Several peripheral DMA handle pointers point to the same DMA handle. Be aware that there is only one stream to perform all the requested DMAs. */ __HAL_LINKDMA(&hsai_BlockB1,hdmarx,hdma_sai1_b); __HAL_LINKDMA(&hsai_BlockB1,hdmatx,hdma_sai1_b); } static uint32_t SAI1_client =0; void HAL_SAI_MspInit(SAI_HandleTypeDef* hsai) { GPIO_InitTypeDef GPIO_InitStruct; /* SAI1 */ if(hsai->Instance==SAI1_Block_A) { /* Peripheral clock enable */ if (SAI1_client == 0) { __HAL_RCC_SAI1_CLK_ENABLE(); } SAI1_client ++; /**SAI1_A_Block_A GPIO Configuration PE2 ------> SAI1_MCLK_A PE4 ------> SAI1_FS_A PE5 ------> SAI1_SCK_A PE6 ------> SAI1_SD_A */ GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF6_SAI1; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); } if(hsai->Instance==SAI1_Block_B) { /* Peripheral clock enable */ if (SAI1_client == 0) { __HAL_RCC_SAI1_CLK_ENABLE(); } SAI1_client ++; /**SAI1_B_Block_B GPIO Configuration PE3 ------> SAI1_SD_B */ GPIO_InitStruct.Pin = GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; GPIO_InitStruct.Alternate = GPIO_AF6_SAI1; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); } } void HAL_SAI_MspDeInit(SAI_HandleTypeDef* hsai) { /* SAI1 */ if(hsai->Instance==SAI1_Block_A) { SAI1_client --; if (SAI1_client == 0) { /* Peripheral clock disable */ __HAL_RCC_SAI1_CLK_DISABLE(); } /**SAI1_A_Block_A GPIO Configuration PE2 ------> SAI1_MCLK_A PE4 ------> SAI1_FS_A PE5 ------> SAI1_SCK_A PE6 ------> SAI1_SD_A */ HAL_GPIO_DeInit(GPIOE, GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6); /* SAI1 DMA Deinit */ HAL_DMA_DeInit(hsai->hdmarx); HAL_DMA_DeInit(hsai->hdmatx); } if(hsai->Instance==SAI1_Block_B) { SAI1_client --; if (SAI1_client == 0) { /* Peripheral clock disable */ __HAL_RCC_SAI1_CLK_DISABLE(); } /**SAI1_B_Block_B GPIO Configuration PE3 ------> SAI1_SD_B */ HAL_GPIO_DeInit(GPIOE, GPIO_PIN_3); /* SAI1 DMA Deinit */ HAL_DMA_DeInit(hsai->hdmarx); HAL_DMA_DeInit(hsai->hdmatx); } }
#ifndef __BSP_RECORDER_H #define __BSP_RECORDER_H #ifdef __cplusplus extern "C" { #endif #include "main.h" #include "bsp_wavplay.h" #define SAI_RX_DMA_BUF_SIZE 4096 //定义RX DMA 数组大小 #define SAI_RX_FIFO_SIZE 10 //定义接收FIFO大小 #define REC_SAMPLERATE 44100 //采样率,44.1Khz uint8_t rec_sai_fifo_read(uint8_t **buf); uint8_t rec_sai_fifo_write(uint8_t *buf); //void rec_sai_dma_rx_callback(void); void recoder_enter_rec_mode(void); void recoder_wav_init(__WaveHeader* wavhead); void recoder_msg_show(uint32_t tsec,uint32_t kbps); void recoder_remindmsg_show(uint8_t mode); void recoder_new_pathname(uint8_t *pname); void wav_recorder(void); #ifdef __cplusplus } #endif #endif /* __BSP_RECORDER_H */
#include "bsp_recorder.h" #include "bsp_audioplay.h" #include "ff.h" #include "bsp_malloc.h" #include "bsp_printf.h" #include "bsp_wm8978.h" #include "bsp_sai.h" #include "delay.h" #include "bsp_key.h" #include "bsp_exfuns.h" #include "string.h" // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //录音机 应用代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //创建日期:2016/1/11 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2014-2024 //All rights reserved // uint8_t *sairecbuf1; //SAI1 DMA接收BUF1 uint8_t *sairecbuf2; //SAI1 DMA接收BUF2 //REC录音FIFO管理参数. //由于FATFS文件写入时间的不确定性,如果直接在接收中断里面写文件,可能导致某次写入时间过长 //从而引起数据丢失,故加入FIFO控制,以解决此问题. volatile uint8_t sairecfifordpos=0; //FIFO读位置 volatile uint8_t sairecfifowrpos=0; //FIFO写位置 uint8_t *sairecfifobuf[SAI_RX_FIFO_SIZE];//定义10个录音接收FIFO FIL* f_rec=0; //录音文件 uint32_t wavsize; //wav数据大小(字节数,不包括文件头!!) uint8_t rec_sta=0; //录音状态 //[7]:0,没有开启录音;1,已经开启录音; //[6:1]:保留 //[0]:0,正在录音;1,暂停录音; void BSP_SAI_REC_M0_RX_Callback(DMA_HandleTypeDef *_hdma) //RX回调函数 { if(rec_sta==0X80)//录音模式 { if(((SCB->CCR)>>16)&0X01)SCB_CleanInvalidateDCache(); rec_sai_fifo_write(sairecbuf1); //sairecbuf1写入FIFO } } void BSP_SAI_REC_M1_RX_Callback(DMA_HandleTypeDef *_hdma) //RX回调函数 { if(rec_sta==0X80)//录音模式 { if(((SCB->CCR)>>16)&0X01)SCB_CleanInvalidateDCache(); rec_sai_fifo_write(sairecbuf2); //sairecbuf2写入FIFO } } //读取录音FIFO //buf:数据缓存区首地址 //返回值:0,没有数据可读; // 1,读到了1个数据块 uint8_t rec_sai_fifo_read(uint8_t **buf) { if(sairecfifordpos==sairecfifowrpos)return 0; sairecfifordpos++; //读位置加1 if(sairecfifordpos>=SAI_RX_FIFO_SIZE)sairecfifordpos=0;//归零 *buf=sairecfifobuf[sairecfifordpos]; return 1; } //写一个录音FIFO //buf:数据缓存区首地址 //返回值:0,写入成功; // 1,写入失败 uint8_t rec_sai_fifo_write(uint8_t *buf) { uint16_t i; uint8_t temp=sairecfifowrpos;//记录当前写位置 sairecfifowrpos++; //写位置加1 if(sairecfifowrpos>=SAI_RX_FIFO_SIZE)sairecfifowrpos=0;//归零 if(sairecfifordpos==sairecfifowrpos) { sairecfifowrpos=temp;//还原原来的写位置,此次写入失败 return 1; } for(i=0;i<SAI_RX_DMA_BUF_SIZE;i++)sairecfifobuf[sairecfifowrpos][i]=buf[i];//拷贝数据 return 0; } //录音 SAI_DMA接收中断服务函数.在中断里面写入数据 void rec_sai_dma_rx_callback(void) { if(rec_sta==0X80)//录音模式 { if(((SCB->CCR)>>16)&0X01)SCB_CleanInvalidateDCache(); if(DMA2_Stream5->CR&(1<<19))rec_sai_fifo_write(sairecbuf1); //sairecbuf1写入FIFO else rec_sai_fifo_write(sairecbuf2); //sairecbuf2写入FIFO } } const uint16_t saiplaybuf[2]={0X0000,0X0000};//2个16位数据,用于录音时SAI Block A主机发送.循环发送0. //进入PCM 录音模式 void recoder_enter_rec_mode(void) { WM8978_ADDA_Cfg(0,1); //开启ADC WM8978_Input_Cfg(1,1,0); //开启输入通道(MIC&LINE IN) WM8978_Output_Cfg(0,1); //开启BYPASS输出 WM8978_MIC_Gain(46); //MIC增益设置 WM8978_SPKvol_Set(0); //关闭喇叭. WM8978_I2S_Cfg(2,0); //飞利浦标准,16位数据长度 BSP_SAIA1_Init(SAI_PROTOCOL_DATASIZE_16BIT, REC_SAMPLERATE); BSP_SAIB1_Init(SAI_PROTOCOL_DATASIZE_16BIT, REC_SAMPLERATE); SAIA_SampleRate_Set(REC_SAMPLERATE);//设置采样率 SAIA1_TX_DMA_Init(16); HAL_DMAEx_MultiBufferStart(&hdma_sai1_a, (uint32_t)&saiplaybuf[0], (uint32_t)&hsai_BlockA1.Instance->DR, (uint32_t)&saiplaybuf[1], 1); SAIB1_RX_DMA_Init(16); HAL_DMA_RegisterCallback(&hdma_sai1_b, HAL_DMA_XFER_CPLT_CB_ID, BSP_SAI_REC_M0_RX_Callback); HAL_DMA_RegisterCallback(&hdma_sai1_b, HAL_DMA_XFER_M1CPLT_CB_ID, BSP_SAI_REC_M1_RX_Callback); HAL_DMAEx_MultiBufferStart_IT(&hdma_sai1_b, /*(uint32_t)&SAI1_Block_B->DR*/(uint32_t)&hsai_BlockB1.Instance->DR, (uint32_t)sairecbuf1, (uint32_t)sairecbuf2, SAI_RX_DMA_BUF_SIZE/2); recoder_remindmsg_show(0); } //进入PCM 放音模式 void recoder_enter_play_mode(void) { WM8978_ADDA_Cfg(1,0); //开启DAC WM8978_Input_Cfg(0,0,0); //关闭输入通道(MIC&LINE IN) WM8978_Output_Cfg(1,0); //开启DAC输出 WM8978_MIC_Gain(0); //MIC增益设置为0 WM8978_SPKvol_Set(50); //喇叭音量设置 recoder_remindmsg_show(1); } //初始化WAV头. void recoder_wav_init(__WaveHeader* wavhead) //初始化WAV头 { wavhead->riff.ChunkID=0X46464952; //"RIFF" wavhead->riff.ChunkSize=0; //还未确定,最后需要计算 wavhead->riff.Format=0X45564157; //"WAVE" wavhead->fmt.ChunkID=0X20746D66; //"fmt " wavhead->fmt.ChunkSize=16; //大小为16个字节 wavhead->fmt.AudioFormat=0X01; //0X01,表示PCM;0X01,表示IMA ADPCM wavhead->fmt.NumOfChannels=2; //双声道 wavhead->fmt.SampleRate=REC_SAMPLERATE;//设置采样速率 wavhead->fmt.ByteRate=wavhead->fmt.SampleRate*4;//字节速率=采样率*通道数*(ADC位数/8) wavhead->fmt.BlockAlign=4; //块大小=通道数*(ADC位数/8) wavhead->fmt.BitsPerSample=16; //16位PCM wavhead->data.ChunkID=0X61746164; //"data" wavhead->data.ChunkSize=0; //数据大小,还需要计算 } //显示录音时间和码率 //tsec:秒钟数. void recoder_msg_show(uint32_t tsec,uint32_t kbps) { // //显示录音时间 // LCD_ShowString(30,210,200,16,16,"TIME:"); // LCD_ShowxNum(30+40,210,tsec/60,2,16,0X80); //分钟 // LCD_ShowChar(30+56,210,':',16,0); // LCD_ShowxNum(30+64,210,tsec%60,2,16,0X80); //秒钟 // //显示码率 // LCD_ShowString(140,210,200,16,16,"KPBS:"); // LCD_ShowxNum(140+40,210,kbps/1000,4,16,0X80); //码率显示 } //提示信息 //mode:0,录音模式;1,放音模式 void recoder_remindmsg_show(uint8_t mode) { if(mode==0) //录音模式 { printf("KEY0:REC/PAUSE\n"); printf("KEY2:STOP&SAVE\n"); printf("WK_UP:PLAY\n"); }else //放音模式 { printf("KEY0:STOP Play\n"); printf("WK_UP:PLAY/PAUSE\n"); } } //通过时间获取文件名 //仅限在SD卡保存,不支持FLASH DISK保存 //组合成:形如"0:RECORDER/REC20120321210633.wav"的文件名 void recoder_new_pathname(uint8_t *pname) { uint8_t res; uint16_t index=0; while(index<0XFFFF) { sprintf((char*)pname,"0:RECORDER/REC%05d.wav",index); res=f_open(ftemp,(const TCHAR*)pname,FA_READ);//尝试打开这个文件 if(res==FR_NO_FILE)break; //该文件名不存在=正是我们需要的. index++; } } //WAV录音 void wav_recorder(void) { uint8_t res,i; uint8_t key; uint8_t rval=0; __WaveHeader *wavhead=0; DIR recdir; //目录 uint8_t *pname=0; uint8_t *pdatabuf; uint8_t timecnt=0; //计时器 uint32_t recsec=0; //录音时间 WM8978_Init(); //初始化WM8978 WM8978_HPvol_Set(40,40); //耳机音量设置 WM8978_SPKvol_Set(40); //喇叭音量设置 while(f_opendir(&recdir,"0:/RECORDER"))//打开录音文件夹 { printf("RECORDER文件夹错误!"); delay_ms(200); f_mkdir("0:/RECORDER"); //创建该目录 } sairecbuf1=mymalloc(SRAMIN,SAI_RX_DMA_BUF_SIZE);//SAI录音内存1申请 sairecbuf2=mymalloc(SRAMIN,SAI_RX_DMA_BUF_SIZE);//SAI录音内存2申请 for(i=0;i<SAI_RX_FIFO_SIZE;i++) { sairecfifobuf[i]=mymalloc(SRAMIN,SAI_RX_DMA_BUF_SIZE);//SAI录音FIFO内存申请 if(sairecfifobuf[i]==NULL)break; //申请失败 } f_rec=(FIL *)mymalloc(SRAMIN,sizeof(FIL)); //开辟FIL字节的内存区域 wavhead=(__WaveHeader*)mymalloc(SRAMIN,sizeof(__WaveHeader));//开辟__WaveHeader字节的内存区域 pname=mymalloc(SRAMIN,30); //申请30个字节内存,类似"0:RECORDER/REC00001.wav" if(!sairecbuf1||!sairecbuf2||!f_rec||!wavhead||!pname||i!=SAI_RX_FIFO_SIZE)rval=1; if(rval==0) { recoder_enter_rec_mode(); //进入录音模式,此时耳机可以听到咪头采集到的音频 pname[0]=0; //pname没有任何文件名 while(rval==0) { key=KEY_Scan(0); switch(key) { case KEY2_PRES: //STOP&SAVE if(rec_sta&0X80)//有录音 { rec_sta=0; //关闭录音 wavhead->riff.ChunkSize=wavsize+36; //整个文件的大小-8; wavhead->data.ChunkSize=wavsize; //数据大小 f_lseek(f_rec,0); //偏移到文件头. f_write(f_rec,(const void*)wavhead,sizeof(__WaveHeader),&bw);//写入头数据 f_close(f_rec); wavsize=0; sairecfifordpos=0; //FIFO读写位置重新归零 sairecfifowrpos=0; } rec_sta=0; recsec=0; break; case KEY0_PRES: //REC/PAUSE if(rec_sta&0X01)//原来是暂停,继续录音 { rec_sta&=0XFE;//取消暂停 }else if(rec_sta&0X80)//已经在录音了,暂停 { rec_sta|=0X01; //暂停 }else //还没开始录音 { recsec=0; recoder_new_pathname(pname); //得到新的名字 printf("录制:%s\n", pname+11); recoder_wav_init(wavhead); //初始化wav数据 res=f_open(f_rec,(const TCHAR*)pname, FA_CREATE_ALWAYS | FA_WRITE); if(res) //文件创建失败 { rec_sta=0; //创建文件失败,不能录音 rval=0XFE; //提示是否存在SD卡 }else { res=f_write(f_rec,(const void*)wavhead,sizeof(__WaveHeader),&bw);//写入头数据 recoder_msg_show(0,0); rec_sta|=0X80; //开始录音 } } break; case WKUP_PRES: //播放最近一段录音 if(rec_sta!=0X80)//没有在录音 { if(pname[0])//如果触摸按键被按下,且pname不为空 { printf("播放:%s\n",pname+11); recoder_enter_play_mode(); //进入播放模式 audio_play_song(pname); //播放pname recoder_enter_rec_mode(); //重新进入录音模式 } } break; } if(rec_sai_fifo_read(&pdatabuf))//读取一次数据,读到数据了,写入文件 { res=f_write(f_rec,pdatabuf,SAI_RX_DMA_BUF_SIZE,(UINT*)&bw);//写入文件 if(res) { printf("write error:%d\r\n",res); } wavsize+=SAI_RX_DMA_BUF_SIZE; }else delay_ms(5); if(recsec!=(wavsize/wavhead->fmt.ByteRate)) //录音时间显示 { recsec=wavsize/wavhead->fmt.ByteRate; //录音时间 recoder_msg_show(recsec,wavhead->fmt.SampleRate*wavhead->fmt.NumOfChannels*wavhead->fmt.BitsPerSample);//显示码率 } } } myfree(SRAMIN,sairecbuf1); //释放内存 myfree(SRAMIN,sairecbuf2); //释放内存 for(i=0;i<SAI_RX_FIFO_SIZE;i++)myfree(SRAMIN,sairecfifobuf[i]);//SAI录音FIFO内存释放 myfree(SRAMIN,f_rec); //释放内存 myfree(SRAMIN,wavhead); //释放内存 myfree(SRAMIN,pname); //释放内存 }
#ifndef __BSP_WAVPLAY_H #define __BSP_WAVPLAY_H #ifdef __cplusplus extern "C" { #endif #include "main.h" // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //WAV 解码代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //创建日期:2016/1/18 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2014-2024 //All rights reserved //******************************************************************************** //V1.0 说明 //1,支持16位/24位WAV文件播放 //2,最高可以支持到192K/24bit的WAV格式. // #define WAV_SAI_TX_DMA_BUFSIZE 4096 //定义WAV TX DMA 数组大小(播放192Kbps@24bit的时候,需要设置4096大才不会卡) //RIFF块 typedef __packed struct { uint32_t ChunkID; //chunk id;这里固定为"RIFF",即0X46464952 uint32_t ChunkSize ; //集合大小;文件总大小-8 uint32_t Format; //格式;WAVE,即0X45564157 }ChunkRIFF ; //fmt块 typedef __packed struct { uint32_t ChunkID; //chunk id;这里固定为"fmt ",即0X20746D66 uint32_t ChunkSize ; //子集合大小(不包括ID和Size);这里为:20. uint16_t AudioFormat; //音频格式;0X01,表示线性PCM;0X11表示IMA ADPCM uint16_t NumOfChannels; //通道数量;1,表示单声道;2,表示双声道; uint32_t SampleRate; //采样率;0X1F40,表示8Khz uint32_t ByteRate; //字节速率; uint16_t BlockAlign; //块对齐(字节); uint16_t BitsPerSample; //单个采样数据大小;4位ADPCM,设置为4 // uint16_t ByteExtraData; //附加的数据字节;2个; 线性PCM,没有这个参数 }ChunkFMT; //fact块 typedef __packed struct { uint32_t ChunkID; //chunk id;这里固定为"fact",即0X74636166; uint32_t ChunkSize ; //子集合大小(不包括ID和Size);这里为:4. uint32_t NumOfSamples; //采样的数量; }ChunkFACT; //LIST块 typedef __packed struct { uint32_t ChunkID; //chunk id;这里固定为"LIST",即0X74636166; uint32_t ChunkSize ; //子集合大小(不包括ID和Size);这里为:4. }ChunkLIST; //data块 typedef __packed struct { uint32_t ChunkID; //chunk id;这里固定为"data",即0X5453494C uint32_t ChunkSize ; //子集合大小(不包括ID和Size) }ChunkDATA; //wav头 typedef __packed struct { ChunkRIFF riff; //riff块 ChunkFMT fmt; //fmt块 // ChunkFACT fact; //fact块 线性PCM,没有这个结构体 ChunkDATA data; //data块 }__WaveHeader; //wav 播放控制结构体 typedef __packed struct { uint16_t audioformat; //音频格式;0X01,表示线性PCM;0X11表示IMA ADPCM uint16_t nchannels; //通道数量;1,表示单声道;2,表示双声道; uint16_t blockalign; //块对齐(字节); uint32_t datasize; //WAV数据大小 uint32_t totsec ; //整首歌时长,单位:秒 uint32_t cursec ; //当前播放时长 uint32_t bitrate; //比特率(位速) uint32_t samplerate; //采样率 uint16_t bps; //位数,比如16bit,24bit,32bit uint32_t datastart; //数据帧开始的位置(在文件里面的偏移) }__wavctrl; uint8_t wav_decode_init(uint8_t* fname,__wavctrl* wavx); uint32_t wav_buffill(uint8_t *buf,uint16_t size,uint8_t bits); //void wav_sai_dma_tx_callback(void); uint8_t wav_play_song(uint8_t* fname); extern __wavctrl wavctrl; //WAV控制结构体 #ifdef __cplusplus } #endif #endif /* __BSP_WAVPLAY_H */
#include "bsp_wavplay.h" #include "bsp_audioplay.h" #include "bsp_printf.h" #include "delay.h" #include "bsp_malloc.h" #include "ff.h" #include "bsp_sai.h" #include "bsp_wm8978.h" #include "bsp_key.h" #include "string.h" // //本程序只供学习使用,未经作者许可,不得用于其它任何用途 //ALIENTEK STM32开发板 //WAV 解码代码 //正点原子@ALIENTEK //技术论坛:www.openedv.com //创建日期:2016/1/18 //版本:V1.0 //版权所有,盗版必究。 //Copyright(C) 广州市星翼电子科技有限公司 2014-2024 //All rights reserved //******************************************************************************** //V1.0 说明 //1,支持16位/24位WAV文件播放 //2,最高可以支持到192K/24bit的WAV格式. // __wavctrl wavctrl; //WAV控制结构体 volatile uint8_t wavtransferend=0; //sai传输完成标志 void BSP_SAI_WAV_M0_TX_Callback(DMA_HandleTypeDef *_hdma) //TX回调函数 { uint32_t fillnum; if((audiodev.status&0X01)==0) { memset(audiodev.saibuf1,0,WAV_SAI_TX_DMA_BUFSIZE); } else { fillnum=wav_buffill(audiodev.saibuf1,WAV_SAI_TX_DMA_BUFSIZE,wavctrl.bps); if(fillnum!=WAV_SAI_TX_DMA_BUFSIZE)//播放结束? { wavtransferend=1; } } } void BSP_SAI_WAV_M1_TX_Callback(DMA_HandleTypeDef *_hdma) //TX回调函数 { uint32_t fillnum; if((audiodev.status&0X01)==0) { memset(audiodev.saibuf2,0,WAV_SAI_TX_DMA_BUFSIZE); } else { fillnum=wav_buffill(audiodev.saibuf2,WAV_SAI_TX_DMA_BUFSIZE,wavctrl.bps); if(fillnum!=WAV_SAI_TX_DMA_BUFSIZE)//播放结束? { wavtransferend=1; } } } //WAV解析初始化 //fname:文件路径+文件名 //wavx:wav 信息存放结构体指针 //返回值:0,成功;1,打开文件失败;2,非WAV文件;3,DATA区域未找到. uint8_t wav_decode_init(uint8_t* fname,__wavctrl* wavx) { FIL*ftemp; uint8_t *buf; uint32_t br=0; uint8_t res=0; ChunkRIFF *riff; ChunkFMT *fmt; ChunkFACT *fact; ChunkDATA *data; ftemp=(FIL*)mymalloc(SRAMIN,sizeof(FIL)); buf=mymalloc(SRAMIN,512); if(ftemp&&buf) //内存申请成功 { res=f_open(ftemp,(TCHAR*)fname,FA_READ);//打开文件 if(res==FR_OK) { f_read(ftemp,buf,512,&br); //读取512字节在数据 riff=(ChunkRIFF *)buf; //获取RIFF块 if(riff->Format==0X45564157)//是WAV文件 { fmt=(ChunkFMT *)(buf+12); //获取FMT块 fact=(ChunkFACT *)(buf+12+8+fmt->ChunkSize);//读取FACT块 if(fact->ChunkID==0X74636166||fact->ChunkID==0X5453494C)wavx->datastart=12+8+fmt->ChunkSize+8+fact->ChunkSize;//具有fact/LIST块的时候(未测试) else wavx->datastart=12+8+fmt->ChunkSize; data=(ChunkDATA *)(buf+wavx->datastart); //读取DATA块 if(data->ChunkID==0X61746164)//解析成功! { wavx->audioformat=fmt->AudioFormat; //音频格式 wavx->nchannels=fmt->NumOfChannels; //通道数 wavx->samplerate=fmt->SampleRate; //采样率 wavx->bitrate=fmt->ByteRate*8; //得到位速 wavx->blockalign=fmt->BlockAlign; //块对齐 wavx->bps=fmt->BitsPerSample; //位数,16/24/32位 wavx->datasize=data->ChunkSize; //数据块大小 wavx->datastart=wavx->datastart+8; //数据流开始的地方. printf("wavx->audioformat:%d\r\n",wavx->audioformat); printf("wavx->nchannels:%d\r\n",wavx->nchannels); printf("wavx->samplerate:%d\r\n",wavx->samplerate); printf("wavx->bitrate:%d\r\n",wavx->bitrate); printf("wavx->blockalign:%d\r\n",wavx->blockalign); printf("wavx->bps:%d\r\n",wavx->bps); printf("wavx->datasize:%d\r\n",wavx->datasize); printf("wavx->datastart:%d\r\n",wavx->datastart); }else res=3;//data区域未找到. }else res=2;//非wav文件 }else res=1;//打开文件错误 } f_close(ftemp); myfree(SRAMIN,ftemp);//释放内存 myfree(SRAMIN,buf); return 0; } //填充buf //buf:数据区 //size:填充数据量 //bits:位数(16/24) //返回值:读到的数据个数 uint32_t wav_buffill(uint8_t *buf,uint16_t size,uint8_t bits) { uint16_t readlen=0; uint32_t bread; uint16_t i; uint32_t *p,*pbuf; if(bits==24)//24bit音频,需要处理一下 { readlen=(size/4)*3; //此次要读取的字节数 f_read(audiodev.file,audiodev.tbuf,readlen,(UINT*)&bread);//读取数据 pbuf=(uint32_t*)buf; for(i=0;i<size/4;i++) { p=(uint32_t*)(audiodev.tbuf+i*3); pbuf[i]=p[0]; } bread=(bread*4)/3; //填充后的大小. }else { f_read(audiodev.file,buf,size,(UINT*)&bread);//16bit音频,直接读取数据 if(bread<size)//不够数据了,补充0 { for(i=bread;i<size-bread;i++)buf[i]=0; } } return bread; } //得到当前播放时间 //fx:文件指针 //wavx:wav播放控制器 void wav_get_curtime(FIL*fx,__wavctrl *wavx) { long long fpos; wavx->totsec=wavx->datasize/(wavx->bitrate/8); //歌曲总长度(单位:秒) fpos=fx->fptr-wavx->datastart; //得到当前文件播放到的地方 wavx->cursec=fpos*wavx->totsec/wavx->datasize; //当前播放到第多少秒了? } //播放某个WAV文件 //fname:wav文件路径. //返回值: //KEY0_PRES:下一曲 //KEY1_PRES:上一曲 //其他:错误 uint8_t wav_play_song(uint8_t* fname) { uint8_t key; uint8_t res; audiodev.file=(FIL*)mymalloc(SRAMIN,sizeof(FIL)); audiodev.saibuf1=mymalloc(SRAMIN,WAV_SAI_TX_DMA_BUFSIZE); audiodev.saibuf2=mymalloc(SRAMIN,WAV_SAI_TX_DMA_BUFSIZE); audiodev.tbuf=mymalloc(SRAMIN,WAV_SAI_TX_DMA_BUFSIZE); if(audiodev.file&&audiodev.saibuf1&&audiodev.saibuf2&&audiodev.tbuf) { memset(audiodev.saibuf1,0,WAV_SAI_TX_DMA_BUFSIZE); memset(audiodev.saibuf2,0,WAV_SAI_TX_DMA_BUFSIZE); res=wav_decode_init(fname,&wavctrl);//得到文件的信息 if(res==0)//解析文件成功 { wavtransferend=0; if(wavctrl.bps==16) { WM8978_I2S_Cfg(2,0); //飞利浦标准,16位数据长度 BSP_SAI1_Init(SAI_PROTOCOL_DATASIZE_16BIT, wavctrl.samplerate); SAIA_SampleRate_Set(wavctrl.samplerate);//设置采样率 SAIA_TX_DMA_Init(16); HAL_DMA_RegisterCallback(&hdma_sai1_a, HAL_DMA_XFER_CPLT_CB_ID, BSP_SAI_WAV_M0_TX_Callback); HAL_DMA_RegisterCallback(&hdma_sai1_a, HAL_DMA_XFER_M1CPLT_CB_ID, BSP_SAI_WAV_M1_TX_Callback); HAL_DMAEx_MultiBufferStart_IT(&hdma_sai1_a, (uint32_t)audiodev.saibuf1, (uint32_t)&hsai_BlockA1.Instance->DR, (uint32_t)audiodev.saibuf2, WAV_SAI_TX_DMA_BUFSIZE/2); } else if(wavctrl.bps==24) { WM8978_I2S_Cfg(2,2); //飞利浦标准,24位数据长度 BSP_SAI1_Init(SAI_PROTOCOL_DATASIZE_24BIT, wavctrl.samplerate); SAIA_SampleRate_Set(wavctrl.samplerate);//设置采样率 SAIA_TX_DMA_Init(24); HAL_DMA_RegisterCallback(&hdma_sai1_a, HAL_DMA_XFER_CPLT_CB_ID, BSP_SAI_WAV_M0_TX_Callback); HAL_DMA_RegisterCallback(&hdma_sai1_a, HAL_DMA_XFER_M1CPLT_CB_ID, BSP_SAI_WAV_M1_TX_Callback); HAL_DMAEx_MultiBufferStart_IT(&hdma_sai1_a, (uint32_t)audiodev.saibuf1, (uint32_t)&hsai_BlockA1.Instance->DR, (uint32_t)audiodev.saibuf2, WAV_SAI_TX_DMA_BUFSIZE/4); } else { res=0XFF; } if(res==0) { res=f_open(audiodev.file,(TCHAR*)fname,FA_READ); //打开文件 if(res==0) { f_lseek(audiodev.file, wavctrl.datastart); //跳过文件头 audiodev.status=3<<0;//开始播放+非暂停 while(res==0) { if(wavtransferend)//播放结束? { res=KEY0_PRES; break; } while(1) { key=KEY_Scan(0); if(key==WKUP_PRES)//暂停 { if(audiodev.status&0X01)audiodev.status&=~(1<<0); else audiodev.status|=0X01; } if(key==KEY2_PRES||key==KEY0_PRES)//下一曲/上一曲 { res=key; break; } wav_get_curtime(audiodev.file,&wavctrl);//得到总时间和当前播放的时间 audio_msg_show(wavctrl.totsec,wavctrl.cursec,wavctrl.bitrate); if((audiodev.status&0X01)==0)delay_ms(10); else break; } } audiodev.status=0; } else { res=0XFF; } } } else { res=0XFF; } } else { res=0XFF; } myfree(SRAMIN,audiodev.tbuf); //释放内存 myfree(SRAMIN,audiodev.saibuf1);//释放内存 myfree(SRAMIN,audiodev.saibuf2);//释放内存 myfree(SRAMIN,audiodev.file); //释放内存 return res; }
总结:
1、
2、
3、
4、
5、
6、
7、void BSP_SAIB1_Init(uint32_t datasize, uint32_t AudioFrequency)函数中需要加入 hsai_BlockB1.Instance->CR1 |= SAI_xCR1_DMAEN;__HAL_SAI_ENABLE(&hsai_BlockB1);void BSP_SAIA1_Init(uint32_t datasize, uint32_t AudioFrequency)中不用加是因为uint8_t SAIA_SampleRate_Set(uint32_t samplerate)中有设置;
HAL库中HAL_StatusTypeDef HAL_SAI_Transmit_DMA(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size)等函数中有设置,但是双缓冲HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength)中没有设置
8、HAL_StatusTypeDef HAL_DMAEx_MultiBufferStart(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t SecondMemAddress, uint32_t DataLength)
播放音乐发送时&hsai_BlockA1.Instance->DR是目的地址;
录音接收时t)&hsai_BlockB1.Instance->DR是源地址
9、SAI DMA中断优先级低于SD DMA中断优先级,否则程序会卡死在读SD DMA中断
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。