【问题标题】:BeagleBone Black interrupts through kernel driverBeagleBone Black 通过内核驱动程序中断
【发布时间】:2015-01-09 18:20:07
【问题描述】:

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

正如我在“AM335x SitaraTM 处理器 - 技术参考手册”的“25.3.3 中断功能”一章中看到的

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

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

• 必须在 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);

有什么想法吗? 谢谢

【问题讨论】:

  • 你有什么问题?

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


【解决方案1】:

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

“AM335x SitaraTM 处理器 - 技术参考手册”的“8.1.12.1.30 CM_PER_GPIO2_CLKCTRL 寄存器(偏移量 = B0h)[reset = 30000h]”

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

【讨论】:

  • 我有 2 个问题:为什么需要为给定的 PIN 设置两个 regs:GPIO_IRQSTATUS_0 和 GPIO_IRQSTATUS_1?第二个:am335x 有几个 GPIO 模块 - 那么为什么只有 2 个寄存器用于启用给定 GPIO 的 IRQ?
【解决方案2】:

要使上述代码正常工作,必须使用 CM_PER_GPIO2_CLKCTRL 寄存器启用 GPIO2 时钟并且必须从 GPIO2 中选择一个 GPIO 引脚。在上面的代码中,使用了 GPIO 36,它位于 GPIO1 上(无论如何都由内部闪存使用)。以下代码启用 GPIO2 时钟并使用 GPIO 68(位于头 P9 引脚 10 顺便说一句):

#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)

// CM_PER (Clock Module Peripheral Registers
#define CM_PER_START_ADDR 0x44e00000
#define CM_PER_SIZE       0x400
#define CM_PER_GPIO2_CLKCTRL 0xb0

// 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 68 // is on P9 pin 10
#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;
  void __iomem *cm_per;
  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);
  }

  /*
    Enable GPIO2 clock
  */
  cm_per = ioremap(CM_PER_START_ADDR, CM_PER_SIZE);
  if(!cm_per) {
    printk (KERN_ERR "HI: ERROR: Failed to remap memory for CM_PER.\n");
    return 0;
  }
  iowrite32(0x02, cm_per + CM_PER_GPIO2_CLKCTRL);
  iounmap(cm_per);

  /**
   * 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);

【讨论】:

    猜你喜欢
    • 2014-12-23
    • 1970-01-01
    • 2015-11-05
    • 1970-01-01
    • 2014-12-15
    • 2016-02-19
    • 1970-01-01
    • 1970-01-01
    • 2020-11-25
    相关资源
    最近更新 更多