c++ - BeagleBone Black 通过内核驱动中断

标签 c++ embedded-linux kernel-module beagleboard beagleboneblack

我正在尝试处理中断,但由于 ioread32 而出现以下错误。

正如我在《AM335x SitaraTM Processors - Technical Reference Manual》的“25.3.3 Interrupt Features”一章看到的

为了在 GPIO 引脚上发生定义的事件(电平或逻辑转换)时向主机处理器生成中断请求,必须按如下方式对 GPIO 配置寄存器进行编程:

• 必须在 GPIO_IRQSTATUS_SET_0 和/或 GPIO_IRQSTATUS_SET_1 寄存器中启用 GPIO channel 的中断。

• 必须在 GPIO_LEVELDETECT0、GPIO_LEVELDETECT1、GPIO_RISINGDETECT 和 GPIO_FALLINGDETECT 寄存器中选择输入 GPIO 上触发中断请求的预期事件。

[ 1737.604270] Loading hello_interrupts module...
[ 1737.604426] HI: Initialized GPIO #36 to IRQ #164
[ 1737.604478] Unhandled fault: external abort on non-linefetch (0x1028) at 0xfa1ac02c
[ 1737.612611] Internal error: : 1028 [#1] SMP THUMB2
[ 1737.617696] Modules linked in: hello_interrupts(O+) g_multi libcomposite omap_rng mt7601Usta(O) [last unloaded: hello_interrupts]
[ 1737.630128] CPU: 0    Tainted: G           O  (3.8.13-bone67 #1)
[ 1737.636513] PC is at hello_interrupts_start+0x8b/0x123 [hello_interrupts]
[ 1737.643717] LR is at _raw_read_unlock+0x7/0x8
[ 1737.648340] pc : [<bf8f508c>]    lr : [<c04cfaf7>]    psr: 80000033
[ 1737.648340] sp : df3fde60  ip : 00000034  fp : c006a001
[ 1737.660481] r10: 00000001  r9 : de594200  r8 : bf8f5001
[ 1737.666011] r7 : 00000000  r6 : bf8f30b8  r5 : 00000000  r4 : fa1ac000
[ 1737.672920] r3 : 48000000  r2 : 00000000  r1 : 481adfff  r0 : fa1ac000
[ 1737.679839] Flags: Nzcv  IRQs on  FIQs on  Mode SVC_32  ISA Thumb  Segment user
[ 1737.687569] Control: 50c5387d  Table: 9f740019  DAC: 00000015
[ 1737.693655] Process insmod (pid: 3040, stack limit = 0xdf3fc240)
[ 1737.700025] Stack: (0xdf3fde60 to 0xdf3fe000)
[ 1737.704659] de60: bf8f30b8 00000000 00400100 df3fc000 c08b5740 c000867f 00000000 de5c3640
[ 1737.713323] de80: 00000000 00000000 00400100 bf8f326c bf8f3260 00000001 bf8f32a8 00000001
[ 1737.721988] dea0: c006a001 c006bd31 bf8f326c 00007fff c0069101 e0dd7000 e0dd6fff bf8f3260
[ 1737.730655] dec0: 00000000 b6f7dd50 df3fc000 bf8f33b4 e0dd6691 c02520d0 6e72656b 00006c65
[ 1737.739320] dee0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1737.747993] df00: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
[ 1737.756662] df20: 00000000 00000000 00000000 c0790a68 20000033 000016a8 b6fa2000 b6f7dd50
[ 1737.765331] df40: 00000080 c000c9e4 df3fc000 00000000 00000000 c006c26f e0dd5000 000016a8
[ 1737.774000] df60: e0dd5ae0 e0dd599f e0dd64c8 000003c8 000004c8 00000000 00000000 00000000
[ 1737.782670] df80: 0000001c 0000001d 00000014 00000012 00000010 00000000 00000000 b6fc0088
[ 1737.791339] dfa0: b6fc0d00 c000c841 00000000 b6fc0088 b6fa2000 000016a8 b6f7dd50 00000002
[ 1737.800008] dfc0: 00000000 b6fc0088 b6fc0d00 00000080 00000000 b6f7dd50 000016a8 00000000
[ 1737.808671] dfe0: 00000000 beb7969c b6f77b07 b6f01fd4 80000010 b6fa2000 c0c92420 c0c92440
[ 1737.817378] [<bf8f508c>] (hello_interrupts_start+0x8b/0x123 [hello_interrupts]) from [<c000867f>] (do_one_initcall+0x1f/0xf4)
[ 1737.829367] [<c000867f>] (do_one_initcall+0x1f/0xf4) from [<c006bd31>] (load_module+0x10d5/0x15b0)
[ 1737.838872] [<c006bd31>] (load_module+0x10d5/0x15b0) from [<c006c26f>] (sys_init_module+0x63/0x88)
[ 1737.848379] [<c006c26f>] (sys_init_module+0x63/0x88) from [<c000c841>] (ret_fast_syscall+0x1/0x46)
[ 1737.857867] Code: 4825 f3d4 debb e036 (6ac5) f3bf 
[ 1737.884765] ---[ end trace cbd53ac03b070f86 ]---

这是我的代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>

#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irq.h>

MODULE_AUTHOR("MGE");
MODULE_DESCRIPTION("A sample driver using interrupts");
MODULE_LICENSE("GPL");

// GPIO Bank 2
#define GPIO2_START_ADDR 0x481AC000
#define GPIO2_SIZE (0x481ADFFF - GPIO2_START_ADDR)

// GPIO memory-mapped register addresses.
#define GPIO_IRQSTATUS_0 0x2C
#define GPIO_IRQSTATUS_1 0x30
#define GPIO_RISINGDETECT 0x148
#define GPIO_FALLINGDETECT 0x14C

#define PIN_A_GPIO 36
#define PIN_A_FLAGS GPIOF_IN
#define PIN_A_LABEL "HI_PIN_A"

static irqreturn_t irq_handler_pin_a (int irq, void *dev_id) {
  printk (KERN_INFO "Hello from irq_handler_pin_a...\n");

  return IRQ_HANDLED;
}

static int __init hello_interrupts_start (void) {
  int retval, irq, regval;
  void __iomem *mem;

  printk (KERN_INFO "Loading hello_interrupts module...\n");

  /**
   * Request the GPIO lines for the IRQ channels.
   */
  retval = gpio_request_one(PIN_A_GPIO, PIN_A_FLAGS, PIN_A_LABEL);

  if (retval) {
    printk (KERN_ERR "HI: Error: Failed to request GPIO pin#%i for IRQ (error %i)\n", PIN_A_GPIO, retval);

//    return -retval;
  }

  irq = gpio_to_irq (PIN_A_GPIO);
  if (irq < 0) {
    printk (KERN_ERR "HI: ERROR: Failed to obtain IRQ number for GPIO #%i (error %i)\n", PIN_A_GPIO, irq);

//    return -irq;
  }

  retval = request_irq (irq, irq_handler_pin_a, 0 /*IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING*/, PIN_A_LABEL, NULL);
  irq_set_irq_type (irq, IRQ_TYPE_EDGE_BOTH);

  if (retval) {
    printk (KERN_ERR "HI: ERROR: The requested IRQ line#%i from GPIO#%i (error %i)\n", irq, PIN_A_GPIO, retval);

//    return -retval;
  }
  else {
    printk (KERN_INFO "HI: Initialized GPIO #%i to IRQ #%i\n", PIN_A_GPIO, irq);
  }

  /**
   * Setup the IRQ registers with the appropriate values.
   */
  mem = ioremap(GPIO2_START_ADDR, GPIO2_SIZE);
  if(!mem) {
    printk (KERN_ERR "HI: ERROR: Failed to remap memory for GPIO Bank 2 IRQ pin configuration.\n");
    return 0;
  }

  // Enable the IRQ ability for GPIO_66.
  regval = ioread32 (mem + GPIO_IRQSTATUS_0);
  regval |= (1 << 2);
  iowrite32 (regval, mem + GPIO_IRQSTATUS_0);

  regval = ioread32 (mem + GPIO_IRQSTATUS_1);
  regval |= (1 << 2);
  iowrite32 (regval, mem + GPIO_IRQSTATUS_1);

  // Set GPIO_66 for rising and falling edge detection.
  regval = ioread32 (mem + GPIO_RISINGDETECT);
  regval |= (1 << 2);
  iowrite32(regval, mem + GPIO_RISINGDETECT);

  regval = ioread32 (mem + GPIO_FALLINGDETECT);
  regval |= (1 << 2);
  iowrite32 (regval, mem + GPIO_FALLINGDETECT);

  // Release the mapped memory.
  iounmap (mem);

  return 0;
}

static void __exit hello_interrupts_end(void) {

  printk ("HI: Releasing IRQ resources...\n");

  free_irq (gpio_to_irq (PIN_A_GPIO), NULL);
  gpio_free (PIN_A_GPIO);

  printk (KERN_INFO "Goodbye hello_interrupts!\n");
}

module_init (hello_interrupts_start);
module_exit (hello_interrupts_end);

有什么想法吗? 谢谢

最佳答案

问题是 GPIO2 模块时钟被禁用。

《AM335x SitaraTM 处理器 - 技术引用手册》的“8.1.12.1.30 CM_PER_GPIO2_CLKCTRL Register (offset = B0h) [reset = 30000h]”

位 1-0: 控制强制时钟的管理方式。 0x0 = DISABLED:模块被 SW 禁用。对模块的任何 OCP 访问都会导致错误,除非是由模块唤醒(异步唤醒)引起的。 0x1 = RESERVED_1:保留 0x2 = ENABLE:模块已明确启用。接口(interface)时钟(如果不用于功能)可以根据时钟域状态进行门控。保证功能时钟保持存在。只要在此配置中,电源域 sleep 转换就不会发生。 0x3 = 保留:保留

关于c++ - BeagleBone Black 通过内核驱动中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26894745/

相关文章:

python - ImageMagick: OSError:/lib/libc.so.6: 找不到版本 `GLIBC_2.XX'

c++ - 在英特尔 Galileo 上运行 C++

c - 使用 writel 将 4 位写入 ioremap 内存地址

linux - 从用户复制函数: write with offsert

C++ 使用带有 boost::lexical_cast 的类

c++ - Win32 : Is it possible to show the window but to hide it from taskbar?

c++ - C++ Visual Studio C2027和C2011错误

c++ - 对象初始化: Init method or stream operator?

linux - 如何修复 “iptables: No chain/target/match by that name” ?

linux-kernel - Linux 内核是否有自己的 SSE/AVX 上下文?