Como gravar bootloader em um ATmega328 sem componentes externos

Para entender melhor os bootloaders, vamos instalar no ATmega328 uma configuração que permite usá-lo com o clock de 8MHz interno, dispensando componentes externos.

Bootloader é um programa especial que roda imediatamente após cada reset e facilita transferir para um microcontrolador os demais programas que o usuário deseja rodar nele.

O bootloader do Arduino é o optiboot, ao menos nas configurações default dos modelos mais comuns. Ele apresenta uma série de vantagens sobre o ATmegaBOOT, o antigo bootloader default: ocupa meros 512 bytes da memória (o antigo ocupava 2K), transfere os programas mais rapidamente, e evita problemas com o watchdog timer.

Embora seja trabalho original, o optiboot tira proveito do que foi desenvolvido por vários bootloaders anteriores, incluindo o original do Arduino, o 1K bootloader (Spiff), o Adaboot (Lady Ada) e outros. Ele foi escrito em C, sem os grandes trechos condicionais em assembly dos bootloads anteriores, e assim é portável por natureza, rodando em placas baseadas em uma grande variedade de microcontroladores da Atmel: ATmega328, ATmega168, ATmega8, ATmega32 e mais.

Como eu gravo bootloaders

É bem fácil encontrar tutoriais sobre como gravar bootloader no Arduino usando a função "Burn Bootloader" da IDE. Eu mesmo já descrevi como a usei para configurar a frequência de clock do ATtiny85.

Para gravar bootloaders em ATmegas que estão em protoboards ou em um circuito externo (e não em um Arduino), eu acabei aprendendo e preferindo um procedimento alternativo, que envolve usar meia dúzia de jumpers para colocá-los sob o controle de um Arduino Uno no qual esteja rodando o sketch Atmega_Board_Programmer, criado por Nick Gammon.

Esse sketch é um primo dos 2 programas que vimos no artigo anterior, que identificam a configuração básica e detalham os fuses de um ATmega. Ele não exige nenhuma alteração no código, basta fazer o download, abrir o projeto na IDE (cada um dos 10 arquivos .h que acompanham o Atmega_Board_Programmer.ino deve ser uma aba, como mostra a imagem acima), compilar e fazer o upload para o Uno.

O conteúdo das variadas abas corresponde a 10 bootloaders diferentes, que serão copiados (mas não instalados!) para o seu Uno e ficarão à disposição para serem instalados no ATmega (que pode ser de vários modelos: ATmega8, ATmega168, ATmega328, ATmega16U2, ATmega32U4, ATmega1280, ATmega1284 e mais) que estiver na protoboard.

O Atmega_Board_Programmer.ino também usa a mesma configuração de conexões entre o Arduino no qual o programa Atmega_Board_Programmer.ino rodará e o o ATmega da protoboard mencionada no artigo anterior. A imagem que abre este artigo ilustra, e a descrição eu cito do artigo anterior sobre inspecionar configurações e fuses do ATmega:

A conexão física

Na tabela a seguir, indico quais pinos do Arduino Uno estão conectados a quais pinos do ATmega328 usando a convenção de numeração do Arduino (e colocando entre parênteses o número do pino do ATmega na contagem simples):

Pino no Arduino Pino no ATmega
9 XTAL1 (9)
10 RST (1)
11 (MOSI) 11 (17)
12 (MISO) 12 (18)
13 (SCK) 13 (19)
5V VCC (7) e AVCC (20)
GND GND (8 e 22)

Temos também alguns outros componentes necessários e/ou recomendados pelo autor do programa, todos conectados ao ATmega que será identificado:

  • Capacitores pequenos (eu usei de 22µF, poderia ser bem menos – o autor usa 0,1µF): estão ali para reduzir o ruído eletromagnético. Um de cada lado do ATmega328, cada um com um terminal no VCC e outro no GND.
  • Resistor de 10KΩ entre o pino RST (1) e o terra: pull-up para evitar resets indevidos.
  • Um led com resistor entre o RST (1) e o terra: está ali no ATmega para debug e visualização. Ele pisca brevemente no momento da execução do programa no Uno.

As conexões que envolvem os pinos 11, 12 e 13 são as responsáveis pela comunicação. A conexão com o pino RST (1) do ATmega é a responsável por resetá-lo para colocá-lo no modo de programação necessário para obter os dados, e a conexão ao pino XTAL1 (9) do ATmega é uma curiosidade interessante: por ela, o sketch rodando no Arduino Uno fornece um sinal de clock para o ATmega, para o caso de este estar configurado para funcionar com clock externo. É possível que a frequência de clock segura oferecida pelo sketch não seja a esperada pelo ATmega, mas ele vai funcionar mesmo assim.

Feito o upload do programa para o Uno e a configuração física da conexão entre ele e o ATmega que está na protoboard, foi só abrir o Monitor Serial, configurar para 115200 e pressionar o botão de reset do Uno, e apareceu a tela a seguir:

Atmega chip programmer.
Written by Nick Gammon.
Version 1.33
Compiled on May  1 2015 at 19:13:17 with Arduino IDE 106.
Attempting to enter programming mode ...
Entered programming mode OK.
Signature = 0x1E 0x95 0x0F 
Processor = ATmega328P
Flash memory size = 32768 bytes.
LFuse = 0xE2 
HFuse = 0xDA 
EFuse = 0xFD 
Lock byte = 0xEF 
Clock calibration = 0xA5 
Type 'L' to use Lilypad (8 MHz) loader, or 'U' for Uno (16 MHz) loader 

A última linha, que destaquei em negrito, é a importante: o programa reconheceu que o meu chip na protoboard é um ATmega368, e está me dando duas opções de bootloader para ele.

O instalador oferece uma opção simples para quem quer rodar o ATmega standalone sem componentes externos: dispensar o cristal ou oscilador.

A diferença entre as duas opções de bootloader oferecidas para esse ATmega328 é profunda. A segunda delas é a mais comum (a do Arduino Uno, com clock de 16MHz regulado por um cristal ou oscilador externo), e a primeira é do interesse de quem está procurando montagens com poucos componentes (é a do Arduino Lilypad, que dispensa cristal/oscilador por funcionar com o clock interno de 8MHz).

Como me interessa bastante a possibilidade de rodar o ATmega368 com poucos componentes adicionais, optei pela opção do Lilypad, digitando “L” na caixa de entrada no alto do Monitor Serial e pressionando o botão Send:

Aí o programa prossegue, com as mensagens abaixo. Note, em negrito na terceira linha, que ele oferece uma oportunidade de desistir, antes de apagar de fato o chip e gravar nele o bootloader escolhido:

Using Lilypad 8 MHz loader.
Bootloader address = 0x7800
Bootloader length = 1932 bytes.
Type 'Q' to quit, 'V' to verify, or 'G' to program the chip with the bootloader ...
Erasing chip ...
Writing bootloader ...
Committing page starting at 0x7800
Committing page starting at 0x7880
(...)
Committing page starting at 0x7F00
Committing page starting at 0x7F80
Written.
Verifying ...
No errors found.
Writing fuses ...
LFuse = 0xE2 
HFuse = 0xDA 
EFuse = 0xFD 
Lock byte = 0xEF 
Clock calibration = 0xA5 
Done.
Programming mode off.
Type 'C' when ready to continue with another chip ...

Após gravar o bootloader, configurar os fuses e verificar, ele oferece, na última linha, a possibilidade de gravar um novo bootloader em mais um chip, se você pressionar “C” (após trocar de chip, claro).

Verificando o que mudou

Eu usei o mesmo ATmega328 do artigo anterior. Se você visitá-lo para reler as mensagens que publiquei na ocasião, verá que ele estava:

  • com o bootloader optiboot_atmega328 (default do Arduino Uno) e
  • com fonte de clock configurada nos fuses para usar um cristal externo.

Com o procedimento descrito acima, é de se esperar que uma nova execução dos programas que listam a configuração mostrem que as duas informações acima mudaram, pois instalamos o bootloader do Lilypad para usar clock interno, sem cristal.

Para ter certeza, vamos conferir. Os detalhes do procedimento a seguir você encontra no artigo anterior.

Primeiro vamos rodar o detector de placas, que informa – entre outras coisas – qual o bootloader instalado. Eis algumas linhas selecionadas da sua nova saída:

Atmega chip detector.
Written by Nick Gammon.
Entered programming mode OK.
Processor = ATmega328P
Bootloader in use: Yes
Bootloader is 2048 bytes starting at 7800
Bootloader name: ATmegaBOOT_168_atmega328_pro_8MHz

Na última linha você pode ver que o optiboot não está mais lá, e foi substituído pelo bootloader original do Arduino, versão 8MHz (que é a frequência do clock interno). Na penúltima linha você pode ver uma consequência disso: ele ocupa 2048 bytes (o optiboot ocupa apenas 512).

Agora vamos rodar o calculador de fuses, que vai informar claramente se a configuração de clock anterior (que usava cristal externo) foi substituída pelo uso de clock interno. Eis as linhas selecionadas com a parte relevante da sua saída:

Atmega fuse calculator.
Written by Nick Gammon.
Entered programming mode OK.
Processor = ATmega328P
Flash memory size = 32768
LFuse = 0xE2 
HFuse = 0xDA 
EFuse = 0xFD 
Clock calibration = 0xA5 
Boot into bootloader.................... [X]
Divide clock by 8....................... [ ]
Clock output............................ [ ]
Bootloader size: 2048 bytes.
Clock source: calibrated internal oscillator.
Brownout detection at: 2.7V.

Destaquei em negrito a linha que traz a nossa resposta: agora o clock está configurado para uso do oscilador interno, e podemos montar esse ATmega em uma placa sem colocar nela um cristal e sua escolta de capacitores.

ATmega sem cristal/oscilador: Vantagens e desvantagens

O oscilador ou o cristal são os responsáveis por definir a frequência do relógio interno que dá a cadência da execução das instruções por uma CPU – em outras palavras, a sua velocidade (embora essa simplificação não seja própria em todos os casos).

Quando montado em uma placa como o Arduino Uno, o ATmega328 é complementado por uma série de periféricos e componentes externos úteis para atividades de desenvolvimento, como os leds de funcionamento, RX e TX, o conversor USB-serial, o regulador de tensão, o ICSP header, o cristal/oscilador de 16MHz e mais.

Ao usar o mesmo ATmega para uma aplicação externa desenvolvida e testada em um Arduino, mas na qual não seja necessário contar com os mesmos periféricos e componentes, você pode escolher quais componentes e periféricos precisa manter, e de modo geral a sua ausência significa deixar de contar com a sua função. Não colocar um led On/Off pode poupar um pouco de duração de uma bateria, por exemplo, em troca de não ter essa forma básica de verificar se o circuito está funcionando. Da mesma forma, não ter um regulador de tensão na placa exigirá receber tensão externa compatível com o que o circuito consome.

No caso do clock externo de 16MHz, que é o centro da escolha que eu destaquei neste artigo, a situação é um pouco diferente. O Arduino Uno vem com um oscilador de 16MHz conectado aos pinos de clock do seu ATmega328, e isso define a frequência de execução de instruções do mesmo.

Montar um ATmega328 numa protoboard ou circuito externo com clock igual ao do Uno é relativamente simples: o oscilador (ou cristal + par de capacitores) de 16 MHz é conectado aos pinos físicos 9 e 10 como exemplificado acima, e aí o microcontrolador vai funcionar na mesma frequência do Uno, podendo usar o mesmo bootloader dele (que você também pode instalar usando o procedimento descrito neste artigo).

Mas o ATmega328 também vem equipado com um oscilador interno, cujo uso é opcional. Ativá-lo (como vimos no procedimento descrito acima, e como eu faço na minha prática usual) permite dispensar totalmente os componentes externos de suporte, mas exige limitar o desempenho: o oscilador interno funciona a 8MHz, metade da frequência do oscilador externo instalado no Uno.

Usando um cristal ou oscilador externo, você pode (oficialmente) acelerar a frequência do ATmega328 até 20MHz, mas os 8 MHz do oscilador interno podem ser muito mais do que o suficiente para diversas aplicações.

Ativar o oscilador interno também limita a precisão dos ciclos, algo que pode vir a atrapalhar as aplicações que exigem sincronização – em especial as que usam protocolos de comunicação em velocidades altas.

Portanto, você pode reduzir o uso de componentes externos até o limite do que poderá fazer falta ao seu circuito: o clock externo pode ou não ser exigido, dependendo da sua demanda de desempenho e precisão.

Instalar bootloader pelo método alternativo: Vantagens e desvantagens

O método tradicional (usando a IDE) é fartamente documentado, e profundamente integrado à IDE, claro. Depois de entender como ele funciona, e como instalar suporte a hardwares não incluídos na IDE default, seu uso vira mera manipulação bem coordenada das opções Board, Serial Port, Programmer e Burn Bootloader do menu Tools.

Já o método que eu prefiro (e descrevi neste artigo) não tem nenhuma integração com a IDE: os modelos de microcontroladores suportados são apenas os que constam no seu código-fonte (não são poucos, mas é difícil expandir), e o mesmo pode ser dito sobre as opções de bootloader disponíveis.

Por não estar integrado à IDE, o meu método tem uma interface pouco visual (mais familiar para as pessoas que conviveram com a informática dos anos 80), mas ao mesmo tempo passa a ser pouco afetado pelas mudanças de versão da IDE, que tem sido frequentes.

Embora eu geralmente use o método para gravar o bootloader do Lilypad, permitindo assim que o ATmega rode sem cristal externo (na metade da frequência de clock do Arduino Uno), ele pode perfeitamente ser usado para gravar o mesmo optiboot do Arduino Uno, que exige a presença do cristal externo.

Um detalhe interessante: alterando configurações da IDE e usando o modo tradicional de instalar o bootloader e configurar os fuses, também é possível usar o clock interno com o optiboot.

No final das contas, tudo isso pode ser uma mera questão de preferência. A minha é a que eu descrevi acima ;-)

Comentar

Dos leds ao Arduino, ESP8266 e mais

Aprenda eletrônica com as experiências de um geek veterano dos bits e bytes que nunca tinha soldado um led na vida, e resolveu narrar para você o que descobre enquanto explora esse universo – a partir da eletrônica básica, até chegar aos circuitos modernos.

Por Augusto Campos, autor do BR-Linux e Efetividade.net.

Recomendados

Livro recomendado


Artigos já disponíveis

Comunidade Arduino

O BR-Arduino é integrante da comunidade internacional de entusiastas do Arduino, mas não tem relação com os criadores e distribuidores do produto, nem com os detentores das marcas registradas.

Livros recomendados