Playing with an old SRAM

Abstract : Setup an old PC SRAM with Arduino, try writes to and reads from ; then display on serial output.

Note : This schematics and code are for didactic / demo purposes only.  It would be silly to use such implementation in a real design. On the other hand, XMEM interface (AVR eXternal MEMory) can probably be used with such SRAM chip.  It will the topic of a next study. Right now I have no AVR/Atmel chip doing XMEM, only Arduino boards, sadly…

Introduction

A friend of mine recently provided me with a bunch of various electronic components (thanks Xavier !). Among them, there was IS61C64 chips : old 8K SRAM cache (picked up in an old PC : 286, 386 or so… ).

Let’s try to write to and then read from the chip’s memory bank.

For this demo I used an Arduino Uno R3 with Atmega328p, which lacks pins to fully cable the SRAM chip. I had to drop some bits on “binding”, only addressing with 6bits (64 byte values accessible, only !).

Pinout of IS61C64

Here is the pinout of this chip. I have a DIP 28 chip instead of SOJ/SOP, but doesn’t matter, i only found datasheet for IS61C64

IS61C64

There is 4 control pins : /OE, /WE, /CE1 and CE2.

How this chip works :

This is an SRAM (i.e. Static Random Access Memory). NB : the word “RAM” itself doesn’t mean much since ROM are not sequencial anymore (like magnectic tape or pattern cards). This is just a “static”, but volatile (which means RAM) electronic memory.

When MCU sets /CE1 and CE2, it can still select READ or WRITE cycle, by setting /OE (Output Enabled =  READ CYCLE) or /WE (Write Enabled = WRIRE CYCLE).

Wiring An Arduino for a Demo

Here is the wiring, it is aimed to ease the code (AVR oriented, using PORTs : B, C, & D). The goal is to ease coding by using some convention (PLEASE NOTE this is my personal inspiration under that mood, not any universial convention, nor an Atmel one) :

PORTB is for “Binding“, i.e. address, and is 6 bits wide. Could be 8 using arduino’s A4 & 5, but there on PORTC I dedicated to Control Bus. Anyone with basic knowledges in C can make this trivial extension — even “Arduino flavoured C” ! (kr-kr-kr… I’m bad, mean and evil >:)

PORTC is for “Control“, i.e. setting (/CE1, CE2, /OE, /WE) state. It’s 4bits wide.

PORTD is for “Data“, i.e. for exchanging data between MCU and the chip. It’s a byte wide.

hardwareschematics

hardware_realActual implementation

The demo code

A mini driver lib for the chip

void init_IS61C64(void) {
    DDRC  = 0x0F;  // Control bus is PORTC[0:3]
    PORTC = 0x05;  // /WE=0 /OE=1 CE2=0 /CE1=1 : IDLE
    DDRD  = 0XFF;  // Set DATA port as output by default
    PORTD = 0x00;  
    DDRB  = 0X3F;  // Only PORTB[0:5] are wired
    PORTB = 0x00;
}

void write_IS61C64(unsigned char address, unsigned char data) {
    // switch portData to read mode
    DDRD = 0xFF;
    PORTD = data;
    // write adress to portB
    PORTB = address;

    PORTC = 0x02;       // /WE=0 /OE=0 CE2=1 /CE1=0
    _NOP();             // theorically useless ! See below in the post.

     // restore 'idle' control state
     PORTC = 0x05;      // /WE=0 /OE=1 CE2=0 /CE1=1
}

unsigned char read_IS61C64(unsigned char address) {
   unsigned char data;//switch portData to read mode
   DDRD = 0x00;
   // write adress to portB
   PORTB = address;

   PORTC = 0x0A;        // /WE=1 /OE=0 CE2=1 /CE1=0
   _NOP();              // theorically useless ! See below in the post.
   data = PIND;

   // restore 'idle' control state
   PORTC = 0x05  ;      // /WE=0 /OE=1 CE2=0 /CE1=1
 
   return data; 
}

The _NOP() instructions are here to extend timing and ensure this old, maybe used SRAM, has enough time to process data. << Just speak slower to elderly >>

Theorically it is useless even with IS61C64-25N. Indeed : 25N is 25ns access time, and 1/25ns = 40Mhz garanteed ! Where most AVR chip are 20MHz max..

The main() function

Nothing spectacular here. But, for the record :

  1. I don’t understand why the 10ms delay after init is not shown in the simulation graph below. Maybe a version mismatch or something, nothing really relevant anyway…
  2. I should get rid off the crappy Arduino’s Serial class. But it doesn’t mean I’ll write in plain C.. I still like the class primitive and templates, when well suited. But I promise the next post implying UART will use something better.
  3. Unsure if it the Serial class, the way I use it, or something else in hardware (or my PC) that make me miss some data. But I recall to meet the same problem some years ago with a different arduino, PC, and OS ! So both first are best candidates.
int main(void) {
    unsigned char result[64] = {0x0A};

    // SETUP
    init_IS61C64();
    delayMicroseconds(10);

    for (int i=0; i<64; i++) {
        write_IS61C64(i, 0xFF-i);
    }

    for (int i=63; i>0; i--) {
        result[i] = read_IS61C64(i);
    }

    Serial.begin(115200);
    Serial.println("+++");
    Serial.println("IS61C64 demo\n___\n");

    for (int i=63; i>0; i--) {
        Serial.println(result[i], HEX);
    }

    int j = 0;
    while (j<256) {
        Serial.write(".");
    } // stuffing PC buffer : avoid losing meaningful data at reset
    //LOOP : do nothing
    while(1) {
        _NOP();
    }

    return 0;
}

Simulating the stuff

SRAM8K_simulationSimulAVR output in GTKWave for the code above

We have multiple discrete phases :

  • Init : the AVR runs self-initialisation  code,
  • Write : the AVR writes to the SRAM. We can see /WE keeps low during the whole phase. Other control pins are constantly switching, then indicating indicating write cycles. Binding (address) bus expose a count up. Data bus expose a count down from 0xFF to 0xC0 as expected.
  • Read : the AVR reads from the SRAM. All Control pins are switching indicating read cycles. Binding bus counts down, and Data bus stays low, because we are simulating here, so there is no actual SRAM to serve data. The aim here is just to check the AVR output pins state through time, not checking the whole design. NB : /WE switches because choosen rest state is “write”.
  • UART init : the AVR initialise Arduino’s USB link through AVR UART.
  • Pause : AVR sleeps.
  • Data transmission : through UART and over USB.

Everything seems OK.

At first I was dumbly trying to send data interleaving reads from memory. I was hoping that Serial.write() was synchronous with transmission acheivement. Stupid guess ! The first simulation quickly showed that there was a mess-up on TX (and then, RX) pin(s), which is also a Data port bus pin…

I realized (by examining SimulAVR execution logs) that Serial.write() only writes into the UART physical buffer and then returns. To ensure pin “housekeeping”, no read nor write should be issued between Serial.begin()  … Serial.end() sequence call.

Conclusion

Everything worked liked a charm on real hardware on the first try (but the UART buffer problem that lead me to print 256 ‘.’ after useful data).

Everything worked… even TOO good !

I mean : on my first try I “forgot” (and was lazy) to wire unused pin to GND (i’m software engineer, heh !)… But I also unwired volontarily Vcc and  (less volontarily) /OE:/

And IT STILL WORKED ! So surprized, I unplugged all Control Bus wires (by that very time, I realized that /OE control was not plugged on SRAM pin)… I then get the expected result, i.e. : only zeros on all  SRAM rows.

Then I believe the chip was powered but some (set of) pulled-up pin, and /OE is not quite important with this chip, at least when /WE is driven.

Going Further…

  • Using XMEM capable chip on a “bread”uino…
  • Implementing string transfer (i.e. read & write burst, holding Control bus state during whole transfer)

 

 

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s