Tôi đã làm điều đó bằng cách kiểm tra các jiffies thay vì thời gian. Tôi nghĩ rằng có ít chi phí theo cách này. Tuy nhiên, tôi vẫn đang tìm cách cải thiện thuật toán gỡ lỗi vì tôi không hoàn toàn hài lòng với nó: vẫn có những lần thoát mặc dù chúng ít thường xuyên hơn trước.
#include <linux/jiffies.h>
extern unsigned long volatile jiffies;
static irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs) {
static unsigned long old_jiffie = 0;
unsigned long diff = jiffies - old_jiffie;
if (diff < 20)
{
return IRQ_HANDLED;
}
printk(KERN_NOTICE "Interrupt [%d] for device %s was triggered, jiffies=%lu, diff=%lu, direction: %d \n",
irq, (char *) dev_id, jiffies, diff, gpio_get_value(GPIO_BUTTON1));
old_jiffie = jiffies;
return IRQ_HANDLED;
}
Tôi đã quản lý để tinh chỉnh thêm thuật toán gỡ lỗi. Bây giờ tôi kích hoạt ngắt khi dòng đạt đến THẤP thay vì cạnh giảm. Sau đó, trong trình xử lý ngắt, sau đó tôi thay đổi ngắt để kích hoạt ở mức CAO vào lần tới, sau đó ở mức THẤP và cứ thế. Điều này kết hợp với phương pháp jiffies từ trên làm giảm đáng kể các lần thoát.
Tôi nghĩ đó là thứ tốt nhất có thể đạt được trong phần mềm. Để cải thiện hơn nữa tôi nghĩ rằng điều này phải được thực hiện trong phần cứng, thực sự. Khi tôi có thời gian tôi sẽ thử với một tụ điện và những thứ như thế này.
Mã đầy đủ dưới đây:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/jiffies.h>
#define DRIVER_AUTHOR ""
#define DRIVER_DESC "Button pad"
extern unsigned long volatile jiffies;
struct _Button
{
unsigned gpio;
int irq;
const char* description;
char last_value;
};
typedef struct _Button Button;
// we want GPIO's 17,27,22 (pin 11,13,15 on P5 pinout raspberry pi rev. 2 board) to generate interrupt
Button button1 = {17, 0, "Gpio for button 1", 1 };
Button button2 = {27, 0, "Gpio for button 2", 1 };
Button button3 = {22, 0, "Gpio for button 3", 1 };
/****************************************************************************/
/* IRQ handler - fired on interrupt */
/****************************************************************************/
static irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
Button* button = (Button*) dev_id;
char value = gpio_get_value(button->gpio);
if (value == button->last_value)
return IRQ_HANDLED;
if (0 == value)
{
static unsigned long old_jiffie = 0;
unsigned long diff = jiffies - old_jiffie;
if (diff < 23)
{
button->last_value = value;
irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
// old_jiffie = jiffies;
return IRQ_HANDLED;
}
printk(KERN_NOTICE "Interrupt [%d] for device %s was triggered, jiffies=%lu, diff=%lu, direction: %d \n",
irq, button->description, jiffies, diff, value);
irq_set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH);
old_jiffie = jiffies;
}
else
{
irq_set_irq_type(irq, IRQ_TYPE_LEVEL_LOW);
}
button->last_value = value;
return IRQ_HANDLED;
}
/****************************************************************************/
/* This function configures interrupts. */
/****************************************************************************/
void int_config(Button* button)
{
if (!button || gpio_request(button->gpio, button->description)) {
printk("GPIO request faiure: %s\n", button->description);
return;
}
gpio_direction_input(button->gpio);
if ( (button->irq = gpio_to_irq(button->gpio)) < 0 ) {
printk("GPIO to IRQ mapping faiure %s\n", button->description);
return;
}
printk(KERN_NOTICE "Mapped int %d\n", button->irq);
if (request_irq(button->irq,
(irq_handler_t ) irq_handler,
IRQF_TRIGGER_LOW,
button->description,
button)) {
printk("Irq Request failure\n");
return;
}
return;
}
/****************************************************************************/
/* This function releases interrupts. */
/****************************************************************************/
void int_release(Button* button) {
free_irq(button->irq, button);
gpio_free(button->gpio);
return;
}
int init_module(void)
{
printk(KERN_INFO "init_module() called\n");
int_config(&button1);
int_config(&button2);
int_config(&button3);
return 0;
}
void cleanup_module(void)
{
printk(KERN_INFO "cleanup_module() called\n");
int_release(&button1);
int_release(&button2);
int_release(&button3);
}
/****************************************************************************/
/* Module licensing/description block. */
/****************************************************************************/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("");
MODULE_DESCRIPTION("Driver for RaspeberryPi's GPIO");