3

我们小组正在使用嵌入式处理器(Phytec LPC3180、ARM9)。我们设计了一个电路板,它在 LPC3180 的一个 I2C 总线上包含四个 MAX3107 UART 芯片。以防万一,我们正在运行内核 2.6.10,这是该处理器可用的最新版本(对该产品的支持不是很好;我们必须开发或修复 Phytec 提供的许多驱动程序,并且 Phytec似乎对升级该产品的 linux 代码(尤其是内核版本)没有兴趣。这太糟糕了,因为 LPC3180 是一个不错的设备,尤其是在不需要以太网且实际上不需要以太网的低功耗嵌入式产品的情况下'不想要以太网(由于以太网控制器芯片的相关功耗)。

当 I2C 总线上的四个设备(MAX3107 UART 芯片)之一接收到一个字符时,它会产生一个中断。所有四个 MAX3107 芯片的中断线是共享的(开漏下拉),并且该线连接到配置为电平中断的 3180 的 GPIO 引脚。当 3017 中的一个产生中断时,将运行一个处理程序,该处理程序执行以下处理(大致):

spin_lock_irqsave();
disable_irq_nosync(irqno);
irq_enabled = 0;
irq_received = 1;
spin_unlock_irqrestore()
set_queued_work();  // Queue up work for all four devices for every interrupt
                    // because at this point we don't know which of the four
                    // 3107's generated the interrupt
return IRQ_HANDLED;

请注意,这是我觉得有些麻烦的地方,即在离开上述代码之前没有重新启用中断。相反,驱动程序的编写使得中断由下半部分工作队列任务重新启用(使用“enable_irq(LPC_IRQ_LINE)函数调用”。由于工作队列任务不在中断上下文中运行,我相信它们可能会休眠,我认为对于中断处理程序来说是个坏主意。

上述方法的基本原理如下: 1. 如果四个 MAX3107 uart 芯片中的一个接收到一个字符并产生一个中断(例如),中断处理程序需要确定四个 I2C 设备中的哪个实际引起了中断。然而,显然,由于 I2C 读取可以休眠,因此无法从上半部中断处理程序的上下文中读取 I2C 设备,这被认为不适合中断处理程序上半部。2.解决上述问题(即哪个设备导致中断)的方法是让中断禁用并退出上半部分处理程序,之后非中断上下文代码可以查询I2C总线上的四个设备中的每一个找出哪个接收到了字符(并因此产生了中断)。3. 一旦下半部分处理程序确定哪个设备产生了中断,下半部分代码就会禁用该芯片上的中断,这样它就不会重新触发到 LPC3180 的中断线。这样做之后,它会读取串行数据并退出。

这里的主要问题似乎是没有办法从中断处理程序上半部分中查询四个 MAX3107 uart 芯片。如果上半部分在返回之前简单地重新启用中断,这将导致同一芯片再次产生中断,我认为导致上半部分禁用中断,安排下半部分工作队列并禁用中断只是发现自己回到了同一个地方,因为在下半部分代码到达导致中断的芯片之前,另一个中断已经发生,等等,......

任何与此驱动程序打交道的建议将不胜感激。我真的不喜欢允许在驱动程序的上半部分禁用中断但在存在上半部分驱动代码之前不重新启用中断的想法。这似乎并不安全。

谢谢,

吉姆

PS:在我的阅读中,我发现线程中断是处理上述要求的一种手段(至少这是我对http://lwn.net/Articles/302043/等网站文章的解释)。我不确定 Phytec 提供的 2.6.10 内核是否包含线程中断函数。我打算在接下来的几天内对此进行调查。

4

2 回答 2

1

如果您的代码编写正确,那么设备是否在处理先前的中断完成之前发出中断并不重要,并且您不希望在上半部分执行阻塞操作是正确的,但是阻塞操作在上半部分是可以接受的下半部分,事实上这也是它们存在的部分原因!

在这种情况下,我会建议一种方法,即上半部分只调度下半部分,然后下半部分循环遍历所有 4 个设备并处理任何待处理的请求。可能有多个设备需要处理,也可能没有。

更新: 确实,您可能会通过负载测试使系统过载,并且可能需要优化软件以处理重负载。此外,我没有自己的 3180 和四个 3107(或类似的)来测试它,所以我在理论上说,但我不清楚为什么你需要完全禁用中断。

一般而言,当硬件设备断言中断时,它不会断言另一个中断,直到当前中断被清除。所以你有 4 台设备共享一个 int 行:

  1. 您的上半部分触发并向工作队列添加一些内容(即触发下半部分)
  2. 您的下半部分扫描该 int 行上的所有设备(即所有四个 3107)
  3. 如果其中一个导致中断,您将读取完全处理数据所需的所有数据(可能将其放入队列中以进行更高级别的处理?)
  4. 您“清除”当前设备上的中断。

当您清除中断时,允许设备触发另一个中断,但之前不允许。

有关此特定设备的更多详细信息:

似乎这个设备(MAX3107)有一个 128 个字的缓冲区,默认情况下,你在每个字之后都会被打断。但似乎您应该能够通过设置 FIFO 级别寄存器来更好地利用缓冲区。然后,只有在 rx 字数之后,您才会被中断(或者如果您将 tx FIFO 填充到超过阈值,在这种情况下您应该放慢传输速度(即在软件中缓冲更多))。

似乎这个想法基本上是定期从设备中提取数据(可能每 100 毫秒或 10 毫秒或任何似乎对您有用的东西),然后只让中断充当您已超过阈值的警告,这可能会安排周期性功能立即执行,或增加调用它的速率。

于 2012-11-26T10:29:05.337 回答
1

启用和禁用中断是因为我们使用基于级别的中断,而不是基于边缘的中断。其后果在驱动程序代码标头中明确解释,Jim,您拥有它。

需要基于级别的中断来避免丢失一个字符的边缘中断,该字符在一个 UART 到达另一个 UART 后立即到达:服务第一个有效地消除了第二个,这样第二个字符就会丢失。事实上,这正是该驱动程序的初始边沿中断版本中发生的情况,一旦 >1 UART 被执行。

当前方案是否存在观察到的失败?

问候, 司机作者(其他人)

于 2012-11-30T21:14:41.930 回答