Concepts First
- Interrupt (EXTI): like a doorbell — when the event happens, the chip stops what it is doing to respond, then resumes; no need to keep watching the pin (polling).
- Trigger mode: falling edge (high→low), rising edge (low→high), low level, or high level. A button grounded produces a falling edge.
- Interrupt callback: the system calls your registered function when triggered (this example prints
Interrupt Trigger!); keep it short.
Example Overview
This page is based on the gpio_interrupt example in the official Bouffalo SDK (examples/peripherals/gpio/gpio_interrupt), which demonstrates GPIO external interrupts (EXTI):
- The serial shell command
gpio_int_test <gpio> <mode>configures a pin as an interrupt input; - 4 trigger modes are supported:
0falling edge,1rising edge,2low level,3high level; - When the pin change meets the trigger condition, the interrupt callback runs and prints
Interrupt Trigger!. - Sibling examples (
examples/peripherals/gpio/):gpio_input_output(basic I/O),gpio_output_with_input(output with input),gpio_validation_cli(CLI validation).
Operation Steps
On all Ai-M6x boards the button is wired to GPIO2, so just use the onboard button; for an external button/jumper wire: one end to GPIO2, the other end to GND, to manually simulate level changes that trigger the interrupt.
Open a terminal and enter the GPIO interrupt example directory (prerequisite: set up the environment as in Quick Start (Linux) or Windows):
cd examples/peripherals/gpio/gpio_interruptRun the build command. The Ai-M62 (BL616) and Ai-M61 (BL618) belong to the same series, so both use bl616:
make CHIP=bl616 BOARD=bl616dkConnect the board with a USB cable, hold the BOOT button (IO2 on the Ai-M61-32S-Kit), briefly press EN/RST to enter download mode, then flash (replace the serial port with the one on your computer):
make flash CHIP=bl616 COMX=/dev/ttyUSB0Open a serial tool (baud rate 2000000). The example prints gpio interrupt at startup. Type gpio_int_test 2 0 and press Enter to configure GPIO2 (onboard button) for falling-edge interrupt, then press the button (or ground the jumper wire and release) — the serial port prints Interrupt Trigger!.
Code Execution Flow
The complete execution flow from startup to running is shown below (loop arrows mean repeated execution):
More trigger modes
Try gpio_int_test 2 1 (rising edge), gpio_int_test 2 2 (low level), or gpio_int_test 2 3 (high level); you can also use another pin, e.g. gpio_int_test 3 0 for GPIO3.
APIs Used by the Example
bflb_device_get_by_name("gpio")
Gets the GPIO device handle.
Parameters:
name: device name string, always"gpio"for GPIO
Return: struct bflb_device_s * device handle
bflb_gpio_init(gpio, pin, mode)
Configures a pin as input (for interrupts: GPIO_INPUT | GPIO_PULLUP | GPIO_SMT_EN).
Parameters:
gpio: GPIO device handlepin: pin number, e.g.GPIO_PIN_2(the button on Ai-M6x boards)mode: mode flags, e.g.GPIO_INPUTwithGPIO_PULLUP
Return: 0 on success; negative error code on failure
bflb_gpio_int_init(gpio, pin, mode)
Initializes the interrupt trigger mode of a pin.
Parameters:
gpio: GPIO device handlepin: pin numbermode: trigger mode,GPIO_INT_TRIG_MODE_SYNC_FALLING_EDGE/SYNC_RISING_EDGE/SYNC_LOW_LEVEL/SYNC_HIGH_LEVEL
Return: 0 on success; negative error code on failure
bflb_gpio_irq_attach(pin, isr)
Registers the interrupt callback for a pin; the system calls it when the interrupt fires.
Parameters:
pin: pin numberisr: callback function, e.g.void isr(uint8_t pin)
Return: none
bflb_irq_enable(irq_num)
Enables the peripheral interrupt. The example disables it first with bflb_irq_disable(gpio->irq_num) while configuring, then enables it.
Parameters:
irq_num: peripheral interrupt number,gpio->irq_numfor GPIO
Return: none
Complete Code
The complete source below matches the effect described on this page. It is based on the official example (examples/peripherals/gpio/gpio_interrupt); the LED pins are adapted to the Ai-M61/62-32S-Kit onboard RGB LED. Collapsed by default, click to expand:
📜 Click to expand gpio_interrupt/main.c full code
#include "bflb_gpio.h"
#include "bflb_mtimer.h"
#include "board.h"
#include "shell.h"
#include "bflb_uart.h"
struct bflb_device_s *gpio;
struct bflb_device_s *uart0;
static uint8_t gpio_int_pin = GPIO_PIN_2; /* button on Ai-M6x boards */
void gpio0_isr(uint8_t pin)
{
if (pin == gpio_int_pin) {
printf("Interrupt Trigger!\r\n");
}
}
int gpio_int_test(int argc, char **argv)
{
printf("Set gpio interrupt triggle mode\r\n");
if ((argc != 3) || (atoi(argv[1]) >= GPIO_PIN_MAX) || (atoi(argv[2]) > 3)) {
printf("Usage: gpio_int_test <gpio> <mode>\r\n"
" 0: GPIO_INT_TRIG_MODE_SYNC_FALLING_EDGE\r\n"
" 1: GPIO_INT_TRIG_MODE_SYNC_RISING_EDGE\r\n"
" 2: GPIO_INT_TRIG_MODE_SYNC_LOW_LEVEL\r\n"
" 3: GPIO_INT_TRIG_MODE_SYNC_HIGH_LEVEL\r\n");
return 1;
}
printf("Set gpio%d interrupt triggle mode to %d\r\n", atoi(argv[1]), atoi(argv[2]));
bflb_irq_disable(gpio->irq_num);
gpio_int_pin = atoi(argv[1]);
bflb_gpio_init(gpio, atoi(argv[1]), GPIO_INPUT | GPIO_PULLUP | GPIO_SMT_EN);
bflb_gpio_int_init(gpio, atoi(argv[1]), atoi(argv[2]));
bflb_gpio_irq_attach(atoi(argv[1]), gpio0_isr);
bflb_irq_enable(gpio->irq_num);
return 0;
}
int main(void)
{
int ch;
board_init();
gpio = bflb_device_get_by_name("gpio");
uart0 = bflb_device_get_by_name("uart0");
printf("gpio interrupt\r\n");
shell_init();
while (1) {
while ((ch = bflb_uart_getchar(uart0)) != -1) {
shell_handler(ch);
}
}
}
SHELL_CMD_EXPORT_ALIAS(gpio_int_test, gpio_int_test, shell gpio_int_test.);FAQ
Nothing happens after typing the command
Set the serial baud rate to 2000000; the command format is gpio_int_test <gpio> <mode>, e.g. gpio_int_test 2 0 (GPIO2 falling edge), with spaces between arguments and Enter at the end.
Pressing the button does not trigger the interrupt
Check that the trigger mode matches the signal direction: grounding the pin with a button produces a falling edge, so use mode 0; for active-high wiring use rising edge or high level.
The interrupt triggers multiple times / bounces
Mechanical buttons bounce when pressed and released, which can trigger the interrupt several times. In a real project, add debounce (re-read the level after a short delay) or use low-level triggering.
Related Best Practices
Have questions?
For any other questions, visit the unified Q&A and discussion board: Ai-Thinker Discussions

