mirror of
https://github.com/TomNisbet/TommyPROM.git
synced 2024-12-22 09:29:38 +00:00
Add support for SST28SF SuperFlash
This commit is contained in:
parent
947dc24adf
commit
035b3412af
@ -9,6 +9,7 @@
|
||||
#define PROM_IS_28C
|
||||
//#define PROM_IS_27
|
||||
//#define PROM_IS_SST39SF
|
||||
//#define PROM_IS_SST28SF
|
||||
//#define PROM_IS_8755A
|
||||
|
||||
// Don't change anything below this comment unless you are adding support for a new device type.
|
||||
@ -18,6 +19,8 @@
|
||||
#include "PromDevice27.h"
|
||||
#elif defined(PROM_IS_SST39SF)
|
||||
#include "PromDeviceSST39SF.h"
|
||||
#elif defined(PROM_IS_SST28SF)
|
||||
#include "PromDeviceSST28SF.h"
|
||||
#elif defined(PROM_IS_8755A)
|
||||
#include "PromDevice8755A.h"
|
||||
// Additional device support goes here...
|
||||
|
254
TommyPROM/PromDeviceSST28SF.cpp
Normal file
254
TommyPROM/PromDeviceSST28SF.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
#include "Configure.h"
|
||||
#if defined(PROM_IS_SST28SF)
|
||||
|
||||
#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);}
|
||||
|
||||
|
||||
PromDeviceSST28SF::PromDeviceSST28SF(uint32_t size, unsigned maxWriteTime, bool polling)
|
||||
: PromDevice(size, 0, maxWriteTime, polling),
|
||||
currentSector(0xffffffff)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void PromDeviceSST28SF::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();
|
||||
}
|
||||
|
||||
|
||||
// Turn off Software Data Protection.
|
||||
ERET PromDeviceSST28SF::disableSoftwareWriteProtect()
|
||||
{
|
||||
return sendSdpSequence(0x041a);
|
||||
}
|
||||
|
||||
// Turn on Software Data Protection.
|
||||
ERET PromDeviceSST28SF::enableSoftwareWriteProtect()
|
||||
{
|
||||
return sendSdpSequence(0x040a);
|
||||
}
|
||||
|
||||
|
||||
// Erase all 256 byte sectors containing the specified address range.
|
||||
ERET PromDeviceSST28SF::erase(uint32_t start, uint32_t end)
|
||||
{
|
||||
start >>= 8;
|
||||
end >>= 8;
|
||||
for (uint32_t sector = start; (sector <= end); sector++)
|
||||
{
|
||||
eraseSector(sector << 8);
|
||||
}
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
|
||||
// BEGIN PRIVATE METHODS
|
||||
//
|
||||
|
||||
// Use the PromAddressDriver to set an address in the two address shift registers.
|
||||
void PromDeviceSST28SF::setAddress(uint32_t address)
|
||||
{
|
||||
PromAddressDriver::setAddress(address);
|
||||
}
|
||||
|
||||
|
||||
// Read a byte from a given address
|
||||
byte PromDeviceSST28SF::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 PromDeviceSST28SF::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 & 0xffffff00) != currentSector)
|
||||
{
|
||||
eraseSector(address);
|
||||
currentSector = address & 0xffffff00;
|
||||
}
|
||||
disableOutput();
|
||||
disableWrite();
|
||||
|
||||
setDataBusMode(OUTPUT);
|
||||
enableChip();
|
||||
setByte(0x10, 0x0000);
|
||||
|
||||
setAddress(address);
|
||||
writeDataBus(value);
|
||||
|
||||
delayMicroseconds(1);
|
||||
enableWrite();
|
||||
delayMicroseconds(1);
|
||||
disableWrite();
|
||||
|
||||
status = waitForWriteCycleEnd(value);
|
||||
|
||||
disableChip();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
bool PromDeviceSST28SF::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 (unsigned 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 sector erase. This is not a complete byte write function
|
||||
// because it does not set the chip enable or the mode of the data bus.
|
||||
void PromDeviceSST28SF::setByte(byte value, uint32_t address)
|
||||
{
|
||||
setAddress(address);
|
||||
writeDataBus(value);
|
||||
|
||||
delayMicroseconds(1);
|
||||
enableWrite();
|
||||
delayMicroseconds(1);
|
||||
disableWrite();
|
||||
}
|
||||
|
||||
// Set an address value and toggle the read control. This is used for control sequences,
|
||||
// like the software write protect. This is not a complete byte read function because it
|
||||
// does not set the chip enable or the mode of the data bus.
|
||||
void PromDeviceSST28SF::getByte(uint32_t address)
|
||||
{
|
||||
setAddress(address);
|
||||
enableOutput();
|
||||
disableOutput();
|
||||
}
|
||||
|
||||
void PromDeviceSST28SF::eraseSector(uint32_t addr)
|
||||
{
|
||||
disableOutput();
|
||||
disableWrite();
|
||||
setDataBusMode(OUTPUT);
|
||||
enableChip();
|
||||
setByte(0x20, 0x0000);
|
||||
setByte(0xD0, addr & 0xffffff00);
|
||||
delay(4);
|
||||
disableChip();
|
||||
}
|
||||
|
||||
|
||||
// Software Data protection is enabled and disabled by reading a sequence of seven
|
||||
// addresses. The sequence only differs by the final address, so this common code is used
|
||||
// for both commands.
|
||||
//
|
||||
// The 2001 SST datasheet is a bit unclear on the sequence. The timing diagrams are
|
||||
// labeled as "Unprotect Disable" and "Protect Disable", which would seem to be protect
|
||||
// and unprotect, respectively. However, the softare command summary table references the
|
||||
// "Protect Disable" timing diagram for the Protect command.
|
||||
ERET PromDeviceSST28SF::sendSdpSequence(uint16_t lastAddress)
|
||||
{
|
||||
disableOutput();
|
||||
disableWrite();
|
||||
enableChip();
|
||||
setDataBusMode(INPUT);
|
||||
|
||||
getByte(0x1823);
|
||||
getByte(0x1820);
|
||||
getByte(0x1822);
|
||||
getByte(0x0418);
|
||||
getByte(0x041b);
|
||||
getByte(0x0419);
|
||||
getByte(lastAddress);
|
||||
|
||||
disableChip();
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
#endif // #if defined(PROM_IS_SST28SF)
|
41
TommyPROM/PromDeviceSST28SF.h
Normal file
41
TommyPROM/PromDeviceSST28SF.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef INCLUDE_PROM_DEVICE_SST28SF_H
|
||||
#define INCLUDE_PROM_DEVICE_SST28SF_H
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "PromDevice.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/*****************************************************************************/
|
||||
/**
|
||||
* PromDeviceSST28SF class
|
||||
*
|
||||
* Provides the device-specific interface to read and write data from an
|
||||
* SST28SF series parallel SuperFlash using the Arduino.
|
||||
*/
|
||||
class PromDeviceSST28SF : public PromDevice
|
||||
{
|
||||
public:
|
||||
PromDeviceSST28SF(uint32_t size, word unsigned maxWriteTime, bool polling);
|
||||
void begin();
|
||||
const char * getName() { return "SST28SF series SuperFlash"; }
|
||||
ERET disableSoftwareWriteProtect();
|
||||
ERET enableSoftwareWriteProtect();
|
||||
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 waitForWriteCycleEnd(byte lastValue);
|
||||
void setByte(byte value, uint32_t address);
|
||||
void getByte(uint32_t address);
|
||||
void eraseSector(uint32_t addr);
|
||||
ERET sendSdpSequence(uint16_t lastAddress);
|
||||
|
||||
|
||||
uint32_t currentSector;
|
||||
|
||||
};
|
||||
|
||||
#endif // #define INCLUDE_PROM_DEVICE_SST28SF_H
|
@ -45,12 +45,12 @@ void PromDeviceSST39SF::begin()
|
||||
}
|
||||
|
||||
|
||||
// Erase all sectors containing the specified address range.
|
||||
// Erase all 4K byte sectors containing the specified address range.
|
||||
ERET PromDeviceSST39SF::erase(uint32_t start, uint32_t end)
|
||||
{
|
||||
start >>= 12;
|
||||
end >>= 12;
|
||||
for (uint32_t sector = start; (start <= end); start++)
|
||||
for (uint32_t sector = start; (sector <= end); sector++)
|
||||
{
|
||||
eraseSector(sector << 12);
|
||||
}
|
||||
@ -95,7 +95,7 @@ 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.
|
||||
// burnByte 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)
|
||||
@ -178,10 +178,9 @@ bool PromDeviceSST39SF::waitForWriteCycleEnd(byte lastValue)
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
// Set an address and data value and toggle the write control. This is used to write
|
||||
// control sequences, like the sector erase. 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);
|
||||
|
@ -11,9 +11,6 @@
|
||||
*
|
||||
* 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
|
||||
{
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "XModem.h"
|
||||
|
||||
|
||||
static const char * MY_VERSION = "3.1";
|
||||
static const char * MY_VERSION = "3.2";
|
||||
|
||||
|
||||
// Global status
|
||||
@ -53,10 +53,17 @@ PromDevice27 prom(32 * 1024L, E27C_PGM_CE, 100L, 25, 0); // 27C257/27E257 with
|
||||
#elif defined(PROM_IS_SST39SF)
|
||||
// Define a device for anSST39SF Flash with the following parameters:
|
||||
// 512K byte device capacity
|
||||
// 10ms max write time
|
||||
// 10us max write time
|
||||
// Data polling supported
|
||||
PromDeviceSST39SF prom(512 * 1024L, 10, true);
|
||||
|
||||
#elif defined(PROM_IS_SST28SF)
|
||||
// Define a device for anSST28SF Flash with the following parameters:
|
||||
// 512K byte device capacity
|
||||
// 40us max write time
|
||||
// Data polling supported
|
||||
PromDeviceSST28SF prom(512 * 1024L, 40, 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);
|
||||
@ -499,6 +506,7 @@ void pokeBytes(char * pCursor)
|
||||
void printRetStatus(ERET status)
|
||||
{
|
||||
switch (status) {
|
||||
case RET_OK: Serial.println(F("OK")); break;
|
||||
case RET_FAIL: Serial.println(F("FAILED")); break;
|
||||
case RET_NOT_SUPPORT: Serial.println(F("NOT SUPPORTED")); break;
|
||||
}
|
||||
|
@ -71,12 +71,13 @@ a version of the programer that supports these chips.
|
||||
|
||||
## Atmel SST39FS Flash
|
||||
|
||||
TommyPROM has a driver for Atmel SST39FS flash chips. This driver replaces the 28C driver at compile time. See configure.h to enable a different driver.
|
||||
TommyPROM has a driver for Atmel SST39FS NOR flash chips. This driver replaces the 28C
|
||||
driver at compile time. See configure.h to enable a different driver.
|
||||
|
||||
The SST39FS chips use fixed 2KB sectors that must be manually erased before a new program
|
||||
The SST39FS chips use fixed 4KB sectors that must be manually erased before a new program
|
||||
operation, but the code manages this transparently. Whenever a write is started to a new
|
||||
segment, the driver first initiates an erase of that sector. A second write to the same
|
||||
sector will not cause an erase, so is is possible to write to a segment multiple times
|
||||
sector will not cause an erase, so it is possible to write to a segment multiple times
|
||||
with no additional steps as long as the writes are to different parts of the sector. For
|
||||
example, 256 bytes could be written to the start of a sector from one file and then 512
|
||||
bytes could be written to the end of the sector from another file.
|
||||
@ -88,6 +89,14 @@ The SST39FS driver supports a manual erase from the command line using the E com
|
||||
This is only needed if data will be rewritten to the same location after a previous write
|
||||
to that sector.
|
||||
|
||||
There is also a driver for the SST28SF0x0 SuperFlash chips. These are an earlier version
|
||||
of the 39SF chips, using 256-byte sectors. The 28SF and 39SF chips are pin compatible,
|
||||
but use different command sets for programming and erasing. For read-only applications,
|
||||
they should be identical, although the 28SF are slower.
|
||||
|
||||
All programming and erase operations for both the 39SF and 28SF chips require only a
|
||||
single 5V power supply.
|
||||
|
||||
## Misc Flash
|
||||
|
||||
#### 29C Series
|
||||
@ -152,6 +161,7 @@ The 8755 build of TommyPROM also has a circuit to control the 25V programming pu
|
||||
|:--- |:--- |:--- |:--- |:--- |
|
||||
|AT28C256 |Atmel, others|EEPROM |28C |Fully supported|
|
||||
|SST39SF040|Microchip |Flash |SST39SF|All SST39SF0x0 supported|
|
||||
|SST28SF040|SST |Flash | |All SST28SF0x0 supported|
|
||||
|WE27C257 |Winbond |EEPROM |27 |Continual 12V or 14V for program/erase|
|
||||
|AT29C010 |Atmel |Flash |28C |Only with 128 byte or less sector size|
|
||||
|8755A |Intel |EPROM |8755A |Requires 25V pulses to program|
|
||||
@ -178,6 +188,13 @@ writing new data. The code keeps track of the current sector and will automatic
|
||||
an erase operation whenever a write starts to a new sector. The _Erase_ command is
|
||||
supported, but is not needed unless overwriting new data to a single sector.
|
||||
|
||||
#### SST28SF040
|
||||
|
||||
This is an earlier version of the SST39SF series chips. They are pin compatible with the
|
||||
39SF series, but use a different command set for programming. Unlike the 39SF, these
|
||||
flash chips support software data protection. The _Lock_ and _Unlock_ commands can be
|
||||
used to enable and disable SDP from the command line.
|
||||
|
||||
#### 27C257
|
||||
|
||||
The Winbond WE27C257 and WE27E257 appear to be identical 32Kx8 EEPROMs. The 27C version
|
||||
@ -212,4 +229,3 @@ for chips with the 256 byte buffer.
|
||||
|:--- |:--- |:--- |:--- |:--- |
|
||||
|M27C4001 |ST Micro |EEPROM | |VCC=6.5V, VPP=12.75V to pgm|
|
||||
|SST27SF020|SST |Flash | |12V continuous for pgm/erase|
|
||||
|SST28SF040|SST |Flash | |5V with cmds|
|
||||
|
Loading…
Reference in New Issue
Block a user