diff --git a/src/Adafruit_SPIFlashBase.cpp b/src/Adafruit_SPIFlashBase.cpp index ce51bae..7d94e68 100644 --- a/src/Adafruit_SPIFlashBase.cpp +++ b/src/Adafruit_SPIFlashBase.cpp @@ -129,6 +129,16 @@ static SPIFlash_Device_t const *findDevice(SPIFlash_Device_t const *device_list, return NULL; } +void Adafruit_SPIFlashBase::write_status_register(uint8_t const status[2]) { + if (_flash_dev->write_status_register_split) { + _trans->writeCommand(SFLASH_CMD_WRITE_STATUS2, status + 1, 1); + } else if (_flash_dev->single_status_byte) { + _trans->writeCommand(SFLASH_CMD_WRITE_STATUS, status + 1, 1); + } else { + _trans->writeCommand(SFLASH_CMD_WRITE_STATUS, status, 2); + } +} + bool Adafruit_SPIFlashBase::begin(SPIFlash_Device_t const *flash_devs, size_t count) { if (_trans == NULL) { @@ -219,19 +229,40 @@ bool Adafruit_SPIFlashBase::begin(SPIFlash_Device_t const *flash_devs, writeEnable(); uint8_t full_status[2] = {0x00, _flash_dev->quad_enable_bit_mask}; - - if (_flash_dev->write_status_register_split) { - _trans->writeCommand(SFLASH_CMD_WRITE_STATUS2, full_status + 1, 1); - } else if (_flash_dev->single_status_byte) { - _trans->writeCommand(SFLASH_CMD_WRITE_STATUS, full_status + 1, 1); - } else { - _trans->writeCommand(SFLASH_CMD_WRITE_STATUS, full_status, 2); - } + write_status_register(full_status); } } else { + /* + * Most of QSPI flash memory ICs have non-volatile QE bit in a status + * register. If it was set once - we need to apply a separate procedure to + * clear it off when the device is connected to a non-QSPI capable bus or it + * has _flash_dev->supports_qspi setting in 'false' state + */ + // Disable Quad Mode if not available + if (!_trans->supportQuadMode() || !_flash_dev->supports_qspi) { + // Verify that QSPI mode is not enabled. + uint8_t status = + _flash_dev->single_status_byte ? readStatus() : readStatus2(); + + // Check the quad enable bit. + if ((status & _flash_dev->quad_enable_bit_mask) != 0) { + writeEnable(); + + uint8_t full_status[2] = {0x00, 0x00}; + write_status_register(full_status); + } + } + // Single mode, use fast read if supported if (_flash_dev->supports_fast_read) { - _trans->setReadCommand(SFLASH_CMD_FAST_READ); + if (_trans->supportQuadMode() && !_flash_dev->supports_qspi) { + /* Re-init QSPI with READOC_FASTREAD and WRITEOC_PP */ + _trans->end(); + _trans->setReadCommand(SFLASH_CMD_FAST_READ); + _trans->begin(); + } else { + _trans->setReadCommand(SFLASH_CMD_FAST_READ); + } } } diff --git a/src/Adafruit_SPIFlashBase.h b/src/Adafruit_SPIFlashBase.h index 2fdaa47..ed41cd5 100644 --- a/src/Adafruit_SPIFlashBase.h +++ b/src/Adafruit_SPIFlashBase.h @@ -75,6 +75,8 @@ class Adafruit_SPIFlashBase { int _ind_pin; bool _ind_active; + void write_status_register(uint8_t const status[2]); + void _indicator_on(void) { if (_ind_pin >= 0) { digitalWrite(_ind_pin, _ind_active ? HIGH : LOW); diff --git a/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp b/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp index 6c4d884..0b77775 100644 --- a/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp +++ b/src/qspi/Adafruit_FlashTransport_QSPI_NRF.cpp @@ -70,11 +70,19 @@ void Adafruit_FlashTransport_QSPI::begin(void) { }, .irq_priority = 7}; + if (_cmd_read != SFLASH_CMD_QUAD_READ) { + qspi_cfg.prot_if.readoc = NRF_QSPI_READOC_FASTREAD; // 0x0B read command + qspi_cfg.prot_if.writeoc = NRF_QSPI_WRITEOC_PP; // 0x02 write command + } + // No callback for blocking API nrfx_qspi_init(&qspi_cfg, NULL, NULL); } -void Adafruit_FlashTransport_QSPI::end(void) { nrfx_qspi_uninit(); } +void Adafruit_FlashTransport_QSPI::end(void) { + nrfx_qspi_uninit(); + _cmd_read = SFLASH_CMD_QUAD_READ; +} void Adafruit_FlashTransport_QSPI::setClockSpeed(uint32_t clock_hz, uint32_t read_hz) { diff --git a/src/qspi/Adafruit_FlashTransport_QSPI_SAMD.cpp b/src/qspi/Adafruit_FlashTransport_QSPI_SAMD.cpp index 9e0546f..c59362b 100644 --- a/src/qspi/Adafruit_FlashTransport_QSPI_SAMD.cpp +++ b/src/qspi/Adafruit_FlashTransport_QSPI_SAMD.cpp @@ -141,16 +141,19 @@ bool Adafruit_FlashTransport_QSPI::eraseCommand(uint8_t command, bool Adafruit_FlashTransport_QSPI::readMemory(uint32_t addr, uint8_t *data, uint32_t len) { - // Command 0x6B 1 line address, 4 line Data - // Quad output mode, read memory type - uint32_t iframe = QSPI_INSTRFRAME_WIDTH_QUAD_OUTPUT | - QSPI_INSTRFRAME_ADDRLEN_24BITS | + uint32_t width = (_cmd_read == SFLASH_CMD_QUAD_READ) + ? QSPI_INSTRFRAME_WIDTH_QUAD_OUTPUT + : QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI; + + // Command 0x6B (or 0x0B) 1 line address, 4 (or 1) line Data + // Quad (or single) output mode, read memory type + uint32_t iframe = width | QSPI_INSTRFRAME_ADDRLEN_24BITS | QSPI_INSTRFRAME_TFRTYPE_READMEMORY | QSPI_INSTRFRAME_INSTREN | QSPI_INSTRFRAME_ADDREN | QSPI_INSTRFRAME_DATAEN | QSPI_INSTRFRAME_DUMMYLEN(8); samd_peripherals_disable_and_clear_cache(); - _run_instruction(SFLASH_CMD_QUAD_READ, iframe, addr, data, len); + _run_instruction(_cmd_read, iframe, addr, data, len); samd_peripherals_enable_cache(); return true; @@ -159,14 +162,21 @@ bool Adafruit_FlashTransport_QSPI::readMemory(uint32_t addr, uint8_t *data, bool Adafruit_FlashTransport_QSPI::writeMemory(uint32_t addr, uint8_t const *data, uint32_t len) { - uint32_t iframe = - QSPI_INSTRFRAME_WIDTH_QUAD_OUTPUT | QSPI_INSTRFRAME_ADDRLEN_24BITS | - QSPI_INSTRFRAME_TFRTYPE_WRITEMEMORY | QSPI_INSTRFRAME_INSTREN | - QSPI_INSTRFRAME_ADDREN | QSPI_INSTRFRAME_DATAEN; + uint32_t width = (_cmd_read == SFLASH_CMD_QUAD_READ) + ? QSPI_INSTRFRAME_WIDTH_QUAD_OUTPUT + : QSPI_INSTRFRAME_WIDTH_SINGLE_BIT_SPI; + + uint32_t iframe = width | QSPI_INSTRFRAME_ADDRLEN_24BITS | + QSPI_INSTRFRAME_TFRTYPE_WRITEMEMORY | + QSPI_INSTRFRAME_INSTREN | QSPI_INSTRFRAME_ADDREN | + QSPI_INSTRFRAME_DATAEN; + + uint8_t cmd = (_cmd_read == SFLASH_CMD_QUAD_READ) + ? SFLASH_CMD_QUAD_PAGE_PROGRAM + : SFLASH_CMD_PAGE_PROGRAM; samd_peripherals_disable_and_clear_cache(); - _run_instruction(SFLASH_CMD_QUAD_PAGE_PROGRAM, iframe, addr, (uint8_t *)data, - len); + _run_instruction(cmd, iframe, addr, (uint8_t *)data, len); samd_peripherals_enable_cache(); return true;