Ich habe es getan, indem ich die Sekunden anstatt der Zeit überprüft habe. Ich denke, auf diese Weise entsteht weniger Aufwand. Ich versuche jedoch immer noch, den Entprellungsalgorithmus zu verbessern, da ich damit nicht ganz zufrieden bin: Es gibt immer noch Bounces, obwohl sie weniger häufig sind als zuvor.
#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;
}
Ich habe es geschafft, den Entprellungsalgorithmus weiter zu verfeinern. Ich löse jetzt den Interrupt aus, wenn die Leitung LOW erreicht, anstatt die Flanke zu fallen. Im Interrupt-Handler ändere ich dann den Interrupt so, dass er beim nächsten Mal auf HIGH, dann auf LOW und so weiter ausgelöst wird. Dies in Kombination mit der Jiffies-Methode von oben reduziert die Bounces erheblich.
Ich denke, es ist das Beste, was man mit Software erreichen kann. Für weitere Verbesserungen denke ich, dass dies tatsächlich in der Hardware gemacht werden muss. Wenn ich Zeit habe, versuche ich es mit einem Kondensator und ähnlichen Dingen.
Der vollständige Code unten:
#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");