2025-07-04 4:08 AM - last edited on 2025-07-04 7:42 AM by Amel NASRI
when i make the macro LUDWIG_SAI_DMA_MODE 0 i can hear audio in continous loop without noise because it runs in blocking mode.when give 1 to LUDWIG_SAI_DMA_MODE, I can able to hear the audio for sometimes after that i hear noise. When i hear noise i suspend the task it will point to while(updatePointer==-1).
/*
* audio.c
*
* Created on: Jun 30, 2025
* Author: KannikaMMallu
*/
#include "audio.h"
#include "sai.h"
#include "tx_api.h"
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
__IO int16_t UpdatePointer = -1;
extern int16_t PlayBuff[PLAY_BUFF_SIZE];
/* USER CODE END PTD */
TX_THREAD audio_thread;
UCHAR audio_thread_stack[4096];
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* USER CODE BEGIN 3 */
void audio_thread_entry(ULONG thread_input)
{
Audio();
}
void Audio_ThreadX_Init(void)
{
// Create the audio thread
tx_thread_create(&audio_thread, "Audio Thread", audio_thread_entry, 0,
audio_thread_stack, sizeof(audio_thread_stack),
10, 10, TX_NO_TIME_SLICE, TX_AUTO_START);
}
/* USER CODE END 3 */
/* Private variables ---------------------------------------------------------*/
int Audio(void)
{
/* USER CODE BEGIN 1 */
//check audio buffer is loaded to internal memory
/* Check if the buffer has been loaded in flash */
SAI_check_audio_buffer();
/* USER CODE END 1 */
#if LUDWIG_SAI_DMA_MODE
SAI_DMA_circular_link_create();
// Pre-fill the entire buffer before starting playback
SAI_read_audio_buffer_from_mem((uint16_t *)PlayBuff, PLAY_BUFF_SIZE);
// Start DMA transfer to I2S
SAI_send_audio_buffer_to_i2s((uint8_t *)PlayBuff, PLAY_BUFF_SIZE);
#endif
while (1)
{
#if LUDWIG_SAI_DMA_MODE
/* Wait a callback event */
while (UpdatePointer == -1);
if(UpdatePointer == 0) //half of the buffer is complete
{
SAI_read_audio_buffer_from_mem((uint16_t *)&PlayBuff[0], PLAY_BUFF_SIZE / 2);
}
else
{
SAI_read_audio_buffer_from_mem((uint16_t *)&PlayBuff[PLAY_BUFF_SIZE / 2], PLAY_BUFF_SIZE / 2);
}
UpdatePointer = -1;
#else
//Read audio buffer of 64 samples
SAI_read_audio_buffer_from_mem((uint16_t *)PlayBuff, PLAY_BUFF_SIZE);
//Send the process data to I2S in blocking mode
SAI_send_audio_buffer_to_i2s((uint8_t *)PlayBuff, PLAY_BUFF_SIZE);
#endif
} //end of while
}
/*
* sai.c
*
* Created on: May 6, 2025
* Author: Mahesha
*/
#include "stm32wbaxx_it.h"
#include "sai.h"
#include "linked_list.h"
extern DMA_QListTypeDef SAIQueue;
int16_t PlayBuff[PLAY_BUFF_SIZE];
extern __IO int16_t UpdatePointer;
static uint32_t PlaybackPosition = PLAY_HEADER;
void SAI_check_audio_buffer(void)
{
/* Check if the buffer has been loaded in flash */
if(*((uint64_t *)AUDIO_FILE_ADDRESS) != 0x017EFE2446464952 )
Error_Handler();
/* Associate the DMA handle */
//__HAL_LINKDMA(&hsai_BlockB1, hdmatx, handle_GPDMA1_Channel1);
}
void SAI_DMA_circular_link_create(void)
{
/* Associate the DMA handle */
__HAL_LINKDMA(&hsai_BlockB1, hdmatx, handle_GPDMA1_Channel1);
MX_SAIQueue_Config();
/* Set queue circular mode for sai queue */
HAL_DMAEx_List_SetCircularMode(&SAIQueue);
/* Link SAI queue to DMA channel */
HAL_DMAEx_List_LinkQ(&handle_GPDMA1_Channel1, &SAIQueue);
}
void SAI_send_audio_buffer_to_i2s(uint8_t *sendPlayBuff, uint16_t Size)
{
#if LUDWIG_SAI_DMA_MODE
if(HAL_OK != HAL_SAI_Transmit_DMA(&hsai_BlockB1, (uint8_t *)sendPlayBuff, Size))
{
Error_Handler();
}
#else
if(HAL_OK != HAL_SAI_Transmit(&hsai_BlockB1, (uint8_t *)sendPlayBuff, Size,5000))
{
Error_Handler();
}
#endif
}
void SAI_read_audio_buffer_from_mem(uint16_t *readPlayBuff, uint16_t Size)
{
/* check the end of the file */
for (uint16_t i = 0; i < Size; i++)
{
if ((PlaybackPosition + Size*2) >= AUDIO_FILE_SIZE)
PlaybackPosition = PLAY_HEADER;
readPlayBuff[i] = *(uint16_t *)(AUDIO_FILE_ADDRESS + PlaybackPosition);
PlaybackPosition += 2;
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/**
* @brief GPDMA1 Initialization Function
* None
* @retval None
*/
void MX_SAI_GPDMA_Init(void)
{
/* USER CODE BEGIN GPDMA1_Init 0 */
/* USER CODE END GPDMA1_Init 0 */
/* Peripheral clock enable */
__HAL_RCC_GPDMA1_CLK_ENABLE();
/* GPDMA1 interrupt Init */
HAL_NVIC_SetPriority(GPDMA1_Channel1_IRQn, 5, 5);
HAL_NVIC_EnableIRQ(GPDMA1_Channel1_IRQn);
/* USER CODE BEGIN GPDMA1_Init 1 */
/* USER CODE END GPDMA1_Init 1 */
handle_GPDMA1_Channel1.Instance = GPDMA1_Channel1;
handle_GPDMA1_Channel1.InitLinkedList.Priority = DMA_HIGH_PRIORITY;
handle_GPDMA1_Channel1.InitLinkedList.LinkStepMode = DMA_LSM_FULL_EXECUTION;
handle_GPDMA1_Channel1.InitLinkedList.LinkAllocatedPort = DMA_LINK_ALLOCATED_PORT0;
handle_GPDMA1_Channel1.InitLinkedList.TransferEventMode = DMA_TCEM_LAST_LL_ITEM_TRANSFER;
handle_GPDMA1_Channel1.InitLinkedList.LinkedListMode = DMA_LINKEDLIST_CIRCULAR;
if (HAL_DMAEx_List_Init(&handle_GPDMA1_Channel1) != HAL_OK)
{
Error_Handler();
}
if (HAL_DMA_ConfigChannelAttributes(&handle_GPDMA1_Channel1, DMA_CHANNEL_NPRIV) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN GPDMA1_Init 2 */
/* USER CODE END GPDMA1_Init 2 */
}
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/**
* @brief Tx Transfer Half completed callbacks
* hsai : pointer to a SAI_HandleTypeDef structure that contains
* the configuration information for SAI module.
* @retval None
*/
void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
{
UpdatePointer = 0;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);
}
/**
* @brief Tx Transfer completed callbacks.
* hsai : pointer to a SAI_HandleTypeDef structure that contains
* the configuration information for SAI module.
* @retval None
*/
void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
{
UpdatePointer = PLAY_BUFF_SIZE/2;
}
void HAL_SAI_ErrorCallback(SAI_HandleTypeDef *hsai)
{
printf("SAI ERROR! ErrorCode=0x%08lX\n", (unsigned long)hsai->ErrorCode);
}