Explorando a arquitetura do ATmega328: identificando a configuração geral e os fuses

Com 2 programas simples é possível ler a configuração geral de vários microcontroladores da família Arduino, e interpretar os fuses e seus significados.

Depois de algum tempo de experiência com as placas de desenvolvimento Arduino, comecei a sentir a demanda por programar diretamente os microcontroladores nos quais as mais populares delas são baseadas: os ATmega328 e seus primos.

Essa demanda continua conectada ao meu interesse em conhecer melhor esse universo, e provavelmente terá continuidade me levando a querer conhecer outras arquiteturas de microcontroladores. Mas não tenho pressa de chegar a eles ;-)

Após montar um primeiro exemplo de Arduino em protoboard e ver como é relativamente simples programar o ATmega328 por esse modo (é basicamente a mesma coisa que eu fiz para programar o ATTiny85, guardadas as peculiaridades), notei que precisava retroceder um passo, e primeiro investigar melhor a arquitetura.

Fiz isso lendo alguns trechos selecionados da datasheet, e por meio de 2 programas que identificam e descrevem os detalhes da arquitetura.

O que vem a seguir é um relato inicial do que eu aprendi e realizei. Ele será seguido por vários outros artigos falando de peculiaridades como o bootloader, o ICSP header, o upload de programas (via SPI e via UART), a montagem do ATmega328 sem componentes externos de suporte, outros chips da família AVR, e mais.

Identificando a configuração do microcontrolador

A primeira experiência é com o detector de placas, um sketch desenvolvido pelo Nick Gammon que usa conhecimentos específicos sobre a arquitetura dos microcontroladores, e especialmente sobre as configurações dos vários modelos de Arduinos, para identificá-los e descrevê-los.

Esse sketch roda em um Arduino Uno e identifica a configuração de outros microcontroladores conectados a ele por meia dúzia de jumpers.

O sketch roda num Uno e controla remotamente via SPI (veremos mais detalhes nos próximos artigos) outros microcontroladores "pelados", colocando esses dispositivos em modo de programação para obter deles as informações de configuração (sem alterá-los).

A versão que eu usei identifica uma variedade de ATtinys, ATmegas e seus primos com suporte USB, e reconhece 36 variedades de bootloaders que podem estar instalados neles – não apenas os que são típicos dos Arduinos, mas também os de modelos especiais, como os Sanguinos, Ruggeduinos, variações especiais do Leonardo, etc.

Não foi necessária nenhuma alteração no software: bastou fazer o download dos 3 arquivos-fonte (board-detector.ino, md5.c e md5.h), abri-los como abas de um mesmo projeto na IDE do Arduino (veja a imagem acima), compilar e transferir para um Arduino Uno.

Quanto à montagem física, é bem simples e, não por coincidência (já que ambas são aplicações de SPI), lembra a montagem que descrevi no artigo sobre programar o ATtiny85 com Arduino.

A minha experiência inicial foi com o ATmega328 da foto acima, no qual colei uma etiqueta com a referência dos pinos com a numeração usada no Arduino, e é a ele que recorrerei para descrever a montagem.

O mapa de pinagem acima pode ajudar quem está conhecendo esse universo, pois indica em marrom o número dos pinos na convenção do Arduino, e na numeração do próprio corpo do chip a contagem física dos pinos.

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 na contagem direta):

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 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.

Detalhe: o sketch funcionou perfeitamente em todos os testes nos quais deixei de incluir os componentes acima, também.

As conexões que envolvem os pinos 11, 12 e 13 (respectivamente MOSI, MISO e SCK) são as responsáveis pela comunicação entre o Arduino e o ATmega da protoboard, usando o protocolo SPI. Se o microcontrolador que você for ler não é um ATmega328, verifique na datasheet dele quais os pinos correspondentes ao MOSI, MISO e SCK, e adapte a ele o lado direito da tabela acima (o lado esquerdo permanece inalterado). Veremos mais detalhes sobre o significado desses pinos em um próximo artigo.

Já 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.

Feita essa configuração física, basta transferir para o Arduino Uno o programa mencionado acima, abrir o Monitor Serial, configurá-lo para a velocidade de 115200, e pressionar o botão de reset do Uno. Se todas as conexões tiverem sido feitas corretamente, vão aparecer no Monitor Serial as configurações do ATmega, assim:

Destaquei em amarelo na imagem acima o bloco que contém as informações que mais me interessavam:

  • Linhas 1 e 2: A assinatura de 3 bytes informada pelo dispositivo, e o nome de dispositivo correspondente (no caso, o modelo do meu ATmega).
  • Linhas 4 a 6: As configurações dos fuses do dispositivo. Os fuses contêm uma série de definições cruciais (como a opção entre usar clock interno ou um cristal externo, por exemplo), descritas detalhadamente na datasheet do microcontrolador. Veremos mais detalhes sobre eles a seguir.
  • Linha 9: Confirma se o ATmega está configurado para usar um bootloader ou não. Note que após um dump do bootloader, o programa também identificou o nome dele – no caso, o optiboot_atmega328, comum nos Arduinos. A função básica do bootloader nos Arduinos é verificar, logo após um reset, se a IDE está tentando enviar um novo programa a ele (geralmente pela porta USB), e recebê-lo.

Entendendo os fuses

No caso do ATmega328, os fuses são listados no capítulo 28.2 da datasheet, e detalhados ao longo de todo o texto dela.

Entre outros recursos, os fuses do ATmega328 definem:

  • Se há bootloader, e o seu tamanho
  • Se há proteção contra queda de tensão (brown-out), e seu limite
  • Se é permitido o reset externo
  • Se é permitida a programação via SPI
  • Se o watchdog timer deve ficar permanentemente ligado
  • A origem e comportamento do clock
  • e mais.

Quando se usa a IDE do Arduino para instalar um bootloader (veremos mais sobre esse assunto em um artigo posterior), ela também configura junto os fuses, de acordo com a definição que consta nas configurações de cada plataforma de hardware suportada.

O ATmega328 tem 3 bytes de fuse, chamados de alto (HF), baixo (LF) e extended (EF). Você pode ver a menção ao valor de todos eles na tela do Monitor Serial que eu reproduzi alguns parágrafos acima, e poderia analisá-los bit a bit, com a ajuda da datasheet, para saber como interpretá-los.

Mas não é necessário tanto esforço: o mesmo autor do programa que produziu a tela acima também criou um calculador de fuses, ou seja, um sketch para interpretar os fuses de um ATmega, com as mesmas conexões físicas usadas no programa acima.

No meu caso, foi só fazer o download e compilar no Uno, abrindo o Monitor Serial configurado para 115.200 como descrito acima, para ver a tela a seguir:

Apesar do nome do programa, ele não se restringe à família ATmega. Veja a seguir o resultado da leitura dos fuses de um ATtiny85 que estava aqui na bancada:

Atmega fuse calculator.
Written by Nick Gammon.
Entered programming mode OK.
Signature = 0x1E 0x93 0x0B
Processor = ATtiny85
Flash memory size = 8192
LFuse = 0xE2
HFuse = 0xDF
EFuse = 0xFF
Lock byte = 0xFF
Clock calibration = 0xA6
Self Programming Enable................. [ ]
External Reset Disable.................. [ ]
Debug Wire Enable....................... [ ]
Enable Serial (ICSP) Programming........ [X]
Watchdog Timer Always On................ [ ]
Preserve EEPROM through chip erase...... [ ]
Divide clock by 8....................... [ ]
Clock output............................ [ ]
Start-up time: SUT0: [X]  SUT1: [ ] (see datasheet)
Clock source: calibrated internal oscillator.
Brownout detection at: disabled.

Compare as duas listagens acima, e você notará que os fuses mencionados para o ATmega não são mesmos mostrados para o ATtiny: cada família e modelo tem os seus próprios, cuja referência e significado você pode encontrar nas respectivas datasheets – e alguns deles serão identificados em artigos posteriores.

Com essas informações à disposição, não apenas tive o incentivo para buscar conhecer melhor os detalhes da arquitetura dos microcontroladores usados em boa parte dos Arduinos, mas também passei a ter à mão um recurso de verificação de configuração útil para o debug de futuros projetos baseados neles.

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