En el proceso de búsqueda del gestor de arranque para el microcontrolador STM8S103F3, se descubrió que los gestores de arranque disponibles están escritos principalmente en "C", "roban" una cantidad significativa de memoria FLASH y transfieren la tabla de vectores de interrupción.
El gestor de arranque era necesario para algún dispositivo al que es imposible conectar el programador.
Se decidió intentar escribir un gestor de arranque usted mismo con los siguientes requisitos:
- el cargador debería llamarse STM8uLoader;
- El código debe estar escrito en ensamblador (el beneficio del ensamblador aún no está legalmente prohibido);
- el gestor de arranque debe ocupar la menor cantidad posible en la memoria FLASH, la cantidad ocupada en la computadora se considerará ilimitada;
- el cargador no debe mover la tabla de vectores de interrupción;
- el gestor de arranque debe tener una funcionalidad mínima, toda la funcionalidad principal debe ser asumida por la computadora;
- el gestor de arranque debe transferir el control al programa de aplicación dentro de un tiempo razonable después de un reinicio / encendido si no hay conexión a la computadora.
La primera condición se
cumplió instantáneamente, pero los requisitos posteriores tuvieron que ser trabajados.
Primera etapa Código de 65 bytes en la memoria FLASH
Para guardar la tabla de vectores en su lugar, se decidió colocar el código al final de la memoria FLASH y cambiarlo inmediatamente desde el vector de volcado $ 8000.
En el arranque, el control se transfiere al código del cargador de arranque a $ 9FC2. El gestor de arranque configura el UART 9600 8N1, espera dos bytes en el UART y, sin esperar, transfiere el control al programa de aplicación en la dirección almacenada en el par $ 9FFE: $ 9FFF.
Si el cargador recibe los bytes alto y bajo del tamaño del volcado esperado del programa host, lo hace, lo deposita en la memoria RAM y le transfiere el control.
Además, toda la atención recae en el programa en la computadora y el volcado que envía. Debería enviar exactamente los volcados necesarios para completar la tarea actual (leer / borrar / escribir / copiar celdas de memoria STM8). Los volcados deberían poder reemplazarse entre sí en la memoria RAM y transferir el control al programa de aplicación.
La dirección de transición a la aplicación es $ 9FFE: $ 9FFF.
El archivo boot_FLASH.asm:stm8/ TITLE "boot_FLASH.asm" .NOLIST #include "STM8S103F3P.inc" .LIST MOTOROLA WORDS segment byte at 8000 'boot_start' boot_start: jp boot_FLASH_start dc.b $00 ; boot_FLASH ; ******************************************************** ; 0x8004...0x9FC1 WORDS ; segment byte at 8004 'main_FLASH' main_FLASH_start: ldw X, #$03FF ldw SP, X mov UART1_BRR1, #13 mov UART1_CR2, #%00001100 main_FLASH_cycle: callr main_delay ; bset PB_DDR,#5 bset PB_CR1,#5 ; byte1_tx: mov UART1_DR, #$80 byte1_wait_tx btjf UART1_SR, #7, byte1_wait_tx callr main_delay boot_RAM_exit1: ; bres PB_DDR,#5 ; bres PB_CR1,#5 ; ; byte2_tx: mov UART1_DR, #$08 byte2_wait_tx btjf UART1_SR, #7, byte2_wait_tx jra main_FLASH_cycle main_delay: decw X jrne main_delay ret segment byte at 9FC2 'boot_FLASH' boot_FLASH_start: mov UART1_BRR1, #13; Fmaster=16/8=2/9600/16 mov UART1_CR2, #%00001100; / ; UART1 RST_SR boot_FLASH_RST_SR_tx: mov UART1_DR, RST_SR ; , ; ; X ( 200 ) ldw X,#0 boot_FLASH_wait_byte1: decw X jreq boot_FLASH_exit; btjf UART1_SR, #5, boot_FLASH_wait_byte1 ; , , ; X ld A, UART1_DR ld XH, A ; boot_FLASH_wait_byte2: btjf UART1_SR, #5, boot_FLASH_wait_byte2 ; ld A, UART1_DR ld XL, A ; X - ; X ldw Y, #$0400 ; Y 0x0400 (RAM_END + 1) ; boot_FLASH_rx_block_wait: btjf UART1_SR, #5, boot_FLASH_rx_block_wait boot_EEPROM_rx_block_entry: decw Y ; Y ld A, UART1_DR ld (Y), A decw X ; X jrne boot_FLASH_rx_block_wait ; jp (Y) ; () boot_FLASH_exit: dc.b $CC boot_FLASH_exit_addr: dc.w main_FLASH_start end ;
Segunda etapa. Tamaño de código 21 bytes en FLASH y 52 bytes en memoria EEPROM
Seleccionar 65 bytes de la memoria FLASH (en STM8S103F3 es solo 8192 bytes) no es humano. Después de todo, la memoria EEPROM innecesaria con sus 640 bytes está cerca. Dividamos el código del gestor de arranque en dos partes boot_FLASH y boot_EEPROM.
Al cargar, el control se transfiere al código boot_FLASH a $ 9FEF. boot_FLASH copia la imagen del código boot_EEPROM de EEPROM en la memoria RAM y le transfiere el control.
Ahora boot_EEPROM configura UART 9600 8N1, espera los bytes UART y, sin esperar, transfiere el control al programa de aplicación (dejaremos la dirección en el mismo lugar $ 9FFE: $ 9FFF).
Si boot_EEPROM recibe un byte con el tamaño del volcado esperado para la memoria RAM, recibe un volcado, coloca el volcado en otra área de la memoria RAM y le transfiere el control.
Además, todo es como en la primera etapa.
Archivo boot_FLASH_EEPROM.asm: stm8/ TITLE "boot_FLASH_EEPROM.asm" .NOLIST #include "STM8S103F3P.inc" .LIST MOTOROLA WORDS segment byte at 4000 'eeprom' ; boot_EEPROM dc.b $35, $0D, $52, $32, $35, $0C, $52, $35 dc.b $35, $01, $52, $31, $5A, $27, $16, $72 dc.b $0B, $52, $30, $F8, $C6, $52, $31, $72 dc.b $0B, $52, $30, $FB, $3B, $52, $31, $4A dc.b $26, $F5, $96, $5C, $FC, $CE, $9F, $FE dc.b $2B, $FA, $90, $AE, $42, $7F, $AE, $02 dc.b $7F, $CC, $9F, $F4 segment byte at 8000 'boot_start' boot_start: jp boot_FLASH_start dc.b $01 ; boot_FLASH_EEPROM ; ******************************************************** ; 0x8004...0x9FEE segment byte at 8004 'main_FLASH' ; main_FLASH_start: ldw X, #$03FF ldw SP, X mov UART1_BRR1, #13 mov UART1_CR2, #%00001100 main_FLASH_cycle: callr main_delay ; bset PB_DDR,#5 bset PB_CR1,#5 ; byte1_tx: mov UART1_DR, #$80 byte1_wait_tx btjf UART1_SR, #7, byte1_wait_tx callr main_delay boot_RAM_exit1: ; bres PB_DDR,#5 ; bres PB_CR1,#5 ; ; byte2_tx: mov UART1_DR, #$08 byte2_wait_tx btjf UART1_SR, #7, byte2_wait_tx jra main_FLASH_cycle main_delay: decw X jrne main_delay ret ; EEPROM -> RAM segment byte at 9FEF 'boot_FLASH' boot_FLASH_start: ldw X, SP ; Y <- { EEPROM_START + RAM_END} ; Y <- { $4000 + $03FF = $43FF } ldw Y, #$43FF boot_FLASH_copy: ld A, (Y) ld (X), A decw Y decw X jrpl boot_FLASH_copy incw X jp (X) boot_FLASH_exit_address: dc.w main_FLASH_start end ;
Ejecute el archivo
runSTM8uLoader.bat , presione el botón de reinicio en la placa, el gestor de arranque envía el byte 0x01. Se envía un volcado con el código del archivo main_RAM.hex a RAM STM8 a través de UART. La placa comienza a parpadear el LED y envía los bytes 0x20 y 0x02. Presione el botón de reinicio nuevamente. Se inicia el programa de aplicación desde la memoria FLASH, el LED comienza a parpadear más rápido y envía los bytes 0x80 y 0x08.
La tercera etapa. Tamaño del código 18 bytes en memoria FLASH y 52 bytes en bytes de OPCIÓN
Por supuesto, nos apuramos con la memoria EEPROM. ¿Dónde guardar los senos y otras mesas ahora? Y con la memoria FLASH, no todo está claro. ¿Quién decidió almacenar la dirección de control de transferencia del programa de aplicación en la memoria FLASH? Y el mismo byte de la versión del gestor de arranque generalmente se almacena en dos lugares a la vez. ¿Dónde exprimir 52 bytes destinados a EEPROM?
Aquí la litografía nos ayuda. La memoria EEPROM consta de 10 bloques de 64 bytes cada uno. Agregar otro bloque a estos bloques, pero con un tamaño diferente, no es económicamente factible. STMicroelectronics hizo exactamente eso, agregó otro bloque de 64 bytes, llamó a esta área Bytes de OPCIÓN y almacena allí importantes configuraciones de microcontroladores no volátiles (para STM8S103F3 es de hasta 11 bytes). Y, por supuesto, STM olvidó mencionar que todavía quedan 53 células funcionales en esta área. Aparentemente hay muchos modelos STM8, debe dejar espacio para futuras configuraciones importantes.
Nuestro gestor de arranque solo reclama el modelo STM8 sin gestores de arranque integrados. Por lo tanto, tomamos las celdas de respaldo del bloque OPTION Bytes hasta ahora que nadie ve. Es cierto que hay un pequeño inconveniente,
pero resuelto . Un programador convencional no le permitirá escribir información en estas celdas.
Al cargar, el control se transfiere al código copy_boot_FLASH inicial a $ 9FF2. boot_FLASH transfiere la imagen del cargador de arranque boot_OPTION desde el área de Bytes de OPCIÓN a la RAM.
boot_OPTION configura el UART 9600 8N1, envía el byte UART con su versión, espera los bytes UART del programa host y, sin esperar 0.2 segundos, transfiere el control al programa de aplicación en la dirección ubicada en el par $ 4831: $ 4832.
Si boot_OPTION, después de enviar un byte con su versión, toma un byte del tamaño del volcado esperado, luego toma el volcado en sí, lo coloca en la memoria RAM y le transfiere el control.
Además, toda la atención recae en el programa en la computadora y el volcado que envía. Debería enviar exactamente los volcados necesarios para completar la tarea actual (leer / borrar / escribir / copiar celdas de memoria STM8). Los volcados deberían poder reemplazarse entre sí en la memoria RAM y transferir el control al programa de aplicación.
La dirección de transición a la solicitud es $ 4831: $ 4832.
Cargador y código de aplicación para ejecutar en la memoria FLASH: stm8/ TITLE "boot_FLASH_OPTION.asm" .NOLIST #include "STM8S103F3P.inc" .LIST MOTOROLA WORDS segment byte at 4800 'boot_OPTION' ; boot_OPTION dc.b $00, $00, $FF, $00, $FF, $00, $FF, $00 dc.b $FF, $00, $FF, $35, $0D, $52, $32, $35 dc.b $0C, $52, $35, $35, $25, $52, $31, $5A dc.b $27, $16, $72, $0B, $52, $30, $F8, $C6 dc.b $52, $31, $72, $0B, $52, $30, $FB, $3B dc.b $52, $31, $4A, $26, $F5, $96, $5C, $FC dc.b $AE, $80, $04, $2B, $FA, $90, $AE, $42 dc.b $7F, $AE, $02, $7F, $CC, $9F, $F6, $00 segment byte at 8000 'boot_start' boot_start: ldw X, SP jp boot_FLASH_start ; ******************************************************** ; 0x8004...0x9FF1 segment byte at 8004 'main_FLASH' ; main_FLASH_start: ldw X, #$03FF ldw SP, X mov UART1_BRR1, #13 mov UART1_CR2, #%00001100 main_FLASH_cycle: callr main_delay ; bset PB_DDR,#5 bset PB_CR1,#5 ; byte1_tx: mov UART1_DR, #$80 byte1_wait_tx btjf UART1_SR, #7, byte1_wait_tx callr main_delay boot_RAM_exit1: ; bres PB_DDR,#5 ; bres PB_CR1,#5 ; ; byte2_tx: mov UART1_DR, #$08 byte2_wait_tx btjf UART1_SR, #7, byte2_wait_tx jra main_FLASH_cycle main_delay: decw X jrne main_delay ret ; OPTION -> RAM segment byte at 9FF2 'boot_FLASH' boot_FLASH_start: ; Y <- { OPTION_START + RAM_END} ; Y <- { $4800 + $03FF = $43FF } ldw Y, #$43FF boot_FLASH_copy: ld A, (Y) ld (X), A decw Y decw X jrpl boot_FLASH_copy incw X jp (X) boot_FLASH_exit_address: dc.w main_FLASH_start end ;
Código de aplicación para ejecución en memoria RAM: stm8/ TITLE “boot_RAM.asm” MOTOROLA #include "STM8S103F3P.inc" BYTES segment byte at 0000 'boot_RAM_data' boot_RAM_start: ; pull-up ( ) , , 14 ; ld A, #%01001100 ; [A6 4C] ; cpl A ; [43] ; ld PA_CR1, A ; [C7 50 03] ; ld PB_CR1, A ; [C7 50 08] ; ld PC_CR1, A ; [C7 50 0D] ; ld PD_CR1, A ; [C7 50 12] PD6(UART1_RX), PD2, PD1 ; UART1 / 9600, (8 , , 1 ) ; mov UART1_BRR2, #0 ; [35 00 52 33] Fmaster=16/8=2 9600 mov UART1_BRR1, #13 ; [35 0D 52 32] Fmaster=16/8=2 9600 mov UART1_CR2, #%00001100 ; [35 0C 52 35] UART1_CR2.TEN <- 1 UART1_CR2.REN <- 1 / ; UART1 boot_RAM_byte1_tx: mov UART1_DR, #$02 boot_RAM_byte1_wait_tx btjf UART1_SR, #7, boot_RAM_byte1_wait_tx ldw X,#0 ; [AE 00 00] boot_FLASH X boot_RAM_wait1: decw X ; [5A] jreq boot_RAM_exit1 ; jra boot_RAM_wait1 boot_RAM_exit1: ; bres PB_DDR,#5 ; bres PB_CR1,#5 ; ; UART1 boot_RAM_byte2_tx: mov UART1_DR, #$20 ; [35 11 52 31] boot_RAM_byte2_wait_tx btjf UART1_SR, #7, boot_RAM_byte2_wait_tx ldw X,#0 ; [AE 00 00] boot_FLASH X boot_RAM_wait2: decw X ; [5A] jreq boot_RAM_exit2 ; jra boot_RAM_wait2 boot_RAM_exit2: ; bset PB_DDR,#5 ; bset PB_CR1,#5 ; jra boot_RAM_byte1_tx end
Ejecute el archivo
runSTM8uLoader.bat , presione el botón de reinicio en el tablero, el gestor de arranque envía el byte 0x25. Se envía un volcado con el código del archivo main_RAM.hex a RAM STM8 a través de UART. La placa comienza a parpadear el LED y envía los bytes 0x20 y 0x02. Presione el botón de reinicio nuevamente. Se inicia el programa de aplicación desde la memoria FLASH, el LED comienza a parpadear más rápido y envía los bytes 0x80 y 0x08.
En la última etapa, para escribir la imagen del cargador de arranque en el área Bytes de OPCIÓN, debe usar el
método . La esencia del método es que primero necesita que el programador escriba el archivo de firmware boot_OPTION_rev25.hex en la memoria STM8 FLAH, reinicie el microcontrolador, el área de Bytes de OPCIÓN se llenará con la información necesaria y el LED se encenderá. Por otra parte, el programador escribe en el archivo de firmware FLASH desde este artículo
boot_FLASH_OPTION.hex .
Se agregó el código de cargador de arranque "limpio" versión 0x14 sin código de aplicación. Desplegó la imagen boot_OPTION en el código fuente. Comentarios corregidos A diferencia de la versión de $ 25, la dirección de transferencia de control de la aplicación se encuentra en las celdas FLASH de $ 9FFE: $ 9FFFF. El tamaño en FLASH es de 20 bytes, respectivamente.
boot_uC_rev14.asm: stm8/ TITLE "boot_uC_rev14.asm" ; boot_uC = boot_OPTION + boot_FLASH MOTOROLA .NOLIST #include "STM8S103F3P.inc" .LIST WORDS ; ******************************************************** segment byte at 4800 'boot_O_IMG' ;0000FF00FF00FF00FF00FF350D523235 ;0C5235351452315A2716720B5230F8C6 ;5231720B5230FB3B52314A26F5965CFC ;CE9FFE2BFA90AE427FAE027FCC9FF400 ; ; $4800 RAM dc.b $00, $00, $FF, $00, $FF, $00, $FF, $00, $FF, $00, $FF ; OPTION (RAM) ; $480B ($0000) boot_O boot_O_start: ; UART 96008N1 Fmaster=16/8=2/9600/16 ; mov UART1_BRR2, #0 ; [35 00 52 33] mov UART1_BRR1, #13 ; [35 0D 52 32] ; UART1_CR2.TEN <- 1 UART1_CR2.REN <- 1 / mov UART1_CR2, #%00001100 ; [35 0C 52 35] ; $4813 ($0008) boot_E_byte1_tx: ; $14 mov UART1_DR, #$14 ; [35 14 52 31] ; , ; ; X ( 200 ) ; clrw X ; [5F] X boot_F ; $4817 ($000C) boot_O_rx_wait_byte: decw X ; [5A] jreq boot_O_exit ; [27 16] btjf UART1_SR, #5, boot_O_rx_wait_byte ; [72 OB 52 30 F8] ; , , A ; $481F ($0014) ld A, UART1_DR ; [C6 52 31] ; $4822 ($0017) boot_O_rx_wait_block: btjf UART1_SR, #5, boot_O_rx_wait_block ; [72 OB 52 30 FB] push UART1_DR ; [3B 52 31] dec A ; [4A] ; A jrne boot_O_rx_wait_block ; [26 F5] ; $482D ($0022) ldw X, SP ; [96] incw X ; [5C] boot_O_exit_to_FLASH: jp (X) ; [FC] ; $4830 ($0025) boot_O_exit: ldw X, boot_F_exit_address ; [CE 9F FE] jrmi boot_O_exit_to_FLASH ; [2B FA] ; if X < $8000 $0000 ; EEPROM boot_O_exit_to_EEPROM: ; Y <- { EEPROM_END} ldw Y, #$427F ; [90 AE 42 7F] ; X <- { EEPROM_END - EEPROM_START } ; EEPROM RAM ldw X, #$027F ; [AE 02 7F] jp boot_F_copy ; [CC 9F F4] ; $483F ($0034) dc.b $00 ; boot_O_end: ; ******************************************************** segment byte at 8000 'RESET_vector' ;96CC9FF0 ldw X, SP ; [96] X <- RAM_END jp boot_F_start ; [CC 9F F0] ; ******************************************************** ; 0x8004...0x9FEF segment byte at 8004 'main_FLASH' ;20FE jra * ; [20 FE] ; ******************************************************** ; boot_FLASH segment byte at 9FF0 'boot_F' ;90AE4C0A90F6F7905A5A2AF85CFC8004 boot_F_start: ; Y <- { boot_O_START + RAM_END} { $480B + $03FF = $4C0A } ldw Y, #$4C0A ; [90 AE 4C 0A] ; ; boot_FLASH, boot_OPTION boot_F_copy: ld A, (Y) ; [90 F6] ld (X), A ; [F7] decw Y ; [90 5A] decw X ; [5A] jrpl boot_F_copy ; [2A F8] X(Y) >= RAM_START(boot_O_START) incw X ; [5C] jp (X) ; [FC] boot_F_exit_address: dc.w $8004 ; [80 04] ; dc.w $0000 ; [00 00] end ;
Se agregó un código de cargador de arranque "limpio" versión 0x25 sin código de aplicación. Desplegó la imagen boot_OPTION en el código fuente. Comentarios corregidos A diferencia de la versión de $ 14, la dirección de transferencia de control de la aplicación se encuentra en las celdas $ 4831: $ 4832 del área OPTION Bytes. El tamaño ocupado en la memoria FLASH, respectivamente, disminuyó a 18 bytes. El tamaño ocupado en el área de Bytes de OPCIÓN no ha cambiado (52 bytes + 1 reserva).
boot_uC_rev14.asm: stm8/ TITLE "boot_uC_rev25.asm" ; boot_uC = boot_OPTION + boot_FLASH MOTOROLA .NOLIST #include "STM8S103F3P.inc" .LIST BYTES ; ******************************************************** ; EEPROM ; boot_O_exit_address $0000 ( <$8000) ; ; segment byte at 0000 'boot_O_IMG' main_ram: ;20FE jra * ; [20 FE] WORDS ; ******************************************************** segment byte at 4800 'boot_O_IMG' ;0000FF00FF00FF00FF00FF350D523235 ;0C5235351452315A2716720B5230F8C6 ;5231720B5230FB3B52314A26F5965CFC ;AE80042BFA90AE427FAE027FCC9FF600 ; ; $4800 RAM dc.b $00, $00, $FF, $00, $FF, $00, $FF, $00, $FF, $00, $FF ; OPTION (RAM) ; $480B ($0000) boot_OPTION boot_O_start: ; UART 96008N1 Fmaster=16/8=2/9600/16 ; mov UART1_BRR2, #0 ; [35 00 52 33] mov UART1_BRR1, #13 ; [35 0D 52 32] ; UART1_CR2.TEN <- 1 UART1_CR2.REN <- 1 / mov UART1_CR2, #%00001100 ; [35 0C 52 35] ; $4813 ($0008) boot_E_byte1_tx: ; $14 mov UART1_DR, #$14 ; [35 14 52 31] ; , ; ; X ( 200 ) ; clrw X ; [5F] X boot_F ; $4817 ($000C) boot_O_rx_wait_byte: decw X ; [5A] jreq boot_O_exit ; [27 16] btjf UART1_SR, #5, boot_O_rx_wait_byte ; [72 OB 52 30 F8] ; , , A ; $481F ($0014) ld A, UART1_DR ; [C6 52 31] ; $4822 ($0017) boot_O_rx_wait_block: btjf UART1_SR, #5, boot_O_rx_wait_block ; [72 OB 52 30 FB] push UART1_DR ; [3B 52 31] dec A ; [4A] ; A jrne boot_O_rx_wait_block ; [26 F5] ; $482D ($0022) ldw X, SP ; [96] incw X ; [5C] boot_O_exit_to_FLASH: jp (X) ; [FC] ; $4830 ($0025) boot_O_exit: dc.b $AE ; ldw X, #boot_O_exit_address ; [AE 80 04] ; $4831 ($0026) ; boot_O_exit_address: dc.w main_flash ; [80 04] ; dc.w main_ram ; [00 00] jrmi boot_O_exit_to_FLASH ; [2B FA] ; if X < $8000 $0000 ; EEPROM boot_O_exit_to_EEPROM: ; Y <- { EEPROM_END} ldw Y, #$427F ; [90 AE 42 7F] ; X <- { EEPROM_END - EEPROM_START } ; EEPROM RAM ldw X, #$027F ; [AE 02 7F] jp boot_F_copy ; [CC 9F F4] ; $483F ($0034) dc.b $00 ; boot_O_end: ; ******************************************************** segment byte at 8000-8003 'RESET_vector' ;96CC9FF2 ldw X, SP ; [96] X <- RAM_END jp boot_F_start ; [CC 9F F2] ; ******************************************************** ; 0x8004...0x9FF1 segment byte at 8004 'main_FLASH' main_flash: ;20FE jra * ; [20 FE] ; ******************************************************** ; boot_FLASH segment byte at 9FF2-9FFF 'boot_F' ;90AE4C0A90F6F7905A5A2AF85CFC boot_F_start: ; Y <- { boot_O_START + RAM_END} { $480B + $03FF = $4C0A } ldw Y, #$4C0A ; [90 AE 4C 0A] ; ; boot_FLASH, boot_OPTION boot_F_copy: ld A, (Y) ; [90 F6] ld (X), A ; [F7] decw Y ; [90 5A] decw X ; [5A] jrpl boot_F_copy ; [2A F8] X(Y) >= RAM_START(boot_O_START) incw X ; [5C] jp (X) ; [FC] end ;
La dirección de transferencia de control de la aplicación en la memoria FLASH se puede seleccionar del rango de $ 8004 ... $ 9FF1. Para una imagen de código de aplicación de la memoria EEPROM, la transferencia de control solo es posible en la dirección $ 0000 en la memoria RAM.
El programa host puede pasar cualquier dirección de transferencia de control como el segundo argumento de línea de comando.
El código fuente del programa host se puede encontrar
aquí . También hay contactos para una comunicación más detallada.
Pido a los lectores críticas específicas y sugerencias para una mayor reducción del código.
También propongo leer el artículo
"Cómo comprimir el gestor de arranque para STM8 al tamaño de 8 bytes en la memoria FLASH" .