Utility sketch to disable SDP on Ben Eater hardware

This commit is contained in:
Tom Nisbet 2020-08-08 21:26:24 -04:00
parent 8ddae82395
commit d414d6ad3a
2 changed files with 180 additions and 0 deletions

View File

@ -0,0 +1,8 @@
Utility to unlock 28C256 Software Data Protection (SDP) for the
[Ben Eater EEPROM](https://github.com/beneater/eeprom-programmer)
programmer design. This hardware is similar to the TommyPROM hardware, but it uses
different shift register chips and different pin assignments.
To meet the timing requirements of the SDP unlock, this code uses direct port writes
to set and read values on the data bus. It will work Arduino Uno and Nano hardware,
but would require changes for other platforms.

View File

@ -0,0 +1,172 @@
// Utility to unlock 28C256 Software Data Protection (SDP) for the Ben Eater EEPROM
// programmer design. This hardware is similar to the TommyPROM hardware, but it uses
// different shift register chips and different pin assignments.
//
// To meet the timing requirements of the SDP unlock, this code uses direct port writes
// to set and read values on the data bus. It will work Arduino Uno and Nano hardware,
// but would require changes for other platforms.
#define SHIFT_DATA 2
#define SHIFT_CLK 3
#define SHIFT_LATCH 4
#define WRITE_EN 13
// 32 byte test pattern to verify the EEPROM device. The pattern includes a walking one
// and a walking zero, which may help to detect pins that are tied together or swapped.
byte data[] = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe,
0x00, 0xff, 0x55, 0xaa, '0', '1', '2', '3'
};
void enableWrite() { digitalWrite(WRITE_EN, LOW);}
void disableWrite() { digitalWrite(WRITE_EN, HIGH);}
void setup() {
// put your setup code here, to run once:
pinMode(SHIFT_DATA, OUTPUT);
pinMode(SHIFT_CLK, OUTPUT);
pinMode(SHIFT_LATCH, OUTPUT);
disableWrite();
pinMode(WRITE_EN, OUTPUT);
Serial.begin(57600);
Serial.print("\nDisabling EEPROM Software Data Protection(SDP)...");
disableSoftwareWriteProtect();
Serial.println(" done\n");
// Program a test pattern and fill the remainder of the first block with 0xff
Serial.print("Programming EEPROM...");
for (word address = 0; (address < sizeof(data)); address++) {
writeEEPROM(address, data[address]);
}
for (word address = sizeof(data); (address < 256); address++) {
writeEEPROM(address, 0xff);
}
Serial.println(" done\n");
// Read and print out the contents of the EERPROM
Serial.println("Reading EEPROM");
printContents();
}
void loop() {
}
// Output the address bits and outputEnable signal using shift registers.
void setAddress(int address, bool outputEnable) {
// Shift the address bits in
shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, (address >> 8) | (outputEnable ? 0x00 : 0x80));
shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address);
// Latch the shift register contents into the output register.
digitalWrite(SHIFT_LATCH, LOW);
digitalWrite(SHIFT_LATCH, HIGH);
digitalWrite(SHIFT_LATCH, LOW);
}
// Read a byte from the EEPROM at the specified address.
byte readEEPROM(int address) {
setDataBusMode(INPUT);
setAddress(address, /*outputEnable*/ true);
return readDataBus();
}
// Write a byte to the EEPROM at the specified address.
void writeEEPROM(int address, byte data) {
setAddress(address, /*outputEnable*/ false);
setDataBusMode(OUTPUT);
writeDataBus(data);
enableWrite();
delayMicroseconds(1);
disableWrite();
delay(10);
}
// Read the first 256 byte block of the EEPROM and dump it to the serial monitor.
void printContents() {
for (int base = 0; (base < 256); base += 16) {
byte data[16];
for (int offset = 0; offset <= 15; offset += 1) {
data[offset] = readEEPROM(base + offset);
}
char buf[80];
sprintf(buf, "%04x: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
base, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
data[8], data[9], data[10], data[11], data[12], data[13], data[14], data[15]);
Serial.println(buf);
}
}
// Write the special six-byte code to turn off Software Data Protection.
void disableSoftwareWriteProtect() {
disableWrite();
setDataBusMode(OUTPUT);
setByte(0xaa, 0x5555);
setByte(0x55, 0x2aaa);
setByte(0x80, 0x5555);
setByte(0xaa, 0x5555);
setByte(0x55, 0x2aaa);
setByte(0x20, 0x5555);
setDataBusMode(INPUT);
delay(10);
}
// Write the special three-byte code to turn on Software Data Protection.
void enableSoftwareWriteProtect() {
disableWrite();
setDataBusMode(OUTPUT);
setByte(0xaa, 0x5555);
setByte(0x55, 0x2aaa);
setByte(0xa0, 0x5555);
setDataBusMode(INPUT);
delay(10);
}
// Set the I/O state of the data bus.
// The 8 bits data bus are is on pins D5..D12.
void setDataBusMode(uint8_t mode) {
// On the Uno and Nano, D5..D12 maps to the upper 3 bits of port D and the
// lower 5 bits of port B.
if (mode == OUTPUT) {
DDRB |= 0x1f;
DDRD |= 0xe0;
} else {
DDRB &= 0xe0;
DDRD &= 0x1f;
}
}
// Read a byte from the data bus. The caller must set the bus to input_mode
// before calling this or no useful data will be returned.
byte readDataBus() {
return (PINB << 3) | (PIND >> 5);
}
// Write a byte to the data bus. The caller must set the bus to output_mode
// before calling this or no data will be written.
void writeDataBus(byte data) {
PORTB = (PORTB & 0xe0) | (data >> 3);
PORTD = (PORTD & 0x1f) | (data << 5);
}
// Set an address and data value and toggle the write control. This is used
// to write control sequences, like the software write protect. This is not a
// complete byte write function because it does not set the chip enable or the
// mode of the data bus.
void setByte(byte value, word address) {
setAddress(address, false);
writeDataBus(value);
delayMicroseconds(1);
enableWrite();
delayMicroseconds(1);
disableWrite();
}