Ao procurar o carregador de inicialização para o microcontrolador STM8S103F3, verificou-se que os gerenciadores de inicialização disponíveis são escritos principalmente em “C”, “roubam” uma quantidade significativa de memória FLASH e transferem a tabela de vetores de interrupção.
O carregador de inicialização era necessário para algum dispositivo ao qual é impossível conectar o programador.
Decidiu-se tentar escrever um gerenciador de inicialização com os seguintes requisitos:
- o carregador deve ser chamado STM8uLoader;
- O código deve ser escrito em assembler (o benefício do assembler ainda não é legalmente proibido);
- o carregador de inicialização deve ocupar a menor quantidade possível na memória FLASH; a quantidade ocupada no computador será considerada ilimitada;
- o carregador não deve mover a tabela de vetores de interrupção;
- o carregador de inicialização deve ter funcionalidade mínima, todas as principais funcionalidades devem ser assumidas pelo computador;
- o carregador de inicialização deve transferir o controle para o programa aplicativo dentro de um tempo razoável após uma redefinição / inicialização, se não houver conexão com o computador.
A primeira condição foi instantaneamente
cumprida , mas os requisitos subsequentes tiveram que ser trabalhados.
Primeira etapa. Código de 65 bytes na memória FLASH
Para salvar a tabela de vetores em seu lugar, foi decidido colocar o código no final da memória FLASH e alternar para ele imediatamente a partir do vetor de despejo $ 8000.
Na inicialização, o controle é transferido para o código do carregador de inicialização em US $ 9FC2. O carregador de inicialização configura o UART 9600 8N1, aguarda dois bytes no UART e, sem esperar, transfere o controle para o programa aplicativo no endereço armazenado no par $ 9FFE: $ 9FFF.
Se o carregador recebe os bytes alto e baixo do tamanho do despejo esperado do programa host, ele pega o despejo em si, coloca o despejo na memória RAM e transfere o controle para ele.
Além disso, todo o cuidado é do programa no computador e do dump que ele envia. Ele deve enviar exatamente os dumps necessários para concluir a tarefa atual (ler / apagar / gravar / copiar células de memória STM8). Os despejos devem poder substituir um ao outro na memória RAM e transferir o controle para o programa aplicativo.
O endereço de transição para o aplicativo é $ 9FFE: $ 9FFF.
O arquivo 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. Tamanho do código 21 bytes em FLASH e 52 bytes na memória EEPROM
Selecionar 65 bytes da memória FLASH (no STM8S103F3 são apenas 8192 bytes) não é humano. Afinal, a memória EEPROM desnecessária, com seus 640 bytes, fica nas proximidades. Vamos dividir o código do carregador de inicialização em duas partes boot_FLASH e boot_EEPROM.
Ao carregar, o controle é transferido para o código boot_FLASH a US $ 9FEF. boot_FLASH copia a imagem de código boot_EEPROM da EEPROM para a memória RAM e transfere o controle para ela.
Agora o boot_EEPROM configura o UART 9600 8N1, aguarda os bytes do UART e, sem esperar, transfere o controle para o programa de aplicativo (deixaremos o endereço no mesmo local $ 9FFE: $ 9FFF).
Se o boot_EEPROM receber um byte com o tamanho do despejo esperado para a memória RAM, ele será despejado em seguida, colocará o despejo em outra área da memória RAM e transferirá o controle para ele.
Além disso, tudo é como no primeiro estágio.
Arquivo 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 ;
Execute o arquivo
runSTM8uLoader.bat , pressione o botão de reset na placa, o carregador de inicialização envia o byte 0x01. Um dump com o código do arquivo main_RAM.hex é enviado para a RAM STM8 via UART. A placa começa a piscar o LED e envia os bytes 0x20 e 0x02. Pressione o botão de reset novamente. O programa aplicativo da memória FLASH é iniciado, o LED começa a piscar mais rapidamente e envia os bytes 0x80 e 0x08.
A terceira etapa. Tamanho do código 18 bytes na memória FLASH e 52 bytes em OPTION Bytes
Obviamente, nos apressamos com a memória EEPROM. Onde armazenar os senos e outras mesas agora? E com a memória FLASH, nem tudo está claro. Quem decidiu armazenar o endereço de controle de transferência do programa aplicativo na memória FLASH? E o mesmo byte da versão do carregador de inicialização geralmente é armazenado em dois locais ao mesmo tempo. Onde espremer 52 bytes destinados à EEPROM?
Aqui a litografia nos ajuda. A memória EEPROM consiste em 10 blocos de 64 bytes cada. Adicionar outro bloco a esses blocos, mas com um tamanho diferente, não é economicamente viável. A STMicroelectronics fez exatamente isso, adicionou outro bloco de 64 bytes, denominado essa área OPTION Bytes e armazena importantes configurações não voláteis do microcontrolador lá (para STM8S103F3 é de até 11 bytes). E, é claro, o STM esqueceu de mencionar que ainda existem 53 células funcionais nessa área. Aparentemente, existem muitos modelos STM8, você precisa deixar espaço para futuras configurações importantes.
Nosso gerenciador de inicialização afirma apenas no modelo STM8 sem gerenciadores de inicialização integrados. Portanto, pegamos as células de backup do bloco OPTION Bytes até agora que ninguém vê. É verdade que há um pequeno,
mas resolvido , inconveniente. Um programador convencional não permitirá que você grave informações nessas células.
Ao carregar, o controle é transferido para o código copy_boot_FLASH inicial em $ 9FF2. boot_FLASH transfere a imagem boot_OPTION bootloader da área de OPTION Bytes para a RAM.
boot_OPTION configura o UART 9600 8N1, envia o byte UART com sua versão, aguarda bytes UART do programa host e, sem esperar 0,2 segundos, transfere o controle para o aplicativo no endereço localizado no par $ 4831: $ 4832.
Se o boot_OPTION, após enviar um byte com sua versão, pegar um byte do tamanho do despejo esperado, ele pegará o despejo em si, colocará o despejo na memória RAM e transferirá o controle para ele.
Além disso, todo o cuidado é do programa no computador e do dump que ele envia. Ele deve enviar exatamente os dumps necessários para concluir a tarefa atual (ler / apagar / gravar / copiar células de memória STM8). Os despejos devem poder substituir um ao outro na memória RAM e transferir o controle para o programa aplicativo.
O endereço de transição para o aplicativo é $ 4831: $ 4832.
Carregador e código do aplicativo para executar na memória 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 do aplicativo para execução na memória 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
Execute o arquivo
runSTM8uLoader.bat , pressione o botão reset na placa, o carregador de inicialização envia o byte 0x25. Um dump com o código do arquivo main_RAM.hex é enviado para a RAM STM8 via UART. A placa começa a piscar o LED e envia os bytes 0x20 e 0x02. Pressione o botão de reset novamente. O programa aplicativo da memória FLASH é iniciado, o LED começa a piscar mais rapidamente e envia os bytes 0x80 e 0x08.
No último estágio, para gravar a imagem do carregador de inicialização na área OPTION Bytes, você deve usar o
método A essência do método é que primeiro você precisa que o programador grave o arquivo de firmware boot_OPTION_rev25.hex na memória STM8 FLAH, reinicie o microcontrolador, a área OPTION Bytes será preenchida com as informações necessárias e o LED acenderá. Então, novamente, o programador grava no arquivo de firmware FLASH deste artigo
boot_FLASH_OPTION.hex .
Adicionada a versão 0x14 do código do carregador de inicialização "limpo" sem o código do aplicativo. Implantou a imagem boot_OPTION no código-fonte. Comentários corrigidos. Diferentemente da versão $ 25, o endereço de transferência de controle do aplicativo está nas células $ 9FFE: $ 9FFFF FLASH. O tamanho em FLASH é 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 ;
Adicionada uma versão 0x25 do código do carregador de inicialização "limpo" sem o código do aplicativo. Implantou a imagem boot_OPTION no código-fonte. Comentários corrigidos. Diferente da versão de US $ 14, o endereço de transferência de controle do aplicativo está nas células $ 4831: $ 4832 da área OPTION Bytes. O tamanho ocupado na memória FLASH, respectivamente, diminuiu para 18 bytes. O tamanho ocupado na área OPTION Bytes não foi alterado (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 ;
O endereço de transferência de controle do aplicativo na memória FLASH pode ser selecionado no intervalo de $ 8004 ... $ 9FF1. Para uma imagem de código de aplicativo da memória EEPROM, a transferência de controle é possível apenas no endereço $ 0000 na memória RAM.
O programa host pode transmitir qualquer endereço de transferência de controle como o segundo argumento da linha de comando.
O código fonte do programa host pode ser encontrado
aqui . Também existem contatos para uma comunicação mais detalhada.
Peço aos leitores críticas direcionadas e sugestões para redução adicional do código.
Proponho também a leitura do artigo
“Como compactar o gerenciador de inicialização do STM8 para o tamanho de 8 bytes na memória FLASH” .