This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Look like a hard coded bug in API generated in build\zephyr\include\generated\syscalls\flash.h

Look like a hard coded bug in API generated in build\zephyr\include\generated\syscalls\flash.h  ? 

-- Found BOARD.dts:  zephyr/boards/arm/nrf52840dk_nrf52840/nrf52840dk_nrf52840.dts.


When the QSPI interface of nRF52840 is set to quad mode, there is a quad enable(QE) bit of the status register of the external QSPI flash is also needed to be set.   The QSPI flash used in the nRF52840_DK is MX25R64 from Macroni and the QE bit is bit 6 of the status registeras indicated in page 26, table 3 of the MX25R64


https://www.mxic.com.tw/Lists/Datasheet/Attachments/7873/MX25U25645G,%201.8V,%20256Mb,%20v1.4.pdf

0x40 is seemed to be hard coded in the API generated in build\zephyr\include\generated\syscalls\flash.h when the QSPI is in Quad mode.  It works fine if you are using the nRF52840_DK, but it may break when you have a custom board with a different flash chip.  I am using GD25LQ80C and the QE bit is bit 9 instead of bit 6 and bit 6 is for block protection, so using the API generated will fail in write operation if QSPI is in quad mode because the chip is block protected.

Page 11 of the following data sheet from gigadevice.  bit 9 is the QE bit and bit 6 is for block protection. 

www.gigadevice.com/.../

There is nothing in the zephyr.dts generated can mislead to a MX25R64 being used
-- Generated zephyr.dts:       build/zephyr/zephyr.dts
qspi: qspi@40029000 {
                        compatible = "nordic,nrf-qspi";
                        #address-cells = < 0x1 >;
                        #size-cells = < 0x0 >;
                        reg = < 0x40029000 0x1000 >;
                        interrupts = < 0x29 0x1 >;
                        status = "okay";
                        label = "QSPI";
                        sck-pin = < 0x13 >;
                        io-pins = < 0x15 >, < 0x17 >, < 0x20 >, < 0x16 >;
                        csn-pins = < 0x21 >;
                        gd25lq80c: gd25lq80ceigr@0 {
                                compatible = "nordic,qspi-nor";
                                reg = < 0x0 >;
                                writeoc = "pp4o";
                                readoc = "read4io";
                                sck-frequency = < 0x1e8480 >;
                                label = "GD25LQ80C";
                                jedec-id = [ C8 60 14 ];
                                sfdp-bfp;
                                size = < 0x800000 >;
                                has-dpd;
                                t-enter-dpd = < 0x64 >;
                                t-exit-dpd = < 0x64 >;
                        };
                };

The following is the waveform captured from the logic analyzer indicating bit 6 of the external flash is being set by the API generated.0x05 is the Read Status Register command(RDRS) and the result is 0x43.   bits 0 and 1 are WEL and WIP.  However, bit 6 is Block protection bit for GD25LQ80C and QE bit for MX25R64.  <---  See the problem!!!

0x05 is the RDSR Read Status command and the 0x43 is the result indicating the bit6(BP for GD25LQ80C but QE for MX25R64).  bits 0 and 1 are WEL and WIP for write enable latched and write in progress.  Repeating 0x05 Read Status commands pulling 0x43 until it became 0x40 when both WIP and WEL were cleared to 0 indicating the write operation was done.  However, 0x40 indicating bit 6 was set.  It is a problem for GD25LQ80C when block protection is set in a write operation, but it is the QE bit for the MX25R64.

Since block protection bit 6 of the status register was set(0x40).  The write enable command(0x06) and program page command(0x32) failed to write data into the GD25LQ80C flash device.  

0x40(bit 6) is cleared when the QSPI interface is set to standard mode.

My set up

-- Zephyr version: 2.4.99

NCS Toolchain 1.6.1 for building.

-- The C compiler identification is GNU 9.2.1

-- The CXX compiler identification is GNU 9.2.1

-- The ASM compiler identification is GNU

I am using a MAC

MAC OS.  Big Sur. ver 11.5.2

Model Name: MacBook Pro

  Model Identifier: MacBookPro14,1

  Processor Name: Dual-Core Intel Core i5

  Processor Speed: 2.3 GHz

  Number of Processors: 1

  Total Number of Cores: 2

  L2 Cache (per Core): 256 KB

  L3 Cache: 4 MB

  Hyper-Threading Technology: Enabled

  Memory: 8 GB

  System Firmware Version: 429.140.8.0.0

Parents
  • Hi

    QE bit handling is specified by the quad-enable-requirements property of the nordic, qspi-nor binding. The default value of this property is "S1B6", and hence the driver sets bit 6 of the first status register byte to enable the Quad mode (that's what is required for the MX25R64). Apart from the "S1B6" value, the QSPI NOR Flash driver also supports the "NONE" value, which prevents the driver from setting any bit in the status register to enable the Quad mode. It seems that for both GD25LQ80C and W25Q32FV this setting should be used, as the QE bit is non-volatile in both flash chips. Thus, the QE bit should be set once to 1 and the driver should be prevented from writing the status register, hence the following line should be added in the "nordic, qspi-nor" compatible mode:

    quad-enable-requirements = "NONE";
    

    For reference, there is a commit that introduced the current way of handling the QE bit (previously, the QSPI NOR Flash driver used a Kconfig option for specifying this bit). The commit message explains why this is done how it is.

    Best regards,

    Simon

  • Hello Simonr,

    Thanks for the effort to help me.  

    Trying quad-enable-requirements = "NONE";

    or
    quad-enable-requirements = "S2B1";   /* for bit 9 */

    I am able to read and write to the external QSPI flash GD25LQ80C, but only in standard mode

    I am checking the Quad mode configuration of the QSPI interface the nRF52840.

    Not sure if the example in/ncs/zephyr/samples/drivers/spi_flash can operate in quad mode.

    static inline int flash_write(const struct device * dev, off_t offset, const void * data, size_t len).
    build\zephyr\include\generated\syscalls\flash.h.   sending out  0x02(Page Program) instead of 0x32(Quad Page Program), so it is operating in standard mode because 0x02 is command for standard mode.
    Is there any example in Nordic SDK using QSPI in Zephyr RTOS environment ??
    Is the SPI driver API generated support Quad mode ??
    Thanks again for the solution using 
    quad-enable-requirements
     
  • No, we don't have any example projects using QSPI in NCS as of yet I'm afraid. You will have to implement the QSPI driver in an example (like the spi_flash example) yourself to make it able to operate in quad mode. You will need to add the following drivers: 

    ncs\modules\hal\nordic\nrfx\hal\nrf_qspi.h
    ncs\modules\hal\nordic\nrfx\drivers\src\nrfx_qspi.c
    ncs\modules\hal\nordic\nrfx\drivers\include\nrfx_qspi.h

    Best regards,

    Simon

Reply
  • No, we don't have any example projects using QSPI in NCS as of yet I'm afraid. You will have to implement the QSPI driver in an example (like the spi_flash example) yourself to make it able to operate in quad mode. You will need to add the following drivers: 

    ncs\modules\hal\nordic\nrfx\hal\nrf_qspi.h
    ncs\modules\hal\nordic\nrfx\drivers\src\nrfx_qspi.c
    ncs\modules\hal\nordic\nrfx\drivers\include\nrfx_qspi.h

    Best regards,

    Simon

Children
  • Hello Simon,

    Thanks for the information for QSPI driver development.  Will look into it.

    However, the driver API generated in

    /zephyr/include/generated/syscalls/flash.h

    support the following functions

    flash_erase(const struct device * dev, off_t offset, size_t size)

    flash_read(const struct device * dev, off_t offset, void * data, size_t len)
    flash_write(const struct device * dev, off_t offset, const void * data, size_t len)
    flash_get_page_info_by_idx(const struct device * dev, uint32_t page_index, struct flash_pages_info * info)
    It would be an improvement if we can change QSPI mode to be STANDARD, DUAL or QUAD with a function
    flash_mode_set(const struct device * dev,  .....  mode).   
     
    Just my 2 cents on the improvement of Zephyr 
    Thanks,
    JC
Related