HOME      PROJETOS      PROGRAMAÇÃO     

Acessando Uma Memória RAM Externa



Nesta matéria vamos ensinar como acessar uma memória RAM externa ao microcontrolador.

O uso de uma memória RAM externa pode ser justificado se pensarmos que há projetos em que é necessário usar muito mais memória do que a disponível na RAM do microcontrolador para armazenar dados resultantes de cálculos, tabelas ou strings de caracteres e, quando isso acontece, só temos duas opções.

A primeira opção é escolher um microcontrolador que tenha memória RAM suficiente, o que pode tornar o projeto mais caro. Essa opção, é claro, a mais fácil de implementar quando existir um microcontrolador com RAM suficiente para atender as necessidades do projeto.

A segunda opção seria usar uma memória RAM externa. Essa opção não é muito fácil de implementar porém é a mais viável do ponto de vista da quantidade de memória RAM que se pode ter disponível para armazenamento de dados.




Funcionamento Básico de uma Memória RAM

Antes de mais nada, devemos deixar claro que memória RAM é uma memória volátil que é apagada quando a energia é desligada.

Uma memória RAM (Randon Access Memory) é uma memória de acesso aleatório, isto é, os bytes que ela armazena podem ser acessados em qualquer sequência usando-se o número do byte que se deseja. Esse número é conhecido como endereço do byte.

As memórias RAM são vendidas em chips das mais diferentes formas, quantidade e número de pinos. Elas também têm diferentes características como tensão de alimentação diferentes, tempo de acesso diferentes e outras. A escolha de uma RAM adequada para um projeto fica por conta do projetista. A verdade é que quase todas elas funcionam da mesma maneira.

O chip de memória RAM geralmente tem 2 pinos de alimentação, um Vcc que é conectado ao pólo positivo da fonte, e um GND que deverá ser conectado ao pólo negativo.

O chip possui uma série de pinos para a porta de endereçamento. Por exemplo, a porta de endereçamento de um chip de memória RAM de 32KBytes (32767 Bytes) tem 15 pinos pois o número 32767 em notação binária se escreve b‘1 1 1 1 1 1 1 1 1 1 1 1 1 1 1‘ (com 15 dígitos 1). A notação hexadecimal para esse número é 0x7FFF. Assumimos que todos saibam como transformar números de uma base para outra.

O chip possui uma porta de dados de 8 bits para entrada (gravação) e saída (leitura) de dados.

O chip deve possuir, também, alguns pinos de controle para que possamos dizer a ele o que desejamos fazer. Basicamente só podemos fazer quatro coisas numa memória RAM:

  1. habilitar o chip de memória
  2. desabilitar o chip de memória
  3. ler um byte
  4. gravar um byte.



Descrição dos Pinos de Controle


Pino CE - Chip Enable

O pino CE (Chip Enable) - esse pino habilita ou desabilita o chip de memória.
Esse pino deve receber um sinal de ativação do microcontrolador para que o chip de memória fique pronto para receber/enviar bytes de/para o microcontrolador. Dependendo do chip usado, esse sinal pode ser active-low ou active-high (ativado quando baixo ou ativado quando alto). Quando esse pino estiver desativado, o chip de memória vai ignorar todos os comandos de leitura e gravação enviados a ele.


Pino WE - Write Enable

O pino WE (Write Enable) - esse pino habilita ou desabilita a gravação.
Toda vez que desejarmos gravar um byte na memória devemos colocar o dado na porta de dados (8 bits) e, em seguida, ativar o sinal desse pino durante um determinado tempo para que o chip possa executar essa tarefa. Passado o tempo determinado, deveremos desativar esse sinal. O tempo de ativação e desativação é muito pequeno, devendo ser da ordem dos nanosegundos. Do mesmo modo que o sinal CE, o sinal WE pode ser active-low ou active-high.


Pino OE - Output Enable

O pino OE (Output Enable) - esse pino habilita ou desabilita a leitura.
Toda vez que desejarmos ler um byte na memória devemos ativar o sinal desse pino durante um determinado tempo para que o chip coloque o byte desejado na porta de dados. Passado o tempo determinado, deveremos desativar esse sinal. O tempo de ativação e desativação desse sinal também é muito pequeno, devendo ser da ordem dos nanosegundos. Do mesmo modo que o sinal CE, o sinal WE pode ser active-low ou active-high.

Abaixo vemos procedimentos genéricos para se ler e gravar um byte numa memória RAM.





Procedimento para gravar um byte na memória RAM

  • Desabilitar os sinais CE, WE e OE.
  • Habilitar o sinal CE.
  • Colocar o endereço na porta de endereço da RAM.
  • Colocar o dado na porta de dados.
  • Esperar um tempo de alguns nanosegundos.
  • Habilitar o sinal WE.
  • Esperar um tempo de alguns nanosegundos.
  • Desabilitar o sinal WE.
  • Desabilitar o sinal CE.



Procedimento para ler um byte na memória RAM

  • Desabilitar os sinais CE, WE e OE.
  • Habilitar o sinal CE.
  • Colocar o endereço na porta de endereço da RAM.
  • Habilitar o sinal OE.
  • Esperar um tempo de alguns nanosegundos.
  • Ler o dado na porta de dados.
  • Desabilitar o sinal OE.
  • Desabilitar o sinal CE.



Nosso Projeto

Para o nosso projeto vamos seleciona o chip de memória RAM UM61256FK-15 que tem capacidade de 32kBytes.
Antes de continuar, faça o download do data sheet do UM61256FK e dê uma olhada para conhecer suas características.
Abaixo, pode-se ver uma foto desse chip.

RAM UM61256FK-15
figura 1



Características do chip UM61256Fk-15

Tensao de alimentação de 5V que elimina a necessidade de uma fonte de tensão diferente da alimentação do PIC.

Tempo de acesso de até 15ns (nanosegundos).

As entradas e saídas de dados permitem sua conexão direta com o microcontrolador, sem necessidade de circuitos auxiliares.

Os pinos de controle CE (pino 20), OE (pino 22) e WE (pino 27) são todos active-low, isto é, são ativados com sinal baixo (0v).

A porta de endereço é formada pelos pinos 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, 23, 24, 25 e 26.

A porta de dados é formada pelos pinos 11, 12, 13, 15, 16, 17, 18 e 19.

O pino 20 é da alimentação Vcc de 5v.

O pino 14 é o Ground.




Considerações sobre Conexões

Num projeto real devemos considerar que uma memória RAM externa, como a selecionada aqui, vai consumir muitas portas de I/O do microcontrolador, não deixando muitas para realizar outras tarefas. No nosso caso, excluindo-se os pinos de alimentação, o chip de memória RAM possui 26

74LS1164N
figura 2
portas para serem conectadas ao microcontrolador.

Com o objetivo de economizar portas de I/O do microcontrolador, devemos usar técnicas que permitam seu interfaceamento com a memória externa. Uma das maneiras de interfacear o microcontrolador e a memória externa é usar um método de comunicação serial onde apenas dois pino de I/O do microcontrolador sejam usados.

Apesar da porta de dados de 8 bits da RAM usarem 8 pinos de I/O do PORTB do PIC, apenas dois pino de I/O foram usados para fazer interface com a porta de endereços da memória RAM que tem 15 pinos (pinos 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 21, 23, 24, 25 e 26). Isso foi conseguido com dois shift registers 74LS164N serial-paralelo, cujo esquema pode ser visto na figura 2, conectados em cascata para receber serialmente do PIC os 15 bits de endereço e transmití-lo de forma paralela para a porta de endereço da RAM externa.

A figura 3 mostra o esquema elétrico de conexões da memória ao microcontrolador. Clique na imagem para ampliá-la. No esquema abaixo, o microcontrolador não foi representado mas apenas os pinos necessários para sua conexão com a memória RAM externa.

Observar que os dois shift registers 74LS164N de 8 bits (SHR-LSB e SHR-MSB) estão ligados para formar um único registrador de 16 bits que receberão o endereço de memória requerido.

Esquema Elétrico - Clique na imagem para ampliar
figura 3

Para transmitir serialmente o endereço ao chip da RAM externa o PIC colocará os 16 bits, um de cada vez, no pino RA0 que está conectado ao pino 1 do registrador SHR-LSB. Com o pino RA1 o PIC enviará o sinal de clock para o pino de clock do registrador SHR-LSB (pino 8) que, por sua vez, está diretamente conectao ao pino de clock do registrador SHR-MSB (pino 8).

A cada transição de clock um dos 16 bit de endereço será enviado pelo PIC ao pino 1 do registrador SHR-LSB e o bit que está no pino 13 de SHR-LSB entrará pelo pino 1 de SHR-MSB. Após 16 transições de clock, o endereço completo ocupará todos os bits dos dois regitradores e estarão presentes na porta de endereço da RAM externa.

Todos os pinos do PORTB (RB0 a RB7) foram usados para a porta de dados e os pinos RA2, RA3 e RA4 foram usados para os sinaais de controle CE, OE e WE respectivamente.




Programa Exemplo

O arquivo RAM-UM61256FK.zip contem o projeto completo para o MPLAB para verificar o funcionamento do uso de uma memória RAM externa. O código fonte esta escrito para um microcontrolador PIC18F4620 mas poderá ser implementado em qualquer microcontrolador da família PIC18F, bastando para isso mudar o código do processador nas diretivas LIST P=18F4620 e #include <P18F4620.INC>.

O programa apresentado neste projeto grava uma string de dados na memória RAM e, em seguida, lê essa string e mostra o resultado num LCD serial conectado aos pinos RD1 e RD2 do PIC. O LCD a ser usado segue o modêlo de projeto apresentado em  Interface para LCD HD44780 com 2 fios 

Mensagem no LCD
figura 4

Este projeto também fornece algumas macros e funções para facilitar as operações de leitura e gravação na memória RAM que podem ser encontradas no arquivo "ramum61256_services.inc" que se encontra dentro do arquivo de distribuição do projeto.

Além disso, o programa também usa os serviços de comunicação com o LCD serial "lcd_services.inc", serviços de strings para facilitar as operações com cadeias de caracteres "string_services.inc" e serviços de retardo de tempo (delays) "delay_services.inc". Todos esses arquivod estão incluidos no programa com a diretiva #include. Os arquivos referentes a esses serviços formam uma infra estrutura de programação assembler e podem ser guardados numa biblioteca para serem usados em outro projetos.



Funcionamento do Serviço de Acesso à RAM

O serviço de acesso a memória RAM, descrito no arquivo "ramum61256_services.inc", possui dois registradores que são usados para conter o endereço corrente da RAM que se deseja acessar, macros instruções e funções decontrole para leitura e gravação.

Os registradores de endereçamento são definidos pelo par RAM_ADDR1:RAM_ADDR0. Quando o programa é iniciado, esses registradores podem conter qualquer endereço e os pinos de controle da RAM podem assumir qualquer estado. A primeira coisa a fazer nesse momento é configurar o par RAM_ADDR1:RAM_ADDR0, fazendo-se uma chamada a função CALL  RAM_INIT que, entre outras coisas, vai fazer os registradores apontarem para o inicio da RAM (endereço 0x0000) e configurar os pinos de controle da RAM externa.

Após a execução de CALL  RAM_INIT, pode-se usar a macro RAM_ADDRESS <endereco> para especificar o endereço de memória que se deseja ler ou gravar. Essa macro carrega o par de registradores RAM_ADDR1:RAM_ADDR0 com o <endereco> e também envia o endereço para o bus da memória RAM. Após um endereço ter sido especificado, través da macro RAM_ADDRESS <endereco>, pode-se ler ou gravar um byte na memória.

Para ler um byte, faça uma chamada à função CALL  RAM_GETCHAR. Essa função vai ler o byte no endereço especificado e colocá-lo no registrador W.

Para gravar um byte na memória RAM, carregue o registrador W com o valor desejado faça uma chamada à função CALL  RAM_PUTCHAR.

Se desejar gravar vários bytes seguidos, a partir de um determinado endereço da RAM, use a macro RAM_ADDRESS <endereco> para especificar o endereço inicial, em seguida use as funções RAM_GETCHAR para ler ou RAM_PUTCHAR para gravar. Após ler ou gravar o byte desejado use a função RAM_INC para avançar para o endereço próximo endereço e repita a leitura ou a gravação.

Gravando 16 bytes a partir do endereço 0x0300 da RAM.

movlw .16 ; quantidade de bytes a ler movwf contador ; carrega o contador RAM_ADDRESS 0x0300 ; endereco inicial na RAM lfsr FSR0, msg001 ; endereco da string na RAM do PIC loop1 movf POSTINC0, w ; pega um byte na RAM do PIC call RAM_PUTCHAR ; grava um caracter na RAM call RAM_INC ; avanca um byte na RAM decfsz contador, f ; fim dos caracteres??? goto loop1 ; NAO --> vai ler o proximo caracter


Lendo 16 bytes a partir do endereço 0x0300 da RAM.

movlw .16 ; quantidade de bytes a ler movwf contador ; carrega o contador RAM_ADDRESS 0x0300 ; endereco inicial na RAM loop1 call RAM_GETCHAR ; le um caracter na RAM movwf buffer ; salva o caracter lido call RAM_INC ; avanca um byte na RAM decfsz contador, f ; fim dos caracteres??? goto loop1 ; NAO --> vai ler o proximo caracter








Descrição das Macros do Serviço de Acesso à RAM



RAM_ADDRESS <endereco>

A macro RAM_ADDRESS carrega o par de registradores de endereço RAM_ADDR1:RAM_ADDR0 com o endereço especificado no parametro <endereco> e o novo valor do endereço será enviado ao bus de endereço da RAM. Exemplo:

RAM_ADDRESS 0x0680



RAM_MVC <origem>, <numero>, <destino>

A macro RAM_MVC move, para o endereço <destino> da RAM externa, uma string de <numero> caracteres que se encontra na RAM do microcontrolador no endereço <origem>. Não há controle de estouro do endereço. Se isso acontecer, o par RAM_ADDR1:RAM_ADDR0 voltará a apontar para o início da RAM externa (endereço 0x0000). Exemplo:

RAM_MVC mgs001, .12, 0x0100



Descrição das Funções do Serviço de Acesso à RAM



RAM_GETCHAR

A função RAM_GETCHAR lê o endereço corrente da RAM, especificado pelo par RAM_ADDR1:RAM_ADDR0, e armazena o seu valor no registrador W.

Entrada: O par RAM_ADDR1:RAM_ADDR0 deve conter o endereço desejado. Saida : W conterá o byte lido. Chamada: CALL RAM_GETCHAR


RAM_INC

Esta função incrementa o endereço da RAM. O par de registradores de endereço RAM_ADDR1:RAM_ADDR0 será incrementado de uma unidade e o novo endereço será enviado ao bus de endereço da RAM.

Entrada: O par RAM_ADDR1:RAM_ADDR0 contem o endereço a ser incrementado. Saida : O par RAM_ADDR1:RAM_ADDR0 será incrementado uma unidade. Chamada: CALL RAM_INC


RAM_INIT

Esta função inicializa o par de registradores de endereços RAM_ADDR1:RAM_ADDR0 fazendo-os apontar para a posição zero (0x0000) da memória e envia esse valor para o bus de endereço da RAM. Além disso, esta função desabilita a leitura e gravação e habilita o chip de memória para torná-lo disponível para as outras funções. Recomenda-se usar essa função uma única vez no início do programa.

Entrada: Não há Saída : Os flags da RAM WE, CE e OE serão desabilitados. O par RAM_ADDR0:RAM_ADDR1 apontará para o endereço 0x0000. Chamada: CALL RAM_INIT


RAM_PUTCHAR

A função RAM_PUTCHAR envia o conteúdo do registrador W para o endereço corrente da memoria RAM, especificado pelo par RAM_ADDR1:RAM_ADDR0.

Entrada: W contem o byte a gravar. Saida : Valor gravado no endereço especificado. Chamada: movlw "X" CALL RAM_PUTCHAR


RAM_SETADDR

Afunção RAM_SETADDR envia os 15 bits de endereço contidos no par de registradores RAM_ADDR0:RAM_ADDR1 para o bus de endereço da RAM. Esta função é de uso interno e não pode ser utilizada pelo programador.

Entrada: O par RAM_ADDR0:RAM_ADDR1 deve conter o endereço desejado. Saida : O endereço presente no bus de endereço da RAM. Chamada: CALL RAM_SETADDR














H P S P I N

Desde 04 de Março de 2010

Atualização: 26 de Apr de 2024