/* 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中断