I'm using an nRF52840 microcontroller on an electronic board to read from and write to an S25FL064 flash memory chip. I'm currently using the nRF5 SDK. Before I could read in Read4IO mode and program in PP4IO mode, I had to perform the following steps:
-
Set
NRFX_QSPI_CONFIG_READOCto 4. -
Set
NRFX_QSPI_CONFIG_WRITEOCto 3. -
I wrote the following code to set the registers to enable the aforementioned functionalities:
{ FLASH_DEBUG("S25FL064L flash detected"); // Define memory addresses for different sections (firmware, LFS) ATMEGA128P_FW_START_ADDR = S25FL064L_START_ADDR; ATMEGA128P_FW_END_ADDR = 0x0000FFFFU; LFS_START_ADDR = ATMEGA128P_FW_END_ADDR + 1; LFS_END_ADDR = S25FL064L_END_ADDR; // Define flash size parameters FLASH_SECTOR_SIZE = S25FL064L_SECTOR_SIZE; FLASH_BLOCK_SIZE = S25FL064L_BLOCK_SIZE; uint8_t data[4]; // Target configuration values for the four registers (SR1V, CR1V, CR2V, CR3V) const uint8_t s25fl064lConfig[4] = {0x02, 0x22, 0x60, 0x74}; // Read Status Register 1 (SR1V) cinstr_cfg.opcode = S25FL064L_RDSR_CMD; cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B; cinstr_cfg.wren = false; err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, &data[0]); APP_ERROR_CHECK(err_code); // Check if Write Enable is needed if ((data[0] & 0x02) != 0x02) { // Write Enable. cinstr_cfg.opcode = S25FL064L_WREN_CMD; cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_1B; cinstr_cfg.wren = true; err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL); APP_ERROR_CHECK(err_code); } // Read Configuration Register 1 Volatile (CR1V) cinstr_cfg.opcode = S25FL064L_RCR_CMD; cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B; cinstr_cfg.wren = false; err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, &data[1]); APP_ERROR_CHECK(err_code); // Read Configuration Register 2 Volatile (CR2V) cinstr_cfg.opcode = S25FL064L_RDCR2_CMD; cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B; cinstr_cfg.wren = false; err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, &data[2]); APP_ERROR_CHECK(err_code); // Read Configuration Register 3 Volatile (CR3V) cinstr_cfg.opcode = S25FL064L_RDCR3_CMD; cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B; cinstr_cfg.wren = false; err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, &data[3]); APP_ERROR_CHECK(err_code); // Check if read registers match desired configuration if ((data[0] != s25fl064lConfig[0]) || (data[1] != s25fl064lConfig[1]) || (data[2] != s25fl064lConfig[2]) || (data[3] != s25fl064lConfig[3])) { // Load configuration values into data buffer data[0] = s25fl064lConfig[0]; // SR1V data[1] = s25fl064lConfig[1]; // CR1V data[2] = s25fl064lConfig[2]; // CR2V data[3] = s25fl064lConfig[3]; // CR3V // Write Registers (using the Write Registers command - WRR) cinstr_cfg.opcode = 0x01; // WRR cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_5B; cinstr_cfg.wren = true; err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, data, NULL); APP_ERROR_CHECK(err_code); } }
Now, I have switched to the nRF5340 microcontroller, which I program using the nRF Connect SDK and the Zephyr OS. I still want to read from and write to an S25FL064 flash memory chip.
I have configured the Devicetree as follows:
&qspi {
status = "okay";
pinctrl-0 = <&qspi_default>;
pinctrl-1 = <&qspi_sleep>;
pinctrl-names = "default", "sleep";
s25fl064l: s25fl064l@0 {
compatible = "nordic,qspi-nor";
reg = <0>;
writeoc = "pp4io";
readoc = "read4io";
sck-frequency = <DT_FREQ_M(32)>;
jedec-id = [01 60 17];
size = <67108864>; /* 64 Mbit = 8MB */
has-dpd;
t-enter-dpd = <10000>;
t-exit-dpd = <35000>;
};
};
However, the flash memory does not work. If I set writeoc = "pp" and readoc = "fastread" instead, the memory works (but obviously this is not the configuration I want).
I also tried adding the following property to the node:
quad-enable-requirements = "S2B1v1";
But it didn't work.
I believe I need to set the flash registers just like I did with the nRF52840 microcontroller, but if I use the function nrfx_qspi_cinstr_xfer, I get errors. Could this be because I don't have control over the flash since it is being controlled by the Devicetree?
Can anyone help me?
In my project, I also use MCUboot, and therefore, the configuration for the s25fl064l node is identical to the configuration used by my application code.