Neste post vou concluir o projeto começado no post anterior. Os problemas que eu tive? Aparentemente foi principalmente mau contato (notadamente na fonte de 5V), mas acabei fazendo também alguns ajustes no hardware e software.
Funciona! |
Hardware
A única mudança foi no acionamento do acoplador ótico que controla os 5V: coloque um resistor de pulldown (para garantir que não é acionado quando o pino do ESP32 estiver como entrada) e mudei o valor do resistor em série (para garantir que vai conduzir). Provavelmente funciona mesmo sem estas mudanças.
O esquema atualizado (mas ainda não muito bonito):
Software: Páginas WEB
O meu código para esta parte se baseou no exemplo de upload de arquivo da biblioteca AutoConnect. As telas e a navegação entre elas estão meio rústicas, mas funciona.
São apenas três páginas (como a animação no início mostra). Na primeira é feito o upload do arquivo hex, na segunda é disparada a gravação e na última é apresentado o resultado.
Na tela de upload eu usei um "custom uploader handler": uma classe personalizada para tratar a recepção de arquivo. A interface desta classe é composta por três métodos: _open, _write e _close (como se fosse escrita em arquivo). O meu método _write examina os dados para ir montando uma linha (finalizada por '\n'). Quando completa a linha, ela é analisada como uma linha de arquivo HEX e os dados a gravar são salvos num vetor global (chamado de 'firmware'). Em seguida volta a montar e tratar a linha seguinte. É bom lembrar que não há garantia que uma chamada ao _write tenham linhas inteiras, portanto o estado da montagem de linha precisa ser preservado pelo objeto.
Software: Gravação do AT89S51
Este era o principal objetivo do projeto, certo? Em princípio é apenas uma questão de enviar os bytes corretos usando SPI, mas tem alguns detalhes:
- O clock do SPI não pode passar de 1/16 do cristal usado. Acabei usando um clock de 300KHz (por motivo ignorado* não funcionou com 500KHz). Para selecionar o clock do SPI usei o método setFrequency(), no ESP32 o uso de startTransaction() tem efeitos colaterais além de configurar a SPI..
- Na maioria dos casos (a exceção é a leitura da Flash por pagina) devem ser enviados quatro bytes para o AT89S51. A resposta que interessa é a que é recebida junto com a transmissão do último byte (lembrando, no SPI transmissão e recepção são simultâneas). Em alguns casos o valor enviado é ignorado pelo AT89S51 (usei 0).
- As leituras da Flash são imediatas e não precisa de intervalo entre elas.
- Para saber quando uma operação de apagamento ou escrita encerrou eu usei o recurso de "Data Polling" onde a leitura após a escrita retorna um valor forçadamente diferente enquanto a operação está sendo executada.
- Para verificar a gravação e testar se a Flash está apagada (só contem 0xFF), usei a leitura por página. Nesta operação são enviados dois bytes (o comando e o número da página). Em seguida devem ser enviados exatamente 256 bytes (o conteúdo deles não importa), para cada byte enviado é recebido um byte que corresponde ao conteúdo da página a partir da posição 0. Com isto se ganha tempo em relação à leitura por byte (para cada posição da Flash teria que enviar 4 bytes), mas tem que tomar cuidado de enviar exatamente os 256 bytes (se enviar menos, os comandos seguintes provocarão leitura, se enviar a mais os bytes a mais serão tratados como comando).
O código completo pode ser visto no github: https://github.com/dquadros/GravadorESP51
Aperfeiçoamentos
O AutoConnect suporta também o ESP8266. Não testei com ele, mas pode ser uma opção para deixar o projeto menor e mais barato.
A forma de gravação da Flash de outros microprocessadores da ATmel é bem parecida. Estudando com carinho os datasheets e sofrendo um pouco com a depuração daria para suportar outros modelos, deixando o gravador mais genérico.
* minha desconfiança é que o conversor de nível não é rápido o suficiente
Atualização 03/03/21: Funcionou a 750KHz substituindo o conversor de nível por um divisor resistivo no MISO e ligando direto MOSI e SCK. Era a montagem que eu tinha feito inicialmente, mas como não estava funcionando sempre (devido ao mau contato) eu coloquei o conversor de nível.
Nenhum comentário:
Postar um comentário