Como escrever um bootloader simples para AVR em linguagem C – (Parte 35/46)

Como escrever um bootloader simples para AVR em linguagem C – (Parte 35/46)

O BootLoader é um código que é executado quando um microcontrolador é ligado ou reiniciado. Basicamente, ele define um ambiente para a execução do código do aplicativo. É o Boot-Loader que configura o hardware e carrega o código da aplicação de qualquer meio de armazenamento ou recebido através de comunicação externa e deixa a aplicação executar. Assim, um Boot-Loader deve executar a seguinte função básica: Inicialize os periféricos do controlador, Inicialize os dispositivos na placa, Permitir que o usuário selecione entre os aplicativos disponíveis para carregar, Carregue o aplicativo selecionado, Deixe o código do aplicativo ser executado. Além das funções mencionadas acima, alguns Boot-Loaders podem executar muitas outras funções e existem Boot-Loaders que não executam todas essas funções, como fornecer opção para selecionar o aplicativo necessário, etc. Os códigos do Boot-Loader em microcontroladores são na verdade muito pequenos e simples em comparação com os Boot-Loaders em dispositivos avançados como PC. Na maioria dos microcontroladores, a funcionalidade de um Boot-Loader é limitada apenas para definir o relógio inicial e outras configurações do microcontrolador, carregar um binário de aplicativo da porta serial, etc.Em um microcontrolador AVR escrever um código Boot-Loader é comparativamente fácil, uma vez que qualquer código escrito na seção BLS da memória flash pode ter acesso completo ao hardware do microcontrolador. A memória flash do microcontrolador AVR é ​​dividida em duas seções; uma seção de flash de aplicativo e uma seção Boot-Loader (BLS).

Qualquer código executado a partir do BLS pode usar o modo de autoprogramação (SPM). Usando o recurso SPM, um código da seção BLS pode ler ou gravar toda a memória flash, incluindo a seção BLS de onde o código está sendo executado. Este recurso pode ser usado para carregar qualquer código binário de aplicativo na memória flash e deixá-lo executar. A inicialização necessária dos periféricos do controlador como USART, bits de porta etc. e a inicialização dos dispositivos externos como LCD etc. pode ser feita a partir do próprio BLS antes de carregar o código da aplicação. Neste projeto, discuta como escrever um código Boot-Loader mais simples para o microcontrolador AVR que pode inicializar os periféricos como USART, porta LED e inicializar um LCD de 4 bits conectado ao controlador e então carregar qualquer aplicativo que tenha sido atualizado no built-in na EEPROM do microcontrolador. O microcontrolador utilizado neste projeto é o ATMEGA16, e o programador utilizado é o USBASP. O AVR Studio 4 é usado como IDE e o software de gravação usado é o AVR-BURNO-MAT.

A memória flash AVR é ​​dividida em duas seções: a seção de aplicativos e a seção Boot-Loader (BLS). No caso do ATMEGA16 possui 16 KB de memória flash dos quais 15 KB são seção de aplicação e os 1 KB restantes são BLS. A arquitetura de memória do ATMEGA16 é mostrada na figura a seguir;

Arquitetura de memória Flash do ATMEGA16

Fig. 2: Arquitetura de memória Flash do ATMEGA16

O código para o BLS e a seção do aplicativo pode ser escrito normalmente e não há muita diferença. A única coisa a ter cuidado é o tamanho do código binário. Não deve ter mais de 1 KB, caso contrário não será possível codificar programado no BLS. O projeto sobre codificação AVR BLS discute como programar um código simples no BLS do microcontrolador ATMEGA16 com a ajuda do estúdio AVR como IDE, USBasp como programador e AVR-Burnomat como software gravador.

Neste projeto específico, o Boot-Loader é codificado para executar UART inicialização junto com um simples LIDERADO inicialização do pino e também uma inicialização de hardware externo do 4 bits LCD. Portanto os códigos da aplicação não requerem esses códigos, ainda assim funcionam porque antes de executar os códigos da aplicação as funções de inicialização serão executadas pelo Boot-Loader.

O código BLS possui funções de inicialização que não deveriam estar presentes nos códigos de aplicação. As funções de inicialização usadas no código Boot-Loader para este projeto são fornecidas abaixo;

Função

Descrição

vazio lcd_init ( vazio )

Inicialize o LCD no modo de 4 bits

vazio usart_init (void)

Inicialize o usart em taxa de transmissão de 9600 com transmissão e recepção habilitadas

DDRD = 0x80;

Inicialização do pino LED como saída

Fig.3: Funções de inicialização usadas código Boot-Loader do AVR

Qualquer código de aplicativo pode usar diretamente as seguintes chamadas de função para acessar USART, LCD e LED sem inicializar suas funções em qualquer lugar do código.

Função

Descrição

lcd_clear

Limpe o LCD

lcd_string

Exibir uma string no LCD

usart_send_string

Envie uma string via usart

PORTD &= 0x7F;

Ligue o LED

PORTD = 0x80;

DESLIGUE o LED

Fig. 4: Chamadas de função usadas pelo código da aplicação para acessar periféricos no AVR

A inicialização do hardware antes de executar o código da aplicação é explicada detalhadamente em um projeto em Inicialização de hardware do AVR BLS.

A principal função do Boot-Loader é carregar um código em formato binário de meio de armazenamento ou que possa ser recebido através da comunicação externa com outros dispositivos para a memória flash. O recurso SPM disponível para o código em execução no BLS auxilia no carregamento de um código binário da aplicação na memória flash. A tarefa de escrever o código BLS com SPM foi simplificada pelas APIs disponíveis no arquivo de cabeçalho . A seguir estão as APIs importantes disponíveis no arquivo de cabeçalho que auxiliam no SPM.

FUNÇÃO

DESCRIÇÃO

PARÂMETRO

boot_page_erase (endereço)

Apague a página flash referida pelo endereço

Um endereço de byte em flash

boot_page_fill (endereço, dados)

Preencha o buffer de página temporário do Boot-Loader para endereço flash com palavra de dados

O endereço é um endereço de byte. Os dados são uma palavra

boot_page_write (endereço)

Grave o buffer de página temporário do Boot-Loader na página flash que contém o endereço

Endereço de byte em flash

Figura 5: APIs importantes no AVR

As etapas necessárias para fazer o SPM na memória flash da aplicação são explicadas em um projeto sobre o uso do SPM na programação flash para flash do AVR.

Neste projeto específico, o Boot-Loader é codificado de tal forma que tentará carregar qualquer código binário do aplicativo que tenha sido carregado na EEPROM interna integrada do microcontrolador AVR. As APIs disponíveis no são usadas para ler os bytes de dados da EEPROM e com a ajuda das APIs do os bytes de dados são armazenados em um buffer temporário e depois transferidos para a seção de aplicação da memória flash.

A API fornecida pelo para ler os bytes de dados da EEPROM integrada do microcontrolador AVR é;

uint8_t eeprom_read_byte (const uint8_t *p)

FUNÇÃO

DESCRIÇÃO

PARÂMETRO

uint8_t eeprom_read_byte (const uint8_t *p)

A função retorna um byte de dados que é armazenado no endereço EEPROM referido pelo ponteiro p

O ponteiro refere-se ao endereço EEPROM do qual o byte de dados precisa ser lido

Figura 6: API para ler bytes de dados da EEPROM integrada do microcontrolador AVR

Com a ajuda das APIs discutidas acima de e pode-se usar o recurso SPM do microcontrolador AVR para escrever um código Boot-Loader que pode carregar um aplicativo que foi programado na EEPROM integrada do microcontrolador AVR. Para isso deve-se seguir os passos mencionados abaixo que são explicados em um projeto sobre o uso de SPM em AVR EEPROM para programação flash.

{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}· {C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}Passo: 1 Apague a página flash que está prestes a escrever

{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}· {C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}Etapa: 2 Armazene o código binário que é lido da EEPROM em um buffer temporário antes de gravar em uma página flash

{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}· {C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}{C}Etapa: 3 Programe o buffer temporário preenchido na página flash já apagada

Depois de executar as três etapas acima, o Boot-Loader pode dar um salto usando a instrução

asm(“jmp 0x0000”);

para a seção de código do aplicativo e deixe o aplicativo recém-programado ser executado.

Atualize o código do Boot-Loader para o BLS primeiro, qualquer código de aplicativo de tamanho pequeno para a memória EEPROM usando as etapas explicadas no projeto anterior em LED piscando do BLS do AVR. Assim que a programação da EEPROM for concluída e o controlador for reiniciado, o Boot-Loader começará a ser executado. Pode-se observar que ele está executando as funções de inicialização e carregando o aplicativo a partir da EEPROM integrada.

Gravando código BLS no BLS do circuito AVR na placa de ensaio

Fig. 7: Gravando código BLS no BLS do circuito AVR na placa de ensaio

Como escrever um bootloader simples para AVR em linguagem C

Display LCD inicializado pelo código BLS na configuração do AVR na placa de ensaio

Fig. 9: Display LCD inicializado pelo código BLS na configuração do AVR na placa de ensaio

Como escrever um bootloader simples para AVR em linguagem C

Fig. 10: USART inicializado com taxa de transmissão de 9600 pelo BLS da configuração do AVR na placa de ensaio

Como escrever um bootloader simples para AVR em linguagem C

Código-fonte do projeto

###


#define F_CPU 8000000
#include #include #include #include #include #include #include #include #include "usart.h" #incluir "lcd.h" int principal (void) { uint16_ti; uint8_tA(512); uint8_t registro; página uint32_t = 0; uint16_t w; caractere não assinado *buf = A; volátil int j = 4; //============================================== ==================================== lcd_init ; //inicialização do LCD lcd_clear ; lcd_1st_line ; lcd_string("ENGENHEIROS"); lcd_2nd_line ; lcd_string("GARAGEM"); _atraso_ms(3000); lcd_clear ; lcd_1st_line ; lcd_string("Inicializando ATMEGA16"); _atraso_ms(2000); lcd_clear ; lcd_1st_line ; lcd_string("LCD(OK)"); lcd_2nd_line ; lcd_string("16*2,4 bits"); _atraso_ms(2000); usart_init ; //inicialização do USART lcd_clear ; lcd_1st_line ; lcd_string("USART(OK)"); lcd_2nd_line ; lcd_string("9600bps, Tx e Rx"); _atraso_ms(2000); lcd_clear ; lcd_1st_line ; lcd_string("carregando aplicativo... "); lcd_2nd_line ; para(eu = 0; eu < 16; eu ++) { _atraso_ms(350); dados_dis(0xFF); } lcd_clear ; lcd_1st_line ; //============================================== ==================================== //############################### Inicializando pela EEPROM ############# ##################// para (eu = 0; eu < 512; eu++) A (i) = eeprom_read_byte ((const uint8_t *) i); enquanto(1) { //============================================== ==========================// se(j) { //Desativa interrupções. sreg = SREG; cli ; eeprom_busy_wait ; boot_page_erase (página); boot_spm_busy_wait ; //Espere até que a memória seja apagada. para (i=0; i { //Configura a palavra little-endian. w = *buf++; w += (*buf++) << 8; boot_page_fill (página + i, w); } boot_page_write (página); // Armazena buffer na página flash. boot_spm_busy_wait ; //Espere até que a memória seja escrita. boot_rww_enable ; SREG = sreg; } outro { asm("jmp 0x0000"); } j--; página = página + 128; //============================================== ==============================// } //############################### Inicializando pela EEPROM ############# ##################// } //#################### LCD #########################//

#define _LCD_H #ifndef F_CPU #define F_CPU 8000000 #endif #include #include #include #define rs PA0 #define rw PA1 #define en PA2 void lcd_init ; void dis_cmd(char); void dis_data(char); void lcdcmd(char); void lcddata(char); vazio lcd_clear(vazio); vazio lcd_2nd_line(vazio); vazio lcd_1st_line(vazio); void lcd_string(const char *dados); void lcd_string(const char *dados) { for(;*dados;dados++) dis_dados (*dados); } void lcd_clear(void) { dis_cmd(0x01); _atraso_ms(10); } void lcd_2nd_line(void) { dis_cmd(0xC0); _atraso_ms(1); } void lcd_1st_line(void) { dis_cmd(0x80); _atraso_ms(1); } void lcd_init // função para inicializar { DDRA=0xFF; dis_cmd(0x02); // para inicializar o LCD no modo de 4 bits. dis_cmd(0x28); //para inicializar o LCD em 2 linhas, 5X7 pontos e modo 4 bits. dis_cmd(0x0C); dis_cmd(0x06); dis_cmd(0x80); dis_cmd(0x01); _atraso_ms(10); } void dis_cmd(char cmd_value) { char cmd_value1; cmd_valor1 = cmd_valor & 0xF0; //mascara a mordidela inferior porque os pinos PA4-PA7 são usados. lcdcmd(cmd_valor1); // envia para LCD cmd_value1 = ((cmd_value<<4) & 0xF0); //desloca 4 bits e mascara lcdcmd(cmd_value1); //envia para LCD } void dis_data(char data_value) { char data_value1; valor_dados1=valor_dados&0xF0; lcddata(dados_valor1); valor_dados1=((valor_dados<<4)&0xF0); lcddata(dados_valor1); } void lcdcmd(char cmdout) { PORTA=cmdout; PORTA&=~(1<

###

Código-fonte do projeto

###


#ifndef _USART_H
#define _USART_H #ifndef F_CPU #define F_CPU 8000000 #fim se #define USART_BAUDRATE 9600 #define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1) #include #include void usart_init ; void usart_putch(envio de caractere não assinado); unsigned int usart_getch ; void usart_init { UCSRB = (1 << RXEN) (1 << TXEN); //Ativa o circuito de transmissão e recepção UCSRC = (1 << URSEL) (1< //Use tamanhos de caracteres de 8 bits UBRRL = BAUD_PRESCALE; // Carrega os 8 bits inferiores do valor da taxa de transmissão. //no byte baixo do registrador UBRR UBRRH = (BAUD_PRESCALE >> 8); // Carrega os 8 bits superiores do valor da taxa de transmissão. //no byte alto do registrador UBRR } void usart_putch(envio de caractere não assinado) { enquanto ((UCSRA & (1 << UDRE)) == 0); // Não faça nada até que o UDR esteja pronto.. // para que mais dados sejam gravados nele UDR = enviar; // Envia o byte } int não assinado usart_getch { enquanto ((UCSRA & (1 << RXC)) == 0); // Não faça nada até que os dados tenham sido recebidos e estejam prontos para serem lidos no UDR retorno(UDR); //retorna o byte } #fim se

#define rs PA0 #define rw PA1 #define en PA2 #include #include void dis_data(char data_value); void usart_putch(envio de caractere não assinado); unsigned int usart_getch ; int principal(void) { int i; não assinado int c; //-------- teste de led -----------// DDRD = 0x80; for (i =0; i < 5; i++) { PORTD = ~PORTD; _atraso_ms(500); } //-------- teste de led -----------// //----- usart + teste de lcd -------// while ( 1 ) { c = usart_getch ; usart_putch((char não assinado)c); dis_data((char)c); } //----- usart + teste lcd -------// } void dis_data(char data_value) { char data_value1; valor_dados1=valor_dados&0xF0; PORTA=dados_valor1; PORTA =(1<


###

Diagramas de circuito

Diagrama de circuito de como escrever um carregador de inicialização simples para AVR em linguagem C

Componentes do Projeto

  • ATmega16
  • LCD
  • LIDERADO
  • Resistor

Vídeo do projeto

Conteúdo Relacionado

Uma rede de sensores é incorporada em todos os...
O controlador do motor é um dos componentes mais...
ESP32-CAM é um módulo de câmera compacto que combina...
A evolução dos padrões USB foi fundamental para moldar...
A SCHURTER anuncia um aprimoramento para sua conhecida série...
A Sealevel Systems anuncia o lançamento da Interface Serial...
A STMicroelectronics introduziu Diodos retificadores Schottky de trincheira de...
Determinar uma localização precisa é necessário em várias indústrias...
O novo VIPerGaN50 da STMicroelectronics simplifica a construção de...
A Samsung Electronics, fornecedora de tecnologia de memória avançada,...
O mercado embarcado tem uma necessidade de soluções de...
Você provavelmente já se deparou com o termo 'arrastar'...
Você provavelmente tem um Isolador de suporte Se você...
Você provavelmente já viu permanecer um isolante sente-se em...
Você provavelmente já viu Isoladores de manilha entronizados em...
Você provavelmente já passou por situações em que o...
Вернуться к блогу

Комментировать

Обратите внимание, что комментарии проходят одобрение перед публикацией.