Переглянути джерело

Use SPI1 on Arduino 101

main
PaulStoffregen 8 роки тому
джерело
коміт
b6dd04096e
1 змінених файлів з 96 додано та 86 видалено
  1. +96
    -86
      SerialFlashChip.cpp

+ 96
- 86
SerialFlashChip.cpp Переглянути файл

#define CSRELEASE() DIRECT_WRITE_HIGH(cspin_basereg, cspin_bitmask) #define CSRELEASE() DIRECT_WRITE_HIGH(cspin_basereg, cspin_bitmask)
#define SPICONFIG SPISettings(50000000, MSBFIRST, SPI_MODE0) #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; uint16_t SerialFlashChip::dirindex = 0;
uint8_t SerialFlashChip::flags = 0; uint8_t SerialFlashChip::flags = 0;
uint8_t SerialFlashChip::busy = 0; uint8_t SerialFlashChip::busy = 0;
uint32_t status; uint32_t status;
//Serial.print("wait-"); //Serial.print("wait-");
while (1) { while (1) {
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT(); CSASSERT();
if (flags & FLAG_STATUS_CMD70) { if (flags & FLAG_STATUS_CMD70) {
// some Micron chips require this different // some Micron chips require this different
// command to detect program and erase completion // command to detect program and erase completion
SPI.transfer(0x70);
status = SPI.transfer(0);
SPIPORT.transfer(0x70);
status = SPIPORT.transfer(0);
CSRELEASE(); CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
//Serial.printf("b=%02x.", status & 0xFF); //Serial.printf("b=%02x.", status & 0xFF);
if ((status & 0x80)) break; if ((status & 0x80)) break;
} else { } else {
// all others work by simply reading the status reg // all others work by simply reading the status reg
SPI.transfer(0x05);
status = SPI.transfer(0);
SPIPORT.transfer(0x05);
status = SPIPORT.transfer(0);
CSRELEASE(); CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
//Serial.printf("b=%02x.", status & 0xFF); //Serial.printf("b=%02x.", status & 0xFF);
if (!(status & 1)) break; if (!(status & 1)) break;
} }


memset(p, 0, len); memset(p, 0, len);
f = flags; f = flags;
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
b = busy; b = busy;
if (b) { if (b) {
// read status register ... chip may no longer be busy // read status register ... chip may no longer be busy
CSASSERT(); CSASSERT();
if (flags & FLAG_STATUS_CMD70) { if (flags & FLAG_STATUS_CMD70) {
SPI.transfer(0x70);
status = SPI.transfer(0);
SPIPORT.transfer(0x70);
status = SPIPORT.transfer(0);
if ((status & 0x80)) b = 0; if ((status & 0x80)) b = 0;
} else { } else {
SPI.transfer(0x05);
status = SPI.transfer(0);
SPIPORT.transfer(0x05);
status = SPIPORT.transfer(0);
if (!(status & 1)) b = 0; if (!(status & 1)) b = 0;
} }
CSRELEASE(); CSRELEASE();
// which apparently have 2 different suspend // which apparently have 2 different suspend
// commands, for program vs erase // commands, for program vs erase
CSASSERT(); CSASSERT();
SPI.transfer(0x06); // write enable (Micron req'd)
SPIPORT.transfer(0x06); // write enable (Micron req'd)
CSRELEASE(); CSRELEASE();
delayMicroseconds(1); delayMicroseconds(1);
cmd = 0x75; //Suspend program/erase for almost all chips cmd = 0x75; //Suspend program/erase for almost all chips
// but Spansion just has to be different for program suspend! // but Spansion just has to be different for program suspend!
if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85; if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85;
CSASSERT(); CSASSERT();
SPI.transfer(cmd); // Suspend command
SPIPORT.transfer(cmd); // Suspend command
CSRELEASE(); CSRELEASE();
if (f & FLAG_STATUS_CMD70) { if (f & FLAG_STATUS_CMD70) {
// Micron chips don't actually suspend until flags read // Micron chips don't actually suspend until flags read
CSASSERT(); CSASSERT();
SPI.transfer(0x70);
SPIPORT.transfer(0x70);
do { do {
status = SPI.transfer(0);
status = SPIPORT.transfer(0);
} while (!(status & 0x80)); } while (!(status & 0x80));
CSRELEASE(); CSRELEASE();
} else { } else {
CSASSERT(); CSASSERT();
SPI.transfer(0x05);
SPIPORT.transfer(0x05);
do { do {
status = SPI.transfer(0);
status = SPIPORT.transfer(0);
} while ((status & 0x01)); } while ((status & 0x01));
CSRELEASE(); CSRELEASE();
} }
} else { } else {
// chip is busy with an operation that can not suspend // 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 wait(); // should we wait without ending
b = 0; // the transaction?? b = 0; // the transaction??
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
} }
} }
do { do {
CSASSERT(); CSASSERT();
// TODO: FIFO optimize.... // TODO: FIFO optimize....
if (f & FLAG_32BIT_ADDR) { 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 { } 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(); CSRELEASE();
p += rdlen; p += rdlen;
addr += rdlen; addr += rdlen;
} while (len > 0); } while (len > 0);
if (b) { if (b) {
CSASSERT(); CSASSERT();
SPI.transfer(0x06); // write enable (Micron req'd)
SPIPORT.transfer(0x06); // write enable (Micron req'd)
CSRELEASE(); CSRELEASE();
delayMicroseconds(1); delayMicroseconds(1);
cmd = 0x7A; cmd = 0x7A;
if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A; if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A;
CSASSERT(); CSASSERT();
SPI.transfer(cmd); // Resume program/erase
SPIPORT.transfer(cmd); // Resume program/erase
CSRELEASE(); CSRELEASE();
} }
SPI.endTransaction();
SPIPORT.endTransaction();
} }


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


if (die_index >= die_count) return; // all dies erased :-) if (die_index >= die_count) return; // all dies erased :-)
uint8_t die_size = 2; // in 16 Mbyte units uint8_t die_size = 2; // in 16 Mbyte units
if (id[2] == 0x22) die_size = 8; if (id[2] == 0x22) die_size = 8;
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT(); CSASSERT();
SPI.transfer(0x06); // write enable command
SPIPORT.transfer(0x06); // write enable command
CSRELEASE(); CSRELEASE();
delayMicroseconds(1); delayMicroseconds(1);
CSASSERT(); CSASSERT();
// die erase command // 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(); CSRELEASE();
//Serial.printf("Micron erase begin\n"); //Serial.printf("Micron erase begin\n");
flags |= (die_index + 1) << 6; flags |= (die_index + 1) << 6;
} else { } else {
// All other chips support the bulk erase command // All other chips support the bulk erase command
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT(); CSASSERT();
// write enable command // write enable command
SPI.transfer(0x06);
SPIPORT.transfer(0x06);
CSRELEASE(); CSRELEASE();
delayMicroseconds(1); delayMicroseconds(1);
CSASSERT(); CSASSERT();
// bulk erase command // bulk erase command
SPI.transfer(0xC7);
SPIPORT.transfer(0xC7);
CSRELEASE(); CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
} }
busy = 3; busy = 3;
} }
{ {
uint8_t f = flags; uint8_t f = flags;
if (busy) wait(); if (busy) wait();
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT(); CSASSERT();
SPI.transfer(0x06); // write enable command
SPIPORT.transfer(0x06); // write enable command
CSRELEASE(); CSRELEASE();
delayMicroseconds(1); delayMicroseconds(1);
CSASSERT(); CSASSERT();
if (f & FLAG_32BIT_ADDR) { 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 { } else {
SPI.transfer16(0xD800 | ((addr >> 16) & 255));
SPI.transfer16(addr);
SPIPORT.transfer16(0xD800 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
} }
CSRELEASE(); CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
busy = 2; busy = 2;
} }


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


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


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


void SerialFlashChip::readID(uint8_t *buf) void SerialFlashChip::readID(uint8_t *buf)
{ {
if (busy) wait(); if (busy) wait();
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT(); 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) { 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(); CSRELEASE();
SPI.endTransaction();
SPIPORT.endTransaction();
//Serial.printf("ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]); //Serial.printf("ID: %02X %02X %02X\n", buf[0], buf[1], buf[2]);
} }


void SerialFlashChip::readSerialNumber(uint8_t *buf) //needs room for 8 bytes void SerialFlashChip::readSerialNumber(uint8_t *buf) //needs room for 8 bytes
{ {
if (busy) wait(); if (busy) wait();
SPI.beginTransaction(SPICONFIG);
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT(); 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++) { for (int i=0; i<8; i++) {
buf[i] = SPI.transfer(0);
buf[i] = SPIPORT.transfer(0);
} }
CSRELEASE(); 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]); // 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]);
} }



Завантаження…
Відмінити
Зберегти