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

USB Mass Storage Class on external QSPI flash

Hello guys,

We are using SES and SDK15.3.0. Our SoC is from nRF52840 family. We have a custom board with external QSPI flash memory that we want to use as USB MSC device. After some consultations with Nordic technical support (see this thread), we selected  MX66L1G45G (3.0V) memory module for our external memory.

usbd_msc example from SDK 15.3.0 did not work on our custom board - disk initialization failed issue:

Changing the addressing mode to 32-bit (because we are using memory that is >128Mb) did not help. We changed the addressing mode inside sdk_config.h file as follows:

// <o> QSPI_CONFIG_ADDRMODE  - Addressing mode.
 
// <0=> 24bit 
// <1=> 32bit 

#ifndef QSPI_CONFIG_ADDRMODE
#define QSPI_CONFIG_ADDRMODE 1
#endif

// <o> NRFX_QSPI_CONFIG_ADDRMODE  - Addressing mode.
 
// <0=> 24bit 
// <1=> 32bit 

#ifndef NRFX_QSPI_CONFIG_ADDRMODE
#define NRFX_QSPI_CONFIG_ADDRMODE 1
#endif

QSPI link between our nRF52840 and external memory is OK because QSPI example is working properly.

Do you have any suggestions on what should we change in order to have usbd_msc example working on our custom board?

Thank you very much for your time and effort! It is really appreciated.

Sincerely,

Bojan.

Parents
  • Hello Bojan, 

    QSPI link between our nRF52840 and external memory is OK because QSPI example is working properly.

     I'm glad to hear that the QSPI example is working properly. 

    Do you have any suggestions on what should we change in order to have usbd_msc example working on our custom board?

    Are the settings the same as with QSPI example? Are you using FAT FS? Can you please provide your project for testing? Difficult for me to say at this moment.

    Thanks!

    Kind regards,
    Øyvind 

  • Hello ,

    Thanks for your reply!

    My starting point is usbd_msc example. Inside sdk_config.h file I just defined and set QSPI_CONFIG_ADDRMODE and NRFX_QSPI_CONFIG_ADDRMODE to have 32-bit addressing mode and that's all. The rest of the code is actually the code from usbd_msc example.

    Yes, FAT FS is used. The issue appears when disk_initialize(0); function is called within fatfs_init(). This is when I get the error "Disk initialization failed".

    Am I missing something?

    Sincerely,

    Bojan.

  • Hi, 

    I've been trying to find a cause as to why this does not work, but I'm running out of ideas. I will forward your case to our QSPI team. Before I do so, can you please try reading QSPI using nrfjprog. See this thread.

    The nrfjprog commands documentation has several QSPI commands that you use to test that the QSPI flash is working as intended. There is a QspiDefault.ini (C:\Program Files\Nordic Semiconductor\nrf-command-line-tools\bin\QspiDefault.ini) that you need to open in a text editor to verify correct settings. 
    A tip from one of my colleagues was to erase the flash using nrfjprog --qspieraseall. See documentation before starting.

    Let me know how that works for you! 

    -Øyvind

  • Hello, .

    I tried using the following nrfjprog command to read the content of the external QSPI:

    nrfjprog --readqspi D:\test_24bit.txt -f nrf52

    The command executed successfully! I did not change anything from the QspiDefault.ini file. After that, I changed AddressMode parameter in QspiDefault.ini file from BIT24 to BIT32 and tried to execute the same command, saving the results into test_32bit.txt file. Again, the command executed successfully. 

    When I compare two .txt files, I can see some differences. You can find the files attached here.

    What I can conclude from those experiments is that QSPI link between nRF52840 and external memory is functional. , you think that usbd_msc example should work in that case?

    Sincerely,

    Bojan.

    test_24bit.txt
    test_32bit.txt

  • Ok, the flash does seemingly work as intended. The issue has to be with a configuration in USBD_MSC. Have you edited the example according to your device? Since the flash on the nRF52840 DK is a 64 Mb external flash memory (MX25R6435F) with 24-bit addressing, have you edited correct memory/block size, addresses, etc in the example?

    From the MX66L1G45G datasheet - given that QSPI example works with 24-bit, but not 32-bit.

    9-11. Enter 4-byte mode (EN4B)
    The EN4B instruction enables accessing the address length of 32-bit for the memory area of higher density (larger
    than 128Mb). The device default is in 24-bit address mode; after sending out the EN4B instruction, the bit5 (4BYTE
    bit) of Configuration Register will be automatically set to "1" to indicate the 4-byte address mode has been enabled.
    Once the 4-byte address mode is enabled, the address length becomes 32-bit instead of the default 24-bit. There
    are three methods to exit the 4-byte mode: writing exit 4-byte mode (EX4B) instruction, Reset or power-off.
    All instructions are accepted normally, and just the address bit is changed from 24-bit to 32-bit.
    The following commands don't support 4-byte address: RDSFDP, RES and REMS.
    The sequence of issuing EN4B instruction is: CS# goes low → sending EN4B instruction to enter 4-byte mode(
    automatically set 4BYTE bit as "1") → CS# goes high.

    8-1. 256Mb Address Protocol
    The original 24 bit address protocol of serial Flash can only access density size below 128Mb. For the memory
    device of 256Mb and above, the 32bit address is requested for access higher memory size. The MX66L1G45G
    provides three different methods to access the whole density:
    (1) Command entry 4-byte address mode:
    Issue Enter 4-Byte mode command to set up the 4BYTE bit in Configuration Register bit. After 4BYTE bit has
    been set, the number of address cycle become 32-bit.
    (2) Extended Address Register (EAR):
    configure the memory device into eight 128Mb segments to select which one is active through the EAR<0-2>.
    (3) 4-byte Address Command Set:
    When issuing 4-byte address command set, 4-byte address (A31-A0) is requested after the instruction code.
    Please note that it is not necessary to issue EN4B command before issuing any of 4-byte command set.

    When your flash is configured correctly, the Read/Write Array Commands (4-Byte Address Command Set) must be used. 

  • Hi .

    To the best of my understanding, MX66L1G45G is by default set to 24-bit addressing and I would need to execute EN4B command in order to use 32-bit addressing and access all memory locations. Correct?

    I did not touch anything in  usbd_msc example except addressing. Can you point the places in example where I need to change memory/block size, addresses...?

    Thanks in advance!

    Sincerely,

    Bojan.

  • bojan said:
    To the best of my understanding, MX66L1G45G is by default set to 24-bit addressing and I would need to execute EN4B command in order to use 32-bit addressing and access all memory locations. Correct?

     Yes, this is correct. Setting the 32-bit ADDRMODE in sdk_config switches driver and internally peripheral to 32-bit. The suggestion from our developer is to test the MSC example with 24-bit and simple QSPI mode. This means configuring: 

    QSPI_CONFIG_READOC = 0
    QSPI_CONFIG_WRITEOC = 0
    QSPI_CONFIG_ADDRMODE = 0 

    On page 22 in the MX66L1G45G datasheet, you find the Enter 4-byte (EN4B) mode and Exit 4-byte (EX4B) mode. To test with 24-bit, be sure to issue EX4B. 

    Edit: Have a look at configure_memory() in examples\peripheral\qspi\main.c, this function shows how to send commands to flash using commands found in modules\nrfx\drivers\src\nrfx_qspi.c

    Please ignore my comment regarding "...have you edited correct memory/block size, addresses, etc in the example?" at this time. 

Reply
  • bojan said:
    To the best of my understanding, MX66L1G45G is by default set to 24-bit addressing and I would need to execute EN4B command in order to use 32-bit addressing and access all memory locations. Correct?

     Yes, this is correct. Setting the 32-bit ADDRMODE in sdk_config switches driver and internally peripheral to 32-bit. The suggestion from our developer is to test the MSC example with 24-bit and simple QSPI mode. This means configuring: 

    QSPI_CONFIG_READOC = 0
    QSPI_CONFIG_WRITEOC = 0
    QSPI_CONFIG_ADDRMODE = 0 

    On page 22 in the MX66L1G45G datasheet, you find the Enter 4-byte (EN4B) mode and Exit 4-byte (EX4B) mode. To test with 24-bit, be sure to issue EX4B. 

    Edit: Have a look at configure_memory() in examples\peripheral\qspi\main.c, this function shows how to send commands to flash using commands found in modules\nrfx\drivers\src\nrfx_qspi.c

    Please ignore my comment regarding "...have you edited correct memory/block size, addresses, etc in the example?" at this time. 

Children
  • Hello, .

    I tried what you suggested. By default in  usbd_msc example, 24-bit and simple QSPI mode is used. This means that

    QSPI_CONFIG_READOC = 0
    QSPI_CONFIG_WRITEOC = 0
    QSPI_CONFIG_ADDRMODE = 0 

    is already set in sdk_config.h file.

    Before calling problematic fatfs_init() function of usbd_msc example, I tried to execute EX4B flash command (0xE9). I first initialized qspi and then applied configure_memory() function like this:

        nrf_drv_qspi_config_t config = NRF_DRV_QSPI_DEFAULT_CONFIG;
    
        err_code = nrf_drv_qspi_init(&config, qspi_handler, NULL);
        APP_ERROR_CHECK(err_code);
        NRF_LOG_INFO("QSPI example started.");
    
        configure_memory();

    Inside configure_memory() function I execute EX4B command:

    static void configure_memory()
    {
        uint8_t temporary = 0x40;
        uint32_t err_code;
        nrf_qspi_cinstr_conf_t cinstr_cfg = {
            .opcode    = QSPI_STD_CMD_RSTEN,
            .length    = NRF_QSPI_CINSTR_LEN_1B,
            .io2_level = true,
            .io3_level = true,
            .wipwait   = true,
            .wren      = true
        };
    
        // Send reset enable
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        // Send reset command
        cinstr_cfg.opcode = QSPI_STD_CMD_RST;
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        // Exit 4-Byte mode - EX4B command
        cinstr_cfg.opcode = QSPI_STD_CMD_EX4B;
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        // Switch to qspi mode
        cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;
        cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, &temporary, NULL);
        APP_ERROR_CHECK(err_code);
    }

    To make sure EX4B command is properly executed, I was reading configuration and status registers (RDCR/RDSR commands) before and after applying EX4B command. Here is what I get:

    Before applying EX4B command:

    <info> app: Configuration register: 0x7
    <info> app: Status register: 0x42
    
    

    After applying EX4B command:

    <info> app: Configuration register: 0x7
    <info> app: Status register: 0x40
    

    Judging by the state of Configuration register (0x7), it seems that flash memory is by default using 24-bit addressing (bit5 (4 BYTE) of the Configuration register is set to 0 even before EX4B command is applied). When I send EN4B command I read 0x27 from the Configuration register which means bit5  of the configuration register is properly set to 1. All this proves to me that there is a proper communication between nRF52840 and QSPI flash.

    Anyway, with EX4B command executed, I still have the same problem with disk_initialize(0) function that is called within fatfs_init() function. disk_initialize(0) returns 1 (which means that m_drives[drv].state is equal to 1 and it should be equal to 0).

    Should I look deeper into disk_initialize(0) function to try to figure out what is wrong there?

    Sincerely,

    Bojan.

  • Hi, .

    Here is what I noticed this morning:

    In a chain of function calls

    fatfs_init() >> disk_initialize(0) >> nrf_blck_dev_init() >> init()

    function

     

    p_blk_dev->p_ops->init(p_blk_dev, ev_handler, p_context);
     

    returns 0x8 error code which should be the code for NRF_ERROR_INVALID_STATE (Invalid state, operation disallowed in this state).

    I am unable to go deeper and explore what happens inside init() function and why the system is in invalid state. Do you have any hints for me?

    Regards,

    Bojan

  • When I remove the code you suggested to add:

        nrf_drv_qspi_config_t config = NRF_DRV_QSPI_DEFAULT_CONFIG;
    
        err_code = nrf_drv_qspi_init(&config, qspi_handler, NULL);
        APP_ERROR_CHECK(err_code);
        NRF_LOG_INFO("QSPI example started.");
    
        configure_memory();

    the init() function returns error code 0x6 - NRF_ERROR_NOT_SUPPORTED! I would say that the issue has something with how SPI/QSPI is initialized and used/configured.

  • Hi Bojan, 

    Can you please share your project?

    Kind regards,
    Øyvind

  • Hello .

    Sure. Find it attached. However, the project is just a copy from usbd_msc example.

    It is placed under examples/peripheral.

    Sincerely,

    Bojan.

    usbd_msc_custom_board.zip

Related