mirror of
https://github.com/TomNisbet/TommyPROM.git
synced 2024-10-12 03:23:56 +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