DRAMARDUINO - Dram tester with Arduino

This is the right place to discuss on how to implement hardware vsync, adding a VIA or AY chipset, puting multiple roms, or how to design a new flash expansion card.
User avatar
iss
Wing Commander
Posts: 1637
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

DRAMARDUINO - Dram tester with Arduino

Post 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 3271 times
Last edited by iss on Thu Oct 29, 2020 7:35 pm, edited 2 times in total.
User avatar
Voyageur
2nd Star Corporal
Posts: 26
Joined: Thu Oct 18, 2018 8:25 am
Location: Sydney

Re: DRAMARDUINO - Dram tester with Arduino

Post 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 !
Oric Atmos : a new life !
User avatar
iss
Wing Commander
Posts: 1637
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: DRAMARDUINO - Dram tester with Arduino

Post 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.
witchy
1st Star Corporal
Posts: 13
Joined: Wed Jun 22, 2016 11:26 pm

Re: DRAMARDUINO - Dram tester with Arduino

Post 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
john
1st Star Corporal
Posts: 9
Joined: Mon Oct 05, 2020 8:11 am

Re: DRAMARDUINO - Dram tester with Arduino

Post 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);
User avatar
HigashiJun
Flying Officer
Posts: 205
Joined: Tue Dec 10, 2019 9:29 am
Location: Tokyo (Japan)

Re: DRAMARDUINO - Dram tester with Arduino

Post by HigashiJun »

Interesting...

I will give it a try on my DRAMARDUINO.

Thanks.
HigashiJun
User avatar
iss
Wing Commander
Posts: 1637
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: DRAMARDUINO - Dram tester with Arduino

Post 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!
Last edited by iss on Thu Oct 29, 2020 9:27 pm, edited 1 time in total.
User avatar
thekorex
Private
Posts: 1
Joined: Thu Oct 29, 2020 11:48 am
Location: Portugal
Contact:

Re: DRAMARDUINO - Dram tester with Arduino

Post 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.
User avatar
iss
Wing Commander
Posts: 1637
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: DRAMARDUINO - Dram tester with Arduino

Post 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!
shift838
Private
Posts: 1
Joined: Wed Dec 09, 2020 10:55 pm

Re: DRAMARDUINO - Dram tester with Arduino

Post 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

User avatar
TA2KQ
Private
Posts: 5
Joined: Sun Feb 07, 2021 6:51 pm

Re: DRAMARDUINO - Dram tester with Arduino

Post 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!
User avatar
mikeb
Flight Lieutenant
Posts: 282
Joined: Wed Sep 05, 2018 8:03 pm
Location: West Midlands, UK
Contact:

Re: DRAMARDUINO - Dram tester with Arduino

Post 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!)
User avatar
iss
Wing Commander
Posts: 1637
Joined: Sat Apr 03, 2010 5:43 pm
Location: Bulgaria
Contact:

Re: DRAMARDUINO - Dram tester with Arduino

Post 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 :).
User avatar
mikeb
Flight Lieutenant
Posts: 282
Joined: Wed Sep 05, 2018 8:03 pm
Location: West Midlands, UK
Contact:

Re: DRAMARDUINO - Dram tester with Arduino

Post 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"? :)
User avatar
TA2KQ
Private
Posts: 5
Joined: Sun Feb 07, 2021 6:51 pm

Re: DRAMARDUINO - Dram tester with Arduino

Post 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!
Post Reply