]> git.the-white-hart.net Git - atmega/chip_tester.git/commitdiff
Initial commit main
authorrs <>
Fri, 12 Sep 2025 22:51:48 +0000 (17:51 -0500)
committerrs <>
Fri, 12 Sep 2025 22:51:48 +0000 (17:51 -0500)
ChipTester.ino [new file with mode: 0644]

diff --git a/ChipTester.ino b/ChipTester.ino
new file mode 100644 (file)
index 0000000..1698e22
--- /dev/null
@@ -0,0 +1,561 @@
+#include "Adafruit_LEDBackpack.h"
+
+#define _countof(x) (sizeof(x) / sizeof (x[0]))
+
+// Using Adafruit's four-digit 7-segment display backpack
+Adafruit_7segment segs = Adafruit_7segment();
+
+
+enum test_op {END, FORCE, ASSERT, DEBUG};
+
+
+struct test_command
+{
+  enum test_op command;
+  const char *right;
+  const char *left;
+};
+
+
+struct chip_entry
+{
+  int part_number;
+  struct test_command *sequence;
+};
+
+
+// -----------------------------------------------------------------------------
+// Test sequences
+
+
+const struct test_command test_74_04[] = {
+  // Test case: ~0 == 1
+  {FORCE,  "10x0x0x", "0x0x0x0"},
+  {ASSERT, "xx1x1x1", "x1x1x1x"},
+
+  // Test case: ~1 == 0
+  {FORCE,  "11x1x1x", "1x1x1x0"},
+  {ASSERT, "xx0x0x0", "x0x0x0x"},
+
+  {END, "", ""},
+};
+
+
+const struct test_command test_74_37[] = {
+  // Test case: 0 nand 0 == 1
+  {FORCE,  "100x00x", "00x00x0"},
+  {ASSERT, "xxx1xx1", "xx1xx1x"},
+
+  // Test case: 0 nand 1 == 1
+  {FORCE,  "101x01x", "01x01x0"},
+  {ASSERT, "xxx1xx1", "xx1xx1x"},
+
+  // Test case: 1 nand 0 == 1
+  {FORCE,  "110x10x", "10x10x0"},
+  {ASSERT, "xxx1xx1", "xx1xx1x"},
+
+  // Test case: 1 nand 1 == 0
+  {FORCE,  "111x11x", "11x11x0"},
+  {ASSERT, "xxx0xx0", "xx0xx0x"},
+
+  {END, "", ""},
+};
+
+
+const struct test_command test_74_109[] = {
+  // Async preset
+  {FORCE,  "110100xx", "10100xx0"}, // Assert preset
+  {ASSERT, "xxxxxx10", "xxxxx10x"},
+  {FORCE,  "110101xx", "10101xx0"}, // Deassert preset
+
+  // Async clear
+  {FORCE,  "100101xx", "00101xx0"}, // Assert clear
+  {ASSERT, "xxxxxx01", "xxxxx01x"},
+  {FORCE,  "110101xx", "10101xx0"}, // Deassert clear
+
+  // J sets on clock edge
+  {FORCE,  "111101xx", "11101xx0"},  // Assert J
+  {FORCE,  "111111xx", "11111xx0"},  // Raise clock
+  {ASSERT, "xxxxxx10", "xxxxx10x"},
+  {FORCE,  "111101xx", "11101xx0"},  // Lower clock
+
+  // No input has no change on clock edge
+  {FORCE,  "110101xx", "10101xx0"},  // Deassert J and K
+  {FORCE,  "110111xx", "10111xx0"},  // Raise clock
+  {ASSERT, "xxxxxx10", "xxxxx10x"},
+  {FORCE,  "110101xx", "10101xx0"},  // Lower clock
+
+  // K resets on clock edge
+  {FORCE,  "110001xx", "10001xx0"},  // Assert K
+  {FORCE,  "110011xx", "10011xx0"},  // Raise clock
+  {ASSERT, "xxxxxx01", "xxxxx01x"},
+  {FORCE,  "110001xx", "10001xx0"},  // Lower clock
+
+  // No input has no change on clock edge
+  {FORCE,  "110101xx", "10101xx0"},  // Deassert J and K
+  {FORCE,  "110111xx", "10111xx0"},  // Raise clock
+  {ASSERT, "xxxxxx01", "xxxxx01x"},
+  {FORCE,  "110101xx", "10101xx0"},  // Lower clock
+
+  // JK toggles on clock edge
+  {FORCE,  "111001xx", "11001xx0"},  // Assert J and K
+  {FORCE,  "111011xx", "11011xx0"},  // Raise clock
+  {ASSERT, "xxxxxx10", "xxxxx10x"},
+  {FORCE,  "111001xx", "11001xx0"},  // Lower clock
+
+  // JK toggles on clock edge
+  {FORCE,  "111001xx", "11001xx0"},  // Assert J and K
+  {FORCE,  "111011xx", "11011xx0"},  // Raise clock
+  {ASSERT, "xxxxxx01", "xxxxx01x"},
+  {FORCE,  "111001xx", "11001xx0"},  // Lower clock
+
+  {END, "", ""},
+};
+
+
+const struct test_command test_74_534[] = {
+  {FORCE,  "1x00xx00x0", "0x00xx00x0"},  // Input zeroes
+  {FORCE,  "1x00xx00x1", "0x00xx00x0"},  // Clock rise
+  {FORCE,  "1x00xx00x0", "0x00xx00x0"},  // Clock fall
+  {ASSERT, "x1xx11xx1x", "x1xx11xx1x"},  // Check for ones (inverted inputs) at outputs
+  {FORCE,  "1x11xx11x0", "0x11xx11x0"},  // Input ones
+  {ASSERT, "x1xx11xx1x", "x1xx11xx1x"},  // Check for ones (previous output) at outputs
+  {FORCE,  "1x11xx11x1", "0x11xx11x0"},  // Clock rise
+  {FORCE,  "1x11xx11x0", "0x11xx11x0"},  // Clock fall
+  {ASSERT, "x0xx00xx0x", "x0xx00xx0x"},  // Check for zeroes (inverted inputs) at outputs
+  {FORCE,  "1x10xx10x0", "0x01xx01x0"},  // Input mix of ones and zeroes
+  {FORCE,  "1x10xx10x1", "0x01xx01x0"},  // Clock rise
+  {FORCE,  "1x10xx10x0", "0x01xx01x0"},  // Clock fall
+  {ASSERT, "x0xx10xx1x", "x1xx01xx0x"},  // Check for inverted inputs at outputs
+  {FORCE,  "1x10xx10x0", "1x01xx01x0"},  // Disable output
+  {ASSERT, "x1xx11xx1x", "x1xx11xx1x"},  // Outputs should float, pulled up
+  {FORCE,  "1x10xx10x0", "0x01xx01x0"},  // Enable output
+  {ASSERT, "x0xx10xx1x", "x1xx01xx0x"},  // Values should still be present
+
+  {END, "", ""},
+};
+
+
+// -----------------------------------------------------------------------------
+// Mapping part numbers to test sequences
+
+
+const struct chip_entry tests[] = {
+  {4,    test_74_04},
+  {37,   test_74_37},
+  {109,  test_74_109},
+  {534,  test_74_534},
+};
+
+
+// -----------------------------------------------------------------------------
+
+
+void force_test_vector(const char *left, const char *right)
+{
+  // Convert the string masks to bit masks
+  uint32_t set_high = 0, outputs = 0;
+
+  for (int i = 0; right[i] != '\0'; i++)
+  {
+    if (right[i] == '1')
+    {
+      set_high |= 1 << (19-i);
+      outputs  |= 1 << (19-i);
+    }
+    else if (right[i] == '0')
+    {
+      outputs  |= 1 << (19-i);
+    }
+    else
+    {
+      // Pin is an input, set bit in set_high to enable pull-up
+      set_high |= 1 << (19-i);
+    }
+  }
+
+  for (int i = 0; left[i] != '\0'; i++)
+  {
+    if (left[i] == '1')
+    {
+      set_high |= 1ul << i;
+      outputs  |= 1ul << i;
+    }
+    else if (left[i] == '0')
+    {
+      outputs  |= 1ul << i;
+    }
+    else
+    {
+      // Pin is an input, set bit in set_high to enable pull-up
+      set_high |= 1ul << i;
+    }
+  }
+
+  force_bit_vector(set_high, outputs);
+}
+
+
+void force_bit_vector(uint32_t set_high, uint32_t outputs)
+{
+  uint8_t port_b = 0, port_c = 0, port_d = 0;
+  uint8_t ddr_b = 0,  ddr_c = 0,  ddr_d = 0;
+
+  // Map bits from test vector to GPIO register bits
+  if (set_high & 0x80000) port_d |= 0x80;
+  if (set_high & 0x40000) port_d |= 0x40;
+  if (set_high & 0x20000) port_d |= 0x20;
+  if (set_high & 0x10000) port_d |= 0x10;
+  if (set_high & 0x08000) port_c |= 0x08;
+  if (set_high & 0x04000) port_c |= 0x04;
+  if (set_high & 0x02000) port_b |= 0x80;
+  if (set_high & 0x01000) port_b |= 0x40;
+  if (set_high & 0x00800) port_b |= 0x20;
+  if (set_high & 0x00400) port_b |= 0x10;
+  if (set_high & 0x00200) port_d |= 0x01;
+  if (set_high & 0x00100) port_d |= 0x02;
+  if (set_high & 0x00080) port_d |= 0x04;
+  if (set_high & 0x00040) port_d |= 0x08;
+  if (set_high & 0x00020) port_c |= 0x01;
+  if (set_high & 0x00010) port_c |= 0x02;
+  if (set_high & 0x00008) port_b |= 0x01;
+  if (set_high & 0x00004) port_b |= 0x02;
+  if (set_high & 0x00002) port_b |= 0x04;
+  if (set_high & 0x00001) port_b |= 0x08;
+
+  if (outputs & 0x80000) ddr_d |= 0x80;
+  if (outputs & 0x40000) ddr_d |= 0x40;
+  if (outputs & 0x20000) ddr_d |= 0x20;
+  if (outputs & 0x10000) ddr_d |= 0x10;
+  if (outputs & 0x08000) ddr_c |= 0x08;
+  if (outputs & 0x04000) ddr_c |= 0x04;
+  if (outputs & 0x02000) ddr_b |= 0x80;
+  if (outputs & 0x01000) ddr_b |= 0x40;
+  if (outputs & 0x00800) ddr_b |= 0x20;
+  if (outputs & 0x00400) ddr_b |= 0x10;
+  if (outputs & 0x00200) ddr_d |= 0x01;
+  if (outputs & 0x00100) ddr_d |= 0x02;
+  if (outputs & 0x00080) ddr_d |= 0x04;
+  if (outputs & 0x00040) ddr_d |= 0x08;
+  if (outputs & 0x00020) ddr_c |= 0x01;
+  if (outputs & 0x00010) ddr_c |= 0x02;
+  if (outputs & 0x00008) ddr_b |= 0x01;
+  if (outputs & 0x00004) ddr_b |= 0x02;
+  if (outputs & 0x00002) ddr_b |= 0x04;
+  if (outputs & 0x00001) ddr_b |= 0x08;
+
+  // Apply all changes as rapidly as possible, port D first because it has power and ground pins
+  PORTD = port_d;
+  PORTC = port_c;
+  PORTB = port_b;
+  DDRD = ddr_d;
+  DDRC = ddr_c;
+  DDRB = ddr_b;
+
+  delay(5);
+}
+
+
+bool assert_values(const char *left, const char *right)
+{
+  // Convert the string masks to bit masks
+  uint32_t check_high = 0, check_low = 0;
+
+  for (int i = 0; right[i] != '\0'; i++)
+  {
+    if (right[i] == '1')
+    {
+      check_high |= 1ul << (19-i);
+    }
+    else if (right[i] == '0')
+    {
+      check_low |= 1ul << (19-i);
+    }
+  }
+
+  for (int i = 0; left[i] != '\0'; i++)
+  {
+    if (left[i] == '1')
+    {
+      check_high |= 1ul << i;
+    }
+    else if (left[i] == '0')
+    {
+      check_low |= 1ul << i;
+    }
+  }
+
+  // Read input pins
+  uint8_t pin_b = PINB;
+  uint8_t pin_c = PINC;
+  uint8_t pin_d = PIND;
+
+  // Map GPIO register bits to test vector bits
+  uint32_t vector = 0;
+
+  if (pin_d & 0x80) vector |= 0x80000;
+  if (pin_d & 0x40) vector |= 0x40000;
+  if (pin_d & 0x20) vector |= 0x20000;
+  if (pin_d & 0x10) vector |= 0x10000;
+  if (pin_c & 0x08) vector |= 0x08000;
+  if (pin_c & 0x04) vector |= 0x04000;
+  if (pin_b & 0x80) vector |= 0x02000;
+  if (pin_b & 0x40) vector |= 0x01000;
+  if (pin_b & 0x20) vector |= 0x00800;
+  if (pin_b & 0x10) vector |= 0x00400;
+  if (pin_d & 0x01) vector |= 0x00200;
+  if (pin_d & 0x02) vector |= 0x00100;
+  if (pin_d & 0x04) vector |= 0x00080;
+  if (pin_d & 0x08) vector |= 0x00040;
+  if (pin_c & 0x01) vector |= 0x00020;
+  if (pin_c & 0x02) vector |= 0x00010;
+  if (pin_b & 0x01) vector |= 0x00008;
+  if (pin_b & 0x02) vector |= 0x00004;
+  if (pin_b & 0x04) vector |= 0x00002;
+  if (pin_b & 0x08) vector |= 0x00001;
+
+  // Check assertions
+  if ((vector & check_high) != check_high) return false;
+  if ((~vector & check_low) != check_low)  return false;
+
+  return true;
+}
+
+
+void debug()
+{
+  uint8_t port_b, pin_b, ddr_b;
+  uint8_t port_c, pin_c, ddr_c;
+  uint8_t port_d, pin_d, ddr_d;
+
+  port_b = PORTB;
+  pin_b = PINB;
+  ddr_b = DDRB;
+
+  port_c = PORTC;
+  pin_c = PINC;
+  ddr_c = DDRC;
+
+  port_d = PORTD;
+  pin_d = PIND;
+  ddr_d = DDRD;
+
+  char hex[] = "0123456789ABCdEF";
+
+  segs.clear();
+  segs.writeDigitAscii(0, 'B');
+  segs.writeDigitAscii(1, 'O');
+  segs.writeColon();
+  segs.writeDigitAscii(3, hex[(port_b >> 4) & 0xf]);
+  segs.writeDigitAscii(4, hex[(port_b >> 0) & 0xf]);
+  segs.writeDisplay();
+  delay(1000);
+
+  segs.clear();
+  segs.writeDigitAscii(0, 'B');
+  segs.writeDigitAscii(1, 'I');
+  segs.writeColon();
+  segs.writeDigitAscii(3, hex[(pin_b >> 4) & 0xf]);
+  segs.writeDigitAscii(4, hex[(pin_b >> 0) & 0xf]);
+  segs.writeDisplay();
+  delay(1000);
+
+  segs.clear();
+  segs.writeDigitAscii(0, 'B');
+  segs.writeDigitAscii(1, 'D');
+  segs.writeColon();
+  segs.writeDigitAscii(3, hex[(ddr_b >> 4) & 0xf]);
+  segs.writeDigitAscii(4, hex[(ddr_b >> 0) & 0xf]);
+  segs.writeDisplay();
+  delay(1000);
+
+
+  segs.clear();
+  segs.writeDigitAscii(0, 'C');
+  segs.writeDigitAscii(1, 'O');
+  segs.writeColon();
+  segs.writeDigitAscii(3, hex[(port_c >> 4) & 0xf]);
+  segs.writeDigitAscii(4, hex[(port_c >> 0) & 0xf]);
+  segs.writeDisplay();
+  delay(1000);
+
+  segs.clear();
+  segs.writeDigitAscii(0, 'C');
+  segs.writeDigitAscii(1, 'I');
+  segs.writeColon();
+  segs.writeDigitAscii(3, hex[(pin_c >> 4) & 0xf]);
+  segs.writeDigitAscii(4, hex[(pin_c >> 0) & 0xf]);
+  segs.writeDisplay();
+  delay(1000);
+
+  segs.clear();
+  segs.writeDigitAscii(0, 'C');
+  segs.writeDigitAscii(1, 'D');
+  segs.writeColon();
+  segs.writeDigitAscii(3, hex[(ddr_c >> 4) & 0xf]);
+  segs.writeDigitAscii(4, hex[(ddr_c >> 0) & 0xf]);
+  segs.writeDisplay();
+  delay(1000);
+
+
+  segs.clear();
+  segs.writeDigitAscii(0, 'D');
+  segs.writeDigitAscii(1, 'O');
+  segs.writeColon();
+  segs.writeDigitAscii(3, hex[(port_d >> 4) & 0xf]);
+  segs.writeDigitAscii(4, hex[(port_d >> 0) & 0xf]);
+  segs.writeDisplay();
+  delay(1000);
+
+  segs.clear();
+  segs.writeDigitAscii(0, 'D');
+  segs.writeDigitAscii(1, 'I');
+  segs.writeColon();
+  segs.writeDigitAscii(3, hex[(pin_d >> 4) & 0xf]);
+  segs.writeDigitAscii(4, hex[(pin_d >> 0) & 0xf]);
+  segs.writeDisplay();
+  delay(1000);
+
+  segs.clear();
+  segs.writeDigitAscii(0, 'D');
+  segs.writeDigitAscii(1, 'D');
+  segs.writeColon();
+  segs.writeDigitAscii(3, hex[(ddr_d >> 4) & 0xf]);
+  segs.writeDigitAscii(4, hex[(ddr_d >> 0) & 0xf]);
+  segs.writeDisplay();
+  delay(1000);
+}
+
+
+void make_safe()
+{
+  // Disconnect all pins by turning them into inputs
+  DDRD = 0x00;
+  DDRC = 0x00;
+  DDRB = 0x00;
+
+  // Assign all outputs to zero to prevent enabling pullups
+  PORTD = 0x00;
+  PORTC = 0x00;
+  PORTB = 0x00;
+}
+
+
+void run_test(int n) {
+  for (int i = 0; i < _countof(tests); i++)
+  {
+    if (tests[i].part_number == n)
+    {
+      test_command *sequence = tests[i].sequence;
+
+      for (int j = 0; sequence[j].command != END; j++)
+      {
+        if (sequence[j].command == FORCE)
+        {
+          force_test_vector(sequence[j].left, sequence[j].right);
+        }
+        if (sequence[j].command == ASSERT)
+        {
+          if (!assert_values(sequence[j].left, sequence[j].right))
+          {
+            make_safe();
+            segs.clear();
+            segs.println("FAIL");
+            segs.writeDisplay();
+            delay(1000);
+            return;
+          }
+        }
+        if (sequence[j].command == DEBUG)
+        {
+          debug();
+        }
+      }
+      make_safe();
+      segs.clear();
+      segs.println("PASS");
+      segs.writeDisplay();
+      delay(1000);
+      return;
+    }
+  }
+
+  // Test not found
+  segs.clear();
+  segs.println(" NO ");
+  segs.writeDisplay();
+  delay(500);
+  segs.clear();
+  segs.println("TEST");
+  segs.writeDisplay();
+  delay(500);
+}
+
+
+int n0, n1, n2, n3;
+int last_key, key;
+uint32_t test_vec;
+
+
+void setup() {
+  make_safe();
+  segs.begin(0x70);
+  n0 = n1 = n2 = n3 = 0;
+  last_key = key = 0;
+  test_vec = 1;
+}
+
+
+void loop() {
+  int key_pin_value = analogRead(A6);
+  last_key = key;
+  if (key_pin_value < 858 + 20 && key_pin_value > 858 - 20) {
+    key = 6;
+  } else if (key_pin_value < 686 + 20 && key_pin_value > 686 - 20) {
+    key = 5;
+  } else if (key_pin_value < 521 + 20 && key_pin_value > 521 - 20) {
+    key = 4;
+  } else if (key_pin_value < 352 + 20 && key_pin_value > 352 - 20) {
+    key = 3;
+  } else if (key_pin_value < 177 + 20 && key_pin_value > 177 - 20) {
+    key = 2;
+  } else if (key_pin_value < 0 + 20) {
+    key = 1;
+  } else {
+    key = 0;
+  }
+
+  if (last_key == 0 && key != 0) {
+    switch (key) {
+    case 1:
+      n0 = n1 = n2 = n3 = 0;
+      break;
+    case 2:
+      n0 = (n0 + 1) % 10;
+      break;
+    case 3:
+      n1 = (n1 + 1) % 10;
+      break;
+    case 4:
+      n2 = (n2 + 1) % 10;
+      break;
+    case 5:
+      n3 = (n3 + 1) % 10;
+      break;
+    case 6:
+      int n = (n3 * 1000) + (n2 * 100) + (n1 * 10) + (n0 * 1);
+      run_test(n);
+      break;
+    }
+  }
+
+  segs.clear();
+  segs.writeDigitNum(4, n0);
+  segs.writeDigitNum(3, n1);
+  if (n2 > 0 || n3 > 0)
+    segs.writeDigitNum(1, n2);
+  if (n3 > 0)
+    segs.writeDigitNum(0, n3);
+  segs.writeDisplay();
+  delay(50);
+}