Showing results for 
Search instead for 
Did you mean: 
New Contributor III

Configuring GPIO in a Linux module. Debouncing and pullup.

I want to connect a button to a GPIO.

I can initialize a GPIO pin using mraa from the user space. Essentially, it writes some values into the files in /sys/class/gpio.

But I prefer to run a kernel module that initializes the GPIO for the button and processes an interrupt when the button is clicked.

I created a sample module. Here is an excerpt:

//GPIO 46

static unsigned int gpioButton = 46;

// Set up the GPIO button

gpio_request(gpioButton, "sysfs");

// Set the button GPIO to be an input


// Debounce the button with a delay of 1000ms

gpio_set_debounce(gpioButton, 1000);

// Causes GPIO 46 to appear in /sys/class/gpio

gpio_export(gpioButton, false);

I tried to change the debounce time to 10000, 100000.

But debouncing doesn't work. The system still detects secondary clicks.

Does Edison support debouncing?

I'm supposed to define pullups using pinctrl, but I haven't got to that part.

I think a DTS file must be defined somehow which initializes all pins.

Tags (1)
0 Kudos
4 Replies

Hi Vincenze,

Is that the entire code you are using?

Could you post how are you loading it as a kernel module? Or are you just running the code in the board?

Is your goal to accomplish something like the example in the Arduino IDE Digital > Debounce?

In mraa, I haven't seen functions to work with Debouncing but if you want to do something like the example I mentioned you can modify the library and include this feature or you can create your code and add all the timing routines required for this.



New Contributor III

Hello, Charlie,

Essentially, I want to know:

1. Does Edison has built-in hardware debouncing support? Some Atmel chips do.

2. How to set the pullup state of a GPIO pin from a Linux module?

3. Is there a simple way of configuring all pins: direction, pullmode, pinmux, etc without writing into /sys/class/gpio? For example, with the help of Device Tree FDTWiki

Edison creates a file in sysfs indicating that it supports debouncing. But I don't see any difference if I enable or disable it.

cat /sys/kernel/debug/gpio_debug/gpio46/current_debounce


Here is the full code of the test module.

I load it using this command:

insmod /lib/modules/3.10.17-yocto-standard/extra/hello.ko

I created a kernel module with a software debouncer and it works. But a built-in solution would be better.

# include

# include

# include

# include // Required for the GPIO functions

# include // Required for the IRQ code



MODULE_DESCRIPTION("A Button test driver");


static unsigned int gpioButton = 46; ///< hard coding the button gpio for this example to P9_27 (GPIO115)

static unsigned int irqNumber; ///< Used to share the IRQ number within this file

static unsigned int numberPresses = 0; ///< For information, store the number of button presses

/// Function prototype for the custom IRQ handler function -- see below for the implementation

static irq_handler_t test_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs);

/** @brief The LKM initialization function

* The static keyword restricts the visibility of the function to within this C file. The __init

* macro means that for a built-in driver (not a LKM) the function is only used at initialization

* time and that it can be discarded and its memory freed up after that point. In this example this

* function sets up the GPIOs and the IRQ

* @return returns 0 if successful


static int __init test_init(void){

int result = 0;

printk(KERN_INFO "GPIO_TEST: Initializing the GPIO_TEST\n");

gpio_request(gpioButton, "sysfs"); // Set up the gpioButton

gpio_direction_input(gpioButton); // Set the button GPIO to be an input

gpio_set_debounce(gpioButton, 1000); // Debounce the button with a delay of 1000ms

gpio_export(gpioButton, false); // Causes gpio 46 to appear in /sys/class/gpio

// the bool argument prevents the direction from being changed

// Perform a quick test to see that the button is working as expected on LKM load

printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpioButton));

// GPIO numbers and IRQ numbers are not the same! This function performs the mapping for us

irqNumber = gpio_to_irq(gpioButton);

printk(KERN_INFO "GPIO_TEST: The button is mapped to IRQ: %d\n", irqNumber);

// This next call requests an interrupt line

result = request_irq(irqNumber, // The interrupt number requested

(irq_handler_t) test_irq_handler, // The pointer to the handler function below

IRQF_TRIGGER_FALLING, // Interrupt on rising edge (button press, not release)

"ebb_gpio_handler", // Used in /proc/interrupts to identify the owner

NULL); // The *dev_id for shared interrupt lines, NULL is okay

printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", result);

return result;


/** @brief The LKM cleanup function

* Similar to the initialization function, it is static. The __exit macro notifies that if this

* code is used for a built-in driver (not a LKM) that this function is not required. Used to release the

* GPIOs and display cleanup messages.


static void __exit test_exit(void){

printk(KERN_INFO "GPIO_TEST: The button state is currently: %d\n", gpio_get_value(gpioButton));

printk(KERN_INFO "GPIO_TEST: The button was pressed %d times\n", numberPresses);

free_irq(irqNumber, NULL); // Free the IRQ number, no *dev_id required in this case

gpio_unexport(gpioButton); // Unexport the Button GPIO

gpio_free(gpioButton); // Free the Button GPIO

printk(KERN_INFO "GPIO_TEST: Goodbye!\n");


/** @brief The GPIO IRQ Handler function

* This function is a custom interrupt handler that is attached to the GPIO above. The same interrupt

* handler cannot be invoked concurrently as the interrupt line is masked out until the function is complete.

* This function is static as it should not be invoked directly from outside of this file.

* @param irq the IRQ number that is associated with the GPIO -- useful for logging.

* @param dev_id the *dev_id that is provided -- can be used to identify which device caused the interrupt

* Not used in this example as NULL is passed.

* @param regs h/w specific register values -- only really ever used for debugging.

* return returns IRQ_HANDLED if successful -- should return IRQ_NONE otherwise.


static irq_handler_t test_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs){

printk(KERN_INFO "GPIO_TEST: Interrupt! (button state is %d)\n", gpio_get_value(gpioButton));

numberPresses++; // Global counter, will be outputted when the module is unloaded

return (irq_handler_t) IRQ_HANDLED; // Announce that the IRQ has been handled correctly


/// This next calls are mandatory -- they identify the initialization function

/// and the cleanup function (as above).




Hi Vincenze,

In order to set the pull-up state of a GPIO from Linux side I suggest you to take a look at the Hardware Guide for the Edison with the Arduino Expansion Board. About the debouncing mode, I will investigate about it and I will let you know as soon as I get more information.




Hi Vincenze,

The Edison does not support debouncing, but there are some workarounds using debouncing switches, circuits or via software like the Arduino example I mentioned above ( Arduino - Debounce)

About a simple way of setting the properties for the GPIOs, there is no simple way to configure all pins, however you can create a script/program to set all the desired pin configurations.