Give this a go. I also added P0.26 as an interrupt instead of polling.
Updated Device Tree (same as before)
/ {
gpio_test {
compatible = "gpio-keys";
// Input pin with interrupt capability
input_pin_26: input_pin_26 {
gpios = <&gpio0 26 GPIO_ACTIVE_HIGH>;
label = "Input Pin 26";
};
// Other input pins (polling)
input_pin_27: input_pin_27 {
gpios = <&gpio0 27 GPIO_ACTIVE_HIGH>;
label = "Input Pin 27";
};
input_pin_28: input_pin_28 {
gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>;
label = "Input Pin 28";
};
input_pin_29: input_pin_29 {
gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>;
label = "Input Pin 29";
};
// Output pin for testing
output_pin_30: output_pin_30 {
gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>;
label = "Output Pin 30";
};
};
};
Updated C Code with Interrupt Support
#include <zephyr/drivers/gpio.h>
#include <zephyr/device.h>
#include <zephyr/kernel.h>
// GPIO specifications
static const struct gpio_dt_spec input_gpio_26 = GPIO_DT_SPEC_GET(DT_NODELABEL(input_pin_26), gpios);
static const struct gpio_dt_spec input_gpio_27 = GPIO_DT_SPEC_GET(DT_NODELABEL(input_pin_27), gpios);
static const struct gpio_dt_spec input_gpio_28 = GPIO_DT_SPEC_GET(DT_NODELABEL(input_pin_28), gpios);
static const struct gpio_dt_spec input_gpio_29 = GPIO_DT_SPEC_GET(DT_NODELABEL(input_pin_29), gpios);
static const struct gpio_dt_spec output_gpio_30 = GPIO_DT_SPEC_GET(DT_NODELABEL(output_pin_30), gpios);
// Interrupt callback data structure
static struct gpio_callback button_cb_data;
// Counter for interrupt events
static volatile uint32_t interrupt_count = 0;
static volatile int last_pin_state = -1;
// Interrupt callback function
void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
// Read the current state of the pin
int current_state = gpio_pin_get_dt(&input_gpio_26);
interrupt_count++;
last_pin_state = current_state;
printk("[INTERRUPT %d] P0.26 changed to: %d (Pin mask: 0x%08X)\n",
interrupt_count, current_state, pins);
}
int main(void)
{
int ret;
// Check if all GPIO devices are ready
if (!gpio_is_ready_dt(&input_gpio_26) ||
!gpio_is_ready_dt(&input_gpio_27) ||
!gpio_is_ready_dt(&input_gpio_28) ||
!gpio_is_ready_dt(&input_gpio_29) ||
!gpio_is_ready_dt(&output_gpio_30)) {
printk("Error: One or more GPIO devices are not ready\n");
return -1;
}
// Configure P0.26 as input with interrupt capability
ret = gpio_pin_configure_dt(&input_gpio_26, GPIO_INPUT);
if (ret < 0) {
printk("Error %d: failed to configure P0.26 as input\n", ret);
return ret;
}
// Configure interrupt on P0.26 for both rising and falling edges
ret = gpio_pin_interrupt_configure_dt(&input_gpio_26, GPIO_INT_EDGE_BOTH);
if (ret < 0) {
printk("Error %d: failed to configure interrupt on P0.26\n", ret);
return ret;
}
// Initialize and add the callback
gpio_init_callback(&button_cb_data, button_pressed, BIT(input_gpio_26.pin));
ret = gpio_add_callback(input_gpio_26.port, &button_cb_data);
if (ret < 0) {
printk("Error %d: failed to add callback\n", ret);
return ret;
}
// Configure other input pins (polling mode)
ret = gpio_pin_configure_dt(&input_gpio_27, GPIO_INPUT);
if (ret < 0) {
printk("Error %d: failed to configure P0.27 as input\n", ret);
return ret;
}
ret = gpio_pin_configure_dt(&input_gpio_28, GPIO_INPUT);
if (ret < 0) {
printk("Error %d: failed to configure P0.28 as input\n", ret);
return ret;
}
ret = gpio_pin_configure_dt(&input_gpio_29, GPIO_INPUT);
if (ret < 0) {
printk("Error %d: failed to configure P0.29 as input\n", ret);
return ret;
}
// Configure output pin
ret = gpio_pin_configure_dt(&output_gpio_30, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
printk("Error %d: failed to configure P0.30 as output\n", ret);
return ret;
}
printk("GPIO configuration complete!\n");
printk("P0.26: Input with interrupt (both edges)\n");
printk("P0.27-29: Input with polling\n");
printk("P0.30: Output for testing\n");
printk("Connect P0.30 to P0.26 to test interrupts\n");
printk("========================================\n");
bool output_state = false;
uint32_t loop_count = 0;
while (1) {
// Toggle output pin
gpio_pin_set_dt(&output_gpio_30, output_state);
// Read polling inputs (P0.27-29)
int pin_27_state = gpio_pin_get_dt(&input_gpio_27);
int pin_28_state = gpio_pin_get_dt(&input_gpio_28);
int pin_29_state = gpio_pin_get_dt(&input_gpio_29);
// Read interrupt pin for comparison
int pin_26_current = gpio_pin_get_dt(&input_gpio_26);
loop_count++;
printk("[POLL %d] P0.30: %d | P0.26: %d | P0.27: %d | P0.28: %d | P0.29: %d | IRQ Count: %d\n",
loop_count, output_state, pin_26_current, pin_27_state, pin_28_state, pin_29_state, interrupt_count);
// Toggle for next iteration
output_state = !output_state;
k_sleep(K_MSEC(2000));
}
return 0;
}
Key Changes for Interrupt Support:
1. Interrupt Configuration
// Configure interrupt on both rising and falling edges
ret = gpio_pin_interrupt_configure_dt(&input_gpio_26, GPIO_INT_EDGE_BOTH);
2. Callback Setup
// Initialize callback structure
gpio_init_callback(&button_cb_data, button_pressed, BIT(input_gpio_26.pin));
// Add callback to GPIO port
gpio_add_callback(input_gpio_26.port, &button_cb_data);
3. Interrupt Handler
void button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
// This function executes in interrupt context
int current_state = gpio_pin_get_dt(&input_gpio_26);
interrupt_count++;
printk("[INTERRUPT] P0.26 changed to: %d\n", current_state);
}
Interrupt Configuration Options:
You can configure different interrupt triggers:
// Rising edge only
gpio_pin_interrupt_configure_dt(&input_gpio_26, GPIO_INT_EDGE_RISING);
// Falling edge only
gpio_pin_interrupt_configure_dt(&input_gpio_26, GPIO_INT_EDGE_FALLING);
// Both edges (as used above)
gpio_pin_interrupt_configure_dt(&input_gpio_26, GPIO_INT_EDGE_BOTH);
// Level triggered (high)
gpio_pin_interrupt_configure_dt(&input_gpio_26, GPIO_INT_LEVEL_HIGH);
// Level triggered (low)
gpio_pin_interrupt_configure_dt(&input_gpio_26, GPIO_INT_LEVEL_LOW);
Expected Output:
When you connect P0.30 to P0.26, you should see:
[POLL 1] P0.30: 0 | P0.26: 0 | P0.27: 0 | P0.28: 0 | P0.29: 0 | IRQ Count: 0
[INTERRUPT 1] P0.26 changed to: 1 (Pin mask: 0x04000000)
[POLL 2] P0.30: 1 | P0.26: 1 | P0.27: 0 | P0.28: 0 | P0.29: 0 | IRQ Count: 1
[INTERRUPT 2] P0.26 changed to: 0 (Pin mask: 0x04000000)
[POLL 3] P0.30: 0 | P0.26: 0 | P0.27: 0 | P0.28: 0 | P0.29: 0 | IRQ Count: 2
Important Notes:
- Interrupt Context: The callback runs in interrupt context, so keep it short and avoid blocking operations. If you need to do further operations use something like a semaphore or kick of a worker task to complete
- Thread Safety: Use
volatile
for variables accessed in both interrupt and main contexts