【问题标题】:request_irq succeeds but interrupt is never detectedrequest_irq 成功但从未检测到中断
【发布时间】:2012-11-18 23:44:44
【问题描述】:

我在 ARM 处理器上运行嵌入式 linux 3.2.6。我正在使用修改版的 atmel 串行驱动程序来控制我设备上的 4 个 USART 端口。当我使用用内核编译的驱动程序时,一切正常。但我想将驱动程序作为内核模块运行。我进行了所有必要的更改并禁用了内部驱动程序,一切似乎都很好。 4 个 tty 设备注册成功,我可以看到我的所有探测和初始化功能都正常工作。

所以问题来了: 当我尝试写入任何设备时,我的“开始传输”函数被调用,但随后等待来自 usart 的中断,该中断从未发生。所以写入只是挂起,使用逻辑分析器我可以看到 RTS 被断言但 tx 线上没有字节显示。我知道我对 request_irq 的调用成功,但我从未在 /proc/interrupts 中看到任何 irq 条目。在驱动程序中,我也尝试过使用 request_irq 为 gpio 线注册一个单独的中断处理程序,效果很好。

我知道这是一个可能难以诊断的问题,但我正在寻找任何可能的建议,以帮助我找到解决方案的正确方向。如果您需要任何澄清,请告诉我。谢谢

【问题讨论】:

  • 另一个想法,当使用 /proc/interupts 中内置的驱动程序时,显示 irq 注册为“AIC”irqs。会不会有什么东西导致高级中断控制器和可加载模块之间断开连接?
  • “我进行了所有必要的更改并禁用了内部驱动程序” 是什么意思?为什么必须“禁用”“内部”驱动程序?这是否意味着内存中可能有两个版本的驱动程序?这是否与无法通过make menuconfig 将 Atmel 串行驱动程序配置为可加载模块这一事实有关?

标签: linux serial-port embedded-linux atmel irq


【解决方案1】:

症状类似于未启用(或关闭)的外设时钟:可以初始化设备而不会出现错误,并且可以设置 I/O 操作,但是设备什么都不做;它玩死了。因为从来没有 I/O开始,你永远不会得到一个指示完成的中断!

要检查的另一件事是arch/arm/mach-xxx/zzz_devices.c 文件中硬件配置结构的条件编译指令。
确保串行端口结构具有以下内容:

#if defined(CONFIG_SERIAL_ATMEL) || defined(CONFIG_SERIAL_ATMEL_MODULE)

不只是

#if defined(CONFIG_SERIAL_ATMEL) 

附录

我可能是错的,但时钟不应该对 CTS 引脚产生任何影响而导致中断,对吧?

不对。
这些数字电路是同步状态机:没有时钟,就无法处理输入引起的状态变化。
此外,SoC 和现代 uController 使用外设时钟作为这些集成外设的开/关开关。硅芯片上的功能(即外围设备)通常比实际可以使用的要多得多,这主要是由于板上的引脚数量不足。因此,禁用未使用设备的时钟以降低功耗。

您过于关注中断。
您没有可解决的中断问题;这些是次要故障。
尝试传输时缺少输出更为显着和具有启发性。
根本原因可能是 USART 设备的配置有缺陷,因为传输位是已配置且可运行的 USART 的自动操作。
如果不工作与工作之间的区别在于 可加载模块静态链接,那么根本原因将是一些基本(和微不足道)的东西,就像我的两个建议一样。

另外,您对#if defined() 缺乏确认,例如你没有回复 “哦,是的,我们已经知道了”,会引发一个巨大的危险信号,上面写着 “先解决我!”

附录 2

在发现无法使用make menuconfig 将 Atmel 串行驱动程序配置/构建为可加载模块后,我很想删除此答案(这是一半答案的前提)。 (当然,Kconfig 文件 可以 被破解以使配置变量 tristate 而不是 boolean 来克服模块限制。)我'我为 OP 留下了评论。但我也想保留对 Stratton 先生的评论,指出.config 文件中的符号是如何(不)使用的。

【讨论】:

  • 非常感谢您的帮助。我要到星期一才能测试。我忘记提到的一件事是我尝试切换 CTS 引脚,该引脚也应该触发中断,但它也失败了。我可能是错的,但时钟不应该对 CTS 引脚产生任何影响而导致中断,对吧?
  • @user1415608 如果 UART 外围设备没有获得时钟,这可能会阻止所有与 UART 相关的功能,包括中断(RTS、CTS 等可能是 GPIO,而不是 UART 的一部分)。未设置的 UART 中断使能位可能是另一个罪魁祸首。还要考虑为什么发送例程会等待中断 - 可能是因为发送寄存器尚未为空。但这可能是启动时的错误假设,并且永远不会清除。您可以尝试在驱动程序启动期间轮询和打印 UART 标志位,甚至强制发送字符。
  • @sawdust - 我不会声称 CONFIG_SOMETHING_MODULE 是一个从未使用过的想法,但通常的情况不是为模块制作单独的配置选项,而是设置配置选项配置模块时改为“m”而不是“y”。要么将通过#if 定义的测试。然而,并非所有可以作为内置工作的东西都可以作为模块工作。特别是对于串行,内核中的其他地方可能有一些关键代码,因为串行通常是第一个调试通道。可能需要在整个树上对标识符进行递归 grep。
  • @ChrisStratton - " 两者都将通过#if defined 测试。" -- Atmel 驱动程序并非如此;您确实需要在编译时测试这两个符号。我已经帮助另一个开发人员解决了 Atmel AT91SAM SoC 上的另一个设备的类似问题(驱动程序在静态链接时工作,在可加载模块时不可用)。并且建议的编辑与 AT91 xxx_devices.c 文件中的其他 Atmel 外设(但不用于 USART)具有完全相同的形式。
  • @sawdust - 你似乎没有抓住重点。大多数 linux 驱动程序对内置形式和模块形式都使用相同的符号,但将其定义为不同的值,“y”或“m”。任何一个值都将通过该符号的#if 定义测试。在“CONFIG_SERIAL_ATMEL”上的网络搜索发现了许多匹配项,其中一个“CONFIG_SERIAL_ATMEL_MODULE”似乎没有找到——尽管我不能保证没有使用这种不寻常机制的代码隐藏在某处。 (也许你能找到它?)将片上 UART 的驱动程序作为模块构建已经有点不寻常了。
【解决方案2】:

所以我终于解决了我的问题。感谢您的回复,他们都没有直接解决我的问题,但他们确实提示进一步检查我的代码。经过一些试验和错误,我终于让它工作了。我最初将每个 usart 的 platform_device 结构从 /mach-at91/xxx_devices.c 移动到我的可加载模块。好吧,由于某种原因,结构没有获得正确的数据以映射到硬件,我想是因为它没有正确链接来自内核的符号(虽然从未收到错误消息),所以一些注册功能不是' t 甚至被调用。我最终将结构和 platform_device_register 调用移回设备文件。我还决定使用原始的 atmel_serial.c 驱动程序保留内置控制台的驱动程序。我必须在设备文件和内置 atmel_serial.c 文件中更改控制台的 platform_device 名称,以免它与我的 usart 端口驱动程序冲突。我发现将 usart 的 platform_device 和 platform_driver 名称从“atmel_usart”以外的任何名称更改都会导致 usart 传输失败。我真的不明白为什么,但我只是将其保留为 atmel_usart 以便它可以工作。

再次感谢所有回复我问题的人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-05
    • 2017-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-17
    相关资源
    最近更新 更多