2296205_zh-CN

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

2296205_zh-CN

2296205_zh-CN

从中断处理程序进行 I/O 操作

本问题的相关参数如下:

1。IDE:适用于 ARM v 2.2 的 S32 DS(是的,我知道这个已经过时了,但是有问题的产品也是;我们需要支持现有代码)

2.芯片:S32K148

3.操作系统视窗 11

4.系统操作系统:裸机


在 ISR 中尝试执行任何类型的 SPI 主传输都会挂起,通常被中断的 API 是阻塞 I/O(I2C 或 SPI)调用。


在阻塞调用(调用 LPSPI_DRV_MasterTransferBlocking())中,通话挂起是因为 SysTick 中断似乎没有发生,因此 MCU 无法感知时间流逝。


在非阻塞调用(LPSPI_DRV_MasterTransfer(),然后是 LPSPI_DRV_MasterGetTransferStatus(SPI1,&byte_remaining))中,byte_remaining 保持原值。我尝试在调用 LPSPI_DRV_MasterAbortTransfer() 进行异步传输之前,添加对 LPSPI_DRV_MasterAbortTransfer(SPI1) 的调用,但结果还是一样。


关于一个半相关的问题,是什么触发了 SysTick_Handler()?我的直觉告诉我,它应该一直运行,每 1 毫秒增加一次刻度计数,但在其正文中设置一个断点似乎只能在某些时间触发。奇怪的是,即使阻塞性 SPI 传输成功,有时也不会触发,如果系统定时器之前未触发,则应触发系统定时器。


另一个半相关的问题是,在 SPI 的 S32 Cookbook 示例代码中,没有使用 SDK 提供的应用程序接口;这些示例直接完成了所有寄存器位操作。是否有更接近生产价值代码的示例,因为它们至少调用了恩智浦的应用程序接口,而不是重新发明轮子?

Re: Doing I/O from an interrupt handler

你好@PetrS


非常感谢。中断优先级确实解决了这个问题。不过,我有一个问题:


我同意在 ISR 中阻塞不是一个好主意,但在单线程应用程序中又有什么办法呢?我可以在应用程序上下文中旋转,直到 SPI 传输完成。这将允许其他 I/O 中断发生(我的理解是,负优先级中断无论如何都会触发;当进入正优先级 ISR 时,它们不会被禁用)。但是在我的情况下,进行重叠的 I/O 既不可能,也不可取。


1.这是不可能的,因为 S32K148 是所有总线的总线主控器。因此,如果它在 ISR 中进行 SPI 传输,则可能无法驱动另一条 I/O 总线,因此无法触发中断。


2.这并不可取,因为 ISR 之间可能存在共享全局,所以我不想在当前 I/O 完成之前启动新的 I/O。


对于单线程裸机应用程序,您建议如何处理这种情况?

Re: Doing I/O from an interrupt handler

您好,

好吧,那么只需中断优先级就能导致这种行为。阻塞 API 会挂起的原因很简单,如果两个中断具有相同的优先级,那么当 GPIO ISR 处于活动状态时,LPSPI ISR 就无法运行。阻塞调用等待 ISR 完成传输并发布信号,但在 GPIO ISR 退出之前,ISR 永远不会获得 CPU 时间。SDK 的驱动程序确实在 LPSPI 中断中完成传输,然后才发布信号量以释放屏蔽调用,因此同等优先级 ISR 将以这种方式使传输陷入僵局。

非阻塞 API 的行为相同:如果从具有相同优先级的 GPIO ISR 调用,LPSPI ISR 无法抢占它的优先级,因此 byte_remaining 永远不会改变,因为驱动程序状态机永远不会被 LPSPI IRQ 服务。只有将 LPSPI 提高到更高优先级(数值较低)后,LPSPI 中断才会立即触发,完成传输,并允许阻塞和非阻塞 API 按预期工作。尝试

/* 在 Cortex-M 上,数字越小优先级越高 */
INT_SYS_SetPriority(SysTick_IRQn, 0); // 如果依赖于 tick 超时
INT_SYS_SetPriority(LPSPI1_IRQn, 1); // 必须高于 GPIO
INT_SYS_SetPriority(PORTC_IRQn, 2); // 您按钮的 PORTx IRQ
 
注意:无论优先级如何修正,建议还是不要在 ISR 中使用阻塞的 SPI API,同样也不要在 ISR 中等待非阻塞传输完成。S32K LPSPI 驱动程序在其中断处理程序中进行传输,长时间的 ISR 会阻止其他中断运行。
 
BR, Petr

Re: Doing I/O from an interrupt handler

您好,

S32K1 SDK 无法阻止 ISR 的 I/O。LPSPI_DRV_MasterTransferBlocking() 等待 OSIF semaphore;在 ISR 上下文中,没有地方可以阻塞,也没有 tick/time base 可以前进,因此会挂起。使用非阻塞 API(LPSPI_DRV_MasterTransfer),在 LPSPI ISR/回调中完成传输,然后向任务/主循环发出信号。此外,SysTick 会在定时器结束时触发,但其处理程序只有在未被屏蔽且具有足够的 NVIC 优先级时才会运行--因此,如果设置了 PRIMASK 或处于更高优先级的 ISR 中,它将被推迟。

烹饪手册项目特意采用轻量级设计,直接展示外围设备的使用,而不使用更高级别的驱动程序抽象;这些项目旨在作为学习的起点,而非生产使用。如果您需要恩智浦驱动程序风格的示例,请参考 SDK 或 RTD 驱动程序/示例项目,而不是烹饪手册。
 
BR, Petr
Re: Doing I/O from an interrupt handler

您好,

即使它现在 "工作 "了,你仍然不应该在 ISR 内进行 SPI 传输。
如果你以后改变了优先级,或添加了另一个外设,你可以很容易地重新创建刚刚诊断出的死锁状态。 最安全的设计是始终缩短 ISR,将真正的工作推迟到主循环。

仅将 ISR 用作触发信号;在 main () 中同步执行 SPI 传输,或者在 ISR 中启动但由 LPSPI ISR 完成的非阻塞传输,主等待完成标志。

BR, Petr

Tags (1)
No ratings
Version history
Last update:
‎01-22-2026 04:24 AM
Updated by: