Goal
This blog is to describe how to use the QSPI flash as the external flash storage. I would introduce some idea how to configure the QSPI flash on the nRF52840 DK board and provide the example code with description on usage.
QSPI Driver
The Quad Serial Peripheral Interface (QSPI) driver includes two layers: the hardware access layer (HAL) and the driver layer (DRV).
The hardware access layer provides basic APIs for accessing the registers of the QSPI peripheral. For details, see the API documentation for QSPI HAL.
The driver layer provides APIs on a higher level than the HAL. For details, see the API documentation for QSPI driver – legacy layer.
Key features include:
- Three standard operations: write, read, and erase.
- Custom instruction sending feature.
- Support for the extended 32-bit addressing mode.
The QSPI Example provides sample code that you can use to quickly get started. Note that before the transmission starts, both the peripheral and memory must be configured, unlike for other drivers, where only the peripheral must be configured.
Driver configuration
The configurable parameters include:
- Pins to be used for QSPI peripheral signals.
- Frequency settings that define the divider of base frequency.
- Clock delay configuration (tSHSL, tWHSL, and tSHWL).
- QSPI mode for read and write operations.
- Extended address mode configuration.
- SPI mode options (Polarization and phase).
Example code
The example is based on the SDK 16.0 and add the QSPI module on its driver.
I add the 5 difference routines on the QSPI.
- ret_code_t module_flash_qspi_init(module_flash_qspi_init_t * p_qspi_init);
- void module_flash_qspi_uninit(void);
- ret_code_t flash_qspi_read(uint32_t * p_rx_buffer, uint32_t const src_address, uint32_t rx_buffer_length);
- ret_code_t flash_qspi_write(uint32_t * p_tx_buffer, uint32_t const dst_address, uint32_t tx_buffer_length);
- ret_code_t flash_qspi_page_erase(uint32_t page_number);
Because of the Word Alignment on the QSPI flash, all the variables need to be aligned with word.
static uint8_t __ALIGN(4) m_buffer_tx[QSPI_TEST_DATA_SIZE]; static uint8_t __ALIGN(4) m_buffer_rx[QSPI_TEST_DATA_SIZE];
Initialize the QSPI module
m_flash_qspi_init.evt_handler = module_flash_qspi_handler;
m_flash_qspi_init.base_address = QSPI_BASE_ADDRESS;
module_flash_qspi_init(&m_flash_qspi_init);
Callback handler
static module_flash_qspi_evt_handler_t module_flash_qspi_handler(module_flash_qspi_report_t * p_qspi_report)
{
switch(p_qspi_report->evt_type)
{
case eflash_QSPI_READ_REQ:
NRF_LOG_INFO("eflash_QSPI_READ_REQ");
break;
case eflash_QSPI_READ_DONE:
NRF_LOG_INFO("eflash_QSPI_READ_DONE");
break;
case eflash_QSPI_WRITE_REQ:
NRF_LOG_INFO("eflash_QSPI_WRITE_REQ");
break;
case eflash_QSPI_WRITE_DONE:
NRF_LOG_INFO("eflash_QSPI_WRITE_DONE");
break;
case eflash_QSPI_ERASE_REQ:
NRF_LOG_INFO("eflash_QSPI_ERASE_REQ");
break;
case eflash_QSPI_ERASE_DONE:
NRF_LOG_INFO("eflash_QSPI_ERASE_DONE");
break;
case eflash_QSPI_UNINIT:
NRF_LOG_INFO("eflash_QSPI_UNINIT");
break;
default:
break;
}
}
All the code can be found at https://github.com/jimmywong2003/nrf52840-QSPI-flash-example/ .