NXP MCU 技术论坛
直播中

凌章致

8年用户 1041经验值
私信 关注
[问答]

S32K344 Flexio模拟SPI程序不能正常执行怎么解决?

S32DS版本3.5
RTD版本:S32K3_RTD_3_0_0_D2303
MCU:S32K344HVS BGA257封装
我需要使用Flexio模拟SPI驱动SD卡,参考了T-Box设计,与示例不同的是SPI传输我采用的是异步DMA方式。测试发现在SPI传输完毕之后,标志位正常置位,但是main函数中程序执行异常。
如下图所示,flag已经置1了,但是不能执行到92行,因此不能正常退出最内层while循环,导致程序卡死。不清楚问题出现的原因,希望有谁能帮帮我,谢谢!

附件是我的测试工程。

回帖(1)

石玉兰

2025-3-26 17:57:42

针对S32K344 Flexio模拟SPI程序卡死在while循环的问题,以下是逐步解决方案:


1. 检查volatile关键字



  • 问题:编译器优化可能导致循环中读取的flag变量未及时更新。

  • 解决:将标志变量声明为volatile,确保每次访问都从内存读取。
     volatile uint8_t transfer_complete_flag = 0;


2. 验证中断服务程序(ISR)



  • 问题:DMA传输完成中断未正确触发或未清除中断标志。

  • 步骤

    • 确认DMA传输完成中断使能(例如DMA_HTIEnDMA_TCIEn)。

    • 在ISR中清除中断标志,避免重复触发:
      void DMA_ISR(void) {
         // 清除中断标志
         DMA_ClearITFlag(DMA_FLAG_TCx); // x为对应通道
         transfer_complete_flag = 1;
      }

    • 检查中断向量表配置,确保ISR正确绑定到DMA通道中断。



3. 核对Flexio和DMA配置



  • Flexio定时器/移位器配置

    • 确认时钟极性(CPOL)和相位(CPHA)与SD卡要求一致。

    • 检查数据位宽(例如8位或16位)是否匹配SPI模式。


  • DMA配置

    • 确保源地址(Flexio数据寄存器)和目的地址(内存缓冲区)正确。

    • 设置传输数据长度(DMA_NDTR)与实际传输字节数一致。

    • 启用DMA传输完成中断(例如DMA_IT_TC)。



4. 调试DMA传输状态



  • 在调试器中查看DMA状态寄存器(如DMA_ISR),确认传输完成标志(TCIF)是否置位。

  • 检查DMA通道是否启用(DMA_CCRx.EN位),传输过程中该位应为1,完成后自动清零。


5. 排查内存屏障问题



  • 在设置transfer_complete_flag前后添加内存屏障指令,确保数据同步:
     __DMB(); // 数据内存屏障
    transfer_complete_flag = 1;
    __DSB(); // 数据同步屏障


6. 检查主循环逻辑



  • 确保循环退出条件仅依赖transfer_complete_flag,无其他隐藏条件。

  • 避免在循环内执行阻塞操作(如延时函数),导致无法及时检测标志变化。


7. 验证硬件信号



  • 使用逻辑分析仪捕获Flexio模拟的SCK、MOSI、MISO信号,确认时序符合SPI协议。

  • 检查SD卡供电和上拉电阻,确保信号完整性。


8. 对比RTD示例代码



  • 参考S32K3 RTD中的Flexio SPI示例(如flexio_spi_dma_transfer),对比配置参数:

    • Flexio时钟源选择(例如内部总线时钟)。

    • 定时器的触发和复位条件。

    • DMA请求映射到Flexio的正确触发源。



9. 调整编译器优化等级



  • 暂时将编译器优化等级调整为-O0(无优化),排除优化导致的异常。

  • 在S32DS中:项目属性 > C/C++ Build > Settings > Tool Settings > Optimization > Level → None (-O0)。


10. 调试流程示例



  • 设置断点

    • 在DMA ISR入口和transfer_complete_flag = 1;处设置断点。

    • while (!transfer_complete_flag);后(即92行)设置断点。


  • 观察现象

    • 触发传输后,程序应进入DMA ISR并置位标志。

    • 退出ISR后,主循环应检测到标志变化并继续执行。


  • 若未触发ISR:检查DMA中断配置和NVIC设置。


11. 代码片段示例(关键部分)


// DMA初始化片段(关键参数)
DMA_InitTypeDef DMA_InitStruct;
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&FLEXIO->SHIFTBUF[0]; // Flexio数据寄存器
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)tx_buffer;
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST; // 或PeripheralSRC
DMA_InitStruct.DMA_BufferSize = BUFFER_SIZE;
DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;
DMA_InitStruct.DMA_Priority = DMA_Priority_High;
DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA_CHANNEL_x, &DMA_InitStruct);
DMA_ITConfig(DMA_CHANNEL_x, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA_CHANNEL_x, ENABLE);

// 启动传输前复位标志
transfer_complete_flag = 0;
FLEXIO_StartTransfer(); // 触发Flexio发送

通过以上步骤逐一排查,应能定位到导致while循环无法退出的根本原因。若仍存在问题,建议提供更详细的代码片段(尤其是中断和DMA配置部分)以进一步分析。

举报

更多回帖

发帖
×
20
完善资料,
赚取积分