Example of how to read QSPI NOR Flash Device ID

Hi, can someone provide an example of reading the device ID from an QSPI flash (NOR)?

I'm trying to get it using my NRF52840 using the nrf sdk17.1 with the flash IC AT25FF081A but not getting correct values, just zeros.

For the AT25FF081A, the read device id cmd is 0x90 and we need to send the cmd byte first on the SI pin, then 3 dummy address bytes on the SI pin then receive the 2 data bytes on the SO pin.

Here is my code:

#define CMD_READ_MANUFACTURER_DEVICE_ID  0x90 // spi mode (not quad)
void read_device_id(void)
{
    uint8_t manufacturer_id, device_id;
    nrfx_err_t err_code;

    // Prepare command
    uint8_t command = CMD_READ_MANUFACTURER_DEVICE_ID;

    // Initialize QSPI peripheral
    uint8_t dummy_addr_bytes[4] = {0};
    uint8_t read_bytes[4] = {0};
    // Configure QSPI command
    nrf_qspi_cinstr_conf_t cinstr_cfg = {
        .opcode    = CMD_READ_MANUFACTURER_DEVICE_ID,
        .length    = sizeof(dummy_addr_bytes),
        .io2_level = true,
        .io3_level = true,
        .wipwait   = true,
        .wren      = false
    };
    


    // Send command with dummy bytes
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, &dummy_addr_bytes, read_bytes);

    
    // Output results
    if(NRFX_SUCCESS != err_code)
    {
        NRF_LOG_ERROR("nrfx_qspi_cinstr_xfer err: %d\n", err_code);
    }

    NRF_LOG_ERROR("Manufacturer ID: 0x%X\n", read_bytes[0]);
    NRF_LOG_ERROR("Device ID: 0x%X\n", read_bytes[1]);
    NRF_LOG_ERROR("last: 0x%X\n", read_bytes[2]);
}

Here is our qspi config

rfx_qspi_config_t nrfx_qspi_config = {                                                                       
        .xip_offset  = NRFX_QSPI_CONFIG_XIP_OFFSET,                         
        .pins = {                                                           
            .sck_pin     = 7,//16,                                
            .csn_pin     = 34,//15,                                
            .io0_pin     = 8, //14,   mosi                            
            .io1_pin     = 6, //29,   miso                           
            .io2_pin     = 10, //22,                                
            .io3_pin     = 9, //23,                                
        },                                                                  
        .prot_if = {                                                        
            .readoc     = (nrf_qspi_readoc_t)  NRFX_QSPI_CONFIG_READOC,       
            .writeoc    = (nrf_qspi_writeoc_t) NRFX_QSPI_CONFIG_WRITEOC,     
            .addrmode   = (nrf_qspi_addrmode_t)NRFX_QSPI_CONFIG_ADDRMODE,   
            .dpmconfig  = false,                                            
        },                                                                  
        .phy_if = {                                                         
            .sck_delay  = (uint8_t)NRFX_QSPI_CONFIG_SCK_DELAY,              
            .dpmen      = false,                                            
            .spi_mode   = (nrf_qspi_spi_mode_t)NRFX_QSPI_CONFIG_MODE,       
            .sck_freq   = (nrf_qspi_frequency_t)NRFX_QSPI_CONFIG_FREQUENCY, 
        },                                                                  
        .irq_priority   = (uint8_t)NRFX_QSPI_CONFIG_IRQ_PRIORITY
    };

  • Hi 

    Often you need to send a reset command first, before reading out the Jedec ID. Have you checked the datasheet if this is necessary? 

    Have you tried to probe the QSPI lines with a scope or logic analyzer to see if the output is as you expect?

    Just looking at the code I can't really spot the issue. 

    Best regards
    Torbjørn

  • That is one way to do it, reset then read the id

    but we want to read the device id after a reset as well (sometime later).

    I guess, my worry is I'm not using nrfx_qspi_cinstr_xfer function correctly.

    If the datasheet says it  needs us to send the 1 byte opcode and then 3 dummy (addr) bytes before it sends back the 2 databytes then am I using the nrf sdk function correctly?

  • Also, I am able to write and read data from the flash IC

    it's just the device id I can't read

  • Ok looks like I got it working now. Here is the code for others to reference

    /* get the manufacturer and device id of the qspi flash ic
       this flash ic has multiple variants (8 Mb, 16 or 32Mb) which have different device id
       it's up to the developer to know which one to look for after calling this function
       the manufacturer id should always be 0x1F
       the 8Mb dev id is 0x45 and the 32Mb version is 0x47 (for example)
    */
    
    NVM_ERROR at25ffxxxx_get_id(at25ffxxxx_t *self, uint8_t *dev_id, uint8_t *manf_id)
    {
        if(NULL == self || NULL == dev_id || NULL == manf_id)
        {
            return NVM_ERROR_INVALID_POINTER;
        }
        nrfx_err_t err_code;
        // Initialize QSPI peripheral
        uint8_t dummy_addr_bytes[8] = {0};
        uint8_t read_bytes[8] = {0};
    
        // Configure QSPI command
        nrf_qspi_cinstr_conf_t cinstr_cfg = {
            .opcode    = CMD_READ_MANUFACTURER_DEVICE_ID,
            .length    = 6, // cmd bytes + 3 addr bytes + 2 data bytes
            .io2_level = true,
            .io3_level = true,
            .wipwait   = true,
            .wren      = false
        };
        
    
        // Send command with dummy bytes
        err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, &dummy_addr_bytes, read_bytes);
    
        
        // Output results
        if(NRFX_SUCCESS != err_code)
        {
            NRF_LOG_ERROR("nrfx_qspi_cinstr_xfer err: %d\n", err_code);
        }
    
        for(int i = 0; i<sizeof(read_bytes); i++)
        {
            NRF_LOG_ERROR("%d 0x%X\n", i, read_bytes[i]);
        }
        *manf_id = read_bytes[3];
        *dev_id = read_bytes[4];
        return err_code == NRFX_SUCCESS ? NVM_ERROR_NONE : NVM_ERROR_READ_DEVID_FAILED;
    }

  • Good to hear you found the issue, and thanks for sharing the solution Slight smile

Related