Created
August 16, 2025 06:57
-
-
Save hidsh/bca78682210d877950dcb231f09bf962 to your computer and use it in GitHub Desktop.
zephyr button w/ "dynamic" pinctrl example for xiao_ble (seeed xiao nrf52840)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# SPDX-License-Identifier: Apache-2.0 | |
cmake_minimum_required(VERSION 3.20.0) | |
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) | |
project(button) | |
target_sources(app PRIVATE src/main.c src/remap.c) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# zephyr/samples/basic/button/boards/custom.conf | |
# | |
# "static" pinctrl to use external-uart breakout (AE-FT2232 / FTDI FT2232D) as /dev/ttyUSB0 | |
# this file is to switch USB-CDC-ACM (/dev/ttyACM0) --> external uart (/dev/ttyUSB0) | |
# Disable USB CDC ACM | |
CONFIG_USB_DEVICE_STACK=n | |
CONFIG_USB_DEVICE_STACK_NEXT=n | |
CONFIG_BOARD_SERIAL_BACKEND_CDC_ACM=n | |
# Enable UART console | |
CONFIG_UART_CONSOLE=y | |
CONFIG_CONSOLE=y |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# based on zephyr/samples/boards/nordic/dynamic_pinctrl/Kconfig | |
# | |
# Copyright (c) 2021 Nordic Semiconductor ASA | |
# SPDX-License-Identifier: Apache-2.0 | |
mainmenu "Dynamic pin control sample" | |
config REMAP_INIT_PRIORITY | |
int "Remap routine initialization priority" | |
default 50 | |
help | |
Initialization priority of the remap routine within the PRE_KERNEL1 level. | |
This priority must be greater than GPIO_INIT_PRIORITY and lower than | |
UART_INIT_PRIORITY. | |
source "Kconfig.zephyr" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CONFIG_GPIO=y | |
# --------------------------------------------- | |
# dynamic-pinctrl | |
# --------------------------------------------- | |
CONFIG_PINCTRL=y | |
CONFIG_PINCTRL_DYNAMIC=y | |
# configure serial and console to come after remap hook | |
CONFIG_SERIAL_INIT_PRIORITY=60 | |
CONFIG_CONSOLE_INIT_PRIORITY=70 | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016 Open-RnD Sp. z o.o. | |
* Copyright (c) 2020 Nordic Semiconductor ASA | |
* | |
* SPDX-License-Identifier: Apache-2.0 | |
* | |
* NOTE: If you are looking into an implementation of button events with | |
* debouncing, check out `input` subsystem and `samples/subsys/input/input_dump` | |
* example instead. | |
*/ | |
#include <zephyr/kernel.h> | |
#include <zephyr/device.h> | |
#include <zephyr/drivers/gpio.h> | |
#include <zephyr/sys/util.h> | |
#include <zephyr/sys/printk.h> | |
#include <inttypes.h> | |
#define SLEEP_TIME_MS 1 | |
/* | |
* Get button configuration from the devicetree sw0 alias. This is mandatory. | |
*/ | |
#define SW0_NODE DT_ALIAS(sw0) | |
#if !DT_NODE_HAS_STATUS_OKAY(SW0_NODE) | |
#error "Unsupported board: sw0 devicetree alias is not defined" | |
#endif | |
static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(SW0_NODE, gpios, | |
{0}); | |
#define SW1_NODE DT_ALIAS(sw1) | |
#if !DT_NODE_HAS_STATUS_OKAY(SW1_NODE) | |
#error "Unsupported board: sw1 devicetree alias is not defined" | |
#endif | |
static const struct gpio_dt_spec button1 = GPIO_DT_SPEC_GET_BY_IDX_OR(SW1_NODE, gpios, | |
0, // idx | |
{0}); | |
static struct gpio_callback button_cb_data; | |
static struct gpio_callback button1_cb_data; | |
/* | |
* The led0 devicetree alias is optional. If present, we'll use it | |
* to turn on the LED whenever the button is pressed. | |
*/ | |
static struct gpio_dt_spec led = GPIO_DT_SPEC_GET_OR(DT_ALIAS(led0), gpios, | |
{0}); | |
void button_pressed(const struct device *dev, struct gpio_callback *cb, | |
uint32_t pins) | |
{ | |
printk("Button pressed at %" PRIu32 " from pin %d\n", k_cycle_get_32(), pins); | |
} | |
int main(void) | |
{ | |
int ret; | |
if (!gpio_is_ready_dt(&button)) { | |
printk("Error: button device %s is not ready\n", | |
button.port->name); | |
return 0; | |
} | |
if (!gpio_is_ready_dt(&button1)) { | |
printk("Error: button1 device %s is not ready\n", | |
button1.port->name); | |
return 0; | |
} | |
ret = gpio_pin_configure_dt(&button, GPIO_INPUT); | |
if (ret != 0) { | |
printk("Error %d: failed to configure %s pin %d\n", | |
ret, button.port->name, button.pin); | |
return 0; | |
} | |
ret = gpio_pin_configure_dt(&button1, GPIO_INPUT); | |
if (ret != 0) { | |
printk("Error %d: failed to configure %s pin %d\n", | |
ret, button1.port->name, button1.pin); | |
return 0; | |
} | |
ret = gpio_pin_interrupt_configure_dt(&button, | |
GPIO_INT_EDGE_TO_ACTIVE); | |
if (ret != 0) { | |
printk("Error %d: failed to configure interrupt on %s pin %d\n", | |
ret, button.port->name, button.pin); | |
return 0; | |
} | |
ret = gpio_pin_interrupt_configure_dt(&button1, | |
GPIO_INT_EDGE_TO_ACTIVE); | |
if (ret != 0) { | |
printk("Error %d: failed to configure interrupt on %s pin %d\n", | |
ret, button1.port->name, button1.pin); | |
return 0; | |
} | |
gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin)); | |
gpio_add_callback(button.port, &button_cb_data); | |
printk("Set up button at %s pin %d\n", button.port->name, button.pin); | |
gpio_init_callback(&button1_cb_data, button_pressed, BIT(button1.pin)); | |
gpio_add_callback(button1.port, &button1_cb_data); | |
printk("Set up button at %s pin %d\n", button1.port->name, button1.pin); | |
if (led.port && !gpio_is_ready_dt(&led)) { | |
printk("Error %d: LED device %s is not ready; ignoring it\n", | |
ret, led.port->name); | |
led.port = NULL; | |
} | |
if (led.port) { | |
ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT); | |
if (ret != 0) { | |
printk("Error %d: failed to configure LED device %s pin %d\n", | |
ret, led.port->name, led.pin); | |
led.port = NULL; | |
} else { | |
printk("Set up LED at %s pin %d\n", led.port->name, led.pin); | |
} | |
} | |
printk("Press the button\n"); | |
if (led.port) { | |
while (1) { | |
/* If we have an LED, match its state to the button's. */ | |
int val = gpio_pin_get_dt(&button); | |
if (val >= 0) { | |
gpio_pin_set_dt(&led, val); | |
} | |
k_msleep(SLEEP_TIME_MS); | |
} | |
} | |
return 0; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2021 Nordic Semiconductor ASA | |
* | |
* SPDX-License-Identifier: Apache-2.0 | |
*/ | |
#include <zephyr/init.h> | |
#include <zephyr/drivers/gpio.h> | |
#include <zephyr/drivers/pinctrl.h> | |
/* make sure devices and remap hook are initialized in the correct order */ | |
BUILD_ASSERT((CONFIG_GPIO_INIT_PRIORITY < CONFIG_REMAP_INIT_PRIORITY) && | |
(CONFIG_REMAP_INIT_PRIORITY < CONFIG_SERIAL_INIT_PRIORITY), | |
"Device driver priorities are not set correctly"); | |
PINCTRL_DT_DEV_CONFIG_DECLARE(DT_NODELABEL(uart0)); | |
/* UART0 alternative configurations (default and sleep states) */ | |
PINCTRL_DT_STATE_PINS_DEFINE(DT_PATH(zephyr_user), uart0_alt_default); | |
#ifdef CONFIG_PM_DEVICE | |
PINCTRL_DT_STATE_PINS_DEFINE(DT_PATH(zephyr_user), uart0_alt_sleep); | |
#endif | |
static const struct pinctrl_state uart0_alt[] = { | |
PINCTRL_DT_STATE_INIT(uart0_alt_default, PINCTRL_STATE_DEFAULT), | |
#ifdef CONFIG_PM_DEVICE | |
PINCTRL_DT_STATE_INIT(uart0_alt_sleep, PINCTRL_STATE_SLEEP), | |
#endif | |
}; | |
#include <zephyr/kernel.h> // printk | |
static int remap_pins(void) | |
{ | |
int ret; | |
printk("-- enter: remap_pins()\n"); | |
const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(DT_ALIAS(sw1), | |
gpios, {0}); | |
if (!gpio_is_ready_dt(&button)) { | |
return -ENODEV; | |
} | |
ret = gpio_pin_configure_dt(&button, GPIO_INPUT); | |
if (ret < 0) { | |
return ret; | |
} | |
/* remap UART0 pins if button is pressed */ | |
if (gpio_pin_get_dt(&button)) { | |
struct pinctrl_dev_config *uart0_config = | |
PINCTRL_DT_DEV_CONFIG_GET(DT_NODELABEL(uart0)); | |
return pinctrl_update_states(uart0_config, uart0_alt, | |
ARRAY_SIZE(uart0_alt)); | |
} | |
printk("-- exit: remap_pins()\n"); | |
return 0; | |
} | |
SYS_INIT(remap_pins, PRE_KERNEL_1, CONFIG_REMAP_INIT_PRIORITY); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// zephyr/samples/basic/button/boards/xiao_ble.overlay | |
// | |
// adopt from zephyr/boards/nordic/nrf52dk/nrf52dk_nrf52810.dts | |
/ { | |
buttons { | |
compatible = "gpio-keys"; | |
button0: button_0 { | |
label = "Push button switch 0"; | |
gpios = <&gpio0 5 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; // P0.05 XIAO #6 D5 --> push switch | |
// zephyr,code = <INPUT_KEY_0>; | |
}; | |
sw1: sw1 { | |
gpios = <&gpio0 4 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; // sw1: P0.04 (XIAO #5 D4) | |
label = "Select ttyUSB0/1"; | |
// zephyr,code = <INPUT_KEY_1>; // optional, for input subsystem | |
}; | |
}; | |
aliases { | |
sw0 = &button0; | |
sw1 = &sw1; | |
uart-0 = &uart0; // Add this alias for the console | |
}; | |
chosen { | |
zephyr,console = &uart0; // Explicitly set UART0 as console | |
}; | |
}; | |
// "static" pinctrl to use external-uart breakout (AE-FT2232 / FTDI FT2232D) as /dev/ttyUSB0 | |
&pinctrl { | |
uart0_default: uart0_default { | |
group1 { | |
psels = <NRF_PSEL(UART_TX, 1, 15)>; // P1.15 XIAO #11 D10 TX --> AE-FT2232 #39 RXD (cross) | |
}; | |
group2 { | |
psels = <NRF_PSEL(UART_RX, 1, 14)>; // P1.14 XIAO #10 D9 RX --> AE-FT2232 #40 TXD (cross) | |
bias-pull-up; | |
}; | |
}; | |
uart0_sleep: uart0_sleep { | |
group1 { | |
psels = <NRF_PSEL(UART_TX, 1, 15)>, | |
<NRF_PSEL(UART_RX, 1, 14)>; | |
low-power-enable; | |
}; | |
}; | |
}; | |
// Enable UART0 | |
&uart0 { | |
status = "okay"; | |
current-speed = <115200>; | |
pinctrl-0 = <&uart0_default>; | |
pinctrl-1 = <&uart0_sleep>; | |
pinctrl-names = "default", "sleep"; | |
}; | |
// --------------------------------------------- | |
// for dynamic-pinctl (to swap pins for uart0) | |
// --------------------------------------------- | |
#include <zephyr/dt-bindings/input/input-event-codes.h> // `zephyr,code` | |
/ { | |
zephyr,user { | |
uart0_alt_default = <&uart0_alt_default>; | |
uart0_alt_sleep = <&uart0_alt_sleep>; | |
}; | |
}; | |
// "dynamic" pinctrl to use external-uart breakout (AE-FT2232 / FTDI FT2232D) as /dev/ttyUSB1 | |
// when pressed sw1 | |
&pinctrl { | |
/* Alternative pin configuration for UART0 */ | |
uart0_alt_default: uart0_alt_default { | |
group1 { | |
// psels = <NRF_PSEL(UART_TX, 0, 26)>; // TXD: P0.26 (XIAO led0:red) | |
psels = <NRF_PSEL(UART_TX, 1, 13)>; // TXD: P1.13 (XIAO #9 D8) | |
}; | |
group2 { | |
psels = <NRF_PSEL(UART_RX, 1, 12)>; // RXD: P1.12 (XIAO #8 D7) | |
bias-pull-up; | |
}; | |
}; | |
uart0_alt_sleep: uart0_alt_sleep { | |
group1 { | |
psels = <NRF_PSEL(UART_TX, 1, 13)>, // TXD: P1.13 (XIAO #9 D8) | |
<NRF_PSEL(UART_RX, 1, 12)>; // RXD: P1.12 (XIAO #8 D7) | |
low-power-enable; | |
}; | |
}; | |
}; | |
/ { | |
// sw0: sw0 { | |
// compatible = "gpio-key"; | |
// gpios = <&gpio0 5 GPIO_ACTIVE_LOW>; // sw0: P0.05 (XIAO #6 D5) | |
// label = "Push Switch"; | |
// zephyr,code = <INPUT_KEY_0>; // optional, for input subsystem | |
// }; | |
// sw1: sw1 { | |
// compatible = "gpio-key"; | |
// gpios = <&gpio0 4 GPIO_ACTIVE_LOW>; // sw1: P0.04 (XIAO #5 D4) | |
// label = "Select ttyUSB0/1"; | |
// zephyr,code = <INPUT_KEY_1>; // optional, for input subsystem | |
// }; | |
// aliases { | |
// // sw0 = &sw0; | |
// sw1 = &sw1; | |
// }; | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
build
run