Last active
May 29, 2017 19:30
-
-
Save mfurtak/64ebab97613349a36cc20f383329dc9d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Designed for use with two 74HC595N shift registers, | |
* one AT28C64B EEPROM, and an Arduino Micro. | |
* | |
* Based on work by Ben Eater from https://www.youtube.com/watch?v=K88pgWhEb1M | |
*/ | |
// Arduino pins connected to the shift register pins | |
#define SHIFT_DATA 2 | |
#define SHIFT_CLK 3 | |
#define SHIFT_LATCH 4 | |
// Arduino pins connected to the 8 EEPROM data I/O lines | |
#define EEPROM_D0 5 | |
// and so on in between here... | |
#define EEPROM_D7 12 | |
// Arduino pin connected to the EEPROM write enable pin | |
#define WRITE_ENABLE 13 | |
/** | |
* Makes the value shifted into the shift registers | |
* available on the output pins | |
*/ | |
void pulseShiftLatch() { | |
digitalWrite(SHIFT_LATCH, LOW); | |
digitalWrite(SHIFT_LATCH, HIGH); | |
// 1 microsecond is the shortest amount of time we can | |
// delay in the Arduino API. The latch pulse needs to | |
// be at least 20ns according to the datasheet. | |
delayMicroseconds(1); | |
digitalWrite(SHIFT_LATCH, LOW); | |
} | |
/** | |
* Pulse the EEPROM write enable (/WE) pin to trigger a | |
* write of the byte on the data lines | |
*/ | |
void pulseWrite() { | |
digitalWrite(WRITE_ENABLE, HIGH); | |
digitalWrite(WRITE_ENABLE, LOW); | |
// 1 microsecond is the shortest amount of time we can | |
// delay in the Arduino API. The write pulse needs to | |
// be at least 100ns according to the datasheet. | |
delayMicroseconds(1); | |
digitalWrite(WRITE_ENABLE, HIGH); | |
// The datasheet claims to need the data to be held for | |
// 0ns after /WE goes high, but if I don't delay, I get | |
// inconsistent reads. | |
delay(10); | |
} | |
/** | |
* Shifts low 13 bits of the the provided int address out | |
* on SHIFT_DATA, most significant bit first. | |
* | |
* The outputEnable flag controls the MSB of the shifted | |
* 16 bit value, which we'll use for the /OE control pin. | |
*/ | |
void setAddress(int address, bool outputEnable) { | |
// Output enable is active low, and we'll ensure that the | |
// MSB of the address is zero, so change nothing if | |
// outputEnable is true. If false, we need to set the MSB | |
// to a 1. | |
int outputEnableBit = outputEnable ? 0x0000 : 0x8000; | |
// The AT28C64B that I am using supports up to 13 bits of | |
// address, so we'll ensure that any higher bits than that | |
// are 0 | |
address = address & 0x1FFF; | |
// Apply the output enable bit to the address value | |
address = address | outputEnableBit; | |
shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address >> 8); | |
shiftOut(SHIFT_DATA, SHIFT_CLK, MSBFIRST, address); | |
pulseShiftLatch(); | |
} | |
/** | |
* Read the byte at the specifed address from the EEPROM | |
*/ | |
byte readByte(int address) { | |
setAddress(address, /* outputEnable */ true); | |
byte data = 0; | |
for (int pin = EEPROM_D7; pin >= EEPROM_D0; pin -= 1) { | |
pinMode(pin, INPUT); | |
data = (data << 1) + digitalRead(pin); | |
} | |
return data; | |
} | |
/** | |
* Write the provided byte to the specified address of the EEPROM | |
*/ | |
void writeByte(int address, byte data) { | |
setAddress(address, /* outputEnable */ false); | |
for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) { | |
pinMode(pin, OUTPUT); | |
digitalWrite(pin, data & 0x01); | |
data = data >> 1; | |
} | |
pulseWrite(); | |
} | |
void beginSerial() { | |
Serial.begin(9600); | |
while (!Serial) { | |
; | |
} | |
} | |
/** | |
* Dump the first 256 bytes of the EEPROM to the serial port | |
*/ | |
void printContents() { | |
beginSerial(); | |
for (int base = 0; base < 256; base += 16) { | |
byte data[16]; | |
for (int offset = 0; offset < 16; offset += 1) { | |
data[offset] = readByte(base + offset); | |
} | |
char buf[80]; | |
sprintf(buf, "%03x: %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); | |
} | |
} | |
/** | |
* Erase the first 256 bytes of the EEPROM by setting them to 0xFF | |
*/ | |
void eraseContents() { | |
for (int i = 0; i < 256; i += 1) { | |
writeByte(i, 0xFF); | |
} | |
} | |
void setup() { | |
pinMode(SHIFT_DATA, OUTPUT); | |
pinMode(SHIFT_CLK, OUTPUT); | |
pinMode(SHIFT_LATCH, OUTPUT); | |
for (int pin = EEPROM_D0; pin <= EEPROM_D7; pin += 1) { | |
pinMode(pin, OUTPUT); | |
} | |
digitalWrite(WRITE_ENABLE, HIGH); | |
pinMode(WRITE_ENABLE, OUTPUT); | |
eraseContents(); | |
char greeting[14] = "Hello, world!"; | |
for (int i = 0; i < 14; i += 1) { | |
writeByte(i, (byte)greeting[i]); | |
} | |
printContents(); | |
} | |
void loop() { | |
// put your main code here, to run repeatedly: | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment