2020-07-19 12:12 PM
Hello,
I want to implement a wav player from an SD/USB, the problem is with the reading of the data, I have the SD mounted, the wav file opened and when it starts reading-sending it through DMA, it does not work correctly, I have tested a basic sinewave, filling an array with the sine data and sending it with HAL_I2S_Transmit_DMA(), and it works, but when I want a constant buffer reading and sending, what I get is that the audio signal takes a sample, repeats the same sample a few times, and then reads the new sample, it does not have a constant flow of reading-sending.
Here I attach you my main and my waveplayer implementation.
Thank you so much
MAIN.C
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2020 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 "dma.h"
#include "fatfs.h"
#include "i2c.h"
#include "i2s.h"
#include "sdio.h"
#include "spi.h"
#include "tim.h"
#include "usart.h"
#include "usb_host.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "wav_player.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define WAV_FILE1 "audio/test.wav"
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/*PCM5102_Config PCM5102_1 = {
.Data_Bits = 16, // 16, 20, 24, 32
.FS = FS_441kHz, // fs
.LRCK_Frequency = FS_441kHz, // fs
.BCK_Frequency = 32 * FS_441kHz, // 32, 48, 64 * fs
};*/
float mySinVal;
float sample_dt;
uint16_t sample_N;
uint16_t i_t;
uint32_t myDacVal;
int16_t dataI2S[100];
#define PI 3.14159f
//Sample rate and Output freq
#define F_SAMPLE 44100.0f
#define F_OUT 80.0f
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void MX_USB_HOST_Process(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
sample_dt = F_OUT/F_SAMPLE;
sample_N = F_SAMPLE/F_OUT;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_I2C1_Init();
MX_I2S2_Init();
MX_SDIO_SD_Init();
MX_USART1_UART_Init();
MX_FATFS_Init();
MX_USB_HOST_Init();
MX_TIM2_Init();
MX_TIM3_Init();
MX_SPI3_Init();
/* USER CODE BEGIN 2 */
//TurnOFF the USER LEDs
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, RESET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, RESET);
FRESULT res;
if(res = f_mount(&SDFatFS, SDPath, 1) == FR_OK){ //If SD card is correctly mounted
HAL_UART_Transmit_IT(&huart1, "SD montada correctamente\n\r", strlen("SD montada correctamente\n\r"));//TX Function
//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, SET); //Turn ON the LED_1
if(wavPlayer_fileSelect("test.wav") == 0){ //If the wav file wasn't correstly opened
//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, SET); //Turn ON the LED_2
HAL_UART_Transmit_IT(&huart1, "Error al abrir el WAV\n\r", strlen("Error al abrir el WAV\n\r"));//TX Function
}
else
{
HAL_UART_Transmit_IT(&huart1, "WAV abierto\n\r", strlen("WAV abierto\n\r"));//TX Function
wavPlayer_play();
HAL_UART_Transmit_IT(&huart1, "WAV PLAY\n\r", strlen("WAV PLAY\n\r"));//TX Function
isPlaying = true;
}
}
else
{
HAL_UART_Transmit_IT(&huart1, "Error al montar la SD\n\r", strlen("Error al montar la SD\n\r"));//TX Function
//HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7, SET); //Turn ON the LED_2
}
/*
//Build Sine wave
for(uint16_t i=0; i<sample_N; i++)
{
mySinVal = sinf(i*2*PI*sample_dt);
dataI2S[i*2] = (mySinVal )*8000; //Right data (0 2 4 6 8 10 12)
dataI2S[i*2 + 1] =(mySinVal )*8000; //Left data (1 3 5 7 9 11 13)
}
HAL_I2S_Transmit_DMA(&hi2s2, (uint16_t *)dataI2S, sample_N*2);
*/
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
MX_USB_HOST_Process();
if(!wavPlayer_isFinished() && isPlaying){
wavPlayer_process();
}
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 4;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S;
PeriphClkInitStruct.PLLI2S.PLLI2SN = 50;
PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
}
/* 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 */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
2020-07-19 12:12 PM
WAV_PLAYER.C
/*
* wav_player.c
*
* Created on: 17 Apr 2020
* Author: Mohamed Yaqoob
*/
#include "wav_player.h"
#include "fatfs.h"
#include "i2s.h"
//WAV File System variables
static FIL wavFile;
//WAV Audio Buffer
static uint32_t fileLength;
#define AUDIO_BUFFER_SIZE 4096*1
static uint8_t audioBuffer[AUDIO_BUFFER_SIZE];
static __IO uint32_t audioRemainSize = 0;
WAV_HeaderTypeDef wavHeader;
//WAV Player
static uint32_t samplingFreq;
static UINT playerReadBytes = 0; //Bytes already rode from the file
static bool isFinished=0;
bool isPlaying = false;
//WAV Player process states
typedef enum
{
PLAYER_CONTROL_Idle=0,
PLAYER_CONTROL_HalfBuffer,
PLAYER_CONTROL_FullBuffer,
PLAYER_CONTROL_EndOfFile,
}PLAYER_CONTROL_e;
static volatile PLAYER_CONTROL_e playerControlSM = PLAYER_CONTROL_Idle;
static void wavPlayer_reset(void)
{
audioRemainSize = 0;
playerReadBytes = 0;
}
/**
* @brief Select WAV file to play
* @retval returns true when file is found in USB Drive
*/
bool wavPlayer_fileSelect(const char* filePath)
{
UINT readBytes = 0;
//Open WAV file
if(f_open(&wavFile, filePath, FA_READ) != FR_OK)
{
return false;
}
//Read WAV file Header
f_read(&wavFile, &wavHeader, sizeof(wavHeader), &readBytes);
//Get audio data size
fileLength = wavHeader.FileSize;
//Play the WAV file with frequency specified in header
samplingFreq = wavHeader.SampleRate;
return true;
}
/**
* @brief WAV File Play
*/
void wavPlayer_play(void)
{
isFinished = false;
//Read Audio data from USB Disk
f_lseek(&wavFile, 0);
f_read (&wavFile, &audioBuffer[0], AUDIO_BUFFER_SIZE, &playerReadBytes);
audioRemainSize = fileLength - playerReadBytes;
//Start playing the WAV
HAL_I2S_Transmit_DMA(&hi2s2, (uint16_t *)&audioBuffer[0], AUDIO_BUFFER_SIZE);
}
/**
* @brief Process WAV
*/
void wavPlayer_process(void)
{
switch(playerControlSM)
{
case PLAYER_CONTROL_Idle:
break;
case PLAYER_CONTROL_HalfBuffer:
playerReadBytes = 0;
playerControlSM = PLAYER_CONTROL_Idle;
f_read (&wavFile, &audioBuffer[0], AUDIO_BUFFER_SIZE/2, &playerReadBytes);
if(audioRemainSize > (AUDIO_BUFFER_SIZE / 2))
{
audioRemainSize -= playerReadBytes;
}
else
{
audioRemainSize = 0;
playerControlSM = PLAYER_CONTROL_EndOfFile;
}
break;
case PLAYER_CONTROL_FullBuffer:
playerReadBytes = 0;
playerControlSM = PLAYER_CONTROL_Idle;
f_read (&wavFile, &audioBuffer[AUDIO_BUFFER_SIZE/2], AUDIO_BUFFER_SIZE/2, &playerReadBytes);
if(audioRemainSize > (AUDIO_BUFFER_SIZE / 2))
{
audioRemainSize -= playerReadBytes;
}
else
{
audioRemainSize = 0;
playerControlSM = PLAYER_CONTROL_EndOfFile;
}
break;
case PLAYER_CONTROL_EndOfFile:
f_close(&wavFile);
wavPlayer_reset();
isFinished = true;
playerControlSM = PLAYER_CONTROL_Idle;
break;
}
}
/**
* @brief WAV stop
*/
void wavPlayer_stop(void)
{
HAL_I2S_DMAStop(&hi2s2);
isFinished = true;
}
/**
* @brief WAV pause/resume
*/
void wavPlayer_pause(void)
{
HAL_I2S_DMAPause(&hi2s2);
}
void wavPlayer_resume(void)
{
HAL_I2S_DMAResume(&hi2s2);
}
/**
* @brief isEndofFile reached
*/
bool wavPlayer_isFinished(void)
{
return isFinished;
}
/**
* @brief Half/Full transfer Audio callback for buffer management
*/
void audioI2S_halfTransfer_Callback(void)
{
playerControlSM = PLAYER_CONTROL_HalfBuffer;
}
void audioI2S_fullTransfer_Callback(void)
{
playerControlSM = PLAYER_CONTROL_FullBuffer;
HAL_I2S_Transmit_DMA(&hi2s2, (uint16_t*)&audioBuffer[AUDIO_BUFFER_SIZE / 2], AUDIO_BUFFER_SIZE / 2);
// audioI2S_changeBuffer((uint16_t*)&audioBuffer[0], AUDIO_BUFFER_SIZE / 2);
}
/**
* @brief Half/Full transfer Audio callback for buffer management
*/
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
if(hi2s->Instance == SPI2)
{
audioI2S_fullTransfer_Callback();
}
}
void HAL_I2S_TxHalfCpltCallback(I2S_HandleTypeDef *hi2s)
{
if(hi2s->Instance == SPI2)
{
audioI2S_halfTransfer_Callback();
}
}
2020-08-10 11:35 PM
also have the same problem, were you able to resolve the problem? (I'm using DMA and interrupt for I2S callback and the audio is very choppy
2022-05-26 06:51 AM
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
if(hi2s->Instance == SPI2)
{
...
while(hi2s2.hdmatx->State != HAL_DMA_STATE_READY);
HAL_I2S_Transmit_DMA(&hi2s2, (uint16_t*)signal_play_buff, nsamples);
...
}
}