Banco de teste para memória RAM HM6116 de 16k – Arduino

Tempo de leitura: 8 minutes

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.

 

Imagens Memorias placa Sistema 3 Siemens
Imagens Memorias placa Sistema 3 Siemens

Funcionamento da memória

Memórias do tipo SRAM (Static Random Access Memorymemó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.

Celula basica de uma SRAM
Celula basica de uma SRAM

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.

Imagem Memória RAM
Imagem Memória RAM

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.

Diagrama de blocos da memória 6116
Diagrama de blocos da memória 6116
Memoria 6116
Memoria 6116

Dinâmica de Funcionamento do teste

Imagem Inicio do Teste
Imagem Inicio 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.

Fluxo de funcionamento do teste
Fluxo de funcionamento do teste

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.

Diagrama temporal Escrita de dados
Diagrama temporal Escrita de dados
Após a escrita dos dados para teste da memória, uma rotina de leitura em cada posição é feita e o valor é comparado com o dado que foi escrito anteriormente. Se o programa encontrar uma falha na comparação o mesmo para a execução com o comando break e o teste deve ser reiniciado novamente. Toda esta dinâmica acontece quando bloquemos o buffer levando o pino CS em nível HIGH, o pino WE da memória em nível HIGH e o pino OE em nível LOW. O diagrama temporal abaixo mostra este processo de leitura da memória em detalhe.
Diagrama temporal de Leitura de dados
Diagrama temporal de Leitura de dados

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).

Esquema de montagem
Esquema de montagem
Todo o projeto foi simulado no software Proteus antes da montagem final na protoboard. O software na versão 8.0 não atendia as minhas necessidades pois não apresentava a opção de leitura do mapa de memórias como indicado na imagem abaixo e somente a versão 7 atendia este requisito.
Imagem escrita no mapa de memória
Imagem escrita no mapa de memória
Imagem simulação proteus
Imagem simulação proteus

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.

Imagem Buffer e Resistências de 22k
Imagem Buffer e Resistências de 22k

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.

PORT A Arduino Mega
PORT A Arduino Mega

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.