mirror of
https://github.com/TomNisbet/TommyPROM.git
synced 2024-11-24 23:31:42 +00:00
Add Hardware Verify sketch
This commit is contained in:
parent
ed539fe310
commit
4529343228
9
HardwareVerify/Configure.h
Normal file
9
HardwareVerify/Configure.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// Uncomment only one of the ARDUINO_IS_ lines to use the fast I/O code for
|
||||||
|
// the data bus, or comment them all out to use the slower bit-at-a-time code.
|
||||||
|
|
||||||
|
//#define ARDUINO_IS_MICRO
|
||||||
|
#define ARDUINO_IS_UNO
|
||||||
|
//#define ARDUINO_IS_NANO
|
||||||
|
|
||||||
|
|
||||||
|
#include "PromDevice28C.h"
|
262
HardwareVerify/HardwareVerify.ino
Normal file
262
HardwareVerify/HardwareVerify.ino
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
/**
|
||||||
|
* Test hardware for ATMEL 28C series EEPROMs.
|
||||||
|
*
|
||||||
|
* The hardware uses two 74LS164 shift registers as the low and
|
||||||
|
* high address registers.
|
||||||
|
**/
|
||||||
|
|
||||||
|
#include "Configure.h"
|
||||||
|
|
||||||
|
#define LED 13
|
||||||
|
|
||||||
|
PromDevice28C prom(32 * 1024L, 64, 10, true);
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLI parse functions
|
||||||
|
*/
|
||||||
|
const char hex[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
|
||||||
|
// Read a line of data from the serial connection.
|
||||||
|
char * readLine(char * buffer, int len)
|
||||||
|
{
|
||||||
|
for (int ix = 0; (ix < len); ix++)
|
||||||
|
{
|
||||||
|
buffer[ix] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// read serial data until linebreak or buffer is full
|
||||||
|
char c = ' ';
|
||||||
|
int ix = 0;
|
||||||
|
do {
|
||||||
|
if (Serial.available())
|
||||||
|
{
|
||||||
|
c = Serial.read();
|
||||||
|
if ((c == '\b') && (ix > 0))
|
||||||
|
{
|
||||||
|
// Backspace, forget last character
|
||||||
|
--ix;
|
||||||
|
}
|
||||||
|
buffer[ix++] = c;
|
||||||
|
Serial.write(c);
|
||||||
|
}
|
||||||
|
} while ((c != '\n') && (ix < len));
|
||||||
|
|
||||||
|
buffer[ix - 1] = 0;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* convert a single hex character [0-9a-fA-F] to its value
|
||||||
|
* @param char c single character (digit)
|
||||||
|
* @return byte value of the digit (0-15)
|
||||||
|
************************************************************/
|
||||||
|
byte hexDigit(char c)
|
||||||
|
{
|
||||||
|
if ((c >= '0') && (c <= '9'))
|
||||||
|
{
|
||||||
|
return c - '0';
|
||||||
|
}
|
||||||
|
else if ((c >= 'a') && (c <= 'f'))
|
||||||
|
{
|
||||||
|
return c - 'a' + 10;
|
||||||
|
}
|
||||||
|
else if ((c >= 'A') && (c <= 'F'))
|
||||||
|
{
|
||||||
|
return c - 'A' + 10;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* convert a hex byte (00 - ff) to byte
|
||||||
|
* @param c-string with the hex value of the byte
|
||||||
|
* @return byte represented by the digits
|
||||||
|
************************************************************/
|
||||||
|
byte hexByte(char * a)
|
||||||
|
{
|
||||||
|
return (hexDigit(a[0]) << 4) | hexDigit(a[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
* convert a hex word (0000 - ffff) to unsigned int
|
||||||
|
* @param c-string with the hex value of the word
|
||||||
|
* @return unsigned int represented by the digits
|
||||||
|
************************************************************/
|
||||||
|
unsigned int hexWord(char * data)
|
||||||
|
{
|
||||||
|
return (hexDigit(data[0]) << 12) |
|
||||||
|
(hexDigit(data[1]) << 8) |
|
||||||
|
(hexDigit(data[2]) << 4) |
|
||||||
|
(hexDigit(data[3]));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void printByte(byte b)
|
||||||
|
{
|
||||||
|
char line[3];
|
||||||
|
|
||||||
|
line[0] = hex[b >> 4];
|
||||||
|
line[1] = hex[b & 0x0f];
|
||||||
|
line[2] = '\0';
|
||||||
|
|
||||||
|
Serial.print(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void printWord(word w)
|
||||||
|
{
|
||||||
|
char line[5];
|
||||||
|
|
||||||
|
line[0] = hex[(w >> 12) & 0x0f];
|
||||||
|
line[1] = hex[(w >> 8) & 0x0f];
|
||||||
|
line[2] = hex[(w >> 4) & 0x0f];
|
||||||
|
line[3] = hex[(w) & 0x0f];
|
||||||
|
line[4] = '\0';
|
||||||
|
|
||||||
|
Serial.print(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************************************************
|
||||||
|
* MAIN
|
||||||
|
*************************************************/
|
||||||
|
word addr = 0;
|
||||||
|
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
// Do this first so that it initializes all of the hardware pins into a
|
||||||
|
// non-harmful state. The Arduino or the target EEPROM could be damaged
|
||||||
|
// if both writing to the data bus at the same time.
|
||||||
|
prom.begin();
|
||||||
|
|
||||||
|
Serial.begin(115200);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
word start = 0;
|
||||||
|
word end = 0xff;
|
||||||
|
byte val = 0xff;
|
||||||
|
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
byte b;
|
||||||
|
word w;
|
||||||
|
bool error = false;
|
||||||
|
char line[20];
|
||||||
|
uint32_t numBytes;
|
||||||
|
|
||||||
|
Serial.print("\n#");
|
||||||
|
Serial.flush();
|
||||||
|
readLine(line, sizeof(line));
|
||||||
|
byte c = tolower(line[0]);
|
||||||
|
if ((c >= 'A') && (c <= 'Z')) {
|
||||||
|
c |= 0x20;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note that the comamnds here allow for direct writing of the 28C control lines with some exceptions to
|
||||||
|
* protect the chip and the host arduino:
|
||||||
|
* 1) When the O command is used to enable chip output, the arduino data bus us set to INPUT
|
||||||
|
* 2) When the D command is used to write data from the arduino, the chip output is disabled
|
||||||
|
* 3) The R command sets to output enable (OE) on the chip (but not the chip enable (CE)) */
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'a':
|
||||||
|
if (hexDigit(line[1]) <= 15)
|
||||||
|
{
|
||||||
|
w = hexWord(line + 1);
|
||||||
|
prom.setAddress(w);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
if (hexDigit(line[1]) <= 15)
|
||||||
|
{
|
||||||
|
prom.disableOutput();
|
||||||
|
prom.setDataBusMode(OUTPUT);
|
||||||
|
b = hexByte(line + 1);
|
||||||
|
prom.writeDataBus(b);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
case 'o':
|
||||||
|
case 'w':
|
||||||
|
if ((line[1] == 'd') || (line[1] == 'e')) {
|
||||||
|
bool enable = line[1] == 'e';
|
||||||
|
if (c == 'c')
|
||||||
|
if (enable) prom.enableChip(); else prom.disableChip();
|
||||||
|
else if (c == 'w')
|
||||||
|
if (enable) prom.enableWrite(); else prom.disableWrite();
|
||||||
|
else { // c == 'o'
|
||||||
|
if (enable)
|
||||||
|
{
|
||||||
|
// Don't allow the prom and the data bus to output at the same time
|
||||||
|
prom.setDataBusMode(INPUT);
|
||||||
|
prom.enableOutput();
|
||||||
|
}
|
||||||
|
else prom.disableOutput();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
prom.setDataBusMode(INPUT);
|
||||||
|
prom.enableOutput();
|
||||||
|
b = prom.readDataBus();
|
||||||
|
printByte(b);
|
||||||
|
Serial.println();
|
||||||
|
prom.disableOutput();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
Serial.println(F("Writing the lock code to enable Software Write Protect mode."));
|
||||||
|
prom.enableSoftwareWriteProtect();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'u':
|
||||||
|
Serial.println(F("Writing the unlock code to disable Software Write Protect mode."));
|
||||||
|
prom.disableSoftwareWriteProtect();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
Serial.print(F("Hardware Verifier - "));
|
||||||
|
Serial.println(prom.getName());
|
||||||
|
Serial.println();
|
||||||
|
Serial.println(F("Valid commands are:"));
|
||||||
|
Serial.println(F(" Axxxx - Set address bus to xxxx"));
|
||||||
|
Serial.println(F(" Dxx - Set Data bus to xx"));
|
||||||
|
Serial.println(F(" Cs - Set Chip enable to state (e=enable, d=disable)"));
|
||||||
|
Serial.println(F(" Os - Set Output enable to state (e=enable, d=disable)"));
|
||||||
|
Serial.println(F(" Ws - Set Write enable to state (e=enable, d=disable)"));
|
||||||
|
Serial.println(F(" R - Read and print the value on the data bus"));
|
||||||
|
Serial.println(F(" L - Send Lock sequence to enable device Software Data Protection"));
|
||||||
|
Serial.println(F(" U - Send Unlock sequence to disable device Software Data Protection"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
70
HardwareVerify/PromAddressDriver.cpp
Normal file
70
HardwareVerify/PromAddressDriver.cpp
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#include "PromAddressDriver.h"
|
||||||
|
|
||||||
|
#define ADDR_CLK_HI A3
|
||||||
|
#define ADDR_CLK_LO A4
|
||||||
|
#define ADDR_DATA A5
|
||||||
|
|
||||||
|
|
||||||
|
void PromAddressDriver::begin()
|
||||||
|
{
|
||||||
|
// The address control pins are always outputs.
|
||||||
|
pinMode(ADDR_DATA, OUTPUT);
|
||||||
|
pinMode(ADDR_CLK_LO, OUTPUT);
|
||||||
|
pinMode(ADDR_CLK_HI, OUTPUT);
|
||||||
|
digitalWrite(ADDR_DATA, LOW);
|
||||||
|
digitalWrite(ADDR_CLK_LO, LOW);
|
||||||
|
digitalWrite(ADDR_CLK_HI, LOW);
|
||||||
|
|
||||||
|
|
||||||
|
// To save time, the setAddress only writes the hi byte if it has changed.
|
||||||
|
// The value used to detect the change is initialized to a non-zero value,
|
||||||
|
// so set an initial address to avoid the the case where the first address
|
||||||
|
// written is the 'magic' initial address.
|
||||||
|
setAddress(0x0000);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set a 16 bit address in the two address shift registers.
|
||||||
|
void PromAddressDriver::setAddress(word address)
|
||||||
|
{
|
||||||
|
static byte lastHi = 0xca;
|
||||||
|
byte hi = address >> 8;
|
||||||
|
byte lo = address & 0xff;
|
||||||
|
|
||||||
|
if (hi != lastHi)
|
||||||
|
{
|
||||||
|
setAddressRegister(ADDR_CLK_HI, hi);
|
||||||
|
lastHi = hi;
|
||||||
|
}
|
||||||
|
setAddressRegister(ADDR_CLK_LO, lo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Shift an 8-bit value into one of the address shift registers. Note that
|
||||||
|
// the data pins are tied together, selecting the high or low address register
|
||||||
|
// is a matter of using the correct clock pin to shift the data in.
|
||||||
|
void PromAddressDriver::setAddressRegister(uint8_t clkPin, byte addr)
|
||||||
|
{
|
||||||
|
// Make sure the clock is low to start.
|
||||||
|
digitalWrite(clkPin, LOW);
|
||||||
|
|
||||||
|
// Shift 8 bits in, starting with the MSB.
|
||||||
|
for (int ix = 0; (ix < 8); ix++)
|
||||||
|
{
|
||||||
|
// Set the data bit
|
||||||
|
if (addr & 0x80)
|
||||||
|
{
|
||||||
|
digitalWrite(ADDR_DATA, HIGH);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
digitalWrite(ADDR_DATA, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(clkPin, HIGH); // Clock in a bit
|
||||||
|
digitalWrite(clkPin, LOW); // Reset the clock pin
|
||||||
|
addr <<= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
17
HardwareVerify/PromAddressDriver.h
Normal file
17
HardwareVerify/PromAddressDriver.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef INCLUDE_PROM_ADDRESS_DRIVER_H
|
||||||
|
#define INCLUDE_PROM_ADDRESS_DRIVER_H
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
class PromAddressDriver {
|
||||||
|
public:
|
||||||
|
static void begin();
|
||||||
|
static void setAddress(word address);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void setAddressRegister(uint8_t clkPin, byte addr);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #define INCLUDE_PROM_ADDRESS_DRIVER_H
|
||||||
|
|
155
HardwareVerify/PromDevice.cpp
Normal file
155
HardwareVerify/PromDevice.cpp
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
#include "Configure.h"
|
||||||
|
#include "PromDevice.h"
|
||||||
|
|
||||||
|
|
||||||
|
PromDevice::PromDevice(unsigned long size, word blockSize, unsigned maxWriteTime, bool polling)
|
||||||
|
: mSize(size),
|
||||||
|
mBlockSize(blockSize),
|
||||||
|
mMaxWriteTime(maxWriteTime),
|
||||||
|
mSupportsDataPoll(polling)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write a block of data to the device. If the device supports block writes,
|
||||||
|
// the data will be broken into chunks and written using the block mode.
|
||||||
|
// Otherwise, each byte will be individually written and verified.
|
||||||
|
bool PromDevice::writeData(byte data[], word len, word address)
|
||||||
|
{
|
||||||
|
bool status = true;
|
||||||
|
|
||||||
|
if (mBlockSize == 0)
|
||||||
|
{
|
||||||
|
// Device does not support block writes.
|
||||||
|
for (word ix = 0; (ix < len); ix++)
|
||||||
|
{
|
||||||
|
if (burnByte(data[ix], address + ix) == false)
|
||||||
|
{
|
||||||
|
status = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
word offset = 0;
|
||||||
|
word chunkSize;
|
||||||
|
if (address & (mBlockSize - 1))
|
||||||
|
{
|
||||||
|
// Address does not start on a block boundary. Adjust the size of
|
||||||
|
// the first block to fit within a single block.
|
||||||
|
chunkSize = mBlockSize - (address & (mBlockSize - 1));
|
||||||
|
chunkSize = (chunkSize > len) ? len : chunkSize;
|
||||||
|
if (burnBlock(data, chunkSize, address) == false)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
offset += chunkSize;
|
||||||
|
len -= chunkSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
// All writes are now aligned to block boundaries, so write full blocks
|
||||||
|
// or remaining length, whichever is smaller.
|
||||||
|
while (len > 0)
|
||||||
|
{
|
||||||
|
chunkSize = (len > mBlockSize) ? mBlockSize : len;
|
||||||
|
if (burnBlock(data + offset, chunkSize, address + offset) == false)
|
||||||
|
{
|
||||||
|
status = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
offset += chunkSize;
|
||||||
|
len -= chunkSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// BEGIN PRIVATE METHODS
|
||||||
|
//
|
||||||
|
|
||||||
|
// Set the I/O state of the data bus.
|
||||||
|
// The first two bits of port D are used for serial, so the 8 bits data bus are
|
||||||
|
// on pins D2..D9.
|
||||||
|
void PromDevice::setDataBusMode(uint8_t mode)
|
||||||
|
{
|
||||||
|
#if defined(ARDUINO_IS_UNO) || defined(ARDUINO_IS_NANO)
|
||||||
|
// On the Uno and Nano, D2..D9 maps to the upper 6 bits of port D and the
|
||||||
|
// lower 2 bits of port B.
|
||||||
|
if (mode == OUTPUT)
|
||||||
|
{
|
||||||
|
DDRB |= 0x03;
|
||||||
|
DDRD |= 0xfc;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DDRB &= 0xfc;
|
||||||
|
DDRD &= 0x03;
|
||||||
|
}
|
||||||
|
#elif defined(ARDUINO_IS_MICRO)
|
||||||
|
// On the Micro, D2..D9 maps to the upper 7 bits of port B and the
|
||||||
|
// lower bit of port D.
|
||||||
|
if (mode == OUTPUT)
|
||||||
|
{
|
||||||
|
DDRB |= 0xfe;
|
||||||
|
DDRD |= 0x01;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DDRB &= 0x01;
|
||||||
|
DDRD &= 0xfe;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
byte bit = 0x01;
|
||||||
|
for (int pin = 2; (pin <= 9); pin++) {
|
||||||
|
pinMode(pin, mode);
|
||||||
|
bit <<= 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 PromDevice::readDataBus()
|
||||||
|
{
|
||||||
|
#if defined(ARDUINO_IS_UNO) || defined(ARDUINO_IS_NANO)
|
||||||
|
return (PINB << 6) | (PIND >> 2);
|
||||||
|
#elif defined(ARDUINO_IS_MICRO)
|
||||||
|
return (PINB & 0xfe) | (PIND & 0x01);
|
||||||
|
#else
|
||||||
|
byte data = 0;
|
||||||
|
byte bit = 0x01;
|
||||||
|
for (int pin = 2; (pin <= 9); pin++) {
|
||||||
|
if (digitalRead(pin) == HIGH) {
|
||||||
|
data |= bit;
|
||||||
|
}
|
||||||
|
bit <<= 1;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 PromDevice::writeDataBus(byte data)
|
||||||
|
{
|
||||||
|
#if defined(ARDUINO_IS_UNO) || defined(ARDUINO_IS_NANO)
|
||||||
|
PORTB = (PORTB & 0xfc) | (data >> 6);
|
||||||
|
PORTD = (PORTD & 0x03) | (data << 2);
|
||||||
|
#elif defined(ARDUINO_IS_MICRO)
|
||||||
|
PORTB = (PORTB & 0x01) | (data & 0xfe);
|
||||||
|
PORTD = (PORTD & 0xfe) | (data & 0x01);
|
||||||
|
#else
|
||||||
|
byte bit = 0x01;
|
||||||
|
for (int pin = 2; (pin <= 9); pin++) {
|
||||||
|
digitalWrite(pin, (data & bit) ? HIGH : LOW);
|
||||||
|
bit <<= 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
48
HardwareVerify/PromDevice.h
Normal file
48
HardwareVerify/PromDevice.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef INCLUDE_PROM_DEVICE_H
|
||||||
|
#define INCLUDE_PROM_DEVICE_H
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* PromDevice class
|
||||||
|
*
|
||||||
|
* Provides the interface to read and write data from a parallel PROM using the
|
||||||
|
* Arduino.
|
||||||
|
*
|
||||||
|
* Block writes are supported on compatible devices by specifying a blockSize
|
||||||
|
* in the constructor. Use zero for devices that only support byte writes.
|
||||||
|
*/
|
||||||
|
class PromDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PromDevice(unsigned long size, word blockSize, unsigned maxWriteTime, bool polling);
|
||||||
|
bool writeData(byte data[], word len, word address);
|
||||||
|
byte readData(word address) { return readByte(address); }
|
||||||
|
|
||||||
|
virtual void begin() = 0;
|
||||||
|
virtual const char * getName() = 0;
|
||||||
|
virtual void disableSoftwareWriteProtect() {}
|
||||||
|
virtual void enableSoftwareWriteProtect() {}
|
||||||
|
|
||||||
|
//protected:
|
||||||
|
unsigned int mSize; // Size of the device, in bytes
|
||||||
|
unsigned int mBlockSize; // Block size for page writes, zero if N/A
|
||||||
|
unsigned int mMaxWriteTime; // Max time (in ms) to wait for write cycle to complete
|
||||||
|
bool mSupportsDataPoll; // End of write detected by data polling
|
||||||
|
|
||||||
|
void setDataBusMode(uint8_t mode);
|
||||||
|
byte readDataBus();
|
||||||
|
void writeDataBus(byte data);
|
||||||
|
|
||||||
|
virtual void setAddress(word address) = 0;
|
||||||
|
virtual byte readByte(word address) = 0;
|
||||||
|
virtual bool burnByte(byte value, word address) = 0;
|
||||||
|
virtual bool burnBlock(byte data[], word len, word address) { return false; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // #define INCLUDE_PROM_DEVICE_H
|
||||||
|
|
211
HardwareVerify/PromDevice28C.cpp
Normal file
211
HardwareVerify/PromDevice28C.cpp
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
#include "Configure.h"
|
||||||
|
|
||||||
|
#include "PromAddressDriver.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PromDevice28C::PromDevice28C(unsigned long size, word blockSize, unsigned maxWriteTime, bool polling)
|
||||||
|
: PromDevice(size, blockSize, maxWriteTime, polling)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void PromDevice28C::begin()
|
||||||
|
{
|
||||||
|
// Define the data bus as input initially so that it does not put out a
|
||||||
|
// signal that could collide with output on the data pins of the EEPROM.
|
||||||
|
setDataBusMode(INPUT);
|
||||||
|
|
||||||
|
// Define the EEPROM control pins as output, making sure they are all
|
||||||
|
// in the disabled state.
|
||||||
|
digitalWrite(OE, HIGH);
|
||||||
|
pinMode(OE, OUTPUT);
|
||||||
|
digitalWrite(CE, HIGH);
|
||||||
|
pinMode(CE, OUTPUT);
|
||||||
|
digitalWrite(WE, HIGH);
|
||||||
|
pinMode(WE, OUTPUT);
|
||||||
|
|
||||||
|
// This chip uses the shift register hardware for addresses, so initialize that.
|
||||||
|
PromAddressDriver::begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write the special six-byte code to turn off Software Data Protection.
|
||||||
|
void PromDevice28C::disableSoftwareWriteProtect()
|
||||||
|
{
|
||||||
|
disableOutput();
|
||||||
|
disableWrite();
|
||||||
|
setDataBusMode(OUTPUT);
|
||||||
|
|
||||||
|
setByte(0xaa, 0x5555);
|
||||||
|
setByte(0x55, 0x2aaa);
|
||||||
|
setByte(0x80, 0x5555);
|
||||||
|
setByte(0xaa, 0x5555);
|
||||||
|
setByte(0x55, 0x2aaa);
|
||||||
|
setByte(0x20, 0x5555);
|
||||||
|
|
||||||
|
setDataBusMode(INPUT);
|
||||||
|
disableChip();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Write the special three-byte code to turn on Software Data Protection.
|
||||||
|
void PromDevice28C::enableSoftwareWriteProtect()
|
||||||
|
{
|
||||||
|
disableOutput();
|
||||||
|
disableWrite();
|
||||||
|
setDataBusMode(OUTPUT);
|
||||||
|
|
||||||
|
setByte(0xaa, 0x5555);
|
||||||
|
setByte(0x55, 0x2aaa);
|
||||||
|
setByte(0xa0, 0x5555);
|
||||||
|
|
||||||
|
setDataBusMode(INPUT);
|
||||||
|
disableChip();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// BEGIN PRIVATE METHODS
|
||||||
|
//
|
||||||
|
|
||||||
|
// Use the PromAddressDriver to set a 16 bit address in the two address shift registers.
|
||||||
|
void PromDevice28C::setAddress(word address)
|
||||||
|
{
|
||||||
|
PromAddressDriver::setAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Read a byte from a given address
|
||||||
|
byte PromDevice28C::readByte(word address)
|
||||||
|
{
|
||||||
|
byte data = 0;
|
||||||
|
setAddress(address);
|
||||||
|
setDataBusMode(INPUT);
|
||||||
|
disableOutput();
|
||||||
|
disableWrite();
|
||||||
|
enableChip();
|
||||||
|
enableOutput();
|
||||||
|
data = readDataBus();
|
||||||
|
disableOutput();
|
||||||
|
disableChip();
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Burn a byte to the chip and verify that it was written.
|
||||||
|
bool PromDevice28C::burnByte(byte value, word address)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
disableOutput();
|
||||||
|
disableWrite();
|
||||||
|
|
||||||
|
setAddress(address);
|
||||||
|
setDataBusMode(OUTPUT);
|
||||||
|
writeDataBus(value);
|
||||||
|
|
||||||
|
enableChip();
|
||||||
|
delayMicroseconds(1);
|
||||||
|
enableWrite();
|
||||||
|
delayMicroseconds(1);
|
||||||
|
disableWrite();
|
||||||
|
|
||||||
|
status = waitForWriteCycleEnd(value);
|
||||||
|
|
||||||
|
disableChip();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PromDevice28C::burnBlock(byte data[], word len, word address)
|
||||||
|
{
|
||||||
|
bool status = false;
|
||||||
|
|
||||||
|
if (len == 0) return true;
|
||||||
|
|
||||||
|
disableOutput();
|
||||||
|
disableWrite();
|
||||||
|
enableChip();
|
||||||
|
|
||||||
|
// Write all of the bytes in the block out to the chip. The chip will
|
||||||
|
// program them all at once as long as they are written fast enough.
|
||||||
|
setDataBusMode(OUTPUT);
|
||||||
|
for (word ix = 0; (ix < len); ix++)
|
||||||
|
{
|
||||||
|
setAddress(address + ix);
|
||||||
|
writeDataBus(data[ix]);
|
||||||
|
|
||||||
|
delayMicroseconds(1);
|
||||||
|
enableWrite();
|
||||||
|
delayMicroseconds(1);
|
||||||
|
disableWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
status = waitForWriteCycleEnd(data[len - 1]);
|
||||||
|
disableChip();
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool PromDevice28C::waitForWriteCycleEnd(byte lastValue)
|
||||||
|
{
|
||||||
|
if (mSupportsDataPoll)
|
||||||
|
{
|
||||||
|
// Verify programming complete by reading the last value back until it matches the
|
||||||
|
// value written twice in a row. The D7 bit will read the inverse of last written
|
||||||
|
// data and the D6 bit will toggle on each read while in programming mode.
|
||||||
|
//
|
||||||
|
// Note that the max readcount is set to the device's maxReadTime (in uSecs)
|
||||||
|
// divided by two because there are two 1 uSec delays in the loop. In reality,
|
||||||
|
// the loop could run for longer because this does not account for the time needed
|
||||||
|
// to run all of the loop code. In actual practice, the loop will terminate much
|
||||||
|
// earlier because it will detect the end of the write well before the max time.
|
||||||
|
setDataBusMode(INPUT);
|
||||||
|
delayMicroseconds(1);
|
||||||
|
for (int readCount = mMaxWriteTime * 1000 / 2; (readCount > 0); readCount--)
|
||||||
|
{
|
||||||
|
enableOutput();
|
||||||
|
delayMicroseconds(1);
|
||||||
|
byte b1 = readDataBus();
|
||||||
|
disableOutput();
|
||||||
|
enableOutput();
|
||||||
|
delayMicroseconds(1);
|
||||||
|
byte b2 = readDataBus();
|
||||||
|
disableOutput();
|
||||||
|
if ((b1 == b2) && (b1 == lastValue))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// No way to detect success. Just wait the max write time.
|
||||||
|
delayMicroseconds(mMaxWriteTime * 1000L);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 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 PromDevice28C::setByte(byte value, word address)
|
||||||
|
{
|
||||||
|
setAddress(address);
|
||||||
|
writeDataBus(value);
|
||||||
|
|
||||||
|
delayMicroseconds(1);
|
||||||
|
enableChip();
|
||||||
|
enableWrite();
|
||||||
|
delayMicroseconds(1);
|
||||||
|
disableChip();
|
||||||
|
disableWrite();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
53
HardwareVerify/PromDevice28C.h
Normal file
53
HardwareVerify/PromDevice28C.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#ifndef INCLUDE_PROM_DEVICE_28C_H
|
||||||
|
#define INCLUDE_PROM_DEVICE_28C_H
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "PromDevice.h"
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/*****************************************************************************/
|
||||||
|
/**
|
||||||
|
* PromDevice28C class
|
||||||
|
*
|
||||||
|
* Provides the device-specific interface to read and write data from a
|
||||||
|
* 28C series parallel EEPROM using the Arduino.
|
||||||
|
*
|
||||||
|
* Block writes are supported on compatible devices by specifying a blockSize
|
||||||
|
* in the constructor. Use zero for byte writes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// IO lines for the EEPROM device control
|
||||||
|
// Pins D2..D9 are used for the data bus.
|
||||||
|
#define WE A0
|
||||||
|
#define CE A1
|
||||||
|
#define OE A2
|
||||||
|
|
||||||
|
class PromDevice28C : public PromDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PromDevice28C(unsigned long size, word blockSize, unsigned maxWriteTime, bool polling);
|
||||||
|
void begin();
|
||||||
|
const char * getName() { return "28C series EEPROM"; }
|
||||||
|
void disableSoftwareWriteProtect();
|
||||||
|
void enableSoftwareWriteProtect();
|
||||||
|
|
||||||
|
//protected:
|
||||||
|
void setAddress(word address);
|
||||||
|
byte readByte(word address);
|
||||||
|
bool burnByte(byte value, word address);
|
||||||
|
bool burnBlock(byte data[], word len, word address);
|
||||||
|
bool waitForWriteCycleEnd(byte lastValue);
|
||||||
|
void setByte(byte value, word address);
|
||||||
|
|
||||||
|
|
||||||
|
// Set the status of the device control pins
|
||||||
|
void enableChip() { digitalWrite(CE, LOW); }
|
||||||
|
void disableChip() { digitalWrite(CE, HIGH);}
|
||||||
|
void enableOutput() { digitalWrite(OE, LOW); }
|
||||||
|
void disableOutput() { digitalWrite(OE, HIGH);}
|
||||||
|
void enableWrite() { digitalWrite(WE, LOW);}
|
||||||
|
void disableWrite() { digitalWrite(WE, HIGH);}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // #define INCLUDE_PROM_DEVICE_28C_H
|
||||||
|
|
61
HardwareVerify/README.md
Normal file
61
HardwareVerify/README.md
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
## hardware Verifier Tool
|
||||||
|
This tools allows access to individual control lines from the Arduino to verify that the hardware was assembled correctly.
|
||||||
|
|
||||||
|
It can be used without a chip installed to scope out address and data lines. It also offers low-level control when the chip
|
||||||
|
is installed.
|
||||||
|
|
||||||
|
Note that the comamnds allow for direct writing of the 28C control lines with some exceptions to protect the chip and the host arduino:
|
||||||
|
|
||||||
|
* When the O command is used to enable chip output, the arduino data bus is set to INPUT
|
||||||
|
* When the D command is used to write data from the arduino, the chip output is disabled
|
||||||
|
* The R command sets the output enable (OE) on the chip, but not the chip enable (CE)
|
||||||
|
|
||||||
|
The session below shows how a write fails to a locked chip and then succeeds once the chip is unlocked.
|
||||||
|
|
||||||
|
```
|
||||||
|
Hardware Verifier - 28C series EEPROM
|
||||||
|
|
||||||
|
Valid commands are:
|
||||||
|
Axxxx - Set address bus to xxxx
|
||||||
|
Dxx - Set Data bus to xx
|
||||||
|
Cs - Set Chip enable to state (e=enable, d=disable)
|
||||||
|
Os - Set Output enable to state (e=enable, d=disable)
|
||||||
|
Ws - Set Write enable to state (e=enable, d=disable)
|
||||||
|
R - Read and print the value on the data bus
|
||||||
|
L - Send Lock sequence to enable device Software Data Protection
|
||||||
|
U - Send Unlock sequence to disable device Software Data Protection
|
||||||
|
|
||||||
|
#l
|
||||||
|
Writing the lock code to enable Software Write Protect mode.
|
||||||
|
|
||||||
|
#a0000
|
||||||
|
|
||||||
|
#ce
|
||||||
|
|
||||||
|
#r
|
||||||
|
22
|
||||||
|
|
||||||
|
#d55
|
||||||
|
|
||||||
|
#we
|
||||||
|
|
||||||
|
#wd
|
||||||
|
|
||||||
|
#r
|
||||||
|
22
|
||||||
|
|
||||||
|
#u
|
||||||
|
Writing the unlock code to disable Software Write Protect mode.
|
||||||
|
|
||||||
|
#d33
|
||||||
|
|
||||||
|
#we
|
||||||
|
|
||||||
|
#wd
|
||||||
|
|
||||||
|
#r
|
||||||
|
33
|
||||||
|
|
||||||
|
#cd
|
||||||
|
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user