External flash S25FL064 and Zephyr

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:

  1. Set NRFX_QSPI_CONFIG_READOC to 4.

  2. Set NRFX_QSPI_CONFIG_WRITEOC to 3.

  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.

Parents Reply Children
No Data
Related