device support for 27E257/27C257

This commit is contained in:
Tom Nisbet 2022-12-10 11:18:52 -05:00
parent fc42ef50e1
commit c6b91d0768
10 changed files with 168 additions and 28 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
.vscode/
.DS_Store
wip/

View File

@ -14,6 +14,13 @@
* Block writes are supported on compatible devices by specifying a blockSize
* in the constructor. Use zero for devices that only support byte writes.
*/
enum ERET {
RET_OK,
RET_FAIL,
RET_NOT_SUPPORT
};
class PromDevice
{
public:
@ -25,9 +32,9 @@ class PromDevice
virtual void begin() = 0;
virtual const char * getName() = 0;
virtual void disableSoftwareWriteProtect() {}
virtual void enableSoftwareWriteProtect() {}
virtual bool erase(uint32_t start, uint32_t end) { return false; }
virtual ERET disableSoftwareWriteProtect() { return RET_NOT_SUPPORT; }
virtual ERET enableSoftwareWriteProtect() { return RET_NOT_SUPPORT; }
virtual ERET erase(uint32_t start, uint32_t end) { return RET_NOT_SUPPORT; }
uint32_t debugBlockWrites; // Number of block write operations
uint32_t debugLastAddress; // Last address with an issue

View File

@ -21,9 +21,10 @@ static void enableWrite() { digitalWrite(WE, LOW); }
static void disableWrite() { digitalWrite(WE, HIGH);}
PromDevice27::PromDevice27(uint32_t size, unsigned long pulseWidthUsec,
PromDevice27::PromDevice27(uint32_t size, E27C_PGM pgmType, unsigned long pulseWidthUsec,
unsigned writeAttempts, unsigned overwriteMultiplier)
: PromDevice(size, 0, 0, false),
mPgmType(pgmType),
mPulseWidthUsec(pulseWidthUsec),
mWriteAttempts(writeAttempts),
mOverwriteMultiplier(overwriteMultiplier)
@ -81,6 +82,19 @@ byte PromDevice27::readByte(uint32_t address)
// Burn a byte to the chip and verify that it was written.
bool PromDevice27::burnByte(byte value, uint32_t address)
{
switch(mPgmType) {
case E27C_PGM_WE: return burnByteWE(value, address); break;
case E27C_PGM_CE: return burnByteCE(value, address); break;
default: return false; // PGM_D13 not implemented yet
}
}
// Burn a byte to the chip and verify that it was written.
// This uses a dedicated WE or PGM chip that operates on TTL levels and is active LOW.
// Overwrite burning is supported.
bool PromDevice27::burnByteWE(byte value, uint32_t address)
{
bool status = false;
unsigned writeCount = 0;
@ -123,6 +137,91 @@ bool PromDevice27::burnByte(byte value, uint32_t address)
return status;
}
// Burn a byte to the chip and verify that it was written.
// This uses an active LOW program pulse on the CE line and a verify operation with CE
// HIGH. Overwrite is not supported, but could be added is a chip is found that needs it.
// Chips that use this mode require a programming voltage on the PGM pin and possibly on
// other pins as well.
//
// VCC may also have a non-standard voltage in program mode. Be sure to separate the
// PROM's VCC line from system VCC if a non-standard voltage is used.
bool PromDevice27::burnByteCE(byte value, uint32_t address)
{
bool status = false;
unsigned writeCount = 0;
byte data = 0;
disableOutput();
disableWrite();
disableChip();
setAddress(address);
while (!status && (writeCount < mWriteAttempts))
{
setDataBusMode(OUTPUT);
writeDataBus(value);
delayMicroseconds(2);
enableChip();
myDelay(mPulseWidthUsec);
disableChip();
delayMicroseconds(2);
++writeCount;
setDataBusMode(INPUT);
enableOutput();
data = readDataBus();
disableOutput();
status = (readDataBus() == value);
}
return status;
}
ERET PromDevice27::erase(uint32_t start, uint32_t end)
{
if (mPgmType != E27C_PGM_CE) return RET_NOT_SUPPORT;
// Erase code for the 27E257 and 27C257. The Vpp and A9 pins are held at 14V for the
// erase and verify cycle. This erases the entire chip, so the start and end address
// parameters are ignored.
disableChip();
disableOutput();
setAddress(0);
setDataBusMode(OUTPUT);
writeDataBus(0xff);
delayMicroseconds(2);
unsigned writeCount = 0;
ERET status = RET_FAIL;
while ((status == RET_FAIL) && (writeCount < mWriteAttempts)) {
setAddress(0);
setDataBusMode(OUTPUT);
writeDataBus(0xff);
delayMicroseconds(2);
enableChip();
delay(100);
disableChip();
delayMicroseconds(2);
// Read back the data to verify all cells are erased. Note That this is done
// while CE is HIGH. This is the erase verify mode.
setDataBusMode(INPUT);
for (uint32_t address = 0; (address < mSize); address++) {
setAddress(address);
enableOutput();
uint8_t b = readDataBus();
disableOutput();
if (b != 0xff) break;
}
status = RET_OK;
}
return status;
}
void PromDevice27::myDelay(unsigned int us)
{
if (us > 16000)
@ -140,4 +239,3 @@ void PromDevice27::myDelay(unsigned int us)
#endif // #if defined(PROM_IS_27)

View File

@ -25,24 +25,35 @@
* See the constructor definition for an explanation of the parameters that
* control programming.
*/
enum E27C_PGM {
E27C_PGM_WE, // Dedicated WE or PGM pin that is active LOW
E27C_PGM_CE, // CE is pulsed low to program, CE HIGH for verify
E27C_PGM_D13 // Program voltage pulse switched using Arduino D13 pin
};
class PromDevice27 : public PromDevice
{
public:
PromDevice27(uint32_t size, unsigned long mPulseWidthUsec, unsigned writeAttempts, unsigned overwriteMultiplier);
PromDevice27(uint32_t size, E27C_PGM pgmType, unsigned long pulseWidthUsec,
unsigned writeAttempts, unsigned overwriteMultiplier);
void begin();
const char * getName() { return "27 series EPROM"; }
ERET erase(uint32_t start, uint32_t end);
protected:
void setAddress(uint32_t address);
byte readByte(uint32_t address);
bool burnByte(byte value, uint32_t address);
bool burnByteWE(byte value, uint32_t address);
bool burnByteCE(byte value, uint32_t address);
void myDelay(unsigned int us);
E27C_PGM mPgmType;
unsigned long mPulseWidthUsec;
unsigned mWriteAttempts;
unsigned mOverwriteMultiplier;
};
#endif // #define INCLUDE_PROM_DEVICE_27_H

View File

@ -45,7 +45,7 @@ void PromDevice28C::begin()
// Write the special six-byte code to turn off Software Data Protection.
void PromDevice28C::disableSoftwareWriteProtect()
ERET PromDevice28C::disableSoftwareWriteProtect()
{
disableOutput();
disableWrite();
@ -61,11 +61,13 @@ void PromDevice28C::disableSoftwareWriteProtect()
setDataBusMode(INPUT);
disableChip();
return RET_OK;
}
// Write the special three-byte code to turn on Software Data Protection.
void PromDevice28C::enableSoftwareWriteProtect()
ERET PromDevice28C::enableSoftwareWriteProtect()
{
disableOutput();
disableWrite();
@ -78,6 +80,8 @@ void PromDevice28C::enableSoftwareWriteProtect()
setDataBusMode(INPUT);
disableChip();
return RET_OK;
}

View File

@ -21,8 +21,8 @@ class PromDevice28C : public PromDevice
PromDevice28C(uint32_t size, word blockSize, unsigned maxWriteTime, bool polling);
void begin();
const char * getName() { return "28C series EEPROM"; }
void disableSoftwareWriteProtect();
void enableSoftwareWriteProtect();
ERET disableSoftwareWriteProtect();
ERET enableSoftwareWriteProtect();
protected:
void setAddress(uint32_t address);
@ -34,4 +34,3 @@ class PromDevice28C : public PromDevice
};
#endif // #define INCLUDE_PROM_DEVICE_28C_H

View File

@ -46,7 +46,7 @@ void PromDeviceSST39SF::begin()
// Erase all sectors containing the specified address range.
bool PromDeviceSST39SF::erase(uint32_t start, uint32_t end)
ERET PromDeviceSST39SF::erase(uint32_t start, uint32_t end)
{
start >>= 12;
end >>= 12;
@ -55,7 +55,7 @@ bool PromDeviceSST39SF::erase(uint32_t start, uint32_t end)
eraseSector(sector << 12);
}
return true;
return RET_OK;
}

View File

@ -21,7 +21,7 @@ class PromDeviceSST39SF : public PromDevice
PromDeviceSST39SF(uint32_t size, word unsigned maxWriteTime, bool polling);
void begin();
const char * getName() { return "SST39SF series NOR Flash"; }
bool erase(uint32_t start, uint32_t end);
ERET erase(uint32_t start, uint32_t end);
protected:

View File

@ -19,7 +19,7 @@
#include "XModem.h"
static const char * MY_VERSION = "3.0";
static const char * MY_VERSION = "3.1";
// Global status
@ -35,17 +35,20 @@ CmdStatus cmdStatus;
// 10ms max write time
// Data polling supported
PromDevice28C prom(32 * 1024L, 64, 10, true);
//PromDevice28C prom(8 * 1024L, 0, 10, true); // 28C64 with no page writes
#elif defined(PROM_IS_27)
// Define a device for a 2764 EPROM with the following parameters:
// 8K byte device capacity
// PGM pin pulses active LOW
// 1000us (1ms) write pulse
// 15 write attempts
// 4x overwrite pulse
PromDevice27 prom(8 * 1024L, 1000L, 15, 4); // 2764 with SEEQ intelligent programming
//PromDevice27 prom(32 * 1024L, 1000L, 25, 3); // 27C256 with SEEQ intelligent programming
//PromDevice27 prom(2 * 1024L, 50000L, 1, 0); // 2716 with single 50ms write
//PromDevice27 prom(64 * 1024L, 100L, 11, 0); // 27C040 with Atmel rapid programming
//PromDevice27 prom(8 * 1024L, E27C_PGM_WE, 1000L, 15, 4); // 2764 with SEEQ intelligent programming
//PromDevice27 prom(32 * 1024L, E27C_PGM_WE, 1000L, 25, 3); // 27C256 with SEEQ intelligent programming
//PromDevice27 prom(2 * 1024L, E27C_PGM_WE, 50000L, 1, 0); // 2716 with single 50ms write
//PromDevice27 prom(64 * 1024L, E27C_PGM_WE, 100L, 11, 0); // 27C040 with Atmel rapid programming
PromDevice27 prom(32 * 1024L, E27C_PGM_CE, 100L, 25, 0); // 27C257/27E257 with 100uS program pulse on CE
#elif defined(PROM_IS_SST39SF)
// Define a device for anSST39SF Flash with the following parameters:
@ -493,7 +496,13 @@ void pokeBytes(char * pCursor)
cmdStatus.info("Poke successful");
}
void printRetStatus(ERET status)
{
switch (status) {
case RET_FAIL: Serial.println(F("FAILED")); break;
case RET_NOT_SUPPORT: Serial.println(F("NOT SUPPORTED")); break;
}
}
#ifdef ENABLE_DEBUG_COMMANDS
/**
@ -686,7 +695,7 @@ void loop()
break;
case CMD_ERASE:
prom.erase(start, end);
printRetStatus(prom.erase(start, end));
break;
case CMD_FILL:
@ -695,8 +704,8 @@ void loop()
break;
case CMD_LOCK:
Serial.println(F("Writing the lock code to enable Software Write Protect mode."));
prom.enableSoftwareWriteProtect();
Serial.print(F("Writing the lock code to enable Software Write Protect mode: "));
printRetStatus(prom.enableSoftwareWriteProtect());
break;
case CMD_POKE:
@ -713,8 +722,8 @@ void loop()
break;
case CMD_UNLOCK:
Serial.println(F("Writing the unlock code to disable Software Write Protect mode."));
prom.disableSoftwareWriteProtect();
Serial.print(F("Writing the unlock code to disable Software Write Protect mode: "));
printRetStatus(prom.disableSoftwareWriteProtect());
break;
case CMD_WRITE:

View File

@ -21,11 +21,12 @@ support for programming.
## EEPROM - Electrically Erasable Programmable Read-only Memory
EEPROMs are the easiest PROMs to use. They usually can be erased and reprogrammed
EEPROMs are the easiest PROMs to use. Modern EEPROMs usually can be erased and reprogrammed
electrically at the individual byte level. This makes them appear similar to a slower
static RAM. All of the interactive features of TommyPROM work well with EEPROMs. Due
to their complexity, EEPROMs typically come in smaller sizes than other technologies.
The largest EEPROM in the 28C family is 32K bytes.
The largest EEPROM in the 28C family is 32K bytes. Some older EEPROMs cannot be reprogrammed at the individual byte level and are instead bulk erased before a new write
operation. Programming and erasing for these chips usually requires voltages higher than 5V.
## Flash ROM
@ -144,3 +145,13 @@ address lines. The Arduino has enough pins to drive all of these directly, with
need for shift registers to create address lines.
The 8755 build of TommyPROM also has a circuit to control the 25V programming pulses.
# Verified Chips
|Model |Manufacturer |Type |Module |Notes|
|:--- |:--- |:--- |:--- |:--- |
|28C256 |Atmel, others|EEPROM |28C |Fully supported|
|SST39SF040|Microchip |Flash |SST39SF|All SST39SF0x0 supported|
|27E257 | |EEPROM |27 |Continual 12V or 14V for program/erase|
|29C010 | |Flash |28C |Only with 128 byte or less sector size|
|8755A |Intel |EPROM |8755A |Requires 25V pulses to program|