Page 1 of 4

DRAMARDUINO - Dram tester with Arduino

Posted: Sat Oct 15, 2016 2:30 pm
by iss
Hi all!

Below you can see all details of my 2-hours 2-dollar project 'DramArduino'.
It's simple and very handy DRAM chip tester. It works with 4164 and 41256 IC's.
Testing is not too fast but acceptable - 4 different passes are performed in about 80 seconds total.
Results are 100% reliable only if the test FAILS - you can throw away the chip without fear.
If the test passes, this doesn't certainly mean that it will work in Oric, because as you know Oric's are very 'sensitive' to DRAM.
Actually this was my goal exactly - to sort out the working chips from about 200 before I'm get bored :).

Working with the tool is easy: place the chip in the ZIF socket, press small reset button, wait until GREEN LED blinks,
if it remains permanently on - chip is OK, if the chip is bad - RED LED lights.
If USB is connected, status is reported in your serial console. This helped me to detect some 'lazy' chips - they failed in
different, on every next test, growing addresses but when they become 'hot' test passes always.
IIRC such fail to boot Oric was reported somewhere in this forum...

Attached are 'schematic', source code and pictures - do with them what you want :).
dramarduino.png
da.jpg
EDIT 2020-10-29: Sketch fixed!
dramarduino.ino.2020-10-29.zip
(1.4 KiB) Downloaded 3351 times

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Wed Jan 16, 2019 1:36 am
by Voyageur
Hi Iss,
Thank you for sharing the DramTester.
I've made one and it works !
I just controlled some 4164 and it is a good and not so long test :)
If you agree, I will show this Arduino shield on flag_fr CEO forum.
Have a good day !

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Wed Jan 16, 2019 8:35 am
by iss
Hello, Voyageur!
I'm very glad that you liked this little tool and I'll be really happy if you share it on CEO forum.

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Sun Mar 10, 2019 7:08 pm
by witchy
Hi Iss,

This was timed beautifully, for an upcoming 'Japanese Computing' exhibition at the Centre For Computing History in Cambridge I was testing my Sanyo MBC555 and the CGA card in there has 8x41256 chips on board. I built the tester on a breadboard and it works perfectly, thanks! Unfortunately it passed all 8 so the fault I have is elsewhere on the board.
dramArduino.jpg

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Mon Oct 05, 2020 9:38 am
by john
Resurrecting a old thread here but looks like there is a critical bug in this code which causes only memory location 0x0000 to be tested.

Code: Select all

void setBus(unsigned int a) {
  int i;
  for (i = 0; i < BUS_SIZE; i++) {
    digitalWrite(a_bus[i], a % 1);
    a /= 2;
  }
}
a%1 will always result in 0 so no matter what value a is, 0 will always be written to the address lines.

Code should be changed to:

Code: Select all

digitalWrite(a_bus[i], a % 2);

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Wed Oct 07, 2020 8:36 am
by HigashiJun
Interesting...

I will give it a try on my DRAMARDUINO.

Thanks.

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Wed Oct 07, 2020 10:01 am
by iss
Wow, nice catch. Interesting is that in my local file it's:

Code: Select all

digitalWrite(a_bus[i], a & 1);
Maybe I've uploaded something preliminary...
First post is now updated with the correct sketch!

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Thu Oct 29, 2020 5:42 pm
by thekorex
Hello everyone, yesterday I got a pack of KM4164B-15 ICs and quickly built a big mess of wires on a breadboard to test them using DramArduino which I want to thank @iss for creating and sharing.

After testing a few of the ICs I noticed the sketch still contains two more occurrences of the problematic % 1 in both fill(int v) and fillx(int v) functions.

I think this will cause fill(int v) to simply test the RAM with zeros, regardeless of the value of v and fillx(int v) to always generate the sequence "0 1 0 1..." and never the opposite one "1 0 1 0..."

Code: Select all

void fill(int v) {
  int r, c, g = 0;
  v %= 1;
  for (c = 0; c < (1<<bus_size); c++) {
    green(g? HIGH : LOW);
    for (r = 0; r < (1<<bus_size); r++) {
      writeAddress(r, c, v);
      if (v != readAddress(r, c))
        error(r, c);
    }
    g ^= 1;
  }
  blink();
}

void fillx(int v) {
  int r, c, g = 0;
  v %= 1;
  for (c = 0; c < (1<<bus_size); c++) {
    green(g? HIGH : LOW);
    for (r = 0; r < (1<<bus_size); r++) {
      writeAddress(r, c, v);
      if (v != readAddress(r, c))
        error(r, c);
      v ^= 1;
    }
    g ^= 1;
  }
  blink();
}
I replaced each function's second line containing

Code: Select all

  v %= 1;
with

Code: Select all

  v &= 1;
to get the lower bit of v and I believe it solves the problem.

Anyway, thank you again for sharing this nice project.

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Thu Oct 29, 2020 7:37 pm
by iss
thekorex wrote: Thu Oct 29, 2020 5:42 pm ...
Thank you for reporting @thekorex!

First post is updated again with the correct sketch!

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Thu Dec 10, 2020 4:52 pm
by shift838
iss wrote: Thu Oct 29, 2020 7:37 pm
thekorex wrote: Thu Oct 29, 2020 5:42 pm ...
Thank you for reporting @thekorex!

First post is updated again with the correct sketch!
I was looking for exactly one of these and found the schematics and sketch here. It works great, but I would like to be able to interface a button to execute the DRAM test, which I have done in the below code. But I want it to stop when it fails, I then want to be able to change the DRAM and hit the button again to start a new test. Currently with the 'While (1);' statement it will put the unit in the endless loop where you have to RESET the arduino to start a new test. I don't want to have to restart the arduino.

I have tried to remove the While statement and put in a 'return;' but that generates just a constant loop of FAILED being printed via the serial monitor and I have to reset the Arduino to stop it.

Looks like this in the serial monitor:

Code: Select all

DRAM TESTER Selected: 256K x 1 
Pass #1...
 FAILED $1
 FAILED $3
 FAILED $5
 FAILED $7
 FAILED $9
 FAILED $B
 FAILED $D
 FAILED $F
 FAILED $11
 FAILED $13
 FAILED $15
 FAILED $17
 FAILED $19
the code is below. any help would be greatly appreciated.

Code: Select all


#include <Bounce2.h>
#include <SoftwareSerial.h>

#define DI          15  // PC1
#define DO           8  // PB0
#define CAS          9  // PB1
#define RAS         17  // PC3
#define WE          16  // PC2

#define XA0         18  // PC4
#define XA1          2  // PD2
#define XA2         19  // PC5
#define XA3          6  // PD6
#define XA4          5  // PD5
#define XA5          4  // PD4
#define XA6          7  // PD7
#define XA7          3  // PD3
#define XA8         14  // PC0

#define M_TYPE      10  // PB2
#define R_LED       11  // PB3
#define G_LED       12  // PB4

#define RXD          0  // PD0
#define TXD          1  // PD1

#define BUS_SIZE     9

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 13;     // the number of the pushbutton pin

// variables will change:
int buttonState = 0;         // variable for reading the pushbutton status
long lastDebounceTime = 0;  // the last time the output pin was toggled
long debounceDelay = 205;    // the debounce time; increase if the output flickers

/* ================================================================== */
volatile int bus_size;

//SoftwareSerial USB(RXD, TXD);

const unsigned int a_bus[BUS_SIZE] = {
  XA0, XA1, XA2, XA3, XA4, XA5, XA6, XA7, XA8
};

//-----------------------------------------------------

void setBus(unsigned int a) {
  int i;
  for (i = 0; i < BUS_SIZE; i++) {
    digitalWrite(a_bus[i], a & 1);
    a /= 2;
  }
}

void writeAddress(unsigned int r, unsigned int c, int v) {
  /* row */
  setBus(r);
  digitalWrite(RAS, LOW);

  /* rw */
  digitalWrite(WE, LOW);

  /* val */
  digitalWrite(DI, (v & 1)? HIGH : LOW);

  /* col */
  setBus(c);
  digitalWrite(CAS, LOW);

  digitalWrite(WE, HIGH);
  digitalWrite(CAS, HIGH);
  digitalWrite(RAS, HIGH);
}

int readAddress(unsigned int r, unsigned int c) {
  int ret = 0;

  /* row */
  setBus(r);
  digitalWrite(RAS, LOW);

  /* col */
  setBus(c);
  digitalWrite(CAS, LOW);

  /* get current value */
  ret = digitalRead(DO);

  digitalWrite(CAS, HIGH);
  digitalWrite(RAS, HIGH);

  return ret;
}

void error(int r, int c)
{
  unsigned long a = ((unsigned long)c << bus_size) + r;
  digitalWrite(R_LED, LOW);
  digitalWrite(G_LED, HIGH);
  interrupts();
  Serial.print(" FAILED $");
  Serial.println(a, HEX);
  Serial.flush();
  //while(1);
  return;
}

void ok(void)
{
  digitalWrite(R_LED, HIGH);
  digitalWrite(G_LED, LOW);
  interrupts();
  Serial.println(" PASSED!");
  Serial.flush();
  //while(1);
  return;
}

void blink(void)
{
  digitalWrite(G_LED, LOW);
  digitalWrite(R_LED, LOW);
  delay(1000);
  digitalWrite(R_LED, HIGH);
  digitalWrite(G_LED, HIGH);
}

void green(int v) {
  digitalWrite(G_LED, v);
}

void fill(int v) {
  int r, c, g = 0;
  v &= 1;
  for (c = 0; c < (1<<bus_size); c++) {
    green(g? HIGH : LOW);
    for (r = 0; r < (1<<bus_size); r++) {
      writeAddress(r, c, v);
      if (v != readAddress(r, c))
        error(r, c);
    }
    g ^= 1;
  }
  blink();
}

void fillx(int v) {
  int r, c, g = 0;
  v &= 1;
  for (c = 0; c < (1<<bus_size); c++) {
    green(g? HIGH : LOW);
    for (r = 0; r < (1<<bus_size); r++) {
      writeAddress(r, c, v);
      if (v != readAddress(r, c))
        error(r, c);
      v ^= 1;
    }
    g ^= 1;
  }
  blink();
}

void setup() {
  int i;
  
// initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT);
  Serial.begin(115200);
  while (!Serial)
    ; /* wait */

  Serial.println();
  Serial.print("DRAM TESTER ");

  for (i = 0; i < BUS_SIZE; i++)
    pinMode(a_bus[i], OUTPUT);
  pinMode(CAS, OUTPUT);
  pinMode(RAS, OUTPUT);
  pinMode(WE, OUTPUT);
  pinMode(DI, OUTPUT);

  pinMode(R_LED, OUTPUT);
  pinMode(G_LED, OUTPUT);

  pinMode(M_TYPE, INPUT);
  pinMode(DO, INPUT);

  digitalWrite(WE, HIGH);
  digitalWrite(RAS, HIGH);
  digitalWrite(CAS, HIGH);

  digitalWrite(R_LED, HIGH);
  digitalWrite(G_LED, HIGH);

if (digitalRead(M_TYPE)) {
    /* jumper not set - 41256 */
    bus_size = BUS_SIZE;
    Serial.print("Selected: 256K x 1 ");
  } else {
    /* jumper set - 4164 */
    bus_size = BUS_SIZE - 1;
    Serial.print("Selected: 64K x 1 ");
  }
  Serial.flush();
  digitalWrite(R_LED, LOW);
  digitalWrite(G_LED, LOW);
  
  //noInterrupts();
  for (i = 0; i < (1 << BUS_SIZE); i++) {
    digitalWrite(RAS, LOW);
    digitalWrite(RAS, HIGH);
  }
  digitalWrite(R_LED, HIGH);
  digitalWrite(G_LED, HIGH);
}

void loop() {
  // read the state of the pushbutton value:
  buttonState = digitalRead(buttonPin);
  
  if ( (millis() - lastDebounceTime) > debounceDelay) {
      if (buttonState == LOW) {
        Serial.println("");
        interrupts(); Serial.println("Pass #1..."); Serial.flush(); noInterrupts(); fillx(0);
        interrupts(); Serial.println("Pass #2..."); Serial.flush(); noInterrupts(); fillx(1);
        interrupts(); Serial.println("Pass #3..."); Serial.flush(); noInterrupts(); fill(0);
        interrupts(); Serial.println("Pass #4..."); Serial.flush(); noInterrupts(); fill(1);
        ok();
        
        lastDebounceTime = millis(); //set the current time
      }
      else if (buttonState == HIGH) {
        lastDebounceTime = millis(); //set the current time
      }//close if/else
  
    }//close if(time buffer)
}//close void loop


Re: DRAMARDUINO - Dram tester with Arduino

Posted: Mon Feb 08, 2021 4:32 pm
by TA2KQ
Hello all,
Came across this forum and topic while searching for an easy solution with Arduino to test DRAM's. Seemed like what I need, so I built it. It's working and it can identify bad chips that I have. I am relatively new to Arduino and by no means a programmer, I could only make heads and tails of 60% of the code so far, I need to learn bit banging and the operators related to get it all, I know. But still something seems strange to me, if anyone can explain why, I will be grateful. There is a pin to select 4164 and 41256 chips that changes the bus size variable accordingly, so far so good, but if I put a 4164 and test it as 41256, it still passes OK, and strangely it also takes as long as a real 41256. Shouldn't it sort of "hit a wall" and return an error when the address incrementing loop goes over XA7 and come to a non-existent XA8 bit?
This may be a very stupid question but please bear with me and explain as plainly as possible why this happens?
Thanks!

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Mon Feb 08, 2021 4:49 pm
by mikeb
TA2KQ wrote: Mon Feb 08, 2021 4:32 pm if I put a 4164 and test it as 41256, it still passes OK, and strangely it also takes as long as a real 41256. Shouldn't it sort of "hit a wall" and return an error when the address incrementing loop goes over XA7 and come to a non-existent XA8 bit?
Hello!

I suspect what you're doing is testing the 4164 completely, four times.

The extra XA8 bit has nowhere to go when testing a 4164, so each row and column address would effectively ignore the upper bit, meaning the count would loop from 65535 back to 0 -- ignoring the upper bit of a binary count doubles the possible addresses.

Because the 8 bit addresses are being used for rows, then columns, you end up with a double count, twice -- i.e. four times.

A similiar thing happens if you read a 2764 EPROM as a 27128 (you end up with two identical sets of data, end to end, not: expected valid data followed by tumbleweeds!)

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Mon Feb 08, 2021 8:21 pm
by iss
Indeed! @mikeb's answer explains very good what happens. Here are 4164 and 41256:
4164-41256.png
As you can see in 4164 pin-1 is NC (Not Connected) internally, so for 4164 it really doesn't matter what logic level you put on it -
the test is repeated 4 times. Additionally from the 'schematics' you can see that the jumper doesn't have any 'electrical' meaning and is used only to 'tell' the software that it has to include the address line A8 in the testing cycle too and so testing time is 4 times longer (per every test). Of course it's possible also autodetection :).

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Tue Feb 09, 2021 5:19 pm
by mikeb
... further thought!

In an actual Oric, the memory test relies on this "missing address line" situation to distinguish between a 4164 (64k/48k Oric) and a 4116 (16k Oric) bank

With the quarter size DRAM chip (16K), now there is nowhere for A7 to go. So whether the row/col address bit 7 is high or low, you get the SAME location in memory based on bits 0..6

The RAM test writes to one location (#4500), reads back from a different one (#0500), and if it works, concludes it's only a 16K Oric (because the memory map wraps around 4 times from #0000-#3FFF, #4000-#7FFF, #8000-#BFFF, and #C000-#FFFF).
iss wrote: Mon Feb 08, 2021 8:21 pm Of course it's possible also autodetection :).
Possible, but caution applies -- if you "auto detect and test" a working 41256 with pin 1 snapped off, won't you get told it's a "working 4164"? :)

Re: DRAMARDUINO - Dram tester with Arduino

Posted: Thu Feb 11, 2021 11:28 am
by TA2KQ
mikeb wrote: Mon Feb 08, 2021 4:49 pm
TA2KQ wrote: Mon Feb 08, 2021 4:32 pm if I put a 4164 and test it as 41256, it still passes OK, and strangely it also takes as long as a real 41256. Shouldn't it sort of "hit a wall" and return an error when the address incrementing loop goes over XA7 and come to a non-existent XA8 bit?
I suspect what you're doing is testing the 4164 completely, four times.
Yes, I figured that out after I posted the question, but it is good to have a confirmation. :-) Thank you for taking the time!