Cuando le das al botón de "Compilar", ocurren tres cosas:
.c a código Ensamblador (Assembly) creando archivos objeto (.o). Hasta este momento, las funciones no tienen una dirección de memoria fija..o, los une y les asigna direcciones físicas reales (ej. 0x08010A42) basándose en las reglas de un archivo de texto llamado Linker Script (.ld).El código C tiene diferentes tipos de datos que deben mapearse a hardware distinto:
.isr_vector: La tabla de interrupciones. Obligatoriamente debe estar al principio de la memoria Flash asignada..text: Tu código ejecutable. Va a la Flash..rodata: Constantes (ej. la llave de AWS o el arreglo de la melodía del zumbador). Van a la Flash para no gastar RAM..data y .bss: Variables que cambian de valor. El Linker anota sus direcciones en la memoria RAM (0x20000000).El STM32F401 tiene sectores de diferentes tamaños. No puedes borrar "medio sector", la borradura de Flash funciona por páginas o sectores completos. El particionamiento ideal es:
0x08000000)0x08010000)0x08040000)Ubicando el Archivo: Si utilizas STM32CubeIDE o un Makefile generado por CubeMX, busca un archivo con la extensión .ld (por ejemplo, STM32F401RETX_FLASH.ld). Este es el mapa maestro que dicta el destino final de cada variable de tu RTOS.
Ejercicio 1: Modificación del Linker Script. Vamos a modificar el archivo .ld de nuestra Aplicación Principal (el código de la Fase 5). Cambiaremos el ORIGIN de la FLASH para que empiece en el Sector 4, y limitaremos su LENGTH para que el compilador nos lance un error inmediato (Memory Overflow) si nuestro código crece demasiado y amenaza con invadir el Slot de Descargas OTA.
/* ========================================================================= */
/* ARCHIVO: STM32F401RETX_FLASH.ld (Para la Aplicación FOTA) */
/* ========================================================================= */
/* Puntos de Entrada y Pila (Stack) */
ENTRY(Reset_Handler)
_estack = 0x20018000; /* Final de los 96K de RAM (Puntero inicial) */
/* Cantidad mínima garantizada para Heap y Stack local */
_Min_Heap_Size = 0x200; /* 512 Bytes */
_Min_Stack_Size = 0x400; /* 1024 Bytes */
/*
* =========================================================================
* PARTICIONAMIENTO DE MEMORIA (MEMORY MAPPING)
* =========================================================================
* Memoria Total Flash : 512 KB (0x08000000 a 0x0807FFFF)
* RAM Total : 96 KB (0x20000000 a 0x20017FFF)
*
* - BOOTLOADER: 0x08000000, LENGTH = 64K (Sectores 0 a 3)
* - APP ACTIVA: 0x08010000, LENGTH = 192K (Sectores 4 y 5) <-- ESTAMOS AQUÍ
* - OTA SLOT: 0x08040000, LENGTH = 256K (Sectores 6 y 7)
* =========================================================================
*/
MEMORY
{
/* Deshabilitamos la dirección base original. Esto obliga al Linker
a reubicar todas las funciones C a partir del Offset 0x10000 */
/* FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 512K (ORIGINAL) */
/* NUEVA CONFIGURACIÓN FOTA APP */
FLASH (rx) : ORIGIN = 0x08010000, LENGTH = 192K
/* La RAM no cambia, ambos (Bootloader y App) la comparten en momentos
diferentes del tiempo (No se ejecutan simultáneamente) */
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 96K
}
/* ========================================================================= */
/* SECCIONES (SECTIONS) */
/* ========================================================================= */
SECTIONS
{
/*
* 1. TABLA DE VECTORES
* Esta sección debe ir obligatoriamente al inicio de la FLASH asiganda.
* El hardware del NVIC la buscará aquí gracias al SCB->VTOR modificado en C.
*/
.isr_vector :
{
. = ALIGN(4);
KEEP(*(.isr_vector)) /* 'KEEP' evita que el optimizador la borre */
. = ALIGN(4);
} >FLASH
/*
* 2. CÓDIGO EJECUTABLE (Texto)
* Aquí va tu lógica de RTOS, drivers HAL y el código C compilado.
*/
.text :
{
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.glue_7) /* glue arm to thumb code */
*(.glue_7t) /* glue thumb to arm code */
KEEP (*(.init))
KEEP (*(.fini))
. = ALIGN(4);
_etext = .; /* Marca el fin de la sección de texto */
} >FLASH
/*
* 3. DATOS DE SOLO LECTURA (Constantes)
* Arreglos de melodías del buzzer, certificados AWS, strings de LCD.
*/
.rodata :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} >FLASH
/*
* 4. DATOS INICIALIZADOS (.data) y NO INICIALIZADOS (.bss)
* Se almacenan en RAM para ser modificables. El código de arranque
* copia los valores iniciales desde la FLASH a la RAM al encender.
*/
.data :
{
/* ... (Configuración estándar de data) ... */
} >RAM AT> FLASH
.bss :
{
/* ... (Configuración estándar de bss) ... */
} >RAM
/* Validaciones finales de Stack y Heap */
._user_heap_stack :
{
. = ALIGN(8);
PROVIDE ( end = . );
PROVIDE ( _end = . );
. = . + _Min_Heap_Size;
. = . + _Min_Stack_Size;
. = ALIGN(8);
} >RAM
}
Objetivo del día: Particionamiento Estático y Protección contra Memory Overflows.
Implementar FOTA no se trata solo de descargar un archivo binario; se trata de gestión del riesgo. En sistemas industriales, no puedes permitir que tu aplicación crezca indefinidamente hasta colisionar con la memoria del Bootloader o con el espacio reservado para la actualización. Un desbordamiento físico arruinaría la integridad del sistema.
Al editar manualmente el **Linker Script (`.ld`)**, has implementado un "Contrato de Espacio" a nivel de compilador. Le dijiste a GCC: *"Tienes exactamente 192 Kilobytes para el código de este Despachador; ni un byte más"*. Si mañana importas una librería criptográfica gigante (como mbedTLS) y el código supera los 192KB, el proceso de construcción (Build Process) abortará con un error contundente (`region FLASH overflowed by X bytes`) en lugar de compilar un binario defectuoso. Además, aseguraste que la **Tabla de Vectores (.isr_vector)** se coloque milimétricamente en el Offset cero del Sector 4 (`0x08010000`), permitiendo que el hardware ARM Cortex-M4 encuentre las interrupciones del Caudalímetro sin fallar. Has convertido la geografía de tu memoria en una fortaleza estática.
ORIGIN a la dirección del sector asignado (ej. 0x08010000).LENGTH actúa como un guardián de seguridad (Boundary Checker). Si el binario compilado supera este tamaño, el Linker abortará la compilación, previniendo invasiones a sectores adyacentes (OTA Slot o Bootloader)..isr_vector debe ser forzada al inicio absoluto de la partición de FLASH. Si esta tabla queda desplazada aunque sea por 4 bytes, las interrupciones del hardware (DMA, UART, TIMERS) apuntarán a código erróneo y la máquina sufrirá un HardFault.0x20000000) al arrancar.