| void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len) | void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len) | ||||
| { | { | ||||
| uint8_t *p = (uint8_t *)buf; | uint8_t *p = (uint8_t *)buf; | ||||
| uint8_t b, f; | |||||
| uint8_t b, f, status; | |||||
| memset(p, 0, len); | memset(p, 0, len); | ||||
| f = flags; | f = flags; | ||||
| SPI.beginTransaction(SPICONFIG); | |||||
| b = busy; | b = busy; | ||||
| if (b) { | if (b) { | ||||
| if (b < 3) { | |||||
| // read status register ... chip may no longer be busy | |||||
| CSASSERT(); | |||||
| if (flags & FLAG_STATUS_CMD70) { | |||||
| SPI.transfer(0x70); | |||||
| status = SPI.transfer(0); | |||||
| if ((status & 0x80)) b = 0; | |||||
| } else { | |||||
| SPI.transfer(0x05); | |||||
| status = SPI.transfer(0); | |||||
| if (!(status & 1)) b = 0; | |||||
| } | |||||
| CSRELEASE(); | |||||
| if (b == 0) { | |||||
| // chip is no longer busy :-) | |||||
| busy = 0; | |||||
| } else if (b < 3) { | |||||
| // TODO: this may not work on Spansion chips | // TODO: this may not work on Spansion chips | ||||
| // which apparently have 2 different suspend | // which apparently have 2 different suspend | ||||
| // commands, for program vs erase | // commands, for program vs erase | ||||
| SPI.beginTransaction(SPICONFIG); | |||||
| CSASSERT(); | |||||
| SPI.transfer(0x06); // write enable (Micron req'd) | |||||
| CSRELEASE(); | |||||
| delayMicroseconds(1); | |||||
| CSASSERT(); | CSASSERT(); | ||||
| SPI.transfer(0x75); // Suspend program/erase | SPI.transfer(0x75); // Suspend program/erase | ||||
| CSRELEASE(); | CSRELEASE(); | ||||
| SPI.endTransaction(); | |||||
| delayMicroseconds(20); // Tsus = 20us | |||||
| if (f & FLAG_STATUS_CMD70) { | |||||
| // Micron chips don't actually suspend until flags read | |||||
| CSASSERT(); | |||||
| SPI.transfer(0x70); | |||||
| do { | |||||
| status = SPI.transfer(0); | |||||
| } while (!(status & 0x80)); | |||||
| CSRELEASE(); | |||||
| } else { | |||||
| delayMicroseconds(20); // Tsus = 20us (Winbond) | |||||
| } | |||||
| } else { | } else { | ||||
| wait(); | |||||
| b = 0; | |||||
| // chip is busy with an operation that can not suspend | |||||
| SPI.endTransaction(); // is this a good idea? | |||||
| wait(); // should we wait without ending | |||||
| b = 0; // the transaction?? | |||||
| SPI.beginTransaction(SPICONFIG); | |||||
| } | } | ||||
| } | } | ||||
| SPI.beginTransaction(SPICONFIG); | |||||
| do { | do { | ||||
| uint32_t rdlen = len; | uint32_t rdlen = len; | ||||
| if (f & FLAG_MULTI_DIE) { | if (f & FLAG_MULTI_DIE) { | ||||
| addr += rdlen; | addr += rdlen; | ||||
| len -= rdlen; | len -= rdlen; | ||||
| } while (len > 0); | } while (len > 0); | ||||
| SPI.endTransaction(); | |||||
| if (b) { | if (b) { | ||||
| SPI.beginTransaction(SPICONFIG); | |||||
| CSASSERT(); | |||||
| SPI.transfer(0x06); // write enable (Micro req'd) | |||||
| CSRELEASE(); | |||||
| delayMicroseconds(1); | |||||
| CSASSERT(); | CSASSERT(); | ||||
| SPI.transfer(0x7A); // Resume program/erase | SPI.transfer(0x7A); // Resume program/erase | ||||
| CSRELEASE(); | CSRELEASE(); | ||||
| SPI.endTransaction(); | |||||
| } | } | ||||
| SPI.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) |