3

Я пытаюсь работать с прерываниями, но из-за ioread32 возникает следующая ошибка.BeagleBone Черные прерывания через драйвер ядра

Как я видел в главе «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); 

Любая идея? Спасибо

+0

Что вы хотите сказать? –

+0

Почему ioread32 не работает –

ответ

3

Проблема была в том, что часы модуля GPIO2 были отключены.

"8.1.12.1.30 CM_PER_GPIO2_CLKCTRL регистра (смещение = B0h) [сброс = 30000h]" из "AM335x SitaraTM процессоров - Техническое Справочное руководство"

Биты 1-0: Контроль пути обязательные часы управляются , 0x0 = ОТКЛЮЧЕНО: модуль отключен SW. Любой доступ OCP к модулю приводит к ошибке, за исключением случаев, вызванных пробуждением модуля (асинхронное пробуждение). 0x1 = RESERVED_1: Зарезервировано 0x2 = ENABLE: модуль явно включен. Интерфейсные часы (если они не используются для функций) могут быть установлены в соответствии с состоянием домена часов. Функциональные часы гарантируют сохранение присутствия. До тех пор, пока в этой конфигурации переход на сон владения домена не может произойти. 0x3 = RESERVED: Зарезервировано

0

Для приведенного выше кода для работы, часы 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);