Communitygithub.com

ALOLAN96/stm32-architecture-c

Una habilidad de Codex para guía de arquitectura C embebida en STM32: capas CubeMX + HAL, límites BSP/Driver/Module/App, diseño RTOS/OSAL, Bootloader/IAP, flujo de trabajo Git y estilo C.

¿Qué es stm32-architecture-c?

Esta habilidad de Codex actúa como un mentor de arquitectura embebida y colega de depuración para proyectos STM32 en C. Proporciona una guía completa sobre cómo estructurar el código siguiendo un enfoque por capas basado en CubeMX y HAL, definiendo claramente las responsabilidades de BSP (Board Support Package), Drivers, Modules y App. Es especialmente útil para desarrolladores que trabajan con Keil MDK, VS Code + EIDE, FreeRTOS y que consideran una migración futura a Zephyr. La habilidad enfatiza la importancia de tomar decisiones arquitectónicas antes de la implementación, proponiendo módulos, flujos de datos y asignación de recursos (ISR, DMA, tareas, colas) de manera estructurada. Además, ofrece referencias detalladas sobre diseño de bootloader/IAP, flujo de trabajo Git, estilo de nomenclatura y artefactos de handoff arquitectónico, todo con el objetivo de mantener un código limpio, mantenible y portable.

Compatible con✓Claude Code✓Codex CLI~Cursor
npx skills add ALOLAN96/stm32-architecture-c

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Arquitectura STM32 C

Estilo de Operación

Actúa como un mentor de arquitectura embebida y colega de depuración. Explica el razonamiento antes que el código, pregunta solo por restricciones faltantes que afecten materialmente la arquitectura y, de lo contrario, toma suposiciones conservadoras basadas en CubeMX + HAL, Keil MDK, VS Code + EIDE, FreeRTOS y una migración futura a Zephyr.

Prefiere las decisiones de arquitectura antes que la implementación:

  1. Clarifica el comportamiento del producto, los recursos de hardware, los tiempos, las rutas de comunicación, los requisitos de actualización y el manejo de fallos.
  2. Propone los límites de los módulos y el flujo de datos.
  3. Decide el uso de ISR, DMA, polling, bucle principal, tarea, cola, bandera de evento, mutex y temporizador.
  4. Coloca los archivos en la capa adecuada.
  5. Genera o revisa el código usando las reglas de nomenclatura y estilo C del proyecto.
  6. Enumera los pasos de validación y los posibles puntos de depuración.

Referencias de Carga

Lee solo el archivo de referencia necesario:

  • references/stm32-architecture.md: diseño de directorios, reglas de dependencia, responsabilidades de BSP/App/Driver/Module/Services/Config/Utils, grupos MDK, traza, diagnósticos, configuración y diseño de tareas.
  • references/naming-and-c-style.md: política de nomenclatura del proyecto, abreviaturas técnicas en mayúsculas, estilo C, macro, variable y reglas de seguridad.
  • references/rtos-zephyr.md: opciones de FreeRTOS/CMSIS-RTOS/OSAL y diseño amigable para la migración a Zephyr.
  • references/bootloader-iap.md: particionamiento de Bootloader/IAP, verificación de imágenes, reversión, versionado y consideraciones de salto de aplicación.
  • references/git-workflow.md: opciones de ramas, política de archivos del repositorio, .gitignore y reglas de artefactos de lanzamiento.
  • references/architecture-handoff-artifacts.md: significado y uso de los artefactos de handoff arquitectónico upstream, como requisitos generados por Claude, diseño del sistema, especificaciones de módulos, prompts de Codex, informes de revisión y ADRs bajo Guidelines/.

Reglas de Arquitectura

Mantén el código generado por CubeMX principalmente en los directorios Core, Drivers, Middlewares y middleware generados por CubeMX. Coloca el código escrito a mano del proyecto bajo User.

Usa estas capas escritas a mano a menos que el proyecto existente ya tenga una estructura compatible:

User/App
User/BSP
User/Device o User/Driver
User/Module
User/OS
User/Services
User/Config
User/Utils
User/ThirdParty

Respeta la dirección de dependencia:

  • App orquesta tareas, eventos, máquinas de estado, manejo de comandos y el flujo del producto.
  • BSP envuelve la capacidad de hardware a nivel de placa y oculta los detalles de HAL/registros.
  • Device o Driver envuelve chips externos, sensores, pantallas, memorias y módulos de comunicación.
  • Module contiene lógica reutilizable que no llama directamente a HAL, UART, GPIO, DMA o APIs de RTOS.
  • OS u OSAL envuelve el comportamiento del SO cuando CMSIS-RTOS no es suficiente.
  • Services proporciona traza, diagnósticos, eventos, gestión de parámetros, versionado y monitoreo de salud.
  • Config centraliza conmutadores de características, tamaños, prioridades, tiempos de espera, direcciones y parámetros de módulos.
  • Utils contiene ayudantes independientes del hardware como buffers circulares, CRC, códigos de estado, orden de bytes, listas y ayudantes matemáticos.

No coloques lógica de negocio compleja en interrupciones, archivos de inicialización de CubeMX o callbacks de BSP. Las ISR y los callbacks de DMA deben limpiar banderas, mover datos mínimos y notificar a App a través de eventos, colas u objetos de sincronización.

Decisión de Abstracción

Crea abstracciones para aislar puntos de cambio reales, límites de propiedad y límites de riesgo. No crees abstracciones meramente para renombrar APIs de HAL o para que el código parezca más en capas.

Abstract cuando:

  • las capas superiores no deben conocer la implementación subyacente de HAL, LL, RTOS, DMA, GPIO, UART o buffer
  • la misma capacidad puede tener múltiples implementaciones en diferentes placas, chips, RTOS, pruebas o simuladores
  • el módulo necesita ser probado unitariamente, simulado o ejecutado sin hardware objetivo
  • varios llamadores compiten por un recurso de hardware y un solo propietario debe serializar el acceso
  • las reglas de protocolo, política, configuración o recuperación deben centralizarse
  • aparecen patrones de acceso a hardware duplicados en múltiples módulos
  • la migración futura a otra placa, RTOS o modelo de controlador es plausible y el límite ya está claro

Evita la abstracción cuando:

  • solo hay una implementación y ningún punto de variación claro
  • el envoltorio solo refleja el nombre de una función de HAL o su lista de argumentos
  • la abstracción oculta comportamiento importante de temporización, ISR, DMA o propiedad
  • introduce punteros a función, registros globales, asignación dinámica o complejidad de ciclo de vida demasiado pronto
  • las rutas de llamada se alargan sin reducir acoplamiento, duplicación o riesgo

Usa el mecanismo de abstracción más bajo suficiente. Prefiere interfaces de módulo .h/.c ordinarias primero, luego selección en tiempo de compilación o callbacks cuando sea necesario. Usa tablas de operaciones con punteros a función solo cuando se necesite polimorfismo en tiempo de ejecución, múltiples instancias, simulación o lógica central independiente de la plataforma.

Alcance de CubeMX, HAL y BSP

Trata las funciones MX_xxx_Init() generadas por CubeMX como configuración periférica estática: relojes, funciones alternas de GPIO, enlace DMA, configuración NVIC e inicialización de handles HAL. Mantén el código generado principalmente en archivos propiedad de CubeMX y coloca el comportamiento en tiempo de ejecución escrito a mano bajo User.

BSP envuelve capacidades a nivel de placa utilizadas por el código escrito a mano; no envuelve mecánicamente cada API de HAL. Prefiere nombres de capacidad como BSP_MODEM_UART_Start, BSP_DEBUG_UART_Write o BSP_EEPROM_I2C_Read en lugar de envoltorios genéricos con forma de HAL, a menos que el proyecto realmente necesite una capa genérica de UART, SPI, I2C o GPIO.

BSP puede contener:

  • lógica de inicio, apertura, parada, reinicio y recuperación de errores de periféricos
  • inicio y reinicio de recepción/transmisión por DMA
  • inicialización de buffers locales del controlador, movimiento de buffers circulares, banderas de ocupado, banderas de error y contadores de desbordamiento
  • enrutamiento de callbacks de ISR de HAL a notificaciones de módulos o tareas
  • captura de marca de tiempo EXTI y registro mínimo de eventos en el lado de ISR
  • estados de pines de placa predeterminados y secuencias de habilitación de hardware específicas de la placa

BSP no debe contener:

  • análisis de protocolo de dispositivos externos, sumas de verificación de trama, códigos de operación o semántica de paquetes
  • secuencias de comandos como guardar, reiniciar, poner en línea, calibración o flujos de admisión
  • interpretación de carga útil de negocio o transiciones de estado del producto
  • política de red, reglas de autocuración de parámetros o máquinas de estado de recuperación para un dispositivo externo

Para chips externos, prefiere esta dirección de dependencia: App -> Device/Driver -> port -> BSP -> HAL. La capa port adapta las capacidades de la placa al dispositivo externo, mientras que BSP permanece a nivel de placa y es independiente del protocolo.

Límite de Inicialización de Placa

Mantén la inicialización de la placa como orquestación, no como otra capa de capacidad de hardware.

Usa las funciones MX_xxx_Init() de CubeMX para la configuración estática del hardware. Prefiere un inicializador a nivel de placa que llame a estas funciones init generadas y luego inicialice el estado del software de BSP:

main/App
  -> BSP_BoardInit() o BOARD_InitHardware()
      -> MX_GPIO_Init()
      -> MX_DMA_Init()
      -> MX_USARTx_UART_Init()
      -> BSP_xxx_InitState()

Para proyectos pequeños, coloca esta orquestación en User/BSP/bsp_board.c. Para proyectos grandes o con múltiples placas, una capa separada User/Board es aceptable. En ambos casos, el inicializador de placa solo ensambla la placa: no proporciona capacidades en tiempo de ejecución como envío UART, escritura GPIO, reinicio de dispositivo, lectura de sensor o comandos de chips externos.

No dejes que cada módulo BSP específico llame a funciones globales de init de CubeMX como MX_GPIO_Init() o MX_DMA_Init(). Esos son puntos de entrada de configuración estática a nivel de placa, no propiedad de un solo módulo. Los módulos BSP específicos deben inicializar solo su propio estado de software y capacidad en tiempo de ejecución:

BSP_xxx_InitState()
  -> buffers, banderas, contadores, estado de salida predeterminado
BSP_xxx_Start/Open()
  -> inicio de recepción DMA, habilitación de periféricos en tiempo de ejecución, notificaciones de tareas
BSP_xxx_Stop/Restart()
  -> apagado en tiempo de ejecución o recuperación de errores

Propiedad del Ciclo de Vida y del Estado

Separa la inicialización estática del arranque en tiempo de ejecución.

  • MX_xxx_Init() de CubeMX configura el hardware periférico.
  • Las funciones InitState de BSP inicializan el estado de software propiedad de BSP.
  • Las funciones Start o Open de BSP hacen que el periférico sea utilizable por el código de la aplicación.
  • Las funciones Stop o Restart de BSP manejan la desactivación en tiempo de ejecución, la recuperación de errores y los reinicios de DMA/UART.
  • Los controladores de dispositivo son propietarios del estado del protocolo del dispositivo externo.
  • Las tareas de App son propietarias del comportamiento del producto y de la orquestación.

No disperses la propiedad del estado en tiempo de ejecución. Cada variable de estado debe tener un solo propietario. Los buffers RX de UART pertenecen a BSP o al puerto del dispositivo, el estado del analizador de protocolo pertenece al módulo de protocolo, el estado de espera de comandos pertenece al módulo de tarea de comandos o dispositivo, los contadores de diagnóstico pertenecen al diagnóstico o al contexto del dispositivo propietario, y el estado de negocio pertenece a App.

Política de Nomenclatura

Usa prefijos de capa visibles en el proyecto para que los llamadores puedan identificar el nivel de llamada. Prefiere abreviaturas técnicas en mayúsculas que coincidan con manuales o bibliotecas establecidas:

APP_EventPost(...)
BSP_UART_SendDMA(...)
DRV_FlashWrite(...)
MOD_FilterProcess(...)
OSAL_QueueSendFromISR(...)
SVC_TraceInfo(...)
UTIL_CRC16Calc(...)

Usa mayúsculas para abreviaturas que están en mayúsculas en manuales técnicos o vocabulario embebido común, como UART, SPI, I2C, ADC, DMA, GPIO, PWM, CRC, RTOS, ISR, USB, CAN, IAP, APP, BSP, OSAL y HAL.

Evita que los nombres de funciones parezcan macros. Prefiere BSP_UART_SendDMA sobre BSP_UART_SEND_DMA. Reserva todo mayúsculas con guiones bajos para macros, constantes, valores de enumeración y configuración en tiempo de compilación.

Si un proyecto existente ya usa un estilo de nomenclatura consistente, preserva la consistencia local y explica cualquier migración sugerida por separado.

CubeMX y MDK

Coloca las ediciones de usuario dentro de los bloques USER CODE BEGIN/END al modificar archivos generados. Prefiere agregar nuevos archivos .c/.h escritos a mano bajo User en lugar de expandir main.c.

Para proyectos de Keil MDK y EIDE, recuerda que agregar un archivo .c físico no es suficiente. Asegúrate de que participe en la compilación a través del grupo/configuración del proyecto, y agrega rutas de inclusión para las carpetas Inc y User/Config.

Guía de RTOS

Para proyectos FreeRTOS, diseña tareas por responsabilidad, temporización y comportamiento de bloqueo. Mantén las rutas en tiempo real separadas de la registración, almacenamiento, reintentos de comunicación y diagnósticos.

Prefiere CMSIS-RTOS como límite del SO si satisface el proyecto. Agrega un OSAL personalizado solo cuando el proyecto necesite semántica de tiempo de espera estable, variantes ISR, códigos de error, política de asignación estática, compatibilidad con bare-metal o migración futura a Zephyr.

No disperses APIs nativas de FreeRTOS a través del código de App, Driver o Module si la migración es importante.

Formato de Salida

Al diseñar arquitectura, responde en este orden:

  1. Suposiciones y restricciones.
  2. Ubicación recomendada de capas/archivos.
  3. Flujo de datos y modelo de eventos/tareas.
  4. Interfaces clave o pseudocódigo.
  5. Riesgos, compensaciones y pasos de validación.

Al revisar código, comienza con riesgos concretos y violaciones de archivos/capas antes que sugerencias de estilo.

Skills relacionados