当在调试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后存有一段缓冲时间。

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐