He escrito una aplicación de cargador de arranque PIC32MX. Me gustaría decirle al enlazador que lo coloque completamente en la memoria de arranque, de modo que todo el espacio del programa se mantenga para la aplicación final.
Actualmente, lo que creo que son las partes relevantes de mi .ld
archivo se ven así:
_RESET_ADDR = 0xBFC00000;
_BEV_EXCPT_ADDR = (0xBFC00000 + 0x380);
_DBG_EXCPT_ADDR = (0xBFC00000 + 0x480);
_DBG_CODE_ADDR = 0xBFC02000;
_DBG_CODE_SIZE = 0xFF0 ;
_GEN_EXCPT_ADDR = _ebase_address + 0x180;
MEMORY
{
kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x10000 /* All C Files will be located here */
kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 /* This memory region is dummy */
exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x200 /* Interrupt vector table */
config3 : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
config2 : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
config1 : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
config0 : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x2FF0 /* C Startup code */
kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x8000
sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000
debug_exec_mem : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
configsfrs : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}
Esta es la secuencia de comandos del enlazador generada por defecto, para un PIC32MX695F512H , aunque la longitud de algunas secciones puede haber cambiado; el diseño de la memoria del chip se encuentra en la página 61 de la hoja de datos.
¿Debería simplemente cambiar el ORIGIN
y LENGTH
de kseg0_program_mem
a los valores de kseg0_boot_mem
y decirle al enlazador que permita secciones superpuestas? Eso no se siente tan limpio. ¿Hay alguna manera de decirle al enlazador que no coloque el código de la aplicación en kseg0_program_mem
sino en kseg0_boot_mem
?
El compilador de C colocará el código de inicio de tiempo de ejecución de C en el kseg0_boot_mem
, que configura la pila, el montón y la inicialización general del procesador. La cantidad de código colocado kseg0_boot_mem
variará entre una compilación de depuración y una de lanzamiento. Si no recuerdo mal, cuando estaba trabajando en un cargador de arranque para un PIC32MX250F, la compilación de depuración ocupaba ~70 % del kseg0_boot_mem
, lo que no era suficiente para mi cargador de arranque.
Si su cargador de arranque es lo suficientemente pequeño como para caber junto kseg0_boot_mem
con el código de inicio de C, reduzca el tamaño de kseg0_boot_mem
y luego muévalo kseg0_program_mem
a la parte superior del nuevo boot_mem
espacio. Tenga en cuenta que no puede mover la ubicación inicial del kseg0_boot_mem
espacio. La ejecución del código comienza en 0xBFC00000
el PIC32 y no hay nada que pueda hacer para cambiar eso. Si desea mover todo el cargador de arranque, también deberá mover la tabla ISR. Por ejemplo:
MEMORY
{
kseg0_program_mem (rx) : ORIGIN = 0xBFC01200, LENGTH = 0x1DF0 /* kseg1_boot is 2FF0 long.*/
kseg0_boot_mem : ORIGIN = 0x9FC00000, LENGTH = 0x1000 /* This memory region is dummy */
exception_mem : ORIGIN = 0xBFC01000, LENGTH = 0x200 /* Relocated ISR table. */
config3 : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
config2 : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
config1 : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
config0 : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x1000 /*This has been reduced in size. Was 0x2FF0*/
kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x8000
sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000
debug_exec_mem : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
configsfrs : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}
NOTA: ¡este es solo un ejemplo de secuencia de comandos del cargador de arranque y de ninguna manera debe copiarse y pegarse en producción!
Dicho esto, puedo decir por experiencia que tratar de incluir un cargador de arranque no trivial en el boot_mem
espacio del programa no funciona. El espacio que queda del código de inicio de C generalmente no es suficiente, especialmente si desea un manejo y validación de errores pesados (¡y sí, SI desea esto!). Eliminar las compilaciones de depuración del arsenal muy limitado de herramientas de depuración integradas tampoco es bueno. Deberá poder depurar en el hardware en algún momento en el futuro. Aprendí esa lección de la manera difícil.
Mi recomendación es dejar la kseg0_boot_mem
sección de código en paz y simplemente trabajar con el kseg0_program_mem
espacio. Tome una porción de la kseg0_program_mem
parte superior o inferior (no importa) y utilícela para el código del gestor de arranque y la tabla ISR. Deje algo de espacio para el crecimiento del código del gestor de arranque también. Tratar con múltiples secuencias de comandos de vinculación es un poco doloroso.
En lugar de hacerlo todo en el enlazador, también puede hacerlo de manera similar a esto
MEMORY
{
kseg0_program_mem (rx) : ORIGIN = 0x9D000000, LENGTH = 0x5000
bootverify_mem (rx) : ORIGIN = 0x9D03FFAC, LENGTH = 0x50
kseg0_boot_mem : ORIGIN = 0x9FC00490, LENGTH = 0xB70
exception_mem : ORIGIN = 0x9FC01000, LENGTH = 0x300
kseg2_boot_mem : ORIGIN = 0x9FC01380, LENGTH = 0xC80
kseg1_boot_mem : ORIGIN = 0xBFC00000, LENGTH = 0x490
debug_exec_mem : ORIGIN = 0xBFC02000, LENGTH = 0xFF0
config3 : ORIGIN = 0xBFC02FF0, LENGTH = 0x4
config2 : ORIGIN = 0xBFC02FF4, LENGTH = 0x4
config1 : ORIGIN = 0xBFC02FF8, LENGTH = 0x4
config0 : ORIGIN = 0xBFC02FFC, LENGTH = 0x4
kseg1_data_mem (w!x) : ORIGIN = 0xA0000000, LENGTH = 0x10000
sfrs : ORIGIN = 0xBF800000, LENGTH = 0x100000
configsfrs : ORIGIN = 0xBFC02FF0, LENGTH = 0x10
}
SECTIONS
{
.config_BFC02FF0 0xBFC02FF0 : {
KEEP(*(.config_BFC02FF0))
} > config3
.config_BFC02FF4 : {
KEEP(*(.config_BFC02FF4))
} > config2
.config_BFC02FF8 : {
KEEP(*(.config_BFC02FF8))
} > config1
.config_BFC02FFC : {
KEEP(*(.config_BFC02FFC))
} > config0
}
PROVIDE(_DBG_CODE_ADDR = 0xBFC02000) ;
PROVIDE(_DBG_CODE_SIZE = 0xFF0) ;
SECTIONS
{
.extra_prgm_mem :
{
*(extra_prgm_mem)
} >kseg0_boot_mem
.extra_prgm_mem2 :
{
KEEP(*(extra_prgm_mem2))
} >kseg2_boot_mem
/*Linker continued*/
Luego, en su código, puede colocar cada función donde desee.
int __attribute__ ((section ("extra_prgm_mem2")))GetVersion(char * Info){
int Result = (Info[4] - '0') * 1000;
Result += ((Info[5] - '0') * 100);
Result += ((Info[6] - '0') * 10);
Result += Info[7] - '0';
}
BOOL __attribute__ ((section ("extra_prgm_mem")))BLMedia_LoadEncryptedFile(char *file_name) {
//Function info
}
Además, tenga en cuenta que si no usa ninguna interrupción, puede ganar otro 0x1000 en el espacio. Por cierto, si esto no es un gestor de arranque en serie, no lo veo adecuado.
Rogelio Rowland
brahans
erik friesen