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.
// Dispara o apagamento da Flash
void ATmega_Erase() {
  // Envia o comando
  ATmega_SendCmd(CMD_APAGA);
  // Dispara o apagamento
  digitalWrite (pinWR, LOW);
  delayMicroseconds(1);
  digitalWrite (pinWR, HIGH);
  delayMicroseconds(1);
  // Aguarda o fim da gravação
  while (digitalRead(pinRdy) == LOW) {
    delay(10);
  }
}

// Grava um fuse do ATmega
void ATmega_WriteFuse (int bs1, int bs2, byte valor) {
  // Envia o comando
  ATmega_SendCmd(CMD_GRAVAFUSES);
  // indica que vai enviar um dado
  digitalWrite (pinXA0, HIGH);
  digitalWrite (pinXA1, LOW);
  // Seleciona low byte
  digitalWrite (pinBS1, LOW);
  // Coloca o dado na via de dados
  PCF8574_Write(valor);
  // Pulsa XTAL1 para registrar o dado
  pulsaXTAL1();
  // Seleciona o fuse
  digitalWrite (pinBS1, bs1);
  digitalWrite (pinBS2, bs2);
  // Dispara a gravação  
  digitalWrite (pinWR, LOW);
  delayMicroseconds(1);
  digitalWrite (pinWR, HIGH);
  delayMicroseconds(1);
  // Aguarda o fim da gravação
  while (digitalRead(pinRdy) == LOW) {
    delay(10);
  }
  // Volta os sinais para o default
  digitalWrite (pinBS1, LOW);
  digitalWrite (pinBS2, LOW);
}

Nenhum comentário: