Guardar una variable entre reinicios en un microcontrolador sin usar memoria flash

Estoy desarrollando un cargador de arranque y tengo algunos problemas para pasar del cargador de arranque a la aplicación. Por lo que puedo ver, el problema se debe a que estoy realizando ciertas inicializaciones en el cargador de arranque que luego también se realizan en la aplicación. Publiqué una pregunta sobre esto en los foros de TI ( https://e2e.ti.com/support/microcontrollers/other/f/908/p/894608/3308592#3308592 ) pero no recibo ninguna respuesta, así que busco para otra forma de arreglarlo.
Mi idea ahora es iniciar el gestor de arranque, descargar la imagen de la aplicación, guardarla en la memoria flash y luego, en lugar de saltar a la aplicación, quiero reiniciar el dispositivo y saltar a la aplicación antes de que se haya realizado ningún tipo de inicialización. No estoy seguro de si esto funcionará, pero he estado atascado en el salto del cargador de arranque a la aplicación por un tiempo y finalmente quiero hacer algún progreso.

Para que esto funcione, el cargador de arranque deberá saber de alguna manera que debe saltar a la aplicación antes de cualquier inicialización. Hasta donde sé, no es posible simplemente escribir en un solo byte en algún lugar de la memoria flash porque requerirá borrar un bloque completo y el tamaño del bloque en el dispositivo que estoy usando es de 8 KB. Parece un desperdicio reservar 8 KB en un dispositivo, solo para poder guardar un valor simple para transferir entre reinicios del sistema.

¿Alguien tiene algún consejo sobre cómo podría lograr esto?

Estoy desarrollando para CC2652R1F usando Code Composer Studio junto con el compilador TI v18.12.5.LTS.

EDITAR :
Intenté usar la situación de kkrambo pero parece que no funciona correctamente.
Edité el archivo de comandos de mi enlazador para incluir una sección .boot_cfg en la RAM con un tamaño de cuatro. Puse el nuevo archivo de comando del enlazador más abajo.
Luego creé una variable global uint32_t configen mi archivo para #pragma DATA_SECTION(config, ".boot_cfg");vincularlo a esa sección, pero no estoy seguro de haberlo hecho correctamente. Después de eso, intenté leer el valor, luego cambiar y luego reiniciar el sistema para ver si funcionaba. Este es el código que usé:

    if (config == 0) {
        GPIO_write(CONFIG_GPIO_LED_RED, CONFIG_GPIO_LED_ON);
        sleep(2);
        config = 2;
        SysCtrlSystemReset();
    } else {
        GPIO_write(CONFIG_GPIO_LED_GREEN, CONFIG_GPIO_LED_ON);
        while(1) {}
    }

Cuando simplemente actualizo el gestor de arranque para no tener que reiniciar el dispositivo usando el depurador porque creo que podría reiniciar la alimentación. Veo que se enciende la luz roja, luego el valor debería cambiar y el sistema debería reiniciarse y luego, con suerte, vería la luz verde se enciende, pero ninguna de las luces se enciende. Así que creo que la SysCtrlSystemReset()función podría no estar funcionando probablemente.
Así que intenté pasar por el cargador de arranque paso a paso, luego, después de la config = 2;declaración, usé el botón de reinicio de la CPU en el IDE para volver al principio, pero luego, cuando vuelvo a la declaración if, el valor sigue siendo 0.

Archivo de comandos del enlazador:

--stack_size=1024   /* C stack is also used for ISR stack */

--heap_size=256

/* Retain interrupt vector table variable                                    */
--retain=g_pfnVectors
/* Override default entry point.                                             */
--entry_point ResetISR
/* Allow main() to take args                                                 */
--args 0x8
/* Suppress warnings and errors:                                             */
/* - 10063: Warning about entry point not being _c_int00                     */
/* - 16011, 16012: 8-byte alignment errors. Observed when linking in object  */
/*   files compiled using Keil (ARM compiler)                                */
--diag_suppress=10063,16011,16012

#define FLASH_BASE              0x0
#define FLASH_SIZE              0x58000
#define RAM_BASE                0x20000000
#define RAM_CFG_BASE            0x20013FFC
#define RAM_CFG_SIZE            0x4 // reserve 4 bytes of ram for bootloader config
#define RAM_SIZE                0x14000 - RAM_CFG_SIZE
#define GPRAM_BASE              0x11000000
#define GPRAM_SIZE              0x2000

#define FLASH_START             FLASH_BASE

#define PAGE_SIZE               0x2000

#define BOOT_BASE               0x50000
#define BOOT_END                FLASH_CCFG_START - 1
#define BOOT_SIZE               ((BOOT_END) - (BOOT_BASE) + 1)

#define APP_BASE                0x0
#define APP_END                 BOOT_BASE
#define APP_SIZE                BOOT_BASE

#define FLASH_CCFG_START        0x00057FA8
#define FLASH_CCFG_END          (FLASH_START + FLASH_SIZE - 1)
#define FLASH_CCFG_SIZE         ((FLASH_CCFG_END) - (FLASH_CCFG_START) + 1)

/* System memory map */

MEMORY
{

    BOOT (RWX)  : origin = BOOT_BASE, length = BOOT_SIZE

    APP (RWX) : origin = APP_BASE, length = APP_SIZE

    FLASH_CCFG (RX) : origin = FLASH_CCFG_START, length = FLASH_CCFG_SIZE

    /* Application uses internal RAM for data */
    SRAM (RWX) : origin = RAM_BASE, length = RAM_SIZE
    RAM_CFG (RWX) : origin = RAM_CFG_BASE, length = RAM_CFG_SIZE
    /* Application can use GPRAM region as RAM if cache is disabled in the CCFG
    (DEFAULT_CCFG_SIZE_AND_DIS_FLAGS.SET_CCFG_SIZE_AND_DIS_FLAGS_DIS_GPRAM = 0) */
    GPRAM (RWX): origin = GPRAM_BASE, length = GPRAM_SIZE
}



/* Create global constant that points to top of stack */
/* CCS: Change stack size under Project Properties    */
__STACK_TOP = __stack + __STACK_SIZE;


/* Section allocation in memory */

SECTIONS
{
    .intvecs        :   > BOOT_BASE
    .text           :   > BOOT
    .TI.ramfunc     : {} load=BOOT, run=SRAM, table(BINIT)
    .const          :   > BOOT
    .constdata      :   > BOOT
    .rodata         :   > BOOT
    .binit          :   > BOOT
    .cinit          :   > BOOT
    .pinit          :   > BOOT
    .init_array     :   > BOOT
    .emb_text       :   > BOOT
    .ccfg           :   > FLASH_CCFG (HIGH)

    .boot_cfg       :   > RAM_CFG
    .vtable         :   > SRAM
    .vtable_ram     :   > SRAM
     vtable_ram     :   > SRAM
    .data           :   > SRAM
    .bss            :   > SRAM
    .sysmem         :   > SRAM
    .stack          :   > SRAM (HIGH)
    .nonretenvar    :   > SRAM

    .gpram          :   > GPRAM

}
¿Usar una EEPROM serial separada?
@DaveTweed Tenemos una EEPROM conectada a través de SPI, pero no estoy seguro de cómo comunicarme con ella sin usar la API de Texas Instruments, que requiere la inicialización que creo que está causando los problemas de salto.
@VincentKen Descúbrelo. Ruta más rápida y fácil.
La API podría estar (re)iniciando la interfaz SPI, lo que no debería ser un problema, pero si está modificando el contenido de su EEPROM, ¡está seriamente dañada!
A menos que la variable que desea guardar sea solo si realizó un arranque suave o no. Debería haber una bandera que pueda monitorear eso, posiblemente en su perro guardián.
@DaveTweed El uso de requiere primero para llamar SPI_init()y luego SPI_open()para abrir una interfaz específica. Puedo llamar al primero antes de cualquier otra inicialización, pero al llamar SPI_open()antes de llamar Board_init()termino en el FaultISR. Creo que esto Board_init()está causando todos estos problemas, así que me gustaría saltar antes de llamarlo.
No entiendo. ¿ Bajo qué condiciones no llamarías Board_init()antes de hacer cualquier otra cosa? Si está haciendo algo que no desea, entonces debe modificarlo.
@DaveTweed Lo Board_init()genera automáticamente Code Composer Studio en función de las definiciones en un archivo .syscfg. La aplicación también tiene su propio Board_init()método, por lo que primero se llama en el cargador de arranque y luego nuevamente en la aplicación. Eliminarlo de la aplicación me permitió tomar algunos pasos adicionales después de saltar usando el depurador. Por supuesto, eventualmente se rompió porque la Board_init()función debe llamarse antes de que se pueda usar cualquier API.

Respuestas (1)

Puede crear una sección personalizada en la RAM que no se inicialice durante el inicio para que los valores anteriores al restablecimiento parcial o al salto permanezcan después. Esto funciona solo para restablecimientos parciales y saltos. Si se desconecta la alimentación (restablecimiento completo), los valores de esta sección no se inicializarán.

Su sistema tiene un código de inicio que configura el entorno de tiempo de ejecución de C antes de llamar a main. Su proyecto puede estar utilizando el código de inicio predeterminado proporcionado por su cadena de herramientas. El código de inicio predeterminado probablemente inicializa la sección .bss a cero e inicializa las variables en la sección .data copiando desde la sección .rodata. Si su cargador de arranque y la aplicación se compilan como proyectos separados, cada uno tiene su propio código de inicio, secciones de secciones .bss, .data y .rodata.

Su proyecto también puede estar utilizando el script de vinculación predeterminado proporcionado por su cadena de herramientas. El script del enlazador predeterminado proporciona las secciones de memoria, incluidos .bss, .data y .rodata. Puede personalizar la secuencia de comandos del enlazador para sus proyectos y agregar una sección personalizada denominada .myspecialsection. Puede ubicar .myspecialsection en una dirección y tamaño fijos para que tanto el cargador de arranque como la aplicación usen la misma memoria para esta sección. Puede hacer que .myspecialsection no sea inicializado por el código de inicio. Y puede asignar variables estáticamente y ubicarlas en .myspecialsection. Ahora el gestor de arranque o la aplicación pueden escribir un valor en .myspecialsection y realizar un reinicio por software o saltar al otro programa y los valores en .myspecialsection mantendrán sus valores.

Lea el manual del enlazador para obtener detalles sobre cómo crear una sección, cómo ubicarla y dimensionarla, cómo hacer que no se inicialice y cómo ubicar variables en la sección.

Además, considere usar una suma de verificación en los datos en .myspecialsection para evitar usar los datos cuando no están inicializados.

Agregué una edición a mi pregunta para mostrar los resultados que obtuve al intentar esto. no estoy seguro si lo hice bien
Compruebe la dirección de la configvariable en el depurador. ¿Es la dirección dentro de la sección .boot_cfg como esperaba? También verifique si el código de inicio está inicializando la sección .boot_cfg. ¿Necesita algún tipo de modificador "NOINIT" en algún lugar del script del enlazador?
Agregar TYPE=NOINITa la definición de la sección parece haberlo solucionado. Pero mientras buscaba formas de iniciar un reinicio por software, encontré que HAL_SYSTEM_RESET()en sus comentarios dice que el sistema CC26xx no ha sido diseñado para manejar reinicios por software y los restablecimientos por software harán que el sistema sea inestable y que use restablecimientos completos en su lugar.