El Badge Hack GDL 2025 es un dispositivo de hardware abierto diseñado para la comunidad de hackers, desarrolladores y entusiastas de la tecnología. Cuenta con un potente procesador Linux capaz de ejecutar aplicaciones personalizadas, junto con una amplia variedad de interfaces para ampliar su funcionalidad.
- RV1106: Procesador Linux de alto rendimiento
- ARM Cortex-A7 + MCU RISC-V
- NPU integrada (Unidad de Procesamiento Neural)
- ISP integrado (Procesador de Señal de Imagen)
- Soporte completo para sistemas operativos Linux
- GPIOs: Múltiples pines de propósito general
- MIPI CSI: Interfaz para cámaras y sensores de imagen
- UART: Comunicación serial asíncrona
- USB: Puerto USB con hub integrado
- Neopixels: LEDs RGB programables WS2812E
- Batería: Soporte para baterías 18650 con gestión de energía
- Buck Converter: Regulación eficiente DC-DC
- Camara: Camara SC3336 de 3MP
El proyecto está dividido en dos directorios principales:
Incluye el diseño principal:
- Procesador RV1106G3
- LEDs Neopixel WS2812E
- Gestión de energía y batería
- Interface MIPI para camara
| Componente | Especificación |
|---|---|
| Procesador | RV1106G3 (ARM Cortex-A7 + RISC-V MCU + NPU + ISP) |
| Sistema Operativo | Linux |
| LEDs | WS2812E Neopixels |
| Batería | Soporte 18650 |
| Interfaces | USB, MIPI CSI, Botones |
El procesador RV1106 ofrece las siguientes interfaces:
- UART: Comunicación serial (debug/terminal)
- SPI: Interfaz periférica de alta velocidad
- I2C: Para sensores, pantallas y otros dispositivos I2C
- USB: Hub USB integrado
- MIPI CSI: Interfaz para cámaras y sensores de imagen
- ISP: Procesador de señal de imagen integrado
- GPIOs: Pines de propósito general
- PWM: Canales PWM para control de LEDs y motores
El Badge Hack GDL 2026 está basado en el hardware y el SDK de la Luckfox Pico Pro Max. Para información técnica adicional sobre la plataforma, puedes consultar la Wiki oficial de Luckfox.
El badge integra el RV1106G3, un microprocesador de bajo consumo de Rockchip que combina una CPU ARM con un coprocesador RISC-V de 32 bits, optimizado para aplicaciones de procesamiento y codificación/decodificación de audio y video.
En esta sección aprenderás cómo:
- Encender y utilizar tu badge
- Tomar fotografías
- Extraer las imágenes a tu computadora
- Personalizar los elementos visuales (OSD) de las fotos
Presiona los botones USER 3 y USER 4 que se encuentran al frente del badge y miras las animaciones del led rgb que preparamos para ti!!
- Alimentar tu badge
Antes de usarlo, asegúrate de que el badge esté correctamente alimentado. Puedes hacerlo de dos maneras:
- Conectando una batería compatible
- Conectándolo mediante USB a una fuente que pueda suministrar energía
- Encender el badge
El badge cuenta con un interruptor físico de encendido/apagado.
- Coloca el switch en la posición ON.
- Una vez encendido, el sistema iniciará automáticamente.
Como confirmación visual de que el dispositivo arrancó correctamente, al iniciar verás una secuencia de parpadeo de color verde en el NeoPixel: dos parpadeos de 1 segundo cada uno (500 ms encendido + 500 ms apagado). Después de esa secuencia, el LED entra a la rutina de animación normal.
- Tomar una fotografía
Con el badge encendido, presiona el botón superior para capturar una fotografía.
Cada imagen se guarda automáticamente en la memoria interna del dispositivo.
Al presionar el botón de captura (KEY_ENTER), el NeoPixel ejecuta un parpadeo de confirmación en color blanco: dos parpadeos rápidos de 500 ms cada uno (250 ms encendido + 250 ms apagado). Este indicador se ejecuta aunque haya otra rutina en curso e interrumpe brevemente la animación actual; al terminar, la rutina continúa como antes.
Las imágenes se transfieren mediante MTP (Media Transfer Protocol), por lo que el badge se comporta como un dispositivo multimedia (similar a un teléfono en modo transferencia de archivos).
- Conectar el badge
Conecta el badge a tu computadora utilizando un cable USB con capacidad de transmisión de datos.
Tanto Windows como Linux cuentan con soporte nativo para MTP.
- Identificar el dispositivo
Al conectarlo, aparecerá un nuevo dispositivo llamado:
Hack GDL 2026
Ubuntu
Windows
Ábrelo como si fuera un teléfono conectado en modo transferencia de archivos.
- Acceder y extraer las imágenes
Dentro del dispositivo encontrarás un almacenamiento llamado:
Hack GDL 2026
Screenshot de Ubuntu
Al acceder, podrás ver:
- Las fotografías capturadas
- Un archivo llamado
photo_config.ini
Desde aquí puedes:
- Copiar las imágenes a tu computadora
- Eliminar fotografías si lo deseas
Screenshot de Ubuntu
El archivo photo_config.ini define la configuración de los OSD (On-Screen Display) que se muestran al momento de capturar una fotografía.
Un ejemplo de configuración es el siguiente:
[osd.2]
type = character
enabled = 1
position_x = 100
position_y = 100
display_text = Hack GDL 2026
[osd.6]
type = image
enabled = 1
position_x = 100
position_y = 640
image_path = /root/electroniccats.bmp
[osd.7]
type = image
enabled = 1
position_x = 1520
position_y = 640
image_path = /root/hack_gdl.bmp
OSD significa On-Screen Display (Visualización en Pantalla). Son elementos gráficos o de texto que se superponen sobre la imagen antes de guardarse.
En este proyecto, los OSD permiten agregar:
- Texto personalizado
- Logos
- Imágenes decorativas
directamente sobre la fotografía capturada.
[osd.2] – Texto personalizado
type = character
Indica que el OSD es texto.
enabled = 1
Activa el OSD (0 lo desactiva).
position_x = 100
position_y = 100
Define la posición del texto en la imagen (coordenadas X,Y).
display_text = Hack GDL 2026
Texto que aparecerá sobre la fotografía.
[osd.6] y [osd.7] – Imágenes superpuestas
type = image
Indica que el OSD es una imagen.
image_path = /root/electroniccats.bmp
Ruta de la imagen que se superpondrá.
position_x / position_y
Definen la ubicación dentro de la fotografía.
En el ejemplo:
- Se coloca el logo electroniccats.bmp en la parte inferior izquierda.
- Se coloca el logo hack_gdl.bmp en la parte inferior derecha.
Puedes modificar:
- El texto mostrado
- Las posiciones
- Activar o desactivar elementos
- Cambiar las imágenes por otras compatibles
Después de modificar el archivo y guardar los cambios, las siguientes fotografías usarán la nueva configuración.
Si tienes curiosidad por conocer cómo funciona el badge internamente, estás en el lugar correcto.
A partir de aquí podrás descubrir cómo se construyó el sistema, cómo se integraron los servicios y cómo funciona la captura de imágenes y la configuración de los OSD.
Esta sección es ideal si quieres:
- Aprender a construir tu propia imagen del sistema
- Entender cómo comunicarte con tu badge (ADB, MTP, consola)
- Compilar y agregar tus propios scripts o servicios
- Agregar soporte para más OSD
- Comprender cómo se configuraron los botones
- Entender cómo se integró y programó el NeoPixel
- Modificar y mejorar el comportamiento actual
Si te interesa experimentar, personalizar y llevar el badge al siguiente nivel, sigue leyendo.
Para interactuar con el badge (ejecutar comandos, ver logs o depurar), debes conectarte al puerto DEBUG SERIAL mostrado en la imagen anterior. Este puerto corresponde a la UART2 del RV1106:
TX → GPIO1_B2_D
RX → GPIO1_B3_U
⚠ Importante: La señal del puerto serial del badge es 3.3V TTL.
Puedes usar cualquier adaptador USB a UART de 3.3V, por ejemplo:
CH340 / CH341 CP2102 / CP2104 FT232RL PL2303 CP2105
Matek F405 adapters (soportan 3.3V)
Asegúrate de:
TX del adaptador → RX del badge
RX del adaptador → TX del badge
GND → GND
[IMAGEN MMALONA DE LA PLACA DONDE SE VEN LOS PINES UART]
A continuación, cómo conectarte desde Linux, macOS y Windows.
Conecta el adaptador USB-serial.
Verifica qué puerto creó:
dmesg | grep tty
Normalmente aparecerá como:
/dev/ttyUSB0
/dev/ttyACM0
Conéctate con screen o minicom:
Con screen (lo más fácil)
screen /dev/ttyUSB0 115200
Para salir: CTRL + A luego K (y confirma).
Con minicom
sudo minicom -b 115200 -D /dev/ttyUSB0
Conecta el adaptador USB-UART.
Ver puertos disponibles:
ls /dev/tty.*
Suelen ser:
/dev/tty.usbserial-*
/dev/tty.wchusbserial*
/dev/tty.SLAB_USBtoUART
Conéctate:
screen /dev/tty.usbserial-XXXX 115200
Para salir: CTRL + A, luego K.
Mac también permite usar CoolTerm (GUI amigable).
Usa un cliente serial como:
PuTTY
TeraTerm
CoolTerm
RealTerm
Conecta el adaptador USB-UART.
Abre el Administrador de dispositivos → “Puertos (COM y LPT)”
Identifica el puerto COM, ejemplo: COM4
Abre PuTTY o TeraTerm y selecciona:
Port: COM4
Baudrate: 115200
Data bits: 8
Parity: None
Stop bits: 1
Flow control: None
Con eso verás la consola del badge.
La comunicación ADB (Android Debug Bridge) está habilitada por defecto en la placa, lo que permite ejecutar comandos, explorar archivos y depurar directamente desde un computador.
Cómo conectarse
- Conecta la placa al computador mediante USB.
- Abre una terminal y ejecuta:
adb devices
Deberías ver la placa listada como un dispositivo conectado. 3. Para acceder al shell de la placa:
adb shell
Descargar ADB
ADB forma parte de las Android Platform Tools y se puede descargar desde la página oficial:
https://developer.android.com/studio/releases/platform-tools
En Linux también se puede instalar directamente con:
sudo apt update
sudo apt install android-tools-adb
Para acceder al dispositivo los accesos son:
usuario: root
password: contrasenia
Antes de comenzar, es necesario que descargues el fork del repositorio de Luckfox SDK que preparamos para construir la imagen de nuestro Badge Hack GDL 2026.
badge_hackgdl_2026.
git clone -b badge_hackgdl_2026 --single-branch https://github.com/ElectronicCats/luckfox-pico.git
Para configurar y habilitar el módulo SPI y los pines gpio es necesario activarlos desde la configuración del DTS dentro del SDK de la placa Luckfox Pico.
Antes de modificar el DTS, primero debemos configurar el SDK. Desde el directorio raíz del proyecto luckfox-sdk, ejecuta:
./build.sh lunch
Aparecerá el siguiente menú para seleccionar la versión de hardware:
You're building on Linux
Lunch menu...pick the Luckfox Pico hardware version:
选择 Luckfox Pico 硬件版本:
[0] RV1103_Luckfox_Pico
[1] RV1103_Luckfox_Pico_Mini
[2] RV1103_Luckfox_Pico_Plus
[3] RV1103_Luckfox_Pico_WebBee
[4] RV1106_Luckfox_Pico_Pro_Max
[5] RV1106_Luckfox_Pico_Ultra
[6] RV1106_Luckfox_Pico_Ultra_W
[7] RV1106_Luckfox_Pico_Pi
[8] RV1106_Luckfox_Pico_Pi_W
[9] RV1106_Luckfox_Pico_86Panel
[10] RV1106_Luckfox_Pico_86Panel_W
[11] RV1106_Luckfox_Pico_Zero
[12] custom
Which would you like? [0~12][default:0]:
En nuestro caso, debemos seleccionar la opción:
4
Esta opción corresponde a la placa RV1106_Luckfox_Pico_Pro_Max, que es la base de nuestro Badge Hack GDL 2026.
A continuación, el sistema solicitará seleccionar el medio de arranque:
Lunch menu...pick the boot medium:
选择启动媒介:
[0] SD_CARD
[1] SPI_NAND
Which would you like? [0~1][default:0]:
Debemos seleccionar:
1
Esto indica que utilizaremos SPI NAND como medio de booteo.
Finalmente, se debe seleccionar la versión del sistema:
Lunch menu...pick the system version:
选择系统版本:
[0] Buildroot
Which would you like? [0][default:0]:
En nuestro caso, solo contamos con:
0
Es decir, utilizaremos Buildroot
Una vez completada la configuración de la placa, es necesario realizar la primera compilación de la imagen ejecutando:
./build.sh
Este proceso puede tardar varios minutos. Al finalizar, el proyecto quedará preparado para continuar con la configuración.
badge_hackgdl_2026, puedes omitir los siguientes pasos o revisarlos únicamente como referencia para entender qué modificaciones se realizaron.
Después de la primera compilación, en el directorio raíz del proyecto se habrá generado un nuevo directorio llamado:
config/
Dentro de este directorio se crean enlaces simbólicos hacia los archivos de configuración de la placa. El archivo que nos interesa es:
dts_config
En el archivo dts_config debemos localizar la configuración correspondiente a spi0 y cambiar su propiedad status de:
status = "disabled";
a:
status = "okay";
La configuración final debe verse de la siguiente manera:
/**********SPI**********/
&spi0 {
status = "okay";
spidev@0 {
spi-max-frequency = <50000000>;
};
fbtft@0 {
spi-max-frequency = <50000000>;
};
};
Con esto, el módulo spi0 quedará habilitado correctamente en el sistema.
En nuestro Badge Hack GDL 2026, los botones físicos se configuran en el Device Tree para que el kernel los reconozca como teclado GPIO. Esto permite leerlos como eventos de entrada (input), por ejemplo desde /dev/input/eventX.
Dentro del árbol raíz del DTS (/ { ... }) se define un nodo gpio_keys que contiene todos los botones:
gpio_keys: gpio-keys {
compatible = "gpio-keys";
pinctrl-names = "default";
pinctrl-0 = <&gpio1_pd3
&gpio2_pb1
&gpio2_pb0
&gpio2_pa7
&gpio2_pa6>;
key_user: key-user {
label = "USER_KEY";
linux,code = <KEY_ENTER>;
gpios = <&gpio1 RK_PD3 GPIO_ACTIVE_LOW>;
debounce-interval = <10>;
wakeup-source;
};
key__user_up: key-user-up {
label = "UP_USER_KEY";
linux,code = <KEY_UP>;
gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_LOW>;
debounce-interval = <10>;
wakeup-source;
};
key_user_right: key-user-right {
label = "RIGHT_USER_KEY";
linux,code = <KEY_RIGHT>;
gpios = <&gpio2 RK_PB0 GPIO_ACTIVE_LOW>;
debounce-interval = <10>;
wakeup-source;
};
key_user_left: key-user-left {
label = "LEFT_USER_KEY";
linux,code = <KEY_LEFT>;
gpios = <&gpio2 RK_PA7 GPIO_ACTIVE_LOW>;
debounce-interval = <10>;
wakeup-source;
};
key_user_down: key-user-down {
label = "DOWN_USER_KEY";
linux,code = <KEY_DOWN>;
gpios = <&gpio2 RK_PA6 GPIO_ACTIVE_LOW>;
debounce-interval = <10>;
wakeup-source;
};
};
compatible = "gpio-keys"→ define que los GPIO se usarán como teclado genérico.pinctrl-0→ referencia a los pines que se configuran más abajo.- Cada nodo
key_*define un botón:label→ nombre descriptivolinux,code→ código de tecla asignado por Linux (KEY_ENTER, KEY_UP, etc.)gpios→ pin físico y lógica (GPIO_ACTIVE_LOW)debounce-interval→ tiempo para filtrar rebotes del botónwakeup-source→ permite que el botón despierte la placa en suspensión Gracias a esta configuración, cada botón se expone como evento de tipo input, listo para ser leído desde programas C o Python.
Los pines que controlan los botones se definen en &pinctrl fuera del nodo raíz:
/**********GPIO*********/
&pinctrl {
gpio1-pd3 {
gpio1_pd3: gpio1-pd3 {
rockchip,pins = <1 RK_PD3 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
gpio2-pb1 {
gpio2_pb1: gpio2-pb1 {
rockchip,pins = <2 RK_PB1 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
gpio2-pb0 {
gpio2_pb0: gpio2-pb0 {
rockchip,pins = <2 RK_PB0 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
gpio2-pa7 {
gpio2_pa7: gpio2_pa7 {
rockchip,pins = <2 RK_PA7 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
gpio2-pa6 {
gpio2_pa6: gpio2_pa6 {
rockchip,pins = <2 RK_PA6 RK_FUNC_GPIO &pcfg_pull_up>;
};
};
};
- Cada pin se configura como GPIO con pull-up interno, garantizando señales estables.
rockchip,pins→ indica banco, pin y función (GPIO).- Esto asegura que los botones funcionen correctamente y puedan ser detectados como entradas digitales.
Con esta configuración:
- Los botones son detectados como teclado GPIO, accesibles vía
/dev/input/eventX. - Se pueden usar en programas C o Python para cambiar modos, activar funciones o interactuar con LEDs.
- Permite integrar la lectura de botones en hilos separados, evitando bloquear otros procesos (por ejemplo el control de LEDs WS2812B).
Para nuestro Badge Hack GDL 2026, se han configurado 5 botones con diferentes funciones:
- Uno de ellos se utiliza para tomar fotografías.
- Dos botones sirven para cambiar el modo del LED Neopixel.
- Los dos botones restantes se dejaron disponibles para el usuario.
¡Así que adelante! Puedes usar estos botones para desarrollar tus propios programas, ya sea en C o Python, y crear tus propios efectos o funcionalidades personalizadas.
El LED RGB WS2812B (mejor conocido como NeoPixel) pueden controlarse utilizando el módulo de spidev a través de la interfaz SPI del RV1106. Es importante destacar que SPI se utiliza como un generador de trenes de pulsos a 800 kHz, lo cual es necesario para el funcionamiento correcto de los NeoPixel.
Una vez habilitado el módulo SPI y generado el sistema con Buildroot, el siguiente paso es crear una aplicación en C que controle los LEDs WS2812B utilizando la interfaz /dev/spidev0.0.
Código completo:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <math.h>
#include <pthread.h>
#include <signal.h>
#include <linux/spi/spidev.h>
#include <linux/input.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <time.h>
#define SPI_DEVICE_PATH "/dev/spidev0.0"
#define SPI_SPEED 2400000
#define NUM_LEDS 1
#define NUM_MODES 5
#define EVENT_DEVICE "/dev/input/event1"
static volatile int running = 1;
static volatile sig_atomic_t blink_request = 0;
typedef struct {
int current_mode;
pthread_mutex_t lock;
} controller_state_t;
controller_state_t state;
void next_mode() {
pthread_mutex_lock(&state.lock);
state.current_mode = (state.current_mode + 1) % NUM_MODES;
printf("[MODE] -> %d\n", state.current_mode);
pthread_mutex_unlock(&state.lock);
}
void prev_mode() {
pthread_mutex_lock(&state.lock);
state.current_mode = (state.current_mode - 1 + NUM_MODES) % NUM_MODES;
printf("[MODE] -> %d\n", state.current_mode);
pthread_mutex_unlock(&state.lock);
}
int get_mode() {
int mode;
pthread_mutex_lock(&state.lock);
mode = state.current_mode;
pthread_mutex_unlock(&state.lock);
return mode;
}
void byte_to_spi(uint8_t byte, uint8_t *out, int *idx) {
for (int i = 0; i < 8; i++) {
if (byte & (1 << (7 - i)))
out[(*idx)++] = 0b1110;
else
out[(*idx)++] = 0b1000;
}
}
void color_to_spi(uint8_t r, uint8_t g, uint8_t b, uint8_t *out, int *idx) {
byte_to_spi(g, out, idx);
byte_to_spi(r, out, idx);
byte_to_spi(b, out, idx);
}
void color_blink(int fd, uint8_t r, uint8_t g, uint8_t b, int count, int half_period_us) {
uint8_t buf[NUM_LEDS * 24];
int len;
for (int n = 0; n < count; n++) {
len = 0;
for (int i = 0; i < NUM_LEDS; i++)
color_to_spi(r, g, b, buf, &len);
write(fd, buf, len);
usleep(half_period_us);
len = 0;
for (int i = 0; i < NUM_LEDS; i++)
color_to_spi(0, 0, 0, buf, &len);
write(fd, buf, len);
usleep(half_period_us);
}
}
void make_frame(int mode, int step, uint8_t *buf, int *len) {
*len = 0;
for (int i = 0; i < NUM_LEDS; i++) {
uint8_t r = 0, g = 0, b = 0;
switch (mode) {
case 0:
break;
case 1: {
double angle = (step % 100) / 100.0 * 2 * M_PI;
double brightness = (sin(angle) + 1.0) / 2.0;
r = (uint8_t)(255 * brightness);
b = (uint8_t)(255 * brightness);
break;
}
case 2:
if (i == (step % NUM_LEDS)) b = 255;
else b = 10;
break;
case 3:
if ((i + step) % 3 == 0) {
r = g = b = 255;
} else {
r = 50;
}
break;
case 4: {
int pos = ((i * 256 / NUM_LEDS) + step) & 255;
if (pos < 85) {
r = pos * 3;
g = 255 - pos * 3;
} else if (pos < 170) {
pos -= 85;
r = 255 - pos * 3;
b = pos * 3;
} else {
pos -= 170;
g = pos * 3;
b = 255 - pos * 3;
}
break;
}
}
color_to_spi(r, g, b, buf, len);
}
}
void *led_thread(void *arg) {
int fd = open(SPI_DEVICE_PATH, O_WRONLY);
if (fd < 0) {
printf("SPI open\n");
return NULL;
}
uint8_t mode = SPI_MODE_0;
uint8_t bits = 8;
ioctl(fd, SPI_IOC_WR_MODE, &mode);
ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &(uint32_t){SPI_SPEED});
uint8_t buffer[NUM_LEDS * 24];
int len;
int step = 0;
color_blink(fd, 0, 255, 0, 2, 500000);
while (running) {
if (blink_request) {
blink_request = 0;
color_blink(fd, 255, 255, 255, 2, 250000);
}
int mode_now = get_mode();
make_frame(mode_now, step, buffer, &len);
write(fd, buffer, len);
step++;
usleep(50000);
}
close(fd);
return NULL;
}
void *button_thread(void *arg) {
struct input_event ev;
while (running) {
int fd = open(EVENT_DEVICE, O_RDONLY);
if (fd < 0) {
sleep(1);
continue;
}
while (running) {
if (read(fd, &ev, sizeof(ev)) == sizeof(ev)) {
if (ev.type == EV_KEY && ev.value == 1) {
if (ev.code == KEY_LEFT)
next_mode();
else if (ev.code == KEY_DOWN)
prev_mode();
else if (ev.code == KEY_ENTER)
blink_request = 1;
}
}
}
close(fd);
}
return NULL;
}
void signal_handler(int sig) {
running = 0;
}
int main() {
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
pthread_mutex_init(&state.lock, NULL);
state.current_mode = 0;
pthread_t t_led, t_btn;
pthread_create(&t_led, NULL, led_thread, NULL);
pthread_create(&t_btn, NULL, button_thread, NULL);
pthread_join(t_led, NULL);
pthread_join(t_btn, NULL);
pthread_mutex_destroy(&state.lock);
return 0;
}
¿Qué hace este programa?
Este programa:
- Controla LEDs WS2812B utilizando SPI
- Genera distintos efectos de iluminación (5 modos)
- Permite cambiar el modo usando botones físicos
- Ejecuta el control de LEDs y la lectura de botones en hilos separados (multithreading)
- Maneja señales del sistema para finalizar correctamente (CTRL+C)
- Muestra un indicador verde de arranque y un parpadeo blanco al capturar fotografía (
KEY_ENTER)
El programa utiliza:
/dev/spidev0.0para transmitir datos a los LEDs/dev/input/event1para leer eventos de botonespthreadpara ejecutar tareas en paraleloioctl()para configurar la interfaz SPI
#define SPI_DEVICE_PATH "/dev/spidev0.0"
#define SPI_SPEED 2400000
#define NUM_LEDS 1
#define NUM_MODES 5
#define EVENT_DEVICE "/dev/input/event1"
Aquí se definen constantes del sistema:
- SPI_DEVICE_PATH → dispositivo SPI utilizado
- SPI_SPEED → velocidad del bus SPI (2.4 MHz)
- NUM_LEDS → número de LEDs en la cadena
- NUM_MODES → cantidad de efectos disponibles
- EVENT_DEVICE → dispositivo de entrada para los botones
static volatile int running = 1;
Variable global que controla la ejecución del programa.
El modificador volatile evita que el compilador optimice su lectura, ya que es compartida entre hilos.
static volatile sig_atomic_t blink_request = 0;
Bandera compartida entre el hilo de botones y el hilo de LEDs. El hilo de botones la activa (= 1) cuando se presiona KEY_ENTER, y el hilo de LEDs la consume (= 0) para disparar el parpadeo blanco de confirmación.
Se usa sig_atomic_t porque su lectura/escritura es atómica, lo que permite señalizar entre hilos sin necesidad de un mutex adicional.
Estructura del estado del controlador
typedef struct {
int current_mode;
pthread_mutex_t lock;
} controller_state_t;
Aquí se define:
- current_mode → modo de animación actual
- lock → mutex para evitar condiciones de carrera
El mutex garantiza que dos hilos no modifiquen el modo al mismo tiempo.
Funciones:
void next_mode()
void prev_mode()
int get_mode()
Estas funciones:
- Bloquean el mutex
- Modifican o leen el modo actual
- Desbloquean el mutex
Esto asegura acceso seguro entre hilos.
El uso de:
(state.current_mode + 1) % NUM_MODES;
permite que el modo vuelva a 0 cuando llega al máximo.
Los WS2812B no usan SPI directamente.
Se “simula” el protocolo utilizando patrones binarios.
Conversión de byte
void byte_to_spi(uint8_t byte, uint8_t *out, int *idx)
Cada bit del byte se convierte en:
- 0b1110 → representa un “1”
- 0b1000 → representa un “0”
Esto genera la temporización correcta para el LED.
Cada byte RGB se convierte en 8 bytes SPI.
Conversión de color
void color_to_spi(uint8_t r, uint8_t g, uint8_t b, ...)
Los WS2812B esperan datos en orden:
G → R → B
Por eso primero se envía g, luego r, luego b.
void make_frame(int mode, int step, ...)
Esta función genera un frame completo de LEDs según el modo actual.
Cada modo hace algo diferente:,
Modo 0 → Apagado
Modo 1 → Efecto respiración usando sin()
Modo 2 → Punto azul en movimiento
Modo 3 → Patrón blanco intermitente
Modo 4 → Rueda de colores tipo arcoíris
El parámetro step permite animación progresiva.
El uso de:
double brightness = (sin(angle) + 1.0) / 2.0;
genera un efecto suave de encendido/apagado.
void color_blink(int fd, uint8_t r, uint8_t g, uint8_t b, int count, int half_period_us)
Función auxiliar que reproduce un parpadeo síncrono del NeoPixel en un color arbitrario. No depende del hilo principal de animación: escribe directamente sobre el fd del SPI con usleep() entre transiciones, por lo que bloquea durante el parpadeo (esto es intencional: queremos un indicador limpio y predecible).
Parámetros:
fd→ file descriptor del SPI ya abiertor, g, b→ color del parpadeocount→ cuántas veces parpadearhalf_period_us→ duración (en microsegundos) de cada semiciclo (encendido y apagado)
Cada llamada produce count ciclos de la forma: encendido half_period_us → apagado half_period_us. Esta función se reutiliza para los dos indicadores del sistema:
- Indicador de arranque:
color_blink(fd, 0, 255, 0, 2, 500000)→ 2 parpadeos verdes de 1 s cada uno - Indicador de captura:
color_blink(fd, 255, 255, 255, 2, 250000)→ 2 parpadeos blancos de 0.5 s cada uno
void *led_thread(void *arg)
Este hilo:
- Abre el dispositivo SPI
- Configura:
- Modo SPI
- Bits por palabra
- Velocidad
- Ejecuta el parpadeo verde de arranque (2 parpadeos de 1 s) como confirmación visual de que el dispositivo se inicializó correctamente:
color_blink(fd, 0, 255, 0, 2, 500000);
- Entra en un bucle:
- Revisa la bandera
blink_request. Si está activa, la limpia y ejecuta el parpadeo blanco (color_blink(fd, 255, 255, 255, 2, 250000)) para confirmar la captura de fotografía. Esto interrumpe brevemente la rutina actual durante 1 s y al terminar la animación continúa donde iba. - Obtiene el modo actual
- Genera el frame
- Lo envía con write()
- Espera 50 ms
- Revisa la bandera
Esto crea la animación continua y permite que los indicadores se muestren sobre cualquier rutina sin necesidad de pausarla manualmente.
void *button_thread(void *arg)
Este hilo:
- Abre /dev/input/event1
- Lee eventos tipo EV_KEY
- Si se presiona:
- KEY_LEFT → siguiente modo
- KEY_DOWN → modo anterior
- KEY_ENTER → levanta la bandera
blink_request = 1para que el hilo de LEDs ejecute el parpadeo blanco de confirmación de captura de fotografía
Permite cambiar efectos en tiempo real y notificar al hilo de LEDs eventos puntuales (como la toma de foto) sin acoplar ambos hilos: el hilo de botones solo levanta la bandera y vuelve inmediatamente a escuchar; el hilo de LEDs es quien decide cuándo atender la solicitud.
void signal_handler(int sig)
Captura:
- SIGINT (Ctrl+C)
- SIGTERM
Cuando ocurre, pone:
running = 0;
Esto detiene ambos hilos de forma limpia.
int main()
La función principal:
- Registra manejadores de señal
- Inicializa el mutex
- Crea dos hilos:
- LED
- Botones
- Espera a que terminen (pthread_join)
- Libera recursos
El programa funciona porque:
- SPI transmite datos continuamente
- Los LEDs reciben un flujo codificado compatible
- Los botones modifican el estado compartido
- El mutex evita conflictos
- Los hilos permiten ejecución paralela
Para controlar la tira de LEDs NeoPixel de manera automática, se creó un script de inicio llamado:
S99neopixel
¿Por qué S99?
- El prefijo
S99indica que se ejecuta casi al final del arranque, después de otros servicios importantes. - Esto asegura que la aplicación de NeoPixel solo se inicie cuando todos los servicios de base del sistema ya estén activos.
- Si hubiera otros scripts con el mismo número (
S99), se ejecuta en orden alfabético, manteniendo un orden predecible.
¿Qué hace este script? Este script permite ejecutar un servicio en segundo plano que controla la tira NeoPixel.
- DAEMON →
/usr/bin/neopixel(el binario que controla los LEDs) - PIDFILE →
/var/run/neopixel.pid(archivo donde se guarda el ID del proceso)
El script soporta los comandos típicos de un servicio:
| Comando | Acción |
|---|---|
| start | Inicia el servicio en segundo plano y crea el PIDFILE |
| stop | Detiene el servicio si está corriendo y elimina el PIDFILE |
| restart | Detiene y luego inicia nuevamente el servicio |
| status | Verifica si el servicio está corriendo y muestra su PID |
| Cómo funciona internamente |
-
Inicio (
start)Usa start-stop-daemon para ejecutar el binario NeoPixel en segundo plano, asegurándose de que:
- Se cree un PID para identificar el proceso
- No se bloquee la ejecución del resto del sistema
-
Detención (
stop)- Revisa el PIDFILE y mata el proceso correspondiente si existe.
- Elimina el PIDFILE para que no queden registros falsos.
-
Reinicio (
restart)
- Ejecuta primero stop, espera 1 segundo y luego start.
- Estado (
status)
- Verifica si el PID registrado en el PIDFILE está activo.
- Informa si el servicio está corriendo o detenido.
Objetivo principal
- Ejecutar la aplicación NeoPixel como un servicio en Linux embebido.
- Integrarse con System V init para arrancar automáticamente al iniciar el sistema.
- Garantizar que la tira de LEDs siempre esté controlada sin intervención manual del usuario.
Para compilar el programa en C para la placa Luckfox Pico, debemos usar la toolchain de ARM incluida en el SDK. La herramienta de compilación se encuentra en:
luckfox-pico/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc
Nota: luckfox-pico es el directorio raíz de tu repositorio Luckfox SDK. Ajusta la ruta si tu repositorio está en otra ubicación.
Crea un archivo llamado Makefile en el mismo directorio que tu código fuente (neopixel.c):
# Compilador cruzado ARM del SDK Luckfox
CC := luckfox-pico/tools/linux/toolchain/arm-rockchip830-linux-uclibcgnueabihf/bin/arm-rockchip830-linux-uclibcgnueabihf-gcc
# Target: ejecutable neopixel
neopixel: neopixel.c
-$(CC) $^ -o $@ -lpthread -lm
La compilación cruzada se aplica siguiendo el ejemplo oficial que proporciona Luckfox en su documentación para el proceso de cross‑compile, donde se explica cómo usar el toolchain incluido en el SDK para generar ejecutables ARM desde un host x86_64. Puedes consultar la guía original aquí: https://wiki.luckfox.com/Luckfox-Pico-Pro-Max/Cross-Compile
Para implementar la captura de fotografías en el Badge Hack GDL, nos apoyamos en la aplicación rkipc, una aplicación demo desarrollada por Rockchip que ya incluye:
- Configuración de cámara
- Funciones internas para captura de imagen
- Integración con el pipeline de video
- Registro automático como servicio al arranque del sistema
Dado que rkipc ya se ejecuta como servicio al iniciar el sistema, se optó por modificar ligeramente su código fuente, en lugar de crear una aplicación independiente.
El archivo modificado se encuentra en:
project/app/rkipc/rkipc/src/rv1106_ipc/main.c
En este archivo se agregó un nuevo hilo encargado de:
- Monitorear eventos de botones
- Ejecutar la función interna
rk_take_photo() - Detectar cambios en el archivo
photo_config.ini - Aplicar configuraciones dinámicas en tiempo real
- Escuchar eventos provenientes de
/dev/input/event1 - Filtrar únicamente el botón configurado como
KEY_ENTER - Ejecutar
rk_take_photo() - Detectar cambios en
photo_config.ini - Aplicar modificaciones en tiempo real sin reiniciar el sistema
- Mantener compatibilidad con la arquitectura existente de
rkipc
static void *take_photo_event(void *arg) {
photo_config_watcher_init();
int key_fd = open("/dev/input/event1", O_RDONLY);
if (key_fd < 0) {
LOG_ERROR("can't open /dev/input/event1\n");
photo_config_watcher_deinit();
return NULL;
}
fd_set rfds;
int nfds = key_fd + 1;
struct timeval timeout;
struct input_event key_event;
ssize_t rb;
while (g_main_run_) {
photo_config_watcher_process();
timeout.tv_sec = 1;
timeout.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(key_fd, &rfds);
int ret = select(nfds, &rfds, NULL, NULL, &timeout);
if (ret < 0) {
if (errno == EINTR)
continue;
LOG_ERROR("select error: %d\n", errno);
break;
}
if (FD_ISSET(key_fd, &rfds)) {
rb = read(key_fd, &key_event, sizeof(key_event));
if (rb != sizeof(key_event)) {
if (rb < 0 && errno != EINTR)
LOG_ERROR("read error: %d\n", errno);
continue;
}
LOG_INFO("[sec:%ld,usec:%ld,type:%d,code:%d,value:%d]\n",
key_event.time.tv_sec,
key_event.time.tv_usec,
key_event.type,
key_event.code,
key_event.value);
if ((key_event.code == KEY_ENTER) && key_event.value) {
rk_take_photo();
}
}
}
photo_config_watcher_deinit();
close(key_fd);
return NULL;
}
La nueva función take_photo_event() fue agregada en el archivo main.c (líneas 147–199), donde se implementa el monitoreo de eventos del dispositivo /dev/input/event1, se filtra el códigos de tecla KEY_ENTER y se ejecuta las función rk_take_photo() al presionar el botón.
Esta función se ejecuta en un hilo independiente creado desde main() mediante:
pthread_create(&key_chk, NULL, take_photo_event, NULL);
El registro del hilo se realiza en main.c (línea 231), donde se crea el thread mediante pthread_create() para ejecutar la función take_photo_event() de manera concurrente con el resto del sistema.
1. Inicialización del watcher
photo_config_watcher_init();
Inicializa un sistema basado en inotify que monitorea cambios en:
/userdata/video0/photo_config.ini
Esto permite aplicar cambios dinámicos de configuración.
2. Apertura del dispositivo de entrada
open("/dev/input/event1", O_RDONLY);
Abre el dispositivo del kernel donde se exponen los botones configurados como gpio-keys.
Si falla, el hilo termina limpiamente.
3. Bucle principal
while (g_main_run_)
El hilo permanece activo mientras el sistema principal esté en ejecución.
En cada iteración:
- Se procesan cambios de configuración
- Se esperan eventos de botón
4. Monitoreo de configuración dinámica
photo_config_watcher_process();
Si detecta modificaciones en photo_config.ini:
- Actualiza
/userdata/rkipc.ini - Actualiza
/oem/usr/share/rkipc-300w.ini - Ejecuta:
rk_param_reload()rk_osd_restart()
Todo sin reiniciar el sistema.
5. Espera de eventos con select()
select(nfds, &rfds, NULL, NULL, &timeout);
Se utiliza para:
- No bloquear indefinidamente
- Reducir consumo de CPU
- Revisar el watcher periódicamente
6. Lectura del evento
read(key_fd, &key_event, sizeof(key_event));
Se valida que la lectura sea completa antes de procesar el evento.
7. Filtrado del botón de fotografía
if ((key_event.code == KEY_ENTER) && key_event.value)
KEY_ENTER→ botón configurado para capturar fotografíavaluedistinto de 0 → botón presionado
Cuando se cumple la condición:
rk_take_photo();
Se ejecuta la función interna de captura de imagen.
8. Finalización del hilo
Al salir del bucle:
photo_config_watcher_deinit();
close(key_fd);
Se liberan los recursos correctamente.
Se agregaron los archivos:
photo_config_watcher.c
photo_config_watcher.h
Ubicados en el mismo directorio que main.c.
Estos archivos implementan un sistema basado en inotify que:
- Monitorea
/userdata/video0 - Detecta cambios en
photo_config.ini - Copia secciones específicas hacia:
/userdata/rkipc.ini/oem/usr/share/rkipc-300w.ini
- Recarga parámetros dinámicamente
1. Origen inicial
Archivo base:
/root/photo_config.ini
Copiado al arrancar mediante el script:
S99photo_config
Este script:
- Verifica que exista el archivo fuente
- Verifica que exista
/userdata/video0 - Copia el archivo solo si no existe
- No sobrescribe configuraciones del usuario
2. Inicialización de rkipc
Archivo base:
/oem/usr/share/rkipc-300w.ini
Es utilizado durante el arranque por:
S21appinit
Durante el arranque:
- Se genera
/userdata/rkipc.ini rkipctrabaja sobre ese archivo- La plantilla corresponde a la cámara detectada (SC3336)
/root/photo_config.ini
│
▼ (S99photo_config)
/userdata/video0/photo_config.ini ← Editable vía MTP
│
▼ (inotify watcher)
┌─────────────────────────────┐
│ photo_config_watcher.c │
└─────────────────────────────┘
│
├──► /userdata/rkipc.ini
└──► /oem/usr/share/rkipc-300w.ini
│
▼
rkipc (OSD actualizado en tiempo real)
MTP (Media Transfer Protocol) es un protocolo diseñado para transferir archivos de medios entre dispositivos y computadoras sin necesidad de montar el almacenamiento como una unidad de disco tradicional. En la Luckfox Pico Pro Max, MTP se utiliza para acceder al directorio /userdata/video0/, donde se guardan las fotos capturadas por la placa mediante la modificación de la función de rkipc y la configuración de los servicios S99photo_config y S99neopixel.
- Activación de MTP en Buildroot
Dentro del archivo de configuración de la placa:
/luckfox-pico/project/cfg/BoardConfig_IPC/BoardConfig-SPI_NAND-Buildroot-RV1106_Luckfox_Pico_Pro_Max-IPC.mk
existe la línea que define el kernel defconfig:
# Kernel defconfig
export RK_KERNEL_DEFCONFIG=luckfox_rv1106_linux_defconfig
Este defconfig apunta al fichero:
luckfox-pico/sysdrv/tools/board/buildroot/luckfox_pico_defconfig
Al final de este archivo se agregó:
BR2_PACKAGE_UMTPRD=y
Esta línea indica a Buildroot que incluya el paquete umtprd en la imagen final. Este paquete es responsable de exponer el almacenamiento de la placa como un dispositivo MTP, permitiendo acceder a /userdata/video0/ desde un computador.
- Configuración MTP en el overlay
Para utilizar MTP se creó un overlay custom dentro del repositorio:
luckfox-pico/project/cfg/BoardConfig_IPC/overlay/overlay-custom
El árbol de directorios utilizado para MTP y otros archivos relacionados quedó así:
overlay-custom
├── etc
└── umtprd
└── umtprd.conf
umtprd.conf: archivo de configuración de MTP que define:
loop_on_disconnect 1
storage "/userdata/video0/" "Hack GDL 2026" "rw"
manufacturer "Electronic Cats"
product "Badge Hack GDL 2026"
serial "4ef1156fc2158798"
firmware_version "Rev A"
interface "MTP"
usb_vendor_id 0x2207
usb_product_id 0x0019
usb_class 0x6
usb_subclass 0x1
usb_protocol 0x1
usb_dev_version 0x3008
usb_functionfs_mode 0x1
usb_dev_path "/dev/ffs-mtp/ep0"
usb_epin_path "/dev/ffs-mtp/ep1"
usb_epout_path "/dev/ffs-mtp/ep2"
usb_epint_path "/dev/ffs-mtp/ep3"
usb_max_packet_size 0x200
Este archivo configura los endpoints USB, la identificación del dispositivo y la ruta del almacenamiento a exponer.
- Modificación del script USB (
S50usbdevice)
El script original encargado de inicializar los USB gadgets (adbd, UMS, RNDIS, MTP, etc.) se encuentra en:
luckfox-pico/sysdrv/tools/board/android-tools/S50usbdevice
Los cambios realizados para habilitar MTP fueron:
- Activar MTP por defecto cambiando:
MTP_EN=off
a
MTP_EN=on
- Crear el endpoint FunctionFS para MTP durante el pre-run de los binarios:
if [ $MTP_EN = on ];then
mkdir -p /dev/ffs-mtp
mount -t functionfs mtp /dev/ffs-mtp
fi
- Ejecutar el demonio
umtprdal iniciar el gadget USB:
run_binary() {
if [ $MTP_EN = on ];then
umtprd &
fi
}
- Se desactivó la sección
use_os_descpara MTP, ya que no era necesaria para la versión de kernel utilizada.
Con estos cambios, al iniciar la placa, el dispositivo MTP queda automáticamente disponible, permitiendo acceder y transferir archivos de /userdata/video0/ desde un computador conectado por USB.
- Beneficios del overlay y configuración MTP
- Permite incluir la configuración de MTP dentro de la imagen del sistema, manteniéndola persistente.
- Se pueden versionar y distribuir los ajustes de MTP junto con otros archivos del overlay.
- Facilita la gestión de fotos y archivos de configuración (
photo_config.ini) sin necesidad de montar manualmente el almacenamiento. - Los permisos de los ficheros dentro del overlay se heredan correctamente a la imagen final, garantizando que los scripts y archivos de configuración funcionen al iniciar.
El sistema utiliza el mecanismo clásico de Linux llamado System V init (SysVinit) para ejecutar automáticamente tareas cuando el dispositivo se enciende.
En términos simples:
System V init es el sistema encargado de arrancar los servicios y aplicaciones necesarias al iniciar Linux.
Durante el arranque, el sistema ejecuta una serie de scripts que siguen esta estructura:
SNNnombre
Donde:
Ssignifica StartNNes un número que indica el orden de ejecuciónnombredescribe qué hace el script
Ejemplo:
S21appinit
S99neopixel
S99photo_config
- Los scripts se ejecutan en orden numérico ascendente según el prefijo
NNdeSNNnombre. - Si dos o más scripts tienen el mismo número, se ejecutan en orden alfabético por el resto del nombre (nombre). Se ejecutarían en este orden:
S21appinitS99neopixelS99photo_config
De esta manera se controla qué se inicia primero y qué después.
El objetivo principal de System V init es:
- Iniciar automáticamente servicios
- Preparar archivos de configuración
- Dejar el sistema listo para funcionar sin intervención del usuario
En este proyecto se utiliza un mecanismo llamado overlay para agregar ficheros y directorios personalizados a la imagen final del sistema Linux embebido. Esto permite incluir configuraciones, scripts y archivos necesarios sin modificar los directorios base del sistema.
Archivo de configuración de la placa
Para la LuckFox Pico Pro Max, la placa con la que trabajamos, existe un archivo de configuración específico en el SDK de LuckFox:
/luckfox-pico/project/cfg/BoardConfig_IPC/BoardConfig-SPI_NAND-Buildroot-RV1106_Luckfox_Pico_Pro_Max-IPC.mk
Dentro de este archivo se declaran los overlays que se incluirán en la imagen:
# declare overlay directory
export RK_POST_OVERLAY="overlay-luckfox-config overlay-luckfox-buildroot-init overlay-luckfox-buildroot-shadow overlay-luckfox-wifibt-firmware"
Para incluir archivos o configuraciones propias, se agrega un overlay custom:
# declare overlay directory
export RK_POST_OVERLAY="overlay-luckfox-config overlay-luckfox-buildroot-init overlay-luckfox-buildroot-shadow overlay-luckfox-wifibt-firmware overlay-custom"
Para que Buildroot pueda usar el overlay custom:
- Crear el directorio en:
luckfox-pico/project/cfg/BoardConfig_IPC/overlay
- Dentro de esa carpeta se encuentran los overlays usados por LuckFox.
- Crear un directorio con el mismo nombre que configuramos en el .mk, en este caso:
overlay-custom
Todos los ficheros y directorios que se agreguen dentro de este overlay heredan sus permisos y propietario al ser copiados en la imagen, lo que garantiza que los servicios y aplicaciones tengan los permisos correctos automáticamente.
El overlay que utilizamos tiene la siguiente estructura de directorios:
overlay-custom
├── etc
│ ├── init.d
│ │ ├── S99neopixel
│ │ └── S99photo_config
│ └── umtprd
│ └── umtprd.conf
├── root
│ ├── electroniccats.bmp
│ ├── hack_gdl.bmp
│ └── photo_config.ini
└── usr
└── bin
└── neopixel
Descripción de los archivos:
S99neopixel→ Script para iniciar el servicio NeoPixel automáticamente.S99photo_config→ Script para inicializar el archivophoto_config.inien/userdata/video0/.electroniccats.bmpyhack_gdl.bmp→ Imágenes OSD usadas por la función de captura de fotografías derkipc.photo_config.ini→ Archivo base de configuración de fotografías.neopixel→ Binario o script que ejecuta el servicio de control de LEDs NeoPixel.umtprd.conf→ Configuración del servicio MTP (umtprd) que expone/userdata/video0/.
Cuando se compila la imagen:
- Todos los ficheros y directorios del overlay se copian automáticamente dentro de la imagen final, en las rutas correspondientes.
- Los permisos y propietario de los ficheros se heredan automáticamente, asegurando que los servicios y aplicaciones funcionen sin necesidad de ajustes manuales.
- Permite personalizar la imagen sin modificar los archivos base de Buildroot, facilitando actualizaciones y mantenimiento.
- Garantiza consistencia y reproducibilidad, ya que cada vez que se reconstruye la imagen, el overlay se aplica de forma automática.
- Asegura que los archivos críticos como scripts de inicio (
S99neopixel,S99photo_config) y configuraciones (photo_config.ini,umtprd.conf) estén disponibles y con los permisos correctos desde el primer arranque.
Para cargar la imagen a traves de windows, es necesario descargar este zip:
https://drive.google.com/file/d/1VYzwWPBUPHTOVj9a0mfiTmSDR1JniMgu/view?usp=drive_link
La carpeta contiene varias imagenes necesarias para el flasheo de la placa Badge Hack GDL 2026. Una vez descargada, por favor seguir las intrucciones de la wiki de luckfox:
https://wiki.luckfox.com/Luckfox-Pico-Pro-Max/Flash-image
-
Descargar y extraer la herramiente de actualizacion de Rockchip.
-
Del release, descargar y descomprimir el archivo comprimido HackGDL-Badge-2026-v1.0.img.
-
Mantenga presionado el botón BOOT mientras conecta la placa a la computadora anfitriona para entrar en modo de flasheo.
-
Una vez que tengas la placa en modo BOOT, procede a flashearla. Para ello, tendras que usar el .img que se encuentra en el archivo previamente descomprimido (modifique la ruta según la ubicación real de la imagen):
sudo ./upgrade_tool uf {PATH-TO-IMAGE}/HackGDL-Badge-2026-v1.0.img
-
Descargar y extraer la herramienta de actualizacion
-
Del release, descargar y descomprimir el archivo comprimido HackGDL-Badge-2026-v1.0.img.
-
Mantenga presionado el botón BOOT mientras conecta la placa a la computadora anfitriona para entrar en modo de flasheo.
-
Una vez que tengas la placa en modo BOOT, procede a flashearla. Para ello, ejecute el programa para flashear el firmware (modifique la ruta según la ubicación real de la imagen) y use el .img previamente descomprimido:
sudo ./upgrade_tool uf {PATH-TO-IMAGE}/HackGDL-Badge-2026-v1.0.img
Este es un proyecto de hardware abierto. Las contribuciones son bienvenidas:
- Haz un fork del repositorio.
- Crea una nueva rama para tu feature (
git checkout -b feature/AmazingFeature) - Haz commit de tus cambios (
git commit -m 'Add some AmazingFeature') - Haz push a tu rama (
git push origin feature/AmazingFeature) - Abre un Pull Request
Este proyecto es de hardware abierto. Consulta los archivos de licencia para más detalles.
Desarollado con ❤️ por Electronic Cats
Electronic Cats invierte tiempo y recursos en proporcionar este diseño de hardware abierto. Por favor, apoya a Electronic Cats y al hardware abierto comprando productos de Electronic Cats.
- Website: https://www.electroniccats.com/
- GitHub: ElectronicCats
- Issues: Usa la sección de Issues en GitHub para reportar problemas o sugerir mejoras
Gracias a toda la comunidad de hardware abierto y a todas las personas que hacen posibles proyectos como este.
Nota: Este badge está diseñado para BugCon 2025. Para más información sobre el evento, visita la página oficial de BugCon.








