terça-feira, fevereiro 28, 2017

28C64: Segundo Round

Como relatei, minhas primeiras experiências com a EEProm 28C64 foram frustrantes. Catalisando o meu lado masoquista, parti para novas experiências, agora ligando a AT28C64B a um Arduino para controlar diretamente cada um dos sinais. Após muita luta com maus contatos e bytes hostis, o resultado continua frustrante, mas contém algumas informações curiosas. Obs: nestes testes usei exclusivamente a AT28C64B da Atmel; outros modelos e outros fabricantes podem ter comportamento diferente.


Montagem

A conexão da 28C64 envolve 26 sinais entre endereço, dados, controle e alimentação.  Por este motivo resolvi usar um Arduino Mega. Embora velocidade não seja a primeira preocupação deste experimento, me pareceu mais apropriado fazer acesso direto aos registradores do ATmega ao invés de usar dezenas de digitalWrite. Após estudar o mapeamento dos pinos do Arduino Mega, decidi pelas seguintes conexões:
  • Os sinais de dados da 28C64 foram ligados ao port A do ATmega.
  • Os sinais de endereço A0 a A7 da 28C64 foram ligados ao port C do ATmega.
  • Os sinais de endereço A8 a A12 da 28C64 foram ligados aos bits 0 a 4 do port K do ATmega.
  • Os sinais de controle CE, OE e WE da 28C64 foram ligados aos bits 5, 6 e 7 do port K do ATmega.
  • A alimentação da 28C64 foi ligada ao pino A7 do Arduino (para simplificar a fiação).
A foto no início mostra a montagem. Inicialmente tinha colocado um soquete ZIF, mas os pinos são muito curtos para um contato confiável com a protoboard.

Leitura

Começando pelo mais simples... Para ler uma posição é necessário colocar o endereço nos pinos certos, virar o PORT A para entrada, baixar os sinais CE e OE, esperar o tempo de acesso e ler no PORT A o resultado. A rotina leMem do programa AT28C64B.ino (nos arquivos do blog) faz isto. É rápido o suficiente para um loop para testar eeprom vazia (todas as posições com 0xFF) ser quase instantâneo.

Escrita Byte a Byte

Aqui começa a complicar. Disparar a escrita é simples: colocar o endereço nos pinos certos, virar o PORT A para saída, colocar nela o dado a gravar, baixar os sinais CE e WE, retorná-los ao nível alto e aguardar a escrita. A rotina escreve faz isto na marra, esperando o tempo máximo de gravação. Em seguida ela faz a leitura para conferir se a gravação foi bem sucedida.

Colocar isto em loop, para gravar a memória toda, resulta em vários minutos de espera. Para melhorar isto, a rotina testaEscrita usa o Data Polling. Na maioria dos casos o tempo de escrita é bem menor que o tempo máximo, é preciso detectar quando a escrita foi concluída. A forma de fazer isto é ler a memória durante a escrita. Enquanto a escrita não termina, apenas os bits 7 e 6 são válidos. O bit 7 contém o valor negado do que foi escrito e o bit 6 alterna entre 0 e 1 a cada escrita. A minha rotina fica em loop (com um timeout) esperando o bit 7 lido ficar igual ao escrito. Quando isto ocorre, é necessário fazer mais uma leitura para determinar o que foi gravado e poder conferir (descobri isto após perder um bom tempo).

Com este aperfeiçoamento, e uma simplificada na mudança dos sinais, consegui gravar toda a memória em cerca de 33 segundos.

Proteção e Desproteção

Esta é uma parte que estava meio misteriosa, mesmo lendo o datasheet e um aplication note (pdf).  No final de tudo, é simples. O processo para proteger e desproteger a memória envolve simular a escrita de valores mágicos em endereços idem. A memória percebe a sequência e, ao invés de disparar a gravação dos bytes "escritos", liga ou desliga a proteção. A sequência de proteção tem três bytes e a de desproteção seis.

O que confunde um pouco na documentação é que a sequência que liga a proteção também pode ser usada para permitir gravações. Indo por partes... A rotina protege envia a sequência que liga a proteção e depois espera um tempo. Após fazer isto, as tentativas de gravação normais não alterarão a memória. Para liberar todas as gravações é necessário enviar a sequência que desliga a proteção (rotina desprotege). Entretanto, mesmo com a proteção ligada, é possível efetuar uma gravação, bastando enviar a sequência de proteção e, logo depois, fazer a operação de gravação. Para confundir um pouco mais, você pode fazer isto quando está ligando a proteção; é isto que aparece nos diagramas e fluxogramas do datasheet.

Apagamento

Estou chamando aqui de apagamento (ou limpeza) escrever 0xFF em toda a memória. Temos várias formas de fazer isto. Uma delas, que eu não tentei, é colocar um pulso de 12V no pino OE. A mais óbvia é usar a minha rotina testaEscrita. Funciona, mas demora 33 segundos.

Para minha surpresa, existe uma forma simples, rápida e ligeiramente secreta de apagar a memória. Secreta a ponto de não estar no datasheet, mas documentada em uma nota de aplicação (pdf). Ok, chega de mistério: novamente basta simular a escrita de valores mágicos em endereços idem. A sequência é de seis bytes e é idêntica à de desproteção, exceto pelo último byte "gravado". A rotina cmdApaga faz isto; demora apenas 20 milisegundos. Eu fico aqui pensando qual a probabilidade de um ruído converter a sequência de desproteção na sequência de apagamento...

Chegamos agora à parte frustrante. Uma opção óbvia para o apagamento é a escrita em página. Resumidamente, você pode (ou poderia...) enviar rapidamente uma sequência de escritas na mesma página de 64 bytes. A memória guarda os bytes em um buffer interno e aguarda o fim da sequência (sinalizado por um tempo maior que 150 uSeg sem tentativa de escrita) para iniciar a operação, que leva aproximadamente o mesmo tempo que gravar uma única posição. Portanto poderíamos fazer a gravação de toda a memória em cerca de 0,5 segundo.

O problema é que não consegui fazer isto funcionar. Ao tentar gravar 64 bytes no modo página o comportamento foi o mesmo visto com o TL866: apenas os 32 últimos bytes da página são gravados. Os primeiros 32 ficam inalterados. O mais curioso é que usando o modo página para gravar 32 bytes tudo funciona como o esperado. Ou a AT28C64 é bugada, ou tem algum detalhe que escapou tanto de mim como dos programadores do TL866.

Nenhum comentário: