zephyr-hola-mundo-blinky

Hola Mundo en Zephyr: tu primer Blinky

  • 4 min

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); 
    }
}
Copied!

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:

  1. No hay números de pin: En ningún sitio hemos puesto 13 o GPIO_5. Usamos DT_ALIAS(led0), que busca en Devicetree qué pin corresponde al alias led0. El mismo código puede funcionar en placas diferentes que definan ese alias y ofrezcan un GPIO compatible.
  2. 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.
  3. 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.
  4. k_msleep: No usamos un bucle for vacío para esperar. k_msleep duerme 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=y
Copied!

Esta 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 .
Copied!

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 flash
Copied!

El 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 a led1 solo funcionará si ese otro alias existe.
  • Error de permisos en Linux: Si west flash falla al abrir el programador USB, instala las reglas udev indicadas en la documentación de la placa o del runner.