学前班
最后登录 1970-1-1
在线时间 小时
注册时间 2022-10-16
22 火花
本帖最后由 fengge0832 于 2022-10-16 19:05 编辑
STM32F407+WM8909硬件组合,音频采样是8K 16bit立体声,采集和播放侧都采用 I2S DMA 双缓冲机制 , 目的减少 CPU 的处理消耗 , 当 codec 接收和写入数据后会产生 DMA 中断 。播放侧设置half-buffer DMA 中断,中断后通过 freeRTOS 信号通知任务线程进行下一个buffer数据拷贝 。 从实际测试情况 , 利用 DMA 双缓冲在 STM 32 中会出现每一秒会多产生4~ 5 个包(每个包32*2字节) , 总数据量是 320 字节的数据。是否有遇到该问题?排查方向是什么?
/* I2S2 init function */
void MX_I2S2_Init(void)
{
hi2s2.Instance = SPI2;
hi2s2.Init.Mode = I2S_MODE_MASTER_TX;
hi2s2.Init.Standard = I2S_STANDARD_PHILIPS;
hi2s2.Init.DataFormat = I2S_DATAFORMAT_16B;
hi2s2.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE;
hi2s2.Init.AudioFreq = I2S_AUDIOFREQ_8K;
hi2s2.Init.CPOL = I2S_CPOL_LOW;
hi2s2.Init.ClockSource = I2S_CLOCK_PLL;
hi2s2.Init.FullDuplexMode = I2S_FULLDUPLEXMODE_DISABLE;
if (HAL_I2S_Init(&hi2s2) != HAL_OK)
{
Error_Handler();
}
}
void HAL_I2S_MspInit(I2S_HandleTypeDef* i2sHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(i2sHandle->Instance==SPI2)
{
/* USER CODE BEGIN SPI2_MspInit 0 */
/* USER CODE END SPI2_MspInit 0 */
/* I2S2 clock enable */
__HAL_RCC_SPI2_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**I2S2 GPIO Configuration
PB12 ------> I2S2_WS
PB13 ------> I2S2_CK
PB15 ------> I2S2_SD
PC6 ------> I2S2_MCK
*/
GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = 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_AF5_SPI2;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* I2S2 DMA Init */
/* SPI2_TX Init */
hdma_spi2_tx.Instance = DMA1_Stream4;
hdma_spi2_tx.Init.Channel = DMA_CHANNEL_0;
hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_spi2_tx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_spi2_tx.Init.Mode = DMA_CIRCULAR;
hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_spi2_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
hdma_spi2_tx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_spi2_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(i2sHandle,hdmatx,hdma_spi2_tx);
/* USER CODE BEGIN SPI2_MspInit 1 */
/* USER CODE END SPI2_MspInit 1 */
}
}
static void mx_audio_play_task(void const* args)
{
struct mx_audio_context* ctx = (struct mx_audio_context*)args;
char pcm_buf[MX_PCM_STERO_SIZE] = { 0 };
uint32_t tmout = MX_AUDIO_STREAM_NONE_TIMEOUT;
uint32_t ts = 0;
int len = 0;
osEvent evt;
error_t err;
/*Make sure buffer is not empty*/
LOGI("start play task %u\r\n", ring_buffer_len(ctx->rbc));
for (;;) {
// 1. blocking wait and the first time tmout = 1 to trigger timeout
evt = osSignalWait(MX_AUDIO_EV_BIT2, tmout);
if (evt.status == osEventTimeout) {
ts = get_micro_seconds();
// 2. obtain buffer data from wireless
len = ring_buffer_get(ctx->rbc, pcm_buf, &ts, MX_PCM_STERO_SIZE);
if (len != MX_PCM_STERO_SIZE) {
len = mx_audio_virtual_stero_data(pcm_buf, MX_PCM_STERO_SIZE);
stats.pcm_in_err_cnt++;
} else {
stats.pcm_in_cnt++;
}
err = mx_pcm_dma_data((uint16_t*)pcm_buf, RSHIFT(MX_PCM_STERO_SIZE, 1));
if (err == -MX_ERROR_IO) {
stats.pcm_out_err_cnt++;
} else {
stats.pcm_out_cnt++;
}
}
if (evt.status == osEventSignal) {
ts = get_micro_seconds();
if (evt.value.signals & MX_AUDIO_EV_BIT2) {
LOGI("DMA I2S Error");
}
}
}
}
void HAL_I2S_M1TxHalfCpltCallback(I2S_HandleTypeDef* hi2s)
{
/*Notify fill data*/
osSignalSet(g_evt_handle, MX_AUDIO_EV_BIT1);
}
我来回答