Trying to cycle through 4-BIT array

I wasn’t completely sure how to word the subject, so I’ll first elaborate on what it is I’m trying to do. I have several dozen 74LS189 IC’s. These are 64-BIT RAM chips that are organized as 16-word by 4-bit arrays. What I’m trying to do is to cycle through each of the 16 memory locations (4 BITS) so that I can test the 16 words (8 BITS).

If that isn’t completely clear, don’t worry. Here’s the simpler version of what I’m trying to do.

A for loop will count from 0 to 15 in order to iterate through the 16 memory locations. When count is 0, I am at memory location 0000. When count is 1, I am at memory location 0001. When count is 2, I am at memory location 0010, and so on until the count is 15, at which point I would be at memory location 1111.

When I am at a given memory location, I am doing a digitalWrite(PIN, [HIGH/LOW]) where HIGH/LOW depends on whether or not a given BIT is ON or OFF.

So for example, when count is 0 and I am at memory location 0000, the code needs to do this:

      digitalWrite(A0, LOW);
      digitalWrite(A1, LOW);
      digitalWrite(A2, LOW);
      digitalWrite(A3, LOW);
  • Where A0, A1, A2, and A3 have been previously defined for a particular PIN#.

Likewise, when I’m at say count 9, I am at memory location 1001, so the code needs to do this:

      digitalWrite(A0, HIGH);
      digitalWrite(A1, LOW);
      digitalWrite(A2, LOW);
      digitalWrite(A3, HIGH);

So my question is…
How can I use the value of count to determine whether or not a given PIN should be HIGH or LOW? I know that (count % 2) will work for the least significant bit, 20. So when count is 0, (count % 2) will be 0 which is correct for the 20 bit. And when count is 1, (count % 2) will be 1 which is again correct for the 20 bit. And (count % 2) works for the 20 bit no matter how high count becomes.

So with that in mind, I can use this code instead:

      digitalWrite(A0, (count % 2);
      digitalWrite(A1, LOW);
      digitalWrite(A2, LOW);
      digitalWrite(A3, HIGH);

But I can’t figure out what I need to do for bits 21, 22, and 23.

So right now, I have a huge list of if then else statements, but I know it can be condensed to 4 lines if I can figure out how to write a formula for the various bits.

  int count;
  int data_count;
  
  for (count = 0 ; count <= 15 ; count++ ) {

    if (count == 0) {
      digitalWrite(A0, LOW);
      digitalWrite(A1, LOW);
      digitalWrite(A2, LOW);
      digitalWrite(A3, LOW);
    } else if (count == 1) {
      digitalWrite(A0, HIGH);
      digitalWrite(A1, LOW);
      digitalWrite(A2, LOW);
      digitalWrite(A3, LOW);     
    } else if (count == 2) {
      digitalWrite(A0, LOW);
      digitalWrite(A1, HIGH);
      digitalWrite(A2, LOW);
      digitalWrite(A3, LOW);         
    } else if (count == 3) {
      digitalWrite(A0, HIGH);
      digitalWrite(A1, HIGH);
      digitalWrite(A2, LOW);
      digitalWrite(A3, LOW);         
    } else if (count == 4) {
      digitalWrite(A0, LOW);
      digitalWrite(A1, LOW);
      digitalWrite(A2, HIGH);
      digitalWrite(A3, LOW);         
    } else if (count == 5) {
      digitalWrite(A0, HIGH);
      digitalWrite(A1, LOW);
      digitalWrite(A2, HIGH);
      digitalWrite(A3, LOW);         
    } else if (count == 6) {
      digitalWrite(A0, LOW);
      digitalWrite(A1, HIGH);
      digitalWrite(A2, HIGH);
      digitalWrite(A3, LOW);         
    } else if (count == 7) {
      digitalWrite(A0, HIGH);
      digitalWrite(A1, HIGH);
      digitalWrite(A2, HIGH);
      digitalWrite(A3, LOW);         
    } else if (count == 8) {
      digitalWrite(A0, LOW);
      digitalWrite(A1, LOW);
      digitalWrite(A2, LOW);
      digitalWrite(A3, HIGH);  
    } else if (count == 9) {
      digitalWrite(A0, HIGH);
      digitalWrite(A1, LOW);
      digitalWrite(A2, LOW);
      digitalWrite(A3, HIGH);         
    } else if (count == 10) {
      digitalWrite(A0, LOW);
      digitalWrite(A1, HIGH);
      digitalWrite(A2, LOW);
      digitalWrite(A3, HIGH);         
    } else if (count == 11) {
      digitalWrite(A0, HIGH);
      digitalWrite(A1, HIGH);
      digitalWrite(A2, LOW);
      digitalWrite(A3, HIGH);  
    } else if (count == 12) {
      digitalWrite(A0, LOW);
      digitalWrite(A1, LOW);
      digitalWrite(A2, HIGH);
      digitalWrite(A3, HIGH);
    } else if (count == 13) {
      digitalWrite(A0, HIGH);
      digitalWrite(A1, LOW);
      digitalWrite(A2, HIGH);
      digitalWrite(A3, HIGH);  
    } else if (count == 14) {
      digitalWrite(A0, LOW);
      digitalWrite(A1, HIGH);
      digitalWrite(A2, HIGH);
      digitalWrite(A3, HIGH);   
    } else if (count == 15) {
      digitalWrite(A0, HIGH);
      digitalWrite(A1, HIGH);
      digitalWrite(A2, HIGH);
      digitalWrite(A3, HIGH);
    }

Hopefully my explanation was clear, and I thank you for taking the time to read my post.

Have you looked at bit operators and shifting? At a glance it sounds like that's the answer you're trying to find.

Bitwise and, & https://www.arduino.cc/en/Reference/BitwiseAnd should do it.

DigitalWrite (A0,count & 1);
DigitalWrite (A1,count & 2);
DigitalWrite (A2,count & 4);
DigitalWrite (A3,count & 8);

You can use logical bit operations; you mask the address with 1, 2, 4 and 8 and compare the result of the masking with 1, 2, 4 and 8 respectively

void setup()
{
  Serial.begin(250000);
  for (int address = 0; address < 16; address++)
  {
    Serial.print("address = "); Serial.println(address);
    Serial.print((address & 0x08) == 0x08);
    Serial.print((address & 0x04) == 0x04);
    Serial.print((address & 0x02) == 0x02);
    Serial.println((address & 0x01) == 0x01);

    digitalwrite(addressPin0, (address & 0x01) == 0x01);
    digitalwrite(addressPin1, (address & 0x02) == 0x02);
    digitalwrite(addressPinPin2, (address & 0x04) == 0x04);
    digitalwrite(addressPin3, (address & 0x08) == 0x08);
  }
}

If your data pins are declared in an array, you can also use a for loop; I’ll leave that up to you to figure out.

Another way might be use of direct port manipulation. This assumes that the pins are all on one port.

PS
@Gabriel_swe, why do you have a smiley :smiley:

Thanks for the lightning fast replies! I'm going to dive into this right now and see if I can figure it out!

@sterretje it wasn't neither stealth change by the forum nor complete code. Pretty obvious it should be 8 and ).

My suggestion result in 1, 2, 4 and 8. I expect digitalWrite(A3,8) to write the pin high.
As I understand it, all non zero numbers is true/high. To be safe, sterretjes has a suggestion. Before I saw it, I was thinking of
Digitalwrite(A2,(count&4)>1). It will always return true or false if compiler change.
(I hope that ^^^^^ will be untouched by the forum) :slight_smile:

:smiley: I know

You sometimes have to be careful with the forum software; hence the use of code tags is advised :wink: Alternative is to use [nobbc]8)[/nobbc] which will result in 8)

blixel:
I wasn’t completely sure how to word the subject, so I’ll first elaborate on what it is I’m trying to do. I have several dozen 74LS189 IC’s. These are 64-BIT RAM chips that are organized as 16-word by 4-bit arrays. What I’m trying to do is to cycle through each of the 16 memory locations (4 BITS) so that I can test the 16 words (8 BITS).

If that isn’t completely clear, don’t worry. Here’s the simpler version of what I’m trying to do.
Hopefully my explanation was clear, and I thank you for taking the time to read my post.

You need something like this:

const int port[] = { // the 4 ports that will generate your address
    A0, A1, A2, A3
};

void makeAddress (void)
{
    uint8_t siz = (sizeof (port) / sizeof (*port)); // how many entries in array
    uint8_t addr; // address 0...15
    uint8_t bit; // bit number 0 thru 3

    for (addr = 0; addr < 16; addr++) {
        for (bit = 0; bit < siz; bit++) {
            // write high or low depending on (address AND bitvalue)
            digitalWrite (port[bit], (addr & (1 << bit)) ? HIGH : LOW);
        }
    }
    // address is setup, pulse CS with WE high and read SRAM data bus
}

Hope this points you in the right direction.

(edit to add): To test this memory, you will need to WRITE to it first, then (hopefully) read back the same thing.

Look up “marching bit ram test” for a way to actually test SRAM (although bit-banging the address and data bus will be SO slow that most any test will probably pass unless the chip is outright dead).

Thanks again for the help everyone. After a couple hours of working on this, based on the feedback I got earlier, the code below is what I came up with.

What I have seems to work perfectly, but I’m sure there is room for optimization. In particular, when I’m reading back the data on the IC, it definitely feels redundant.

Anyway … I have 5 of these chips that I know are defective in various ways, and another 40+ that I believe are good. This bit of code allows me to swap them out quickly and run through the test. All I’m doing is testing to see if each bit can go HIGH and LOW. If they can do that, then I assume they can take any possible value, so there’s no need to test all 256 possibilities for each memory location.

I welcome any feedback as to the method I’m using. If it seems invalid, or incomplete, let me know. But it seems correct to me.

Code improvements are also welcome, though I need not delve too deeply into perfecting this as it’s kind of a one time thing for testing all these chips.

Good Chip

If a bit will not go HIGH or will not go LOW, then it’s like a dead pixel basically. The memory location is no good, so the chip is no good.

Bad Chip with 1 stuck BIT.

Bad Chip that is FUBAR (this picture is cut down to just the last bit of output from the serial console)

#include <avr/sleep.h>

// Arduino PIN -> 74LS189 PIN
//           2 -> A0 (PIN  1 on 74LS189)
//           3 -> A1 (PIN 15 on 74LS189)
//           4 -> A2 (PIN 14 on 74LS189)
//           5 -> A3 (PIN 13 on 74LS189)

#define memoryIC_A0 2
#define memoryIC_A1 3
#define memoryIC_A2 4
#define memoryIC_A3 5

// Arduino PIN -> 74LS189 PIN
//           6 -> D1 (PIN  4 on 74LS189)
//           7 -> D2 (PIN  6 on 74LS189)
//           8 -> D3 (PIN 10 on 74LS189)
//           9 -> D4 (PIN 12 on 74LS189)

#define memoryIC_D1 6
#define memoryIC_D2 7
#define memoryIC_D3 8
#define memoryIC_D4 9

// Arduino PIN -> 74LS189 PIN
//          10 -> O1 (PIN  5 on 74LS189)
//          11 -> O2 (PIN  7 on 74LS189)
//          12 -> O3 (PIN  9 on 74LS189)
//          13 -> O4 (PIN 11 on 74LS189)

#define memoryIC_O1 10
#define memoryIC_O2 11
#define memoryIC_O3 12
#define memoryIC_O4 13

// Write Enable PIN
// Arduino PIN -> 74LS189 PIN
//          14 -> WE (PIN  3 on 74LS189)
#define memoryIC_WE 14

// Serial Console Speed
#define conSpeed 250000

void setup() {

  // ADDRESS LINES on the Arduino are OUTPUT
  // because we need to INPUT on the 74LS189
  pinMode(memoryIC_A0, OUTPUT);
  pinMode(memoryIC_A1, OUTPUT);
  pinMode(memoryIC_A2, OUTPUT);
  pinMode(memoryIC_A3, OUTPUT);

  // DATA LINES on the Arduino are OUTPUT
  // because we need to INPUT on the 74LS189
  pinMode(memoryIC_D1, OUTPUT);
  pinMode(memoryIC_D2, OUTPUT);
  pinMode(memoryIC_D3, OUTPUT);
  pinMode(memoryIC_D4, OUTPUT);
  
  // OUTPUT LINES on the Arduino are INPUT
  // because we need to OUTPUT on the 74LS189
  pinMode(memoryIC_O1, INPUT);
  pinMode(memoryIC_O2, INPUT);
  pinMode(memoryIC_O3, INPUT);
  pinMode(memoryIC_O4, INPUT);

  // WRITE ENABLE PIN
  pinMode(memoryIC_WE, OUTPUT);

  // Enable Serial Console
  Serial.begin(conSpeed);
}

void loop() {
  
  int count      = 0;
  int delayTime  = 50;
  int delayWrite = 1;
  int errorCount = 0;

  Serial.print("------------------\n");
  Serial.print("Beginning New Test\n");
  Serial.print("------------------\n");
  

  // Cycle through each memory location.
  // Turn all BITS ON, then check the OUTPUT to make sure all BITS are ON
  // Remember, the OUTPUT is inverse logic, so when all BITS are ON,
  // we should actually be reading 0's. So if we read a 1 instead of a 0,
  // there is an error.
  //
  // After that...
  //
  // Turn all BITS OFF, then check the OUTPUT to make sure all BITS are OFF
  // Noting once again the inverse logic. So we should be reading 1's when
  // the BITS are OFF.
    
  for (count = 0 ; count <= 15 ; count++ ) {
    Serial.print("Count: ");
    Serial.print(count);
    Serial.print("\n");

    // Use BIT LOGIC operations to cycle through
    // the various memory address locations 
    digitalWrite(memoryIC_A0, (count & 0x01) == 0x01);
    digitalWrite(memoryIC_A1, (count & 0x02) == 0x02);
    digitalWrite(memoryIC_A2, (count & 0x04) == 0x04);
    digitalWrite(memoryIC_A3, (count & 0x08) == 0x08);

    // Turn all bits ON
    digitalWrite(memoryIC_D1, HIGH);
    digitalWrite(memoryIC_D2, HIGH);
    digitalWrite(memoryIC_D3, HIGH);
    digitalWrite(memoryIC_D4, HIGH);

    // Enable WRITE
    digitalWrite(memoryIC_WE, LOW);

    // Wait the defined amount of time
    delay(delayWrite);

    // Disable WRITE
    digitalWrite(memoryIC_WE, HIGH);

    // Wait the defined amount of time
    delay(delayWrite);


    // Read back the value from the IC
   
    if (digitalRead(memoryIC_O1) == 1) {
      errorCount++;
      Serial.print("\nERROR DETECTED DURING ON CYCLE\n");
      Serial.print("Memory Location: ");
      Serial.print(count);
      Serial.print("\tBIT: 0");
      Serial.print("\n\n\n");
      delay(delayTime);
    }
    if (digitalRead(memoryIC_O2) == 1) {
      errorCount++;
      Serial.print("\nERROR DETECTED DURING ON CYCLE\n");
      Serial.print("Memory Location: ");
      Serial.print(count);
      Serial.print("\tBIT: 1");
      Serial.print("\n\n\n");
      delay(delayTime);
    }
    if (digitalRead(memoryIC_O3) == 1) {
      errorCount++;
      Serial.print("\nERROR DETECTED DURING ON CYCLE\n");
      Serial.print("Memory Location: ");
      Serial.print(count);
      Serial.print("\tBIT: 2");
      Serial.print("\n\n\n");
      delay(delayTime);
    }
    if (digitalRead(memoryIC_O4) == 1) {
      errorCount++;
      Serial.print("\nERROR DETECTED DURING ON CYCLE\n");
      Serial.print("Memory Location: ");
      Serial.print(count);
      Serial.print("\tBIT: 3");
      Serial.print("\n\n\n");
      delay(delayTime);
    }    
    
    // Turn all bits OFF
    digitalWrite(memoryIC_D1, LOW);
    digitalWrite(memoryIC_D2, LOW);
    digitalWrite(memoryIC_D3, LOW);
    digitalWrite(memoryIC_D4, LOW);

    // Enable WRITE
    digitalWrite(memoryIC_WE, LOW);

    // Wait the defined amount of time
    delay(delayWrite);

    // Disable WRITE
    digitalWrite(memoryIC_WE, HIGH);

    // Wait the defined amount of time
    delay(delayWrite);

    
    // Read back the value from the IC
    
    if (digitalRead(memoryIC_O1) == 0) {
      errorCount++;
      Serial.print("\nERROR DETECTED DURING OFF CYCLE\n");
      Serial.print("Memory Location: ");
      Serial.print(count);
      Serial.print("\tBIT: 0");
      Serial.print("\n\n\n");
      delay(delayTime);
    }
    if (digitalRead(memoryIC_O2) == 0) {
      errorCount++;
      Serial.print("\nERROR DETECTED DURING OFF CYCLE\n");
      Serial.print("Memory Location: ");
      Serial.print(count);
      Serial.print("\tBIT: 1");
      Serial.print("\n\n\n");
      delay(delayTime);
    }
    if (digitalRead(memoryIC_O3) == 0) {
      errorCount++;
      Serial.print("\nERROR DETECTED DURING OFF CYCLE\n");
      Serial.print("Memory Location: ");
      Serial.print(count);
      Serial.print("\tBIT: 2");
      Serial.print("\n\n\n");
      delay(delayTime);
    }
    if (digitalRead(memoryIC_O4) == 0) {
      errorCount++;
      Serial.print("\nERROR DETECTED DURING OFF CYCLE\n");
      Serial.print("Memory Location: ");
      Serial.print(count);
      Serial.print("\tBIT: 3");
      Serial.print("\n\n\n");
      delay(delayTime);
    }  
  } // end of for loop

  
  
  // Now we just want to output some final information to the user
  Serial.print("\n");
  
  // Error report
  if (errorCount > 0) {
    Serial.print("!!! ");
    Serial.print(errorCount);
    if (errorCount == 1) {
      Serial.print(" error detected !!!\n");
    } else {
      Serial.print(" errors detected !!!\n");
    }
  } else {
    Serial.print("No errors detected.\n");
  }
  
  // All done.
  Serial.print("\nTest is done.\n\n");
  delay(delayTime);
  
  // No need to rerun the test in an infinite loop, so just
  // put the Arduino to sleep when the test is done.
  cli();
  sleep_enable();
  sleep_cpu();
} // end of program

Nice work; there is however a lot more to memory testing then just a write and a read back; you for example never check if to physically adjacent memory locations (that is not necessarily location 0 and 1) are affecting each other. You can look at e.g. the detailed descriptions that are used by memtest86.