Перейти к содержанию
    

Проблема опроса матрицы кнопок

Помогите, пожалуйста с проблемой очень начинающему "программисту"!

 

К отладочной плате SK-AT91SAM9G45-XC6SLX_V1B с установленным на нее Linux kernel, подключена матрица кнопок с подтяжкой к питанию. Написал модуль линукса, чтобы он мне в устройстве "\dev\Keys" показывал какая кнопка нажата. Линии матрицы я подвязал к прерываниям, а столбцы к нулям. При нажатии на кнопку, модуль по отрицательному фронту запускает прерывание и начинает сканировать все кнопки, создавая еще прерывания и так, пока не выдаст ошибку или пока не отпустить кнопку.

Как сделать так, чтобы прерывания не вызывались во время выполнения функции прерывания??

 

Флаги все перебрал, disable_irq вообще не вариант((

 

Ошибка в командной строке появляется после нажатия на кнопку более секунды!

 

#irq 88: nobody cared (try booting with the "irqpoll" option)

[<c002f584>] (unwind_backtrace+0x0/0xf4) from [<c0066dc8>] (__report_bad_irq+0x74/0xa4)

[<c0066dc8>] (__report_bad_irq+0x74/0xa4) from [<c0066f7c>] (note_interrupt+0x184/0x1f4)

[<c0066f7c>] (note_interrupt+0x184/0x1f4) from [<c00678a0>] (handle_simple_irq+0x7c/0x94)

[<c00678a0>] (handle_simple_irq+0x7c/0x94) from [<c0033448>] (gpio_irq_handler+0xb8/0xdc)

[<c0033448>] (gpio_irq_handler+0xb8/0xdc) from [<c0029044>] (asm_do_IRQ+0x44/0xa4)

[<c0029044>] (asm_do_IRQ+0x44/0xa4) from [<c0029ad4>] (__irq_svc+0x34/0x60)

Exception stack(0xc042df70 to 0xc042dfb8)

df60: 00000000 0005317f 0005217f 60000013

df80: c042c000 c04526e8 c042fb88 c042fb80 70022f5c 41069265 70022f28 00000000

dfa0: 600000d3 c042dfb8 c002b52c c002b538 60000013 ffffffff

[<c0029ad4>] (__irq_svc+0x34/0x60) from [<c002b538>] (default_idle+0x2c/0x34)

[<c002b538>] (default_idle+0x2c/0x34) from [<c002b3c0>] (cpu_idle+0x6c/0xa4)

[<c002b3c0>] (cpu_idle+0x6c/0xa4) from [<c03150e0>] (rest_init+0xc8/0x120)

[<c03150e0>] (rest_init+0xc8/0x120) from [<c0008e60>] (start_kernel+0x414/0x5ac)

[<c0008e60>] (start_kernel+0x414/0x5ac) from [<70008034>] (0x70008034)

handlers:

[<c01fef60>] (my_interrupt+0x0/0x22c)

Disabling IRQ #88

 

После одной ошибки на линии прерывания он больше не выполняет прерывание по фронтам, а делает прерывание самостоятельно через какое-то время. А в столбце "CPU0" в таблице "#cat /dev/interrupts" ничего не меняется!

 

Пробовал даже переназначать порты input на output (а output на input) в цикле опроса, чтобы прерываний не происходило, но и это не помогло((

 

 

 

#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <asm/uaccess.h>

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

#include <mach/gpio.h>

#include <asm-generic/gpio.h>
#include <mach/at91_pio.h>
#include <asm/gpio.h>

static int my_dev_id;
int bline[6];
unsigned long save_key = 0;


const char button_name[30][15] = {
{"Button Clear\n"},{"Left line 1\n"},{"Left line 2\n"},{"Left line 3\n"},{"Left line 4\n"},{"Return\n"},\
{"Escape\n"},{"Right line 1\n"},{"Right line 2\n"},{"Right line 3\n"},{"Right line 4\n"},{"Down\n"},\
{"Up\n"},{"Bk Sp\n"},{"Enter\n"},{"7\n"},{"4\n"},{"1\n"},{"0\n"},{"F1\n"},{"8\n"},\
{"5\n"},{"2\n"},{".\n"},{"F2\n"},{"9\n"},{"6\n"},{"3\n"},{"+/-\n"},{"F3\n"}};


char * str_word (void)
{
unsigned int count;
for (count = 29; count>=1; count--) if (save_key&(0x1<<count)) break;
return &button_name[count];
}


static ssize_t hello_read(struct file * file, char * buf, 
              size_t count, loff_t *ppos)
{
    char *hello_str = str_word ();
    int len; 

    len = strlen(hello_str); 
    if (count < len)    return -EINVAL;
    if (*ppos != 0)    return 0;
    if (copy_to_user(buf, hello_str, len))    return -EINVAL;
    *ppos = len;
    return len;
}

static irqreturn_t my_interrupt (int irq, void *dev_id) {

unsigned char line;
unsigned long key = 0;


at91_set_gpio_output(AT91_PIN_PB6, 1);    
at91_set_gpio_output(AT91_PIN_PB7, 1);    
at91_set_gpio_output(AT91_PIN_PB8, 1);    
at91_set_gpio_output(AT91_PIN_PB9, 1);    
at91_set_gpio_output(AT91_PIN_PB10, 1);    

key = 0;
for (line =1; line<=5; line++) {

if (line == 5) at91_set_gpio_output(AT91_PIN_PB6, 0);
if (line == 4) at91_set_gpio_output(AT91_PIN_PB7, 0);
if (line == 3) at91_set_gpio_output(AT91_PIN_PB8, 0);
if (line == 2) at91_set_gpio_output(AT91_PIN_PB9, 0);
if (line == 1) at91_set_gpio_output(AT91_PIN_PB10, 0);

key <<= 6;

if (!at91_get_gpio_value(AT91_PIN_PB26)) key |= (0x1<<6);
if (!at91_get_gpio_value(AT91_PIN_PB25)) key |= (0x1<<5);
if (!at91_get_gpio_value(AT91_PIN_PB24)) key |= (0x1<<4);
if (!at91_get_gpio_value(AT91_PIN_PB23)) key |= (0x1<<3);
if (!at91_get_gpio_value(AT91_PIN_PB22)) key |= (0x1<<2);
if (!at91_get_gpio_value(AT91_PIN_PB28)) key |= (0x1<<1);

if (line == 5) at91_set_gpio_output(AT91_PIN_PB6, 1);
if (line == 4) at91_set_gpio_output(AT91_PIN_PB7, 1);
if (line == 3) at91_set_gpio_output(AT91_PIN_PB8, 1);
if (line == 2) at91_set_gpio_output(AT91_PIN_PB9, 1);
if (line == 1) at91_set_gpio_output(AT91_PIN_PB10, 1);

}

if (key==0) save_key |= 0x1;
else save_key = key;



at91_set_gpio_output(AT91_PIN_PB6, 0);    
at91_set_gpio_output(AT91_PIN_PB7, 0);    
at91_set_gpio_output(AT91_PIN_PB8, 0);    
at91_set_gpio_output(AT91_PIN_PB9, 0);    
at91_set_gpio_output(AT91_PIN_PB10, 0);    


return IRQ_NONE;
} 


static const struct file_operations hello_fops = {
    .owner        = THIS_MODULE,
    .read        = hello_read,
};

static struct miscdevice hello_dev = {
    MISC_DYNAMIC_MINOR,
    "Key",
    &hello_fops
};


static int __init my_init ( void){

unsigned long irqflags;
printk(KERN_INFO "My_init\n");
at91_set_gpio_output(AT91_PIN_PB6, 0);    
at91_set_gpio_output(AT91_PIN_PB7, 0);    
at91_set_gpio_output(AT91_PIN_PB8, 0);    
at91_set_gpio_output(AT91_PIN_PB9, 0);    
at91_set_gpio_output(AT91_PIN_PB10, 0);    

at91_set_gpio_input(AT91_PIN_PB22, 1);
at91_set_gpio_input(AT91_PIN_PB23, 1);
at91_set_gpio_input(AT91_PIN_PB24, 1);
at91_set_gpio_input(AT91_PIN_PB25, 1);
at91_set_gpio_input(AT91_PIN_PB26, 1);
at91_set_gpio_input(AT91_PIN_PB28, 1);


bline[0] = gpio_to_irq(AT91_PIN_PB22);
    if (bline[0] < 0) {printk(KERN_INFO "\n\nError_button_22_irq!!\n\n");}
bline[1] = gpio_to_irq(AT91_PIN_PB23);
    if (bline[1] < 0) {printk(KERN_INFO "\n\nError_button_23_irq!!\n\n");}
bline[2] = gpio_to_irq(AT91_PIN_PB24);
    if (bline[2] < 0) {printk(KERN_INFO "\n\nError_button_24_irq!!\n\n");}
bline[3] = gpio_to_irq(AT91_PIN_PB25);
    if (bline[3] < 0) {printk(KERN_INFO "\n\nError_button_25_irq!!\n\n");}
bline[4] = gpio_to_irq(AT91_PIN_PB26);
    if (bline[4] < 0) {printk(KERN_INFO "\n\nError_button_26_irq!!\n\n");}
bline[5] = gpio_to_irq(AT91_PIN_PB28);
    if (bline[5] < 0) {printk(KERN_INFO "\n\nError_button_28_irq!!\n\n");}

irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_SHARED;

if (request_irq( bline[0], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[1], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[2], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[3], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[4], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;
if (request_irq( bline[5], my_interrupt, irqflags, "my_interrupt", &my_dev_id) ) return -1;

    if (misc_register(&hello_dev)) printk(KERN_ERR   "Error\n");

printk( KERN_INFO "Siccessfully loading ISR handler on IRQ %d\n", irqq );
return 0;
}

static void __exit my_exit(void) {
int x;
for (x=0; x<=5; x++) synchronize_irq (bline[x]);
for (x=0; x<=5; x++) free_irq(bline[x], &my_dev_id);

printk(KERN_INFO "Successfully unloading, irq_counter = %d\n", irq_counter);
}
module_init(my_init);
module_exit(my_exit);
MODULE_AUTHOR("My_copy_internet");
MODULE_DESCRIPTION("LDD:1.0 s_08/lab1_interrupt.c");
MODULE_LICENSE( "GPL v2");

gpio_keys.txt

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Помогите, пожалуйста с проблемой очень начинающему "программисту"!

 

http://lxr.free-electrons.com/source/drive...rix_keypad.c#L2

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Доброго времени суток.

Сразу вопрос: почему возникла надобность писать свой модуль? Можно ведь воспользоватся готовым - для этого необходимо установить опцию в ядре CONFIG_KEYBOARD_MATRIX и описать в платформе или DTS как подключены кнопки.

 

update:

sasamy опередил :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сразу вопрос: почему возникла надобность писать свой модуль? Можно ведь воспользоватся готовым - для этого необходимо установить опцию в ядре CONFIG_KEYBOARD_MATRIX и описать в платформе или DTS как подключены кнопки.

 

У меня случайно даже пример есть как подключить на неиспользуемом ISI матрицу 4х4 :)

arch/arm/mach-at91/board-sam9m10g45ek.c

...
#include <linux/input/matrix_keypad.h>
...

/*
* GPIO keyboard
*/
#if defined(CONFIG_KEYBOARD_MATRIX) || defined(CONFIG_KEYBOARD_MATRIX_MODULE)
static const uint32_t ek_keymap[] = {
/* KEY(row, col, keycode) */
KEY(0, 0, KEY_0),
KEY(0, 1, KEY_1),
KEY(0, 2, KEY_2),
KEY(0, 3, KEY_3),

KEY(1, 0, KEY_4),
KEY(1, 1, KEY_5),
KEY(1, 2, KEY_6),
KEY(1, 3, KEY_7),

KEY(2, 0, KEY_8),
KEY(2, 1, KEY_9),
KEY(2, 2, KEY_COMMA),
KEY(2, 3, KEY_ESC),
KEY(3, 0, KEY_E),
KEY(3, 1, KEY_UP),
KEY(3, 2, KEY_ENTER),
KEY(3, 3, KEY_DOWN),
};

static const struct matrix_keymap_data ek_keymap_data = {
.keymap		= ek_keymap,
.keymap_size	= ARRAY_SIZE(ek_keymap),
};

static const uint32_t ek_row_gpios[] =
{
  AT91_PIN_PB21,
  AT91_PIN_PB22,
  AT91_PIN_PB24,
  AT91_PIN_PB26
};

static const uint32_t ek_col_gpios[] =
{
  AT91_PIN_PB28,
  AT91_PIN_PB23,
  AT91_PIN_PB25,
  AT91_PIN_PB27
};

static struct matrix_keypad_platform_data ek_mkp_pdata = {
.keymap_data		= &ek_keymap_data,
.row_gpios		= ek_row_gpios,
.col_gpios		= ek_col_gpios,
.num_row_gpios		= ARRAY_SIZE(ek_row_gpios),
.num_col_gpios		= ARRAY_SIZE(ek_col_gpios),
.col_scan_delay_us	= 10,
.debounce_ms		= 10,
.wakeup			= 1,
.active_low		= 1,
};

static struct platform_device ek_mkp_device = {
.name		= "matrix-keypad",
.id		= -1,
.dev		= {
	.platform_data	= &ek_mkp_pdata,
},
};

static void __init ek_add_device_mkp(void)
{
int i;

for (i = 0; i < ARRAY_SIZE(ek_row_gpios); i++) {
	at91_set_GPIO_periph(ek_row_gpios[i], 1);
	at91_set_deglitch(ek_row_gpios[i], 1);
}

for (i = 0; i < ARRAY_SIZE(ek_col_gpios); i++)
	at91_set_gpio_output(ek_col_gpios[i], 0);

platform_device_register(&ek_mkp_device);	

}
#else
static void __init ek_add_device_mkp(void) {}
#endif
.....
static void __init ek_board_init(void)
{
....
/* GPIO keyboard */
ek_add_device_mkp();
....

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Сразу вопрос: почему возникла надобность писать свой модуль? Можно ведь воспользоватся готовым - для этого необходимо установить опцию в ядре CONFIG_KEYBOARD_MATRIX и описать в платформе или DTS как подключены кнопки.

 

Просто, для изучения ОС писал простой модуль опроса матрицы и наткнулся на ошибку в прерываниях, как избавиться от нее я не понял.. Ну, буду тогда использовать Linux/drivers/input/keyboard/matrix_keypad.c

 

sasamy, спасибо за пример!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А кто-нибудь может подсказать, как вывести консоль на дисплей (/dev/tty1), используя клавиатуру матрицы кнопок с драйвером "Linux/drivers/input/keyboard/matrix_keypad.c"???

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А кто-нибудь может подсказать, как вывести консоль на дисплей (/dev/tty1), используя клавиатуру матрицы кнопок с драйвером "Linux/drivers/input/keyboard/matrix_keypad.c"???

 

Я помню только принцип, т.к. в последний раз с год назад возился.

Все мыши и клавиатуры определены как класс input:

/dev/input/

by-id event0 event10 event12 event3 event5 event7 event9 mouse0

by-path event1 event11 event2 event4 event6 event8 mice

 

Точнее вам надо, чтобы устройство возникло здесь:

/sys/class/input/

а в /dev/input/ оно попадет автоматически.

 

Для каждого eventX можно посмотреть к какому устройству он принадлежит

cat /sys/class/input/event0/device/name

 

Надо написать еще один драйвер, взаимодействующий с тем, что читает кнопки, либо модифицировать ваш, чтобы он попал в input. В документации ядра есть информация, а также куча примеров в самом ядре. Остальное делается в пользовательском пространстве.

Я делал только для Х11, но уверен, что и для остального это совсем не сложно.

Изменено пользователем Tarbal

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А кто-нибудь может подсказать, как вывести консоль на дисплей (/dev/tty1), используя клавиатуру матрицы кнопок с драйвером "Linux/drivers/input/keyboard/matrix_keypad.c"???

 

Если корневая собрана в buildroot или вообще стандартный init, то добавить в /etc/inittab строку (если ее нет)

tty1::respawn:/sbin/getty 38400 tty1 linux

 

матричная клавиатура - стандартное устройство ввода, ничего дополнительно для нее не нужно, разве что включить в ядре интерфейс, если не включен

http://lxr.free-electrons.com/source/drive...ut/Kconfig#L142

 

 

Изменено пользователем sasamy

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Точно. В кернеле ничего делать не надо.

http://lxr.free-electrons.com/source/drive...rix_keypad.c#L2

драйвер оперирует с устройством input_dev.

 

 

Значит вы сможете увидеть, что устройство появилось в системе прочитав имя в одном из

/sys/class/input/event0/device/name

она совпадет с заданным в строке 567 файла:

http://lxr.free-electrons.com/source/drive...rix_keypad.c#L2

.name = "matrix-keypad",

Изменено пользователем Tarbal

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...