#include "audio_hal.h" #include #include "main.h" #include "elog.h" #include "FreeRTOS.h" #include "queue.h" #include "heap.h" static const char *TAG = "audio_hal"; typedef struct { void *buffer_ptr; uint32_t buffer_size; } audio_sample_t; static QueueHandle_t audio_queue = NULL; static uint8_t *audio_buffer = NULL; static uint32_t audio_buffer_length = 0; static uint8_t audio_buffer_underrun_warn_flag = 0; void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai) { BaseType_t need_yield = pdFALSE; audio_sample_t sample; if (xQueueReceiveFromISR(audio_queue, &sample, &need_yield) == pdTRUE) { memcpy(&audio_buffer[0], sample.buffer_ptr, sample.buffer_size); //复制到第一个缓冲区 free(sample.buffer_ptr); //释放使用完的缓冲区 } HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_SET); portYIELD_FROM_ISR(need_yield); } void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai) { BaseType_t need_yield = pdFALSE; audio_sample_t sample; if (xQueueReceiveFromISR(audio_queue, &sample, &need_yield) == pdTRUE) { memcpy(&audio_buffer[audio_buffer_length / 2], sample.buffer_ptr, sample.buffer_size); //复制到第二个缓冲区 free(sample.buffer_ptr); //释放使用完的缓冲区 } HAL_GPIO_WritePin(LED_R_GPIO_Port, LED_R_Pin, GPIO_PIN_RESET); portYIELD_FROM_ISR(need_yield); } void audio_hal_start(uint32_t sample_count, uint8_t sample_size) { audio_buffer_length = sample_count * sample_size * 2; //双缓冲 elog_info(TAG, "audio_hal_start: sample_count=%d, sample_size=%d, allocating %d bytes for audio buffer", sample_count, sample_size, audio_buffer_length); if (audio_buffer != NULL) { elog_warn(TAG, "audio_hal_start: audio_buffer is not freed"); free_ahb(audio_buffer); } audio_buffer = malloc_ahb(audio_buffer_length); memset(audio_buffer, 0, audio_buffer_length); if (audio_queue != NULL) { elog_warn(TAG, "audio_hal_start: audio_queue is not deleted"); vQueueDelete(audio_queue); } audio_queue = xQueueCreate(AUDIO_HAL_SAMPLE_QUEUE_SIZE, sizeof(audio_sample_t)); audio_buffer_underrun_warn_flag = 0; HAL_SAI_Transmit_DMA(&hsai_BlockB1, audio_buffer, sample_count * 2); //开始DMA循环发送 } void audio_hal_stop(void) { HAL_SAI_DMAStop(&hsai_BlockB1); audio_sample_t sample; while (xQueueReceive(audio_queue, &sample, 0) == pdTRUE) { free(sample.buffer_ptr); elog_debug(TAG, "audio_hal_stop: freeing unused buffer"); } vQueueDelete(audio_queue); audio_queue = NULL; free_ahb(audio_buffer); audio_buffer = NULL; } void audio_hal_write(void *buffer_ptr, uint32_t buffer_size) { if (buffer_size == 0) { return; } audio_sample_t sample = { .buffer_ptr = buffer_ptr, .buffer_size = buffer_size }; if (uxQueueSpacesAvailable(audio_queue) == AUDIO_HAL_SAMPLE_QUEUE_SIZE && audio_buffer_underrun_warn_flag != 0) { elog_warn(TAG, "audio_hal_write: audio sample queue is empty before xQueueSend"); } xQueueSend(audio_queue, &sample, portMAX_DELAY); //发送缓冲区到队列中 audio_buffer_underrun_warn_flag = 1; //屏蔽首次报错 }