From: rs <> Date: Fri, 12 Sep 2025 22:51:48 +0000 (-0500) Subject: Initial commit X-Git-Url: https://git.the-white-hart.net/?a=commitdiff_plain;h=refs%2Fheads%2Fmain;p=atmega%2Fchip_tester.git Initial commit --- d09b48be5fd70311ac531c5ab3f89fa576d89819 diff --git a/ChipTester.ino b/ChipTester.ino new file mode 100644 index 0000000..1698e22 --- /dev/null +++ b/ChipTester.ino @@ -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); +}