forked from Apple-2-HW/TommyPROM
Add preliminary support for SST39SF flash
This commit is contained in:
parent
7483cc5b59
commit
fb877244c1
@ -8,6 +8,7 @@
|
||||
|
||||
#define PROM_IS_28C
|
||||
//#define PROM_IS_27
|
||||
//#define PROM_IS_SST39SF
|
||||
//#define PROM_IS_8755A
|
||||
|
||||
// Don't change anything below this comment unless you are adding support for a new device type.
|
||||
@ -15,6 +16,8 @@
|
||||
#include "PromDevice28C.h"
|
||||
#elif defined(PROM_IS_27)
|
||||
#include "PromDevice27.h"
|
||||
#elif defined(PROM_IS_SST39SF)
|
||||
#include "PromDeviceSST39SF.h"
|
||||
#elif defined(PROM_IS_8755A)
|
||||
#include "PromDevice8755A.h"
|
||||
// Additional device support goes here...
|
||||
|
@ -27,6 +27,7 @@ class PromDevice
|
||||
virtual const char * getName() = 0;
|
||||
virtual void disableSoftwareWriteProtect() {}
|
||||
virtual void enableSoftwareWriteProtect() {}
|
||||
virtual bool erase(uint32_t start, uint32_t end) { return false; }
|
||||
|
||||
uint32_t debugBlockWrites; // Number of block write operations
|
||||
uint32_t debugLastAddress; // Last address with an issue
|
||||
|
252
TommyPROM/PromDeviceSST39SF.cpp
Normal file
252
TommyPROM/PromDeviceSST39SF.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
#include "Configure.h"
|
||||
#if defined(PROM_IS_SST39SF)
|
||||
|
||||
#include "PromAddressDriver.h"
|
||||
|
||||
// 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
|
||||
|
||||
// Set the status of the device control pins
|
||||
static void enableChip() { digitalWrite(CE, LOW); }
|
||||
static void disableChip() { digitalWrite(CE, HIGH);}
|
||||
static void enableOutput() { digitalWrite(OE, LOW); }
|
||||
static void disableOutput() { digitalWrite(OE, HIGH);}
|
||||
static void enableWrite() { digitalWrite(WE, LOW); }
|
||||
static void disableWrite() { digitalWrite(WE, HIGH);}
|
||||
|
||||
|
||||
PromDeviceSST39SF::PromDeviceSST39SF(uint32_t size, unsigned maxWriteTime, bool polling)
|
||||
: PromDevice(size, 0, maxWriteTime, polling),
|
||||
currentSector(0xffffffff)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void PromDeviceSST39SF::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 PromDeviceSST39SF::disableSoftwareWriteProtect()
|
||||
{
|
||||
disableOutput();
|
||||
disableWrite();
|
||||
enableChip();
|
||||
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 PromDeviceSST39SF::enableSoftwareWriteProtect()
|
||||
{
|
||||
disableOutput();
|
||||
disableWrite();
|
||||
enableChip();
|
||||
setDataBusMode(OUTPUT);
|
||||
|
||||
setByte(0xaa, 0x5555);
|
||||
setByte(0x55, 0x2aaa);
|
||||
setByte(0xa0, 0x5555);
|
||||
|
||||
setDataBusMode(INPUT);
|
||||
disableChip();
|
||||
}
|
||||
|
||||
|
||||
// Erase all sectors containing the specified address range.
|
||||
bool PromDeviceSST39SF::erase(uint32_t start, uint32_t end)
|
||||
{
|
||||
start >>= 12;
|
||||
end >>= 12;
|
||||
for (uint32_t sector = start; (start <= end); start++)
|
||||
{
|
||||
eraseSector(sector << 12);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// BEGIN PRIVATE METHODS
|
||||
//
|
||||
|
||||
// Use the PromAddressDriver to set an address in the two address shift registers.
|
||||
void PromDeviceSST39SF::setAddress(uint32_t address)
|
||||
{
|
||||
PromAddressDriver::setAddress(address);
|
||||
}
|
||||
|
||||
|
||||
// Read a byte from a given address
|
||||
byte PromDeviceSST39SF::readByte(uint32_t 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 PromDeviceSST39SF::burnByte(byte value, uint32_t address)
|
||||
{
|
||||
bool status = false;
|
||||
|
||||
// Erase a sector before writing any new data to it. Note that multiple
|
||||
// burbByte calls to the same sector will only do an erase on the first call.
|
||||
// If multiple burn calls will be needed for the same address, it is up to the
|
||||
// caller to erase the sector before writing.
|
||||
if ((address & 0xfffff000) != currentSector)
|
||||
{
|
||||
eraseSector(address);
|
||||
currentSector = address & 0xfffff000;
|
||||
}
|
||||
disableOutput();
|
||||
disableWrite();
|
||||
|
||||
setDataBusMode(OUTPUT);
|
||||
enableChip();
|
||||
setByte(0xaa, 0x5555);
|
||||
setByte(0x55, 0x2aaa);
|
||||
setByte(0xa0, 0x5555);
|
||||
|
||||
|
||||
setAddress(address);
|
||||
setDataBusMode(OUTPUT);
|
||||
writeDataBus(value);
|
||||
|
||||
//enableChip();
|
||||
delayMicroseconds(1);
|
||||
enableWrite();
|
||||
delayMicroseconds(1);
|
||||
disableWrite();
|
||||
|
||||
status = waitForWriteCycleEnd(value);
|
||||
|
||||
disableChip();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
bool PromDeviceSST39SF::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.
|
||||
//
|
||||
// This loop code takes about 18uSec to execute. The max readcount is set to the
|
||||
// device's maxReadTime (in uSecs) divided by ten rather than eighteen to ensure
|
||||
// that it runs at least as long as the chip's timeout value, even if some code
|
||||
// optimizations are made later. In actual practice, the loop will terminate much
|
||||
// earlier because it will detect the end of the write well before the max time.
|
||||
byte b1=0, b2=0;
|
||||
setDataBusMode(INPUT);
|
||||
delayMicroseconds(1);
|
||||
for (int readCount = 1; (readCount < (mMaxWriteTime * 100)); readCount++)
|
||||
{
|
||||
enableChip();
|
||||
enableOutput();
|
||||
delayMicroseconds(1);
|
||||
b1 = readDataBus();
|
||||
disableOutput();
|
||||
disableChip();
|
||||
enableChip();
|
||||
enableOutput();
|
||||
delayMicroseconds(1);
|
||||
b2 = readDataBus();
|
||||
disableOutput();
|
||||
disableChip();
|
||||
if ((b1 == b2) && (b1 == lastValue))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
debugLastExpected = lastValue;
|
||||
debugLastReadback = b2;
|
||||
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 PromDeviceSST39SF::setByte(byte value, uint32_t address)
|
||||
{
|
||||
setAddress(address);
|
||||
writeDataBus(value);
|
||||
|
||||
delayMicroseconds(1);
|
||||
enableWrite();
|
||||
delayMicroseconds(1);
|
||||
disableWrite();
|
||||
}
|
||||
|
||||
void PromDeviceSST39SF::eraseSector(uint32_t addr)
|
||||
{
|
||||
disableOutput();
|
||||
disableWrite();
|
||||
|
||||
setDataBusMode(OUTPUT);
|
||||
enableChip();
|
||||
setByte(0xaa, 0x5555);
|
||||
setByte(0x55, 0x2aaa);
|
||||
setByte(0x80, 0x5555);
|
||||
setByte(0xaa, 0x5555);
|
||||
setByte(0x55, 0x2aaa);
|
||||
setByte(0x30, addr & 0xfffff000);
|
||||
delay(25);
|
||||
disableChip();
|
||||
}
|
||||
|
||||
#endif // #if defined(PROM_IS_SST39SF)
|
41
TommyPROM/PromDeviceSST39SF.h
Normal file
41
TommyPROM/PromDeviceSST39SF.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef INCLUDE_PROM_DEVICE_SST39SF_H
|
||||
#define INCLUDE_PROM_DEVICE_SST39SF_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "PromDevice.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* PromDeviceSST39SF class
|
||||
*
|
||||
* Provides the device-specific interface to read and write data from an
|
||||
* SST39SF series parallel NOR Flash using the Arduino.
|
||||
*
|
||||
* Block writes are supported on compatible devices by specifying a blockSize
|
||||
* in the constructor. Use zero for byte writes.
|
||||
*/
|
||||
class PromDeviceSST39SF : public PromDevice
|
||||
{
|
||||
public:
|
||||
PromDeviceSST39SF(uint32_t size, word unsigned maxWriteTime, bool polling);
|
||||
void begin();
|
||||
const char * getName() { return "SST39SF series NOR Flash"; }
|
||||
void disableSoftwareWriteProtect();
|
||||
void enableSoftwareWriteProtect();
|
||||
bool 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 waitForWriteCycleEnd(byte lastValue);
|
||||
void setByte(byte value, uint32_t address);
|
||||
void eraseSector(uint32_t addr);
|
||||
|
||||
uint32_t currentSector;
|
||||
|
||||
};
|
||||
|
||||
#endif // #define INCLUDE_PROM_DEVICE_SST39SF_H
|
@ -19,7 +19,7 @@
|
||||
#include "XModem.h"
|
||||
|
||||
|
||||
static const char * MY_VERSION = "2.7";
|
||||
static const char * MY_VERSION = "2.8";
|
||||
|
||||
|
||||
// Global status
|
||||
@ -47,6 +47,13 @@ PromDevice27 prom(8 * 1024L, 1000L, 15, 4); // 2764 with SEEQ intelligent prog
|
||||
//PromDevice27 prom(2 * 1024L, 50000L, 1, 0); // 2716 with single 50ms write
|
||||
//PromDevice27 prom(64 * 1024L, 100L, 11, 0); // 27C040 with Atmel rapid programming
|
||||
|
||||
#elif defined(PROM_IS_SST39SF)
|
||||
// Define a device for anSST39SF Flash with the following parameters:
|
||||
// 512K byte device capacity
|
||||
// 10ms max write time
|
||||
// Data polling supported
|
||||
PromDeviceSST39SF prom(512 * 1024L, 10, true);
|
||||
|
||||
#elif defined(PROM_IS_8755A)
|
||||
// Define a device for an Intel 8755A with a fixed size of 2K and no other parameters.
|
||||
PromDevice8755A prom(2 * 1024L);
|
||||
@ -74,9 +81,10 @@ const char hex[] = "0123456789abcdef";
|
||||
enum {
|
||||
// CLI Commands
|
||||
CMD_INVALID,
|
||||
CMD_BLANK,
|
||||
CMD_CHECKSUM,
|
||||
CMD_DUMP,
|
||||
CMD_ERASED,
|
||||
CMD_ERASE,
|
||||
CMD_FILL,
|
||||
CMD_LOCK,
|
||||
CMD_POKE,
|
||||
@ -133,9 +141,10 @@ byte parseCommand(char c)
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'b': cmd = CMD_BLANK; break;
|
||||
case 'c': cmd = CMD_CHECKSUM; break;
|
||||
case 'd': cmd = CMD_DUMP; break;
|
||||
case 'e': cmd = CMD_ERASED; break;
|
||||
case 'e': cmd = CMD_ERASE; break;
|
||||
case 'f': cmd = CMD_FILL; break;
|
||||
case 'l': cmd = CMD_LOCK; break;
|
||||
case 'p': cmd = CMD_POKE; break;
|
||||
@ -657,6 +666,10 @@ void loop()
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case CMD_BLANK:
|
||||
erasedBlockCheck(start, end);
|
||||
break;
|
||||
|
||||
case CMD_CHECKSUM:
|
||||
w = checksumBlock(start, end);
|
||||
Serial.print(F("Checksum "));
|
||||
@ -672,8 +685,8 @@ void loop()
|
||||
dumpBlock(start, end);
|
||||
break;
|
||||
|
||||
case CMD_ERASED:
|
||||
erasedBlockCheck(start, end);
|
||||
case CMD_ERASE:
|
||||
prom.erase(start, end);
|
||||
break;
|
||||
|
||||
case CMD_FILL:
|
||||
@ -748,9 +761,10 @@ void loop()
|
||||
Serial.println(prom.getName());
|
||||
Serial.println();
|
||||
Serial.println(F("Valid commands are:"));
|
||||
Serial.println(F(" Bsssss eeeee - Check to see if device range is Blank/erased (all FF)"));
|
||||
Serial.println(F(" Csssss eeeee - Compute checksum from device"));
|
||||
Serial.println(F(" Dsssss eeeee - Dump bytes from device to terminal"));
|
||||
Serial.println(F(" Esssss eeeee - Check to see if device range is Erased (all FF)"));
|
||||
Serial.println(F(" Esssss eeeee - Erase address range on device (needed for some Flash)"));
|
||||
Serial.println(F(" Fsssss eeeee dd - Fill block on device with fixed value"));
|
||||
Serial.println(F(" L - Lock (enable) device Software Data Protection"));
|
||||
Serial.println(F(" Psssss dd dd... - Poke (write) values to device (up to 32 values)"));
|
||||
|
Loading…
Reference in New Issue
Block a user