功能描述:利用STM32H7B0的I2S(用DMA)接口发送数据给DAC(每秒发一次,一次持续发送100毫秒),发完数据后就停止I2S和DMA,等下一秒再启动发送数据。
存在的问题:每次启动I2S发送数据,就出现一次破音,请问这是什么问题,如何解决?
1、DMA配置如下:
// 初始化dma
uint8 dma_i2s_init_dma()
{
HAL_StatusTypeDef halFLag = HAL_ERROR;
// 使能dma时钟
__HAL_RCC_DMA1_CLK_ENABLE();
// 失能DMA-TX
HAL_DMA_DeInit(&g_dmaTxHandle);
// 初始化DMA发送通道
g_dmaTxHandle.Instance = DMA1_Stream1;
g_dmaTxHandle.Init.Request = DMA_REQUEST_SPI1_TX; // 请求源
g_dmaTxHandle.Init.Direction = DMA_MEMORY_TO_PERIPH; // 存储器到外设
g_dmaTxHandle.Init.PeriphInc = DMA_PINC_DISABLE;
g_dmaTxHandle.Init.MemInc = DMA_MINC_ENABLE;
g_dmaTxHandle.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
g_dmaTxHandle.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
g_dmaTxHandle.Init.Mode = DMA_NORMAL; // 普通模式
g_dmaTxHandle.Init.Priority = DMA_PRIORITY_MEDIUM;
g_dmaTxHandle.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
g_dmaTxHandle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL; // 16字节
g_dmaTxHandle.Init.MemBurst = DMA_MBURST_INC4; // 一次取16字节
g_dmaTxHandle.Init.PeriphBurst = DMA_PBURST_SINGLE;
halFLag = HAL_DMA_Init(&g_dmaTxHandle);
if (halFLag != HAL_OK)
{
return 0;
}
// 链接I2S句柄和Dma句柄
__HAL_LINKDMA(&g_i2sHandle, hdmatx, g_dmaTxHandle);
// DMA中断使能
HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn);
return 1;
}
2、I2S配置如下(MCLK:12.288MHz,LRCK:48KHz):
// 初始化i2s外设
uint8 dma_i2s_init_i2s()
{
HAL_StatusTypeDef halFLag = HAL_ERROR;
dma_i2s_init_clock(); // 初始化时钟
dma_i2s_init_gpio(); // 初始化i2s的管脚
dma_i2s_init_dma(); // 初始化DMA
// 失能I2S
HAL_I2S_DeInit(&g_i2sHandle);
// 组织I2S发送通信参数
g_i2sHandle.Instance = SPI1; // 复用SPI1
g_i2sHandle.Init.Mode = I2S_MODE_MASTER_TX; // 主控制器
g_i2sHandle.Init.Standard = I2S_STANDARD_PHILIPS; // 飞利浦协议
g_i2sHandle.Init.DataFormat = I2S_DATAFORMAT_24B; // 24bit
g_i2sHandle.Init.MCLKOutput = I2S_MCLKOUTPUT_ENABLE; // 主时钟输出
g_i2sHandle.Init.AudioFreq = I2S_AUDIOFREQ_48K; // 采样率
g_i2sHandle.Init.CPOL = I2S_CPOL_LOW; // 空闲状态,时钟为低电平
g_i2sHandle.Init.FirstBit = I2S_FIRSTBIT_MSB; // 大端模式,高字节在前
g_i2sHandle.Init.WSInversion = I2S_WS_INVERSION_ENABLE; // LRCK翻转,左低右高
g_i2sHandle.Init.Data24BitAlignment = I2S_DATA_24BIT_ALIGNMENT_LEFT;
g_i2sHandle.Init.MasterKeepIOState = I2S_MASTER_KEEP_IO_STATE_DISABLE;
// 初始化I2S句柄
halFLag = HAL_I2S_Init(&g_i2sHandle);
if (halFLag != HAL_OK)
{
return 0;
}
return 1;
}
3、停止DMA和I2S
// I2S发送完成的回调函数
void HAL_I2S_TxCpltCallback(I2S_HandleTypeDef *hi2s)
{
__HAL_DMA_CLEAR_FLAG(hi2s, DMA_FLAG_TCIF1_5); // 清除中断标识
uint32 dwFactor = 4096;
uint32 dwFlag = 0; // I2S发送完成标识符,非0标识发送完成
SPI_TypeDef *pSpi = (SPI_TypeDef *)hi2s->Instance; // SPI外设
// 等待i2s移位寄存器发送完成
while (1)
{
dwFlag = pSpi->SR & dwFactor;
if (dwFlag)
{
HAL_I2S_DMAStop(hi2s); // 停止I2S发送
g_byI2sCpltFlag = 0; // 信号已发完
break;
}
}
return;
} |