terça-feira, julho 07, 2020

Programação "Alta Voltagem" do ATmega - Parte 5

Com o hardware já funcionando e sucesso na colocação no modo de programação e na leitura da identificação do ATmega, agora é hora de fazer algo útil: apagar a memória Flash e colocar os fuses nos valores de fábrica.


O comando para limpar a Flash é o Chip Erase. Alguns detalhes importantes:
  • Dependendo do bit EESAVE dos fuses, a EEProm poderá ser apagada junto com a Flash.
  • Após o apagamento da memória os "Lock bits" são limpos. Estes bits podem impedir a leitura e escrita da Flash, uma vez ligados a única forma de desligá-los é fazendo Chip Erase.
  • O Chip Erase não altera os fuses
Executar o comando Chip Erase não é muito complicado:
  • Setar XA1=1 e XA0=0, para indicar que vamos enviar um comando
  • Setar BS1=0 para indicar que vamos transferir um byte menos significativo
  • Colocar o código do comando (0x80) nos pinos de dados
  • Pulsar o sinal XTAL1 para carregar o comando no ATmega
  • Colocar o sinal WR em nível baixo e retorná-lo ao nível alto, para iniciar o apagamento. 
  • O sinal RDY vai para o nível baixo, indicando que o ATmega está ocupado processando o comando.
  • Aguardar o sinal RDY retornar ao nível alto, indicando o fim do apagamento.

Como ainda não estudamos a leitura da Flash por enquanto não vamos conferir o resultado do apagamento.

Para completar a "limpeza" do ATmega vamos gravar os valores padrões nos fuses. A gravação dos fuses requer os seguintes passos:
  • Setar XA1=1 e XA0=0, para indicar que vamos enviar um comando
  • Setar BS1=0 para indicar que vamos transferir um byte menos significativo
  • Colocar o código do comando (0x40) nos pinos de dados
  • Pulsar o sinal XTAL1 para carregar o comando no ATmega
  • Setar XA1=0 e XA0=1, para indicar que vamos enviar um dado
  • Setar BS1=0 para indicar que vamos transferir um byte menos significativo
  • Colocar o novo valor do fuse  nos pinos de dados
  • Pulsar o sinal XTAL1 para carregar o comando no ATmega
  • Selecionar o fuse através do sinais BS1 e BS2 (ver abaixo)
  • Colocar o sinal WR em nível baixo e retorná-lo ao nível alto, para iniciar a gravação. 
  • O sinal RDY vai para o nível baixo, indicando que o ATmega está ocupado processando o comando.
  • Aguardar o sinal RDY retornar ao nível alto, indicando o fim da gravação.
  • Retornar os sinais BS1 e BS2 para o nível baixo
As combinações de BS1 e BS2 para selecionar os fuses:


O código completo (Apaga) está no meu github. Abaixo as rotinas que implementam os passos listados acima e mais a leitura do fuse.
  1. // Dispara o apagamento da Flash  
  2. void ATmega_Erase() {  
  3.   // Envia o comando  
  4.   ATmega_SendCmd(CMD_APAGA);  
  5.   // Dispara o apagamento  
  6.   digitalWrite (pinWR, LOW);  
  7.   delayMicroseconds(1);  
  8.   digitalWrite (pinWR, HIGH);  
  9.   delayMicroseconds(1);  
  10.   // Aguarda o fim da gravação  
  11.   while (digitalRead(pinRdy) == LOW) {  
  12.     delay(10);  
  13.   }  
  14. }  
  15.   
  16. // Grava um fuse do ATmega  
  17. void ATmega_WriteFuse (int bs1, int bs2, byte valor) {  
  18.   // Envia o comando  
  19.   ATmega_SendCmd(CMD_GRAVAFUSES);  
  20.   // indica que vai enviar um dado  
  21.   digitalWrite (pinXA0, HIGH);  
  22.   digitalWrite (pinXA1, LOW);  
  23.   // Seleciona low byte  
  24.   digitalWrite (pinBS1, LOW);  
  25.   // Coloca o dado na via de dados  
  26.   PCF8574_Write(valor);  
  27.   // Pulsa XTAL1 para registrar o dado  
  28.   pulsaXTAL1();  
  29.   // Seleciona o fuse  
  30.   digitalWrite (pinBS1, bs1);  
  31.   digitalWrite (pinBS2, bs2);  
  32.   // Dispara a gravação    
  33.   digitalWrite (pinWR, LOW);  
  34.   delayMicroseconds(1);  
  35.   digitalWrite (pinWR, HIGH);  
  36.   delayMicroseconds(1);  
  37.   // Aguarda o fim da gravação  
  38.   while (digitalRead(pinRdy) == LOW) {  
  39.     delay(10);  
  40.   }  
  41.   // Volta os sinais para o default  
  42.   digitalWrite (pinBS1, LOW);  
  43.   digitalWrite (pinBS2, LOW);  
  44. }  

Nenhum comentário: