Un Blinky es el programa mínimo que hace parpadear un LED y sirve para comprobar que la cadena de compilación, el flasheo y el acceso al hardware funcionan.
Puede parecer trivial, pero conseguir que un LED parpadee en un sistema operativo en tiempo real como Zephyr implica que has configurado correctamente el entorno, el toolchain, el programador y que entiendes mínimamente cómo el OS habla con el hardware.
Vamos a escribir, compilar y flashear nuestro primer programa en Zephyr.
El código: main.c
Siguiendo la estructura del artículo anterior, crea un archivo src/main.c y pega el siguiente código. Ahora desgranaremos las partes menos familiares.
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
/* 1. Obtenemos el nodo del DeviceTree para el led0 */
/* El nodo "led0" suele estar definido por defecto en casi todas las placas */
#define LED0_NODE DT_ALIAS(led0)
/* 2. Verificamos que el nodo existe y tiene driver asociado */
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
int main(void)
{
int ret;
/* 3. Comprobamos si el dispositivo está listo */
if (!gpio_is_ready_dt(&led)) {
return 0;
}
/* 4. Configuramos el pin como salida activa */
ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
return 0;
}
/* 5. Bucle infinito */
while (1) {
/* Cambiamos el estado del LED */
ret = gpio_pin_toggle_dt(&led);
if (ret < 0) {
return ret;
}
/* Dormimos el hilo 1000 milisegundos (1 segundo) */
k_msleep(1000);
}
}Cómo funciona el código
Si vienes de Arduino, quizá estés pensando: “¿Tanto código para un simple digitalWrite?”.
Sí y no. Zephyr emplea más elementos porque busca validar el hardware y mantener la portabilidad. Estas son las diferencias principales:
- No hay números de pin: En ningún sitio hemos puesto
13oGPIO_5. UsamosDT_ALIAS(led0), que busca en Devicetree qué pin corresponde al aliasled0. El mismo código puede funcionar en placas diferentes que definan ese alias y ofrezcan un GPIO compatible. - Verificaciones de seguridad: Usamos
gpio_is_ready_dt. En sistemas profesionales, no asumimos que el hardware está ahí; preguntamos al OS si el driver se ha cargado correctamente. - API “dt”: Verás muchas funciones acabadas en
_dt(Devicetree). Son las funciones modernas de Zephyr que leen la configuración del pin (pull-up, pull-down, polaridad) directamente de la definición de la placa. k_msleep: No usamos un bucleforvacío para esperar.k_msleepduerme el hilo y libera la CPU para que el sistema operativo pueda hacer otras cosas (como gestionar el Bluetooth o ahorrar energía).
Esta abstracción es la potencia de Zephyr. Si mañana cambias el diseño de la PCB y el LED pasa del pin 5 al pin 20, solo cambias un archivo de configuración (el Overlay), no el código C.
Configuración: prj.conf
Para que este código compile, necesitamos decirle al Kernel que queremos usar el driver de GPIO.
Abre el archivo prj.conf y añade:
CONFIG_GPIO=yEsta opción incluye el subsistema GPIO en la configuración final.
Compilando el proyecto
Volvemos a la terminal con el entorno virtual de Python activado. Para una nRF52840 DK, el board target actual es nrf52840dk/nrf52840:
Ejecutamos:
west build -p always -b nrf52840dk/nrf52840 .Si todo va bien, terminaremos con un mensaje de éxito.
Flasheando la placa
Conecta la placa al USB.
Zephyr usa el comando west flash para programar. West es listo y sabe qué herramienta usar por debajo (JLink para Nordic, Esptool para ESP32, OpenOCD para STM32, etc.).
west flashEl runner depende de la placa: west flash puede utilizar J-Link, OpenOCD, pyOCD, esptool u otra herramienta. Revisa el error y la documentación de tu placa si falta algún programa o permiso.
Si aparecen mensajes de escritura y verificación, mira la placa. ¿Parpadea el LED?
¡Enhorabuena! Acabas de ejecutar el hilo principal de un sistema operativo de tiempo real.
¿Qué ha pasado realmente?
Arranque: Al encenderse, la placa ejecutó el código de inicio de Zephyr (pre-main).
Kernel: Se inicializó el Kernel, el gestor de memoria y los drivers (GPIO).
Main: Se creó el hilo principal que llamó a la función main().
Bucle: El hilo cambia el LED y después se duerme. Durante ese intervalo, el kernel puede ejecutar otros hilos y dejar la CPU en idle cuando no queda trabajo pendiente.
:::
Solución de problemas comunes
- Error:
DT_ALIAS(led0)no existe: La placa no define ese alias. Tendrás que añadirlo mediante un overlay o elegir una placa que lo proporcione; cambiar aled1solo funcionará si ese otro alias existe. - Error de permisos en Linux: Si
west flashfalla al abrir el programador USB, instala las reglasudevindicadas en la documentación de la placa o del runner.