Я пытаюсь работать с прерываниями, но получаю следующую ошибку из-за ioread32.
Как я видел в главе «25.3.3 Функции прерывания» в «Процессоры AM335x SitaraTM — Техническое справочное руководство»
Чтобы сгенерировать запрос прерывания на хост-процессор после определенного события (уровня или логического перехода), происходящего на выводе GPIO, регистры конфигурации GPIO должны быть запрограммированы следующим образом:
• Прерывания для канала GPIO должны быть включены в регистрах GPIO_IRQSTATUS_SET_0 и / или GPIO_IRQSTATUS_SET_1.
• Ожидаемые события на входе GPIO для запуска запроса прерывания должны быть выбраны в регистрах GPIO_LEVELDETECT0, GPIO_LEVELDETECT1, GPIO_RISINGDETECT и GPIO_FALLINGDETECT.
[ 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 были отключены.
«8.1.12.1.30 CM_PER_GPIO2_CLKCTRL Регистр (смещение = B0h) [сброс = 30000h]» из «Процессоры AM335x SitaraTM — Техническое справочное руководство»
Биты 1-0:
Контролировать способ управления обязательными часами.
0x0 = ОТКЛЮЧЕНО: модуль отключен ПО. Любой доступ OCP к модулю приводит к ошибке, за исключением случаев, когда это происходит из-за активации модуля (асинхронного включения).
0x1 = RESERVED_1: зарезервировано
0x2 = ENABLE: модуль явно включен. Часы интерфейса (если они не используются для функций) могут быть стробированы согласно состоянию домена часов. Функциональные часы гарантированно остаются на месте. Пока в этой конфигурации переход в спящий режим не может происходить.
0x3 = ЗАБРОНИРОВАНО: Зарезервировано
Чтобы приведенный выше код работал, часы GPIO2 должны быть включены с помощью регистра CM_PER_GPIO2_CLKCTRL а также вывод GPIO от GPIO2 должен быть выбран. В приведенном выше коде использовался 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);