happy__yun 2025-10-26 12:08 采纳率: 0%
浏览 33

HC32F460使用SPI做从机出现故障错误和数据欠载错误

HC32F460JETA 使用SPI做从机,主机SPI一直发送数据,从机一直发生模式故障错误和数据欠载错误。
尝试使用两种方法解决:
1.使用发送空闲中断一直发送数据。
2.在接收中断中接收到数据后就发送数据。
但这两种方式均没有解决。

  • 写回答

4条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-10-26 12:22
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .
    每日一句正能量,让它带给您好心情:别让负面的声音,淹没你内心的坚定。
    .

    针对HC32F460作为SPI从机时出现的模式故障错误和数据欠载错误,我来分析可能的原因和解决方案。

    问题分析

    1. 模式故障错误 (Mode Fault Error)

    模式故障通常发生在:

    • SPI主从设备配置不匹配(时钟极性/相位)
    • 从机在非预期时刻检测到片选信号变化
    • 硬件连接问题

    2. 数据欠载错误 (Data Underrun Error)

    数据欠载错误发生在:

    • 从机发送缓冲区为空时主机仍在读取数据
    • 从机响应速度跟不上主机发送速度
    • 中断处理不及时

    解决方案

    1. 检查SPI配置匹配

    确保主从设备的SPI配置完全一致:

    // HC32F460 SPI从机配置示例
    void SPI_Slave_Config(void)
    {
        stc_spi_init_t stcSpiInit;
        
        MEM_ZERO_STRUCT(stcSpiInit);
        stcSpiInit.enClkDiv = SpiClkDiv2;        // 从机时钟分频
        stcSpiInit.enFrameWidth = SpiFrameWidth8; // 8位数据帧
        stcSpiInit.enWorkMode = SpiWorkMode3;     // CPOL=1, CPHA=1
        stcSpiInit.enCommMode = SpiCommModeFullDuplex;
        stcSpiInit.enSpiMode = SpiModeSlave;      // 从机模式
        stcSpiInit.enIntType = SpiIntRxBuf | SpiIntErr; // 启用接收和错误中断
        
        SPI_Init(SPI1, &stcSpiInit);
        SPI_Cmd(SPI1, Enable);
    }
    

    2. 优化中断处理

    使用DMA方式处理数据收发,避免中断延迟:

    // 配置SPI DMA
    void SPI_DMA_Config(void)
    {
        // 接收DMA配置
        stc_dma_config_t stcDmaCfg;
        MEM_ZERO_STRUCT(stcDmaCfg);
        stcDmaCfg.u16BlockSize = 1;
        stcDmaCfg.u16TransferCnt = 1;
        stcDmaCfg.enSrcAddrMode = DmaAddrModeFix;
        stcDmaCfg.enDesAddrMode = DmaAddrModeFix;
        stcDmaCfg.enDataWidth = DmaDataWidth8;
        stcDmaCfg.enDmaMode = DmaModeOne;
        
        // SPI接收DMA
        DMA_Init(DMA_CH0, &stcDmaCfg);
        DMA_SetDesAddr(DMA_CH0, (uint32_t)&SPI1->DR);
        DMA_SetSrcAddr(DMA_CH0, (uint32_t)rx_buffer);
        
        // SPI发送DMA  
        DMA_Init(DMA_CH1, &stcDmaCfg);
        DMA_SetDesAddr(DMA_CH1, (uint32_t)tx_buffer);
        DMA_SetSrcAddr(DMA_CH1, (uint32_t)&SPI1->DR);
    }
    

    3. 实现环形缓冲区

    使用环形缓冲区管理数据流:

    #define BUFFER_SIZE 64
    
    
    typedef struct {
        uint8_t data[BUFFER_SIZE];
        volatile uint16_t head;
        volatile uint16_t tail;
    } ring_buffer_t;
    
    
    ring_buffer_t rx_buf, tx_buf;
    
    
    // 环形缓冲区写入
    bool ring_buffer_write(ring_buffer_t *buf, uint8_t data)
    {
        uint16_t next = (buf->head + 1) % BUFFER_SIZE;
        if(next == buf->tail) return false; // 缓冲区满
        
        buf->data[buf->head] = data;
        buf->head = next;
        return true;
    }
    
    
    // 环形缓冲区读取
    bool ring_buffer_read(ring_buffer_t *buf, uint8_t *data)
    {
        if(buf->head == buf->tail) return false; // 缓冲区空
        
        *data = buf->data[buf->tail];
        buf->tail = (buf->tail + 1) % BUFFER_SIZE;
        return true;
    }
    

    4. 错误处理机制

    完善错误中断处理:

    void SPI1_IRQHandler(void)
    {
        // 检查模式故障错误
        if(SPI_GetStatus(SPI1, SpiModeFault) == Set)
        {
            SPI_ClearStatus(SPI1, SpiModeFault);
            // 重新初始化SPI
            SPI_DeInit(SPI1);
            SPI_Slave_Config();
            return;
        }
        
        // 检查数据欠载错误
        if(SPI_GetStatus(SPI1, SpiUnderrunErr) == Set)
        {
            SPI_ClearStatus(SPI1, SpiUnderrunErr);
            // 立即填充发送缓冲区
            SPI_SendData(SPI1, dummy_data);
        }
        
        // 处理接收数据
        if(SPI_GetStatus(SPI1, SpiRxBufFull) == Set)
        {
            uint8_t received_data = SPI_ReceiveData(SPI1);
            ring_buffer_write(&rx_buf, received_data);
            
            // 如果有待发送数据,立即发送
            uint8_t send_data;
            if(ring_buffer_read(&tx_buf, &send_data))
            {
                SPI_SendData(SPI1, send_data);
            }
            else
            {
                // 发送哑数据避免欠载
                SPI_SendData(SPI1, 0xFF);
            }
        }
    }
    

    5. 硬件检查要点

    1. 时钟配置:确保SPI时钟不超过从机最大支持频率
    2. 片选信号:检查CS信号是否稳定,无毛刺
    3. 电平匹配:确认IO电平兼容性
    4. 布线质量:检查信号完整性,特别是高速时钟

    6. 调试建议

    // 添加调试信息输出
    void debug_spi_status(void)
    {
        printf("SPI Status:\n");
        printf("Mode Fault: %d\n", SPI_GetStatus(SPI1, SpiModeFault));
        printf("Underrun Error: %d\n", SPI_GetStatus(SPI1, SpiUnderrunErr));
        printf("TX Empty: %d\n", SPI_GetStatus(SPI1, SpiTxBufEmpty));
        printf("RX Full: %d\n", SPI_GetStatus(SPI1, SpiRxBufFull));
    }
    

    建议优先尝试DMA方案,它能有效解决因中断响应延迟导致的数据欠载问题。同时仔细检查硬件连接和SPI时序配置,确保主从设备参数完全匹配。

    评论

报告相同问题?

问题事件

  • 修改了问题 10月26日
  • 创建了问题 10月26日