En un microcontrolador clásico operando en Bare-Metal, el código C tiene acceso irrestricto a toda la memoria RAM. Esto es un peligro mortal en sistemas concurrentes. Si instalas un RTOS y la "Tarea de Pantalla" tiene un error aritmético (desbordamiento de puntero), puede escribir datos accidentalmente en la dirección de memoria donde reside la variable estado_valvula de la "Tarea de Metrología". El despachador se abrirá solo. Para evitar esto, las normativas de aviación exigen que cada tarea esté encapsulada físicamente.
El ARM Cortex-M4 cuenta con un coprocesador de seguridad integrado llamado MPU (Memory Protection Unit). El MPU te permite definir regiones de memoria estrictas para cada tarea del RTOS. Cuando el planificador (Scheduler) cambia el contexto a la Tarea A, reconfigura instantáneamente el MPU para que la Tarea A solo pueda leer y escribir en su propio bloque de RAM. Si la Tarea A intenta tocar la RAM del Kernel o la RAM de la Tarea B, el hardware dispara una interrupción inmediata llamada MemManage_Handler, cortando la ejecución de la tarea corrupta en un solo ciclo de reloj, antes de que el daño ocurra.
Paso 1: Uso de SafeRTOS o FreeRTOS-MPU.
El repositorio estándar de FreeRTOS opera sin protección de memoria para ser rápido. Para sistemas industriales certificados (IEC 61508), debes compilar la variante FreeRTOS-MPU. Esta variante fuerza a que las tareas se creen en modo no privilegiado (Unprivileged) y te obliga a pasarle al planificador un arreglo con las direcciones de RAM exactas donde la tarea tiene permitido vivir.
Paso 2: Interceptar el `MemManage_Handler`.
Cuando el hardware detecta una violación, invoca esta interrupción. En un entorno de aviación, esta función no se queda en un bucle infinito; guarda el registro del fallo en la memoria EEPROM/SRAM de respaldo (Continuous Journaling), apaga los actuadores de inmediato y reinicia el procesador (Hard Reset) para purgar la corrupción en microsegundos.
Observa cómo la programación abandona el paradigma de "declarar variables libres" y se convierte en la delimitación estricta de áreas físicas en el silicio.
/**
* @file rtos_mpu_isolation.c
* @brief Configuración de Hardware MPU para aislamiento espacial de tareas en FreeRTOS
*/
#include "stm32f4xx_hal.h"
#include "FreeRTOS.h"
#include "task.h"
// Definición estricta de límites de RAM para la Tarea de Pantalla (Peligrosa/Inestable)
#define LCD_TASK_RAM_BASE 0x20008000
#define LCD_TASK_RAM_SIZE MPU_REGION_SIZE_4KB
// =========================================================================
// CONFIGURACIÓN DE LA UNIDAD DE PROTECCIÓN DE MEMORIA (MPU)
// =========================================================================
/**
* @brief Configura el hardware MPU antes de arrancar el RTOS Scheduler.
*/
void System_MPU_Config(void) {
MPU_Region_InitTypeDef MPU_InitStruct = {0};
// 1. Deshabilitar MPU para configuración segura
HAL_MPU_Disable();
// 2. Región 1: Área de ejecución de la Tarea LCD (Aislada)
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.BaseAddress = LCD_TASK_RAM_BASE;
MPU_InitStruct.Size = LCD_TASK_RAM_SIZE;
// PERMISOS DE ACCESO CRÍTICOS:
// MPU_REGION_PRIV_RW_URO: El Kernel (Privileged) puede leer y escribir.
// La Tarea (Unprivileged User) solo puede Leer. NO PUEDE escribir fuera de sus límites.
MPU_InitStruct.AccessPermission = MPU_REGION_PRIV_RW_URO;
// Propiedades físicas para prevención de ejecución de código malicioso en RAM
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
// 3. Activar el MPU con la región de fondo (Background Region)
// para permitir acceso total a las interrupciones del Kernel.
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
// =========================================================================
// EL TRIBUNAL DE HARDWARE (Manejador de Faltas de Memoria)
// =========================================================================
/**
* @brief Interrupción disparada físicamente en 1 ciclo de reloj si una tarea
* intenta tocar memoria que no le pertenece.
*/
void MemManage_Handler(void) {
// 1. Apagar electroválvula inmediatamente por seguridad de hardware
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
// 2. Leer registros de estado de falla para saber qué tarea intentó el hack/corrupción
uint32_t fault_address = SCB->MMFAR; // MemManage Fault Address Register
// 3. Guardar en Journaling (Registro BKP RTC)
// (Ej. log_fault_to_rtc(fault_address));
// 4. Reinicio táctico del sistema
NVIC_SystemReset();
}
Objetivo del día: Garantizar la integridad operativa mediante hardware enforcing en entornos RTOS concurrentes.
Hemos diseñado tu Despachador de Gas LP para soportar explosiones externas, apagones y hackeos mTLS. Pero, ¿quién vigila al vigilante? Al abandonar la simplicidad del bucle secuencial (Bare-Metal) e instalar un RTOS para manejar interfaces gráficas o redes, invitas al caos de la concurrencia a tu memoria RAM. En lenguajes de bajo nivel como C, la ausencia de control automático de límites (Bounds Checking) significa que un desbordamiento de búfer al dibujar la pantalla LCD podría sobreescribir la memoria donde se almacenan los mililitros exactos que el cliente está pagando.
Al implementar la **MPU (Unidad de Protección de Memoria)** en conjunto con una versión fortificada de FreeRTOS, creas murallas de silicio infranqueables entre tus procesos. El hardware del STM32 actúa como un juez implacable. Si la tarea del Wi-Fi enloquece e intenta leer la variable secreta de las válvulas, la MPU detendrá el procesador en nanosegundos disparando el `MemManage_Handler`. El daño está contenido. La válvula se cierra automáticamente. Has elevado el software de una simple máquina a una arquitectura de supervivencia matemática requerida por la aeronáutica.