Banco de teste para memória RAM HM6116 de 16k – Arduino
Neste artigo iremos descrever a implementação de um sistema para testar antigas memórias RAM, estática, modelo HM6116LP-4 que ainda são utilizadas em equipamentos industriais. No meu caso, estas memórias estão aplicadas em uma placa de memória de um antigo sistema de CNC da Siemens denominado Sinumerik Sistema 3. Minha necessidade era testar a integridade de escrita e leitura das memórias e é este o tema deste artigo.
Conteudo
Funcionamento da memória
Memórias do tipo SRAM (Static Random Access Memory, memória estática de acesso aleatório) mantém os dados armazenados desde que seja mantida sua alimentação, não precisando que as células que armazenam os bits sejam atualizadas, processo usualmente chamada de refreshing, como é o caso das memórias DRAM. A estrutura básica de uma SRAM é indicada na figura abaixo.
Apesar de não ser necessária a atualização constante, essa memória ainda pode ter a característica de ser volátil, ou seja, após um tempo sem energia a informação guardada por ela pode ser perdida. Outra desvantagem é que são mais caras, complexas e menos densas, ocupando mais espaço, quando comparadas às DRAM.
Mas a vantagem de apresentar um tempo de acesso menor e, consequentemente serem mais rápidas, justifica seu uso em certos nichos, como em cache L1 e L2 presentes em processadores ea algumas aplicações muito específicas em equipamentos especiais. Além disso, as memórias estáticas consomem mais energia e aquecem mais quando comparadas com as DRAM. Memórias estáticas usam circuitos no modelo flip-flop para armazenar os dados.
A memória que estamos trabalhando neste Lab apresenta um tamanho de 2048 palavras de 8 bits. Este tamanho não é algo grande quando comparado as memorias das máquinas atuais que possuem no mínimo 1 GB para o correto funcionamento, porém, para uma máquina fabricada no ano de 1987 a associação destas memórias era a única solução para a implantação dos sistemas.
Para endereçar 2048 posições diferentes de memória são necessários 11 bits de dados. O diagrama de blocos funcional desta memória está apresentado abaixo e ilustra os 11 bits utilizados para o endereçamento, os 8 bits de dados e as 3 entradas de controle além do Vcc e Vss totalizando um encapsulamento de 24 pinos.
Dinâmica de Funcionamento do teste
Um diagrama funcional do teste da memória é apresentado abaixo. O teste é iniciado quando o usuário pressiona o botão de início (Obvio isto!). O valor a ser escrito na memória é enviado ao lado B do buffer que ainda está desabilitado. A linha de controle OE (Output Enable) da memória permanece em nível alto e o outro pino de controle WE (Write Enable) vai a nível zero. O buffer é então habilitado, permitindo a passagem do dado do lado B para o lado A habilitando assim a escrita em cada posição de memória que é incrementada com um contador binário que inicia seu valor em 0x000 e termina em 0x7FF.
Entre o incremento de cada endereço, o pino WE deve ir a nível alto e logo após a nível baixo novamente para que a escrita seja efetivada. Esta dinâmica de funcionamento é exemplificada no diagrama temporal fornecido pelo datasheet do fabricante e ilustrado abaixo.
Quando a comparação é bem sucedida, uma rotina que apaga todos os dados escritos nas posições de memorias escrevendo o valor 0x000 em cada uma é executada.
Diagrama de ligação
O diagrama de ligações está indicado abaixo. Não há complexidade em executar estas ligações visto que todos os componentes trabalham no mesmo nível de tensão de alimentação (5Vcc).
Na imagem abaixo temos o detalhe do componente buffer (SNx4LS245 Octal Bus Transceivers With 3-State Outputs) e das resistências utilizadas para o Pull down dos pinos de entrada do Arduino e do botão de início do teste.
Algoritmo e testes
O algoritmo que determina todo o funcionamento desta aplicação está descrito abaixo e alguns comentários estão inseridos no corpo do código para um melhor entendimento.
/*************************************************************************** * Banco de teste de memórias RAM HM6116LP-4 com o Arduino ***************************************************************************/ #include <LiquidCrystal.h> LiquidCrystal lcd(12, 11, 10, 9, 8, 7); /****************************************************************************/ // Declaração de variáveis e vetores utilizados uint8_t entDataPins[8]; uint8_t entDataPinsLeng = 8; uint8_t test; uint8_t valueTest = 0x0F; uint8_t inputByteRead; int adrPins[11]; int counter = 0; uint8_t flag; /***************************************************************************/ // Declaração dos pinos utilizados const int writeMem = 41; const int readMem = 52; const int enabBuff = 42; const int btnInicia = 51; int adrPinsLeng = 11; void setup(){ //Atribuição dos pinos a cada posição do vetor relacionado a linha de Dados entDataPins[0] = 43; // Pino D0 da Memória entDataPins[1] = 44; // Pino D1 da Memória entDataPins[2] = 45; // Pino D2 da Memória entDataPins[3] = 46; // Pino D3 da Memória entDataPins[4] = 47; // Pino D4 da Memória entDataPins[5] = 48; // Pino D5 da Memória entDataPins[6] = 49; // Pino D6 da Memória entDataPins[7] = 50; // Pino D7 da Memória //Atribuição dos pinos a cada posição do vetor relacionado a linha de Endereço adrPins[0] = 30; // Pino A0 da Memória adrPins[1] = 31; // Pino A1 da Memória adrPins[2] = 32; // Pino A2 da Memória adrPins[3] = 33; // Pino A3 da Memória adrPins[4] = 34; // Pino A4 da Memória adrPins[5] = 35; // Pino A5 da Memória adrPins[6] = 36; // Pino A6 da Memória adrPins[7] = 37; // Pino A7 da Memória adrPins[8] = 38; // Pino A8 da Memória adrPins[9] = 39; // Pino A9 da Memória adrPins[10] = 40; // Pino A10 da Memória // Atribuição Pinos de Endereço da memória for (int thisPin = 0; thisPin < adrPinsLeng; thisPin++) { pinMode(adrPins[thisPin], OUTPUT); digitalWrite(adrPins[thisPin],LOW); } // Faz acesso direto e configura Pinos de Dados da memória DDRA = 0x00; // Atribuição Pinos de entrada de dados na memória for (int thisPin = 0; thisPin < entDataPinsLeng; thisPin++) { pinMode(entDataPins[thisPin], OUTPUT); digitalWrite(entDataPins[thisPin],LOW); } // Configura pinos de controle de escrita pinMode(writeMem, OUTPUT); digitalWrite(writeMem,HIGH); // Configura pinos de controle de leitura pinMode(readMem, OUTPUT); digitalWrite(readMem,HIGH); // Configura pinos de habilitação do buffer pinMode(enabBuff, OUTPUT); digitalWrite(enabBuff,HIGH); // Configura pino para o botão de inico do teste pinMode(btnInicia, INPUT); // Configura numeros de linhas e colunas no LCD lcd.begin(16, 2); // Excreve mensagens no LCD lcd.setCursor(0, 0); lcd.print(" Teste Memoria"); lcd.setCursor(0, 1); lcd.print("RAM: HM6116LP-4"); delay(500); lcd.setCursor(0, 0); lcd.print("Inicie o teste "); lcd.setCursor(0, 1); lcd.print(" "); } void loop(){ if (digitalRead(btnInicia)){ write8bits(0xFF); counter =0; digitalWrite(writeMem,LOW); delayMicroseconds(1); digitalWrite(writeMem,HIGH); flag = 1; lcd.clear(); } while(flag == 1){ lcd.setCursor(0, 0); lcd.print("Escrevendo... "); digitalWrite(enabBuff,LOW); for (int i = 0; i < adrPinsLeng; i++){ write11bits(counter); digitalWrite(writeMem,LOW); delayMicroseconds(1); digitalWrite(writeMem,HIGH); } lcd.setCursor(0, 1); lcd.print("0x"); lcd.print(counter,HEX); if (counter <= 2047){ counter ++; } else{ counter =0; delayMicroseconds(1); digitalWrite(enabBuff,HIGH); flag = 2; lcd.clear(); } } while(flag == 2){ lcd.setCursor(0, 0); lcd.print("Lendo... "); lcd.setCursor(0, 1); lcd.print("0x"); lcd.print(counter,HEX); digitalWrite(enabBuff,HIGH); digitalWrite(writeMem,HIGH); digitalWrite(readMem,LOW); write8bits(0x00); for (int i = 0; i < adrPinsLeng; i++){ write11bits(counter); inputByteRead = PINA; if (inputByteRead == 0xFF){ delayMicroseconds(1); lcd.setCursor(7, 1); lcd.print("ok"); } else{ lcd.setCursor(7, 1); lcd.print("Falha"); break; } if (counter <= 2047){ counter ++; } else{ counter =0; digitalWrite(readMem,HIGH); digitalWrite(enabBuff,HIGH); lcd.clear(); flag = 3; } } } while(flag == 3){ lcd.setCursor(0, 0); lcd.print("Apagando... "); write8bits(0x00); digitalWrite(enabBuff,LOW); for (int i = 0; i < adrPinsLeng; i++){ write11bits(counter); digitalWrite(writeMem,LOW); delayMicroseconds(1); digitalWrite(writeMem,HIGH); } lcd.setCursor(0, 1); lcd.print("0x"); lcd.print(counter,HEX); lcd.print(" "); if (counter <= 2047){ counter ++; } else{ counter =0; delayMicroseconds(1); digitalWrite(enabBuff,HIGH); flag = 4; lcd.clear(); } } while(flag == 4){ lcd.setCursor(0, 0); lcd.print("Teste Concluido "); lcd.setCursor(0, 1); lcd.print("Reinicie um novo"); if (digitalRead(btnInicia)) flag = 0; } } //Função que escreve 8 bits de dados em pinos específicos void write8bits(uint8_t value) { for (int i = 0; i < 8; i++) { digitalWrite(entDataPins[i], (value >> i) & 0x01); } } //Função que escreve 11 bits de dados em pinos específicos void write11bits(int value) { for (int i = 0; i < 11; i++) { digitalWrite(adrPins[i], (value >> i) & 0x01); } }
Um detalhe importante foi o uso do acesso direto de dados que trafegam em um Port específico do microcontrolador, neste caso os pinos 22 a 29 que representam o PORT A.
Este acesso foi importante no momento de comparação do dado escrito em posições especificas da memória e que são lidos no PORT A, graças a velocidade de leitura dos registradores de entrada do microcontrolador utilizando este método, com o dado padrão escrito na etapa de escrita do teste, que no caso foi 0x7FF.
Conclusão
Neste Artigo implementamos um banco de testes para as antigas memórias HM6116, do tipo SRAM, que ainda são utilizadas em aplicações industriais. Além do aprendizado em programação e esquemático de circuitos eletrônicos, este Artigo nos mostrou os aspectos do real funcionamento de uma memória, ainda que seja uma “primitiva”, porém funcional e ainda em operação.