QSPI Flash interface with R7FA4M3AF MCU

Hi,

I am currently working on interfacing the QSPI Flash AT25FF321A with the R7FA4M3AF3CFP MCU. While everything functions correctly in extended SPI mode, I am encountering issues in QPI mode.

I have attached the schematic snapshots and relevant code sections to assist in debugging this issue. Please note that I have utilized a mixed pin group for the QSPI configuration. Despite my efforts, I am unable to read even Manufacturer/Device ID in QPI mode. I am including the firmware section related to this issue.

I would greatly appreciate your assistance in resolving this matter.

Code : 

void qspi_test()
{
// Initialize QSPI configuration and open the QSPI interface
spi_flash_cfg_t l_qspi_cfg;
memcpy((spi_flash_cfg_t *)&l_qspi_cfg, (spi_flash_cfg_t *)&g_qspi0_cfg, sizeof(spi_flash_cfg_t));
l_qspi_cfg.spi_protocol = SPI_FLASH_PROTOCOL_QPI;
l_qspi_cfg.page_program_address_lines = SPI_FLASH_DATA_LINES_4;
l_qspi_cfg.page_program_command = 0x32;
R_QSPI_Open(&g_qspi0_ctrl, &l_qspi_cfg);

fsp_err_t err;
uint8_t command[8];
uint8_t read_data[2];
uint8_t status[2];
uint8_t manufacturer_id = 0;
uint8_t device_id = 0;
uint8_t data[3]; // Adjusted size to fit commands and data

// Step 1: Enable Quad Mode (Set QE bit in Status Register 2)
// Write Enable before writing to the status register
data[0] = 0x06; // Write Enable command
err = R_QSPI_DirectWrite(&g_qspi0_ctrl, data, 1, false);
if (err != FSP_SUCCESS)
{
return;
}
R_BSP_SoftwareDelay(5, BSP_DELAY_UNITS_MILLISECONDS); // Short delay after Write Enable

// Read the current Status Register 2
data[0] = 0x35; // Read Status Register 2 command
err = R_QSPI_DirectWrite(&g_qspi0_ctrl, data, 1, true);
if (err != FSP_SUCCESS)
{
return;
}
err = R_QSPI_DirectRead(&g_qspi0_ctrl, status, 2);
if (err != FSP_SUCCESS)
{
return;
}

// Set the QE bit in Status Register 2
status[1] |= 0x02; // Set QE bit

// Write Enable again before writing the updated status register
data[0] = 0x06; // Write Enable command
err = R_QSPI_DirectWrite(&g_qspi0_ctrl, data, 1, false);
if (err != FSP_SUCCESS)
{
return;
}
R_BSP_SoftwareDelay(5, BSP_DELAY_UNITS_MILLISECONDS); // Short delay after Write Enable

// Write the updated status register (SR1 and SR2)
data[0] = 0x01; // Write Status Register command
data[1] = status[0]; // Status Register 1 (unchanged)
data[2] = status[1]; // Status Register 2 (QE bit set)
err = R_QSPI_DirectWrite(&g_qspi0_ctrl, data, 3, true);
if (err != FSP_SUCCESS)
{
return;
}
R_BSP_SoftwareDelay(1000, BSP_DELAY_UNITS_MILLISECONDS); // Increased delay for status register write

// Poll the status register to wait for write completion
do {
data[0] = 0x05; // Read Status Register command
err = R_QSPI_DirectWrite(&g_qspi0_ctrl, data, 1, true);
if (err != FSP_SUCCESS)
{
return;
}
err = R_QSPI_DirectRead(&g_qspi0_ctrl, status, 1);
if (err != FSP_SUCCESS)
{
return;
}
} while (status[0] & 0x01); // Wait while the device is busy

// Step 3: Prepare the command sequence for Quad I/O Read Manufacturer/Device ID
command[0] = 0x94; // Command for Quad I/O Read Manufacturer/Device ID
command[1] = 0x00; // Dummy address byte 1
command[2] = 0x00; // Dummy address byte 2
command[3] = 0x00; // Dummy address byte 3
command[4] = 0x00; // Mode byte (ignored, 2 clocks)
command[5] = 0x00; // Dummy byte (4 clocks)

// Step 4: Send the command sequence using 1-bit for command and 4-bit for address/data
err = R_QSPI_DirectWrite(&g_qspi0_ctrl, command, 6, true);
if (err != FSP_SUCCESS)
{
return;
}

// Short delay to ensure command is processed
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);

// Step 5: Read Manufacturer ID and Device ID (2 bytes) in Quad I/O mode
err = R_QSPI_DirectRead(&g_qspi0_ctrl, read_data, 2);
if (err != FSP_SUCCESS)
{
return;
}

// Step 6: Retrieve Manufacturer and Device ID from read data
manufacturer_id = read_data[0];
device_id = read_data[1];
R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);

}

Schematic Snap:

FSP Configurator Snaps:

Thanks,

Parth

  • Can you pullup all lines. Here EK-RA6M3 schematics.

  • Thanks for going through my query.

    Tried with pull-ups, still facing same issue.

    Regards,

    Parth

  • The AT25FF321A only supports receiving commands on a single pin :- 

    The SI (or IO0) pin.

    You can't use Quad SPI protocol to communicate with the AT25FF321A, as in Quad SPI protocol the commands are sent on all 4 QIO pins.

    You will have to use Extended SPI mode :- 

  • Could you please help me to modify the below code to write and read back few bytes using the quad write (32h) command? I've tried everything, but I haven't had any success so far.

    Code -

    void qspi_test()
    {
    uint8_t data[10];
    uint8_t id_data[2];
    uint8_t status[2]; // Buffer for status registers
    uint32_t timeout_ms;
    uint32_t elapsed_time;
    uint32_t polling_interval;
    uint8_t command[10];
    spi_flash_cfg_t qspi_cfg;
    uint32_t device_size_bytes;

    // Copy and modify QSPI configuration
    memcpy((spi_flash_cfg_t *)&qspi_cfg, (spi_flash_cfg_t *)&g_qspi0_cfg, sizeof(spi_flash_cfg_t));
    qspi_cfg.spi_protocol = SPI_FLASH_PROTOCOL_EXTENDED_SPI;
    qspi_cfg.page_program_command = 0x32;
    R_QSPI_Open(&g_qspi0_ctrl, &qspi_cfg);

    // Step 1: Check and set Quad Enable (QE) bit if not set
    uint8_t cmd_read_status[1] = {0x35}; // Read Status Register 2 command
    R_QSPI_DirectWrite(&g_qspi0_ctrl, cmd_read_status, 1, true);
    R_QSPI_DirectRead(&g_qspi0_ctrl, status, 1);

    if (!(status[0] & 0x02)) // Check if QE bit is set
    {
    // QE bit not set, set it explicitly
    uint8_t cmd_write_enable[1] = {0x06}; // Write Enable command
    uint8_t cmd_write_status[2] = {0x31, 0x02}; // Write Status Register 2 command, setting QE bit

    R_QSPI_DirectWrite(&g_qspi0_ctrl, cmd_write_enable, 1, false);
    R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_MILLISECONDS);

    R_QSPI_DirectWrite(&g_qspi0_ctrl, cmd_write_status, 2, false);
    R_BSP_SoftwareDelay(2, BSP_DELAY_UNITS_MILLISECONDS);

    // Poll the status register to wait for write completion
    do {
    data[0] = 0x35; // Read Status Register command
    R_QSPI_DirectWrite(&g_qspi0_ctrl, data, 1, true);
    R_QSPI_DirectRead(&g_qspi0_ctrl, status, 1);
    } while (status[0] & 0x02); // Wait while the device is busy
    }

    // enter into extended SPI mode
    R_QSPI_SpiProtocolSet(&g_qspi0_ctrl, SPI_FLASH_PROTOCOL_EXTENDED_SPI);
    R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS);


    // Step 2 : Erase the sector/block
    err2 = R_QSPI_Erase(&g_qspi0_ctrl, 0, 4096);
    R_BSP_SoftwareDelay(100, BSP_DELAY_UNITS_MILLISECONDS);


    // Step 3 : write bytes
    address = 0;
    data[0] = 0x67;
    data[1] = 0x85;
    R_QSPI_Write(&g_qspi0_ctrl, data, (uint8_t *)QSPI_FLASH_ADDRESS(PAGE_FIRST), 1);

    // Poll the status register to wait for write completion
    do {
    data[0] = 0x05; // Read Status Register command
    R_QSPI_DirectWrite(&g_qspi0_ctrl, data, 1, true);
    R_QSPI_DirectRead(&g_qspi0_ctrl, status, 1);
    } while (status[0] & 0x01); // Wait while the device is busy


    // Step 4 : Read-back
    memcpy(read_data, (uint8_t *)QSPI_FLASH_ADDRESS(PAGE_FIRST), 25);
    R_BSP_SoftwareDelay(10, BSP_DELAY_UNITS_MILLISECONDS);

    }

    Thanks,
    Parth