Parcourir la source

Use SPI1 on Arduino 101

main
PaulStoffregen il y a 8 ans
Parent
révision
b6dd04096e
1 fichiers modifiés avec 96 ajouts et 86 suppressions
  1. +96
    -86
      SerialFlashChip.cpp

+ 96
- 86
SerialFlashChip.cpp Voir le fichier

@@ -32,6 +32,16 @@
#define CSRELEASE() DIRECT_WRITE_HIGH(cspin_basereg, cspin_bitmask)
#define SPICONFIG SPISettings(50000000, MSBFIRST, SPI_MODE0)

#if defined(__arc__)
// Use SPI1 on Arduino 101 (accesses chip already on the board)
#define SPIPORT SPI1
#elif 0
// Add cases here, if you wish to use other SPI ports...
#else
// Otherwise, use the normal SPI port.
#define SPIPORT SPI
#endif

uint16_t SerialFlashChip::dirindex = 0;
uint8_t SerialFlashChip::flags = 0;
uint8_t SerialFlashChip::busy = 0;
@@ -51,23 +61,23 @@ void SerialFlashChip::wait(void)
uint32_t status;
//Serial.print("wait-");
while (1) {
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
if (flags & FLAG_STATUS_CMD70) {
// some Micron chips require this different
// command to detect program and erase completion
SPI.transfer(0x70);
status = SPI.transfer(0);
SPIPORT.transfer(0x70);
status = SPIPORT.transfer(0);
CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
//Serial.printf("b=%02x.", status & 0xFF);
if ((status & 0x80)) break;
} else {
// all others work by simply reading the status reg
SPI.transfer(0x05);
status = SPI.transfer(0);
SPIPORT.transfer(0x05);
status = SPIPORT.transfer(0);
CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
//Serial.printf("b=%02x.", status & 0xFF);
if (!(status & 1)) break;
}
@@ -83,18 +93,18 @@ void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len)

memset(p, 0, len);
f = flags;
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
b = busy;
if (b) {
// read status register ... chip may no longer be busy
CSASSERT();
if (flags & FLAG_STATUS_CMD70) {
SPI.transfer(0x70);
status = SPI.transfer(0);
SPIPORT.transfer(0x70);
status = SPIPORT.transfer(0);
if ((status & 0x80)) b = 0;
} else {
SPI.transfer(0x05);
status = SPI.transfer(0);
SPIPORT.transfer(0x05);
status = SPIPORT.transfer(0);
if (!(status & 1)) b = 0;
}
CSRELEASE();
@@ -106,37 +116,37 @@ void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len)
// which apparently have 2 different suspend
// commands, for program vs erase
CSASSERT();
SPI.transfer(0x06); // write enable (Micron req'd)
SPIPORT.transfer(0x06); // write enable (Micron req'd)
CSRELEASE();
delayMicroseconds(1);
cmd = 0x75; //Suspend program/erase for almost all chips
// but Spansion just has to be different for program suspend!
if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85;
CSASSERT();
SPI.transfer(cmd); // Suspend command
SPIPORT.transfer(cmd); // Suspend command
CSRELEASE();
if (f & FLAG_STATUS_CMD70) {
// Micron chips don't actually suspend until flags read
CSASSERT();
SPI.transfer(0x70);
SPIPORT.transfer(0x70);
do {
status = SPI.transfer(0);
status = SPIPORT.transfer(0);
} while (!(status & 0x80));
CSRELEASE();
} else {
CSASSERT();
SPI.transfer(0x05);
SPIPORT.transfer(0x05);
do {
status = SPI.transfer(0);
status = SPIPORT.transfer(0);
} while ((status & 0x01));
CSRELEASE();
}
} else {
// chip is busy with an operation that can not suspend
SPI.endTransaction(); // is this a good idea?
SPIPORT.endTransaction(); // is this a good idea?
wait(); // should we wait without ending
b = 0; // the transaction??
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
}
}
do {
@@ -149,14 +159,14 @@ void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len)
CSASSERT();
// TODO: FIFO optimize....
if (f & FLAG_32BIT_ADDR) {
SPI.transfer(0x03);
SPI.transfer16(addr >> 16);
SPI.transfer16(addr);
SPIPORT.transfer(0x03);
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPI.transfer16(0x0300 | ((addr >> 16) & 255));
SPI.transfer16(addr);
SPIPORT.transfer16(0x0300 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
SPI.transfer(p, rdlen);
SPIPORT.transfer(p, rdlen);
CSRELEASE();
p += rdlen;
addr += rdlen;
@@ -164,16 +174,16 @@ void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len)
} while (len > 0);
if (b) {
CSASSERT();
SPI.transfer(0x06); // write enable (Micron req'd)
SPIPORT.transfer(0x06); // write enable (Micron req'd)
CSRELEASE();
delayMicroseconds(1);
cmd = 0x7A;
if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A;
CSASSERT();
SPI.transfer(cmd); // Resume program/erase
SPIPORT.transfer(cmd); // Resume program/erase
CSRELEASE();
}
SPI.endTransaction();
SPIPORT.endTransaction();
}

void SerialFlashChip::write(uint32_t addr, const void *buf, uint32_t len)
@@ -184,10 +194,10 @@ void SerialFlashChip::write(uint32_t addr, const void *buf, uint32_t len)
//Serial.printf("WR: addr %08X, len %d\n", addr, len);
do {
if (busy) wait();
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
// write enable command
SPI.transfer(0x06);
SPIPORT.transfer(0x06);
CSRELEASE();
max = 256 - (addr & 0xFF);
pagelen = (len <= max) ? len : max;
@@ -195,21 +205,21 @@ void SerialFlashChip::write(uint32_t addr, const void *buf, uint32_t len)
delayMicroseconds(1); // TODO: reduce this, but prefer safety first
CSASSERT();
if (flags & FLAG_32BIT_ADDR) {
SPI.transfer(0x02); // program page command
SPI.transfer16(addr >> 16);
SPI.transfer16(addr);
SPIPORT.transfer(0x02); // program page command
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPI.transfer16(0x0200 | ((addr >> 16) & 255));
SPI.transfer16(addr);
SPIPORT.transfer16(0x0200 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
addr += pagelen;
len -= pagelen;
do {
SPI.transfer(*p++);
SPIPORT.transfer(*p++);
} while (--pagelen > 0);
CSRELEASE();
busy = 4;
SPI.endTransaction();
SPIPORT.endTransaction();
} while (len > 0);
}

@@ -232,32 +242,32 @@ void SerialFlashChip::eraseAll()
if (die_index >= die_count) return; // all dies erased :-)
uint8_t die_size = 2; // in 16 Mbyte units
if (id[2] == 0x22) die_size = 8;
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPI.transfer(0x06); // write enable command
SPIPORT.transfer(0x06); // write enable command
CSRELEASE();
delayMicroseconds(1);
CSASSERT();
// die erase command
SPI.transfer(0xC4);
SPI.transfer16((die_index * die_size) << 8);
SPI.transfer16(0x0000);
SPIPORT.transfer(0xC4);
SPIPORT.transfer16((die_index * die_size) << 8);
SPIPORT.transfer16(0x0000);
CSRELEASE();
//Serial.printf("Micron erase begin\n");
flags |= (die_index + 1) << 6;
} else {
// All other chips support the bulk erase command
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
// write enable command
SPI.transfer(0x06);
SPIPORT.transfer(0x06);
CSRELEASE();
delayMicroseconds(1);
CSASSERT();
// bulk erase command
SPI.transfer(0xC7);
SPIPORT.transfer(0xC7);
CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
}
busy = 3;
}
@@ -266,22 +276,22 @@ void SerialFlashChip::eraseBlock(uint32_t addr)
{
uint8_t f = flags;
if (busy) wait();
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPI.transfer(0x06); // write enable command
SPIPORT.transfer(0x06); // write enable command
CSRELEASE();
delayMicroseconds(1);
CSASSERT();
if (f & FLAG_32BIT_ADDR) {
SPI.transfer(0xD8);
SPI.transfer16(addr >> 16);
SPI.transfer16(addr);
SPIPORT.transfer(0xD8);
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPI.transfer16(0xD800 | ((addr >> 16) & 255));
SPI.transfer16(addr);
SPIPORT.transfer16(0xD800 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
busy = 2;
}

@@ -290,23 +300,23 @@ bool SerialFlashChip::ready()
{
uint32_t status;
if (!busy) return true;
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
if (flags & FLAG_STATUS_CMD70) {
// some Micron chips require this different
// command to detect program and erase completion
SPI.transfer(0x70);
status = SPI.transfer(0);
SPIPORT.transfer(0x70);
status = SPIPORT.transfer(0);
CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
//Serial.printf("ready=%02x\n", status & 0xFF);
if ((status & 0x80) == 0) return false;
} else {
// all others work by simply reading the status reg
SPI.transfer(0x05);
status = SPI.transfer(0);
SPIPORT.transfer(0x05);
status = SPIPORT.transfer(0);
CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
//Serial.printf("ready=%02x\n", status & 0xFF);
if ((status & 1)) return false;
}
@@ -339,7 +349,7 @@ bool SerialFlashChip::begin(uint8_t pin)

cspin_basereg = PIN_TO_BASEREG(pin);
cspin_bitmask = PIN_TO_BITMASK(pin);
SPI.begin();
SPIPORT.begin();
pinMode(pin, OUTPUT);
CSRELEASE();
readID(id);
@@ -348,23 +358,23 @@ bool SerialFlashChip::begin(uint8_t pin)
if (size > 16777216) {
// more than 16 Mbyte requires 32 bit addresses
f |= FLAG_32BIT_ADDR;
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
if (id[0] == ID0_SPANSION) {
// spansion uses MSB of bank register
CSASSERT();
SPI.transfer16(0x1780); // bank register write
SPIPORT.transfer16(0x1780); // bank register write
CSRELEASE();
} else {
// micron & winbond & macronix use command
CSASSERT();
SPI.transfer(0x06); // write enable
SPIPORT.transfer(0x06); // write enable
CSRELEASE();
delayMicroseconds(1);
CSASSERT();
SPI.transfer(0xB7); // enter 4 byte addr mode
SPIPORT.transfer(0xB7); // enter 4 byte addr mode
CSRELEASE();
}
SPI.endTransaction();
SPIPORT.endTransaction();
if (id[0] == ID0_MICRON) f |= FLAG_MULTI_DIE;
}
if (id[0] == ID0_SPANSION) {
@@ -389,51 +399,51 @@ bool SerialFlashChip::begin(uint8_t pin)
void SerialFlashChip::sleep()
{
if (busy) wait();
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPI.transfer(0xB9); // Deep power down command
SPIPORT.transfer(0xB9); // Deep power down command
CSRELEASE();
}

void SerialFlashChip::wakeup()
{
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPI.transfer(0xAB); // Wake up from deep power down command
SPIPORT.transfer(0xAB); // Wake up from deep power down command
CSRELEASE();
}

void SerialFlashChip::readID(uint8_t *buf)
{
if (busy) wait();
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPI.transfer(0x9F);
buf[0] = SPI.transfer(0); // manufacturer ID
buf[1] = SPI.transfer(0); // memory type
buf[2] = SPI.transfer(0); // capacity
SPIPORT.transfer(0x9F);
buf[0] = SPIPORT.transfer(0); // manufacturer ID
buf[1] = SPIPORT.transfer(0); // memory type
buf[2] = SPIPORT.transfer(0); // capacity
if (buf[0] == ID0_SPANSION) {
buf[3] = SPI.transfer(0); // ID-CFI
buf[4] = SPI.transfer(0); // sector size
buf[3] = SPIPORT.transfer(0); // ID-CFI
buf[4] = SPIPORT.transfer(0); // sector size
}
CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
//Serial.printf("ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]);
}

void SerialFlashChip::readSerialNumber(uint8_t *buf) //needs room for 8 bytes
{
if (busy) wait();
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPI.transfer(0x4B);
SPI.transfer16(0);
SPI.transfer16(0);
SPIPORT.transfer(0x4B);
SPIPORT.transfer16(0);
SPIPORT.transfer16(0);
for (int i=0; i<8; i++) {
buf[i] = SPI.transfer(0);
buf[i] = SPIPORT.transfer(0);
}
CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
// Serial.printf("Serial Number: %02X %02X %02X %02X %02X %02X %02X %02X\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
}


Chargement…
Annuler
Enregistrer