Fundamentos de Portabilidad RTOS en Microcontroladores STM32
La adaptación de sistemas RTOS (FreeRTOS, RT-Thread, Zephyr) a plataformas STM32 requiere un entendimiento profundo de la capa de abstracción de hardware, mecanismos de interrupción y gestión de contexto. Este proceso implica una transición de programación bare-metal a modelos de concurrencia determinísticos.
Vector de Interrupciones y Gestión de Contexto
Los núcleos Cortex-M utilizan tablas de vectores para manejar excepciones, donde el planificador RTOS depende de SysTick y PendSV para cambios de contexto. PendSV debe ejecutarse con prioridad mínima para evitar interrupciones de usuario:
// Configuración de prioridad en stm32f4xx_it.c
void PendSV_Handler(void) {
// Gestión interna del RTOS
NVIC_SetPriority(PendSV_IRQn, PRIORIDAD_MIN); // 0xFF
}
Reconfiguración del Proceso de Inicio
El manejador Reset_Handler debe inicializar el RTOS:
- Deshabilitar interrupciones globales
- Configurar reloj principal y periféricos críticos
- Invocar inicializador del núcleo RTOS
- Convertir main() en función de tarea inicial
Modelo de Memoría y Pilas
| Tipo | Modo Bare-Metal | Modo RTOS |
|---|---|---|
| Pila Principal (MSP) | Única para todo el sistema | Solo para ISR y llamadas al sistema |
| Pila de Proceso (PSP) | Inactiva | Asignada por tarea mediante xTaskCreate() |
Sistema de Verificación de Registros Cortex-M
Consistencia de SCB, NVIC y SysTick
SCB->VTOR debe apuntar a la tabla de vectores con alineación de 256 bytes:
ldr r0, =VTOR_ADDR
ldr r1, [r0]
ldr r2, =__TablaVectores
cmp r1, r2
bne error_vtor
Configuración MPU
Reglas esenciales para regiones MPU:
- Alineación de dirección base según tamaño de región
- Tamaño de región potencia de 2 (32B–4GB)
- Prohibición de solapamiento de regiones
uint8_t idx = MPU_ObtenerRegion();
uint32_t rbar = MPU->RBAR;
uint32_t rasr = MPU->RASR;
if ((rbar & 0x1F) != (rasr & 0x1E)) {
// Error de alineación
}
Calibración de SysTick
Los errores acumulados en la cadena de reloj afectan la precisión:
uint32_t freq = HAL_RCC_GetHCLKFreq();
uint32_t reload = (freq / 8) / TICK_RATE - 1;
| Fuente de Error | Desvaición Típica |
|---|---|
| HSI ±1% | ±47.6 ns/tic |
| Envejecimiento cristal | ±20 ppm |
Verificación de Tareas y Aislamiento de Memoria
Comparación dinámica de punteros de pila:
uint32_t nivel_agua = pxTareaObtenerMaxUsoStack(NULL);
uint32_t *sp_actual;
__asm("MRS %0, psp" : "=r"(sp_actual));
Adaptación de Componentes RTOS
Mecanismo PendSV
Secuencia crítica en manejadores:
PendSV_Handler:
CPSID I
MRS R0, PSP
STMDB R0!, {R4-R11}
CPSIE I
BX LR
Configuración MPU Dinámica
uint32_t rasr = MPU->RASR;
configASSERT(rasr & HABILITADO);
configASSERT((rasr & TAMANO) == TAMANO_ESPERADO);
Diagnóstico de Fallos
Análisis de HardFault
void HardFault_Handler() {
__asm(
"tst lr, #4\n\t"
"ite eq\n\t"
"mrseq r0, msp\n\t"
"mrsne r0, psp\n\t"
"ldr r1, =BFAR_ADDR\n\t"
"ldr r2, [r1]\n\t"
"bkpt #0\n\t"
);
}
Detección de Pérdida de Ticks
uint32_t t0, t1;
void SysTick_Handler() {
t0 = DWT->CYCCNT;
xManejadorSysTick();
t1 = DWT->CYCCNT;
}
| Retardo (ciclos) | Severidad |
|---|---|
| < 500 | Baja |
| 1200–3500 | Media-Alta |