Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 64 additions & 12 deletions SerialFlash.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@
#include <Arduino.h>
#include <SPI.h>

// supports auto growing files when writing
#define SF_FEATURE_AUTO_GROW

#define SF_OK 0
#define SF_ERROR_FAILED 1
#define SF_ERROR_WRITING 2
#define SF_ERROR_DISK_FULL 3
#define SF_ERROR_OVERFLOW 4
#define SF_ERROR_CLOSED 5

class SerialFlashFile;

class SerialFlashChip
Expand All @@ -50,18 +60,22 @@ class SerialFlashChip
static void write(uint32_t addr, const void *buf, uint32_t len);
static void eraseAll();
static void eraseBlock(uint32_t addr);
static void unprotectAll();

static SerialFlashFile open(const char *filename);
static bool create(const char *filename, uint32_t length, uint32_t align = 0);
static bool createErasable(const char *filename, uint32_t length) {
return create(filename, length, blockSize());
}
static SerialFlashFile open(const char *filename, char mode = 'r');
static SerialFlashFile create(const char *filename, uint32_t length, uint32_t align = 0);
static SerialFlashFile createErasable(const char *filename, uint32_t length);
static bool exists(const char *filename);
static bool remove(const char *filename);
static bool remove(SerialFlashFile &file);
static void opendir() { dirindex = 0; }
static bool readdir(char *filename, uint32_t strsize, uint32_t &filesize);

static uint8_t lastErr; //last error
private:
friend class SerialFlashFile;
static uint32_t totalCapacity; //flash total capacity
static bool writing; // file opened for incremental writing
static uint16_t dirindex; // current position for readdir()
static uint8_t flags; // chip features
static uint8_t busy; // 0 = ready
Expand All @@ -82,31 +96,70 @@ class SerialFlashFile
return false;
}
uint32_t read(void *buf, uint32_t rdlen) {
if (!address) {
SerialFlashChip::lastErr = SF_ERROR_CLOSED;
return 0;
}
if (offset + rdlen > length) {
if (offset >= length) return 0;
if (offset >= length) {
SerialFlashChip::lastErr = SF_ERROR_OVERFLOW;
return 0;
}
rdlen = length - offset;
}
SerialFlash.read(address + offset, buf, rdlen);
offset += rdlen;
SerialFlashChip::lastErr = SF_OK;
return rdlen;
}
char read() {
char b = -1;
read(&b, 1);
return b;
}
uint32_t write(const void *buf, uint32_t wrlen) {
if (offset + wrlen > length) {
if (offset >= length) return 0;
wrlen = length - offset;
if (!address) {
SerialFlashChip::lastErr = SF_ERROR_CLOSED;
return 0;
}
if (length > 0) {
if (offset + wrlen > length) {
if (offset >= length) {
SerialFlashChip::lastErr = SF_ERROR_OVERFLOW;
return 0;
}
wrlen = length - offset;
}
} else {
// handle auto growing
if (address + offset < SerialFlashChip::totalCapacity) {
if (address + offset + wrlen > SerialFlashChip::totalCapacity) {
wrlen = SerialFlashChip::totalCapacity - address + offset;
}
} else {
SerialFlashChip::lastErr = SF_ERROR_DISK_FULL;
return 0;
}
}

SerialFlash.write(address + offset, buf, wrlen);
offset += wrlen;
SerialFlashChip::lastErr = SF_OK;
return wrlen;
}
void seek(uint32_t n) {
// seeking is not allowed while writing to an auto growing file
if (length == 0) {
SerialFlashChip::lastErr = SF_ERROR_WRITING;
return;
}
offset = n;
}
uint32_t position() {
return offset;
}
uint32_t size() {
return length;
return length ? length : offset;
}
uint32_t available() {
if (offset >= length) return 0;
Expand All @@ -115,8 +168,7 @@ class SerialFlashFile
void erase();
void flush() {
}
void close() {
}
void close();
uint32_t getFlashAddress() {
return address;
}
Expand Down
34 changes: 31 additions & 3 deletions SerialFlashChip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
uint16_t SerialFlashChip::dirindex = 0;
uint8_t SerialFlashChip::flags = 0;
uint8_t SerialFlashChip::busy = 0;
bool SerialFlashChip::writing = false;
uint8_t SerialFlashChip::lastErr = SF_OK;
uint32_t SerialFlashChip::totalCapacity = 0;

static volatile IO_REG_TYPE *cspin_basereg;
static IO_REG_TYPE cspin_bitmask;
Expand All @@ -51,6 +54,7 @@ static SPIClass& SPIPORT = SPI;
void SerialFlashChip::wait(void)
{
uint32_t status;
uint8_t safety = 16; //prevent busy loop
//Serial.print("wait-");
while (1) {
SPIPORT.beginTransaction(SPICONFIG);
Expand All @@ -73,6 +77,11 @@ void SerialFlashChip::wait(void)
//Serial.printf("b=%02x.", status & 0xFF);
if (!(status & 1)) break;
}
safety--;
if (0 == safety) {
yield(); //prevent watchdog reset
safety = 16;
}
}
busy = 0;
//Serial.println();
Expand Down Expand Up @@ -264,6 +273,23 @@ void SerialFlashChip::eraseAll()
busy = 3;
}

void SerialFlashChip::unprotectAll()
{
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
// write enable command
SPIPORT.transfer(0x06);
CSRELEASE();
delayMicroseconds(1);
CSASSERT();
// Write status register
SPIPORT.transfer(0x01);
SPIPORT.transfer(0x02); //WEL=1, rest of the bits are 0
CSRELEASE();
SPIPORT.endTransaction();
wait();
}

void SerialFlashChip::eraseBlock(uint32_t addr)
{
uint8_t f = flags;
Expand Down Expand Up @@ -393,6 +419,7 @@ bool SerialFlashChip::begin(uint8_t pin)
}
flags = f;
readID(id);
totalCapacity = size;
return true;
}

Expand Down Expand Up @@ -453,8 +480,9 @@ uint32_t SerialFlashChip::capacity(const uint8_t *id)
{
uint32_t n = 1048576; // unknown chips, default to 1 MByte

if (id[0] == ID0_ADESTO && id[1] == 0x89) {
n = 1048576*16; //16MB
if (id[0] == ID0_ADESTO) {
//bottom 5 bits of ID1 specify capacity
n = 1ul << (15 + (id[1] & 0b11111));
} else
if (id[2] >= 16 && id[2] <= 31) {
n = 1ul << id[2];
Expand Down Expand Up @@ -526,5 +554,5 @@ AT25SF128A 32 64
// SST26VF064 8 ? BF 26 43
// LE25U40CMC 1/2 64 62 06 13
// Adesto AT25SF128A 16 1F 89 01

// Adesto AT25SF641B 8 ? 1F 88 01
SerialFlashChip SerialFlash;
Loading