STM32F407跑FreeRTOS,SPI读ADXL345隔几小时就死机,头大
各位同行,真心求教。板子是STM32F407+FreeRTOS,通过SPI1读ADXL345三轴数据,DMA方式,10ms周期任务里读,跑了大概3到5个小时不定时死机,HardFault。产线小批量试产20台,已经有三台复现,客户催得急。
现象是死机前最后一次读的数据正常,之后SPI的BUSY位一直置位,DMA通道卡死。我怀疑是任务和中断的临界区没处理好,但临界区进出都成对,也加过打印。试过降SPI时钟从10.5M降到5M,跑了8小时没死,但降频影响采样节拍,不太想这么交付。
现在怀疑两个方向:一是DMA完成中断里调用了RTOS的API但优先级配置有问题,二是SPI的CS引脚在DMA传输边界被别的任务抢了。内存上heap看了没溢出,栈也加了watermark。
有没有踩过类似坑的兄弟指点下,尤其是SPI+DMA在RTOS下的边界处理,bug多半出在边界,但我没抓准是哪个。先谢过。
回答(3)
先别急着降频,5M能扛8小时说明时序余量问题,根子没除。SPI BUSY卡死+DMA通道挂,八成是DMA完成中断里优先级踩了RTOS的坑。查三点:1)DMA完成中断优先级必须调到configMAX_SYSCALL_INTERRUPT_PRIORITY数值之上(即逻辑优先级更低),中断里调xSemaphoreGiveFromISR前确认没在临界区外乱给;2)CS用软件控制的话,DMA完成中断里立即拉高,别等任务调度,否则下一次传输CS还低着,从机把MISO拉住BUSY就清了不了;3)开SPI Error中断,把OVR/MODF/CRCERR都捕获打印,HardFault前大概率有溢出。直接看参考手册SPI的SR和DMA的ISR寄存器,比猜快。
你这现象我倾向是DMA完成中断抢了SPI中断,导致BUSY位卡死。先查两处:1) DMA完成中断优先级必须低于SPI中断(NVIC里SPI1_IRQn > DMA2_StreamX_IRQn数值更小),否则SPI的TXE/RXNE来不及处理。2) DMA中断里调xSemaphoreGiveFromISR必须用portYIELD_FROM_ISR,别忘了检查configMAX_SYSCALL_INTERRUPT_PRIORITY,SPI和DMA中断优先级都必须≥它。另外CS引脚用软件控制的话,确认DMA传输完成到拉高CS之间没被高优先级任务抢占,加个__disable_irq()保护拉CS那几行。降频能好说明就是时序竞争,直接看手册DMA+SPI章节最快。
兄弟这现象我遇到过类似的。BUSY位一直置位+降频能扛住,八成不是临界区问题,而是SPI的CS或DMA时序有竞争。先查三点:一是DMA完成中断优先级,必须低于configMAX_SYSCALL_INTERRUPT_PRIORITY,且中断里别调非FromISR的API;二看CS引脚是不是用GPIO软件翻转,DMA还没收完就拉高CS,ADXL345会卡住总线,建议CS也交给SPI硬件NSS或用DMA传输完成回调里再拉;三是SPI1和DMA的时钟使能、通道映射有没有在任务里重复初始化。降频能稳通常是时序余量问题,重点查CS和DMA的配合时序,用示波器抓CS和SCK相位最直接。