GD32\STM32使用SPI在DMA模式下出现的数据错位总结
·
当在调试SPI在DMA模式下进行读取磁编码器的过程中发现,数据总有几率错位,原启动DMA程序代码为
void BSP_SPI_START_DMA(spi_read_mode_e mode)
{
// 1. 确保DMA通道禁用
dma_channel_disable(DMA0, DMA_CH1);
dma_channel_disable(DMA0, DMA_CH2);
// 2. 重新设置传输数量
DMA_CHCNT(DMA0, DMA_CH1) = ARRAYSIZE; // RX
DMA_CHCNT(DMA0, DMA_CH2) = ARRAYSIZE; // TX
if(mode == 1) {SET_1_CS_LOW;}
else if(mode == 2) {SET_2_CS_LOW;}
dma_channel_enable(DMA0, DMA_CH1);
dma_channel_enable(DMA0, DMA_CH2);
spi_dma_enable(SPI0, SPI_DMA_TRANSMIT); //先启动发送
spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
}
该代码看起来没有问题,但是在实际工作时,有以下问题
1、先启动的DMA采集,但是没有先启动SPI(虽然后续测试出该问题可能不是导致数据错位的元凶);
2、没有清楚SPI的缓冲区,若该缓冲区存在某一些错误的数据,会影响数据移位。(后确定为元凶)
修改后代码为
void BSP_SPI_START_DMA(spi_read_mode_e mode)
{
// 1. 确保DMA通道禁用
dma_channel_disable(DMA0, DMA_CH1);
dma_channel_disable(DMA0, DMA_CH2);
while(SPI_STAT(SPI0) & SPI_STAT_RBNE) {
(void)SPI_DATA(SPI0);
}
// 2. 重新设置传输数量
DMA_CHCNT(DMA0, DMA_CH1) = ARRAYSIZE; // RX
DMA_CHCNT(DMA0, DMA_CH2) = ARRAYSIZE; // TX
spi_dma_enable(SPI0, SPI_DMA_TRANSMIT);
spi_dma_enable(SPI0, SPI_DMA_RECEIVE);
if(mode == READ_1) {SET_1_CS_LOW;}
else if(mode == READ_2) {SET_2_CS_LOW;}
__DSB(); // 确保写操作完成
__NOP(); __NOP(); __NOP(); // 额外插入约3-5个NOP,提供100ns+的建立时间
dma_channel_enable(DMA0, DMA_CH1);
dma_channel_enable(DMA0, DMA_CH2);
}
相比较源代码修改有3点(根据AI工具提供的代码修改)
1、将SPI启动放到DMA启动前面
2、增加SPI缓冲区清除
3、拉低CS后存有一段缓冲时间。
更多推荐



所有评论(0)