Mistake on this page?
Report an issue in GitHub or email us

QuadSPI (QSPI)

QSPI class hierarchy

QSPI class hierarchy

The QSPI driver in Mbed OS provides functionality to configure and access QSPI devices connected over a QuadSPI interface.

The QSPI protocol provides a serial communication interface on four data lines between the host and the device. It uses up to six lines in total: one line for chip select, one line for clock and four lines for data in/out. You can use this interface for communication with QSPI devices, such as Flash memory, display devices and other types of devices providing QuadSPI communication support. You can also configure the QSPI interface to work in Single-SPI (traditional SPI) mode or Dual-SPI mode.

The default configuration for the QSPI interface is 1 MHz, Single-SPI, Mode 0.

The above diagram shows an example hardware configuration of a Flash memory connected over a QSPI interface.

For more information, please review the related content.

QuadSPI class reference

Public Member Functions
 QSPI (PinName io0, PinName io1, PinName io2, PinName io3, PinName sclk, PinName ssel=NC, int mode=0)
 Create a QSPI master connected to the specified pins. More...
qspi_status_t configure_format (qspi_bus_width_t inst_width, qspi_bus_width_t address_width, qspi_address_size_t address_size, qspi_bus_width_t alt_width, qspi_alt_size_t alt_size, qspi_bus_width_t data_width, int dummy_cycles)
 Configure the data transmission format. More...
qspi_status_t set_frequency (int hz=1000000)
 Set the qspi bus clock frequency. More...
qspi_status_t read (int address, char *rx_buffer, size_t *rx_length)
 Read from QSPI peripheral with the preset read_instruction and alt_value. More...
qspi_status_t write (int address, const char *tx_buffer, size_t *tx_length)
 Write to QSPI peripheral using custom write instruction. More...
qspi_status_t read (int instruction, int alt, int address, char *rx_buffer, size_t *rx_length)
 Read from QSPI peripheral using custom read instruction, alt values. More...
qspi_status_t write (int instruction, int alt, int address, const char *tx_buffer, size_t *tx_length)
 Write to QSPI peripheral using custom write instruction, alt values. More...
qspi_status_t command_transfer (int instruction, int address, const char *tx_buffer, size_t tx_length, const char *rx_buffer, size_t rx_length)
 Perform a transaction to write to an address(a control register) and get the status results. More...

QuadSPI example

/*
* Copyright (c) 2018 ARM Limited. All rights reserved.
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#if !DEVICE_QSPI
#error [NOT_SUPPORTED] QSPI not supported for this target
#endif

#include "mbed.h"
#include "drivers/QSPI.h"

// For Nordic platforms, use fast read. The QSPI flash memory start address,
// along with the total buffer size, needs to be 4-byte aligned, or divisible by 4.
#if TARGET_NORDIC
#define CMD_READ           0x0B // Fast read
#else
#define CMD_READ           0x03
#endif
#define CMD_WRITE          0x02
#define CMD_ERASE          0x20
#define CMD_RDSR           0x5
#define CMD_WREN           0x6
#define CMD_RSTEN          0x66
#define CMD_RST            0x99
#define STATUS_REG_SIZE    2
#define BIT_WIP            0x1
#define BIT_WEL            0x2
#define BUF_SIZE           12

// hardware ssel (where applicable)
QSPI qspi_device(QSPI_FLASH1_IO0, QSPI_FLASH1_IO1, QSPI_FLASH1_IO2, QSPI_FLASH1_IO3, QSPI_FLASH1_SCK, QSPI_FLASH1_CSN); // io0, io1, io2, io3, sclk, ssel

static bool mem_ready()
{
    char status_value[STATUS_REG_SIZE] = {0xFF};
    int retries = 10000;
    bool mem_ready = true;

    do {
        retries--;
        if (QSPI_STATUS_OK != qspi_device.command_transfer(CMD_RDSR, -1, NULL, 0, status_value, STATUS_REG_SIZE)) {
            printf("Reading Status Register failed \n");
        }
        wait_ms(1);
    } while ((status_value[0] & BIT_WIP) != 0 && retries);

    if ((status_value[0] & BIT_WIP) != 0) {
        printf ("mem_ready FALSE: status value = 0x%x\n", (int)status_value[0]);
        mem_ready = false;
    }
    return mem_ready;
}

static int write_enable()
{
    char status_value[STATUS_REG_SIZE] = {0};
    int status = -1;

    if (QSPI_STATUS_OK != qspi_device.command_transfer(CMD_WREN, -1, NULL, 0, NULL, 0)) {
        printf("Sending WREN command FAILED \n");
        return status;
    }

    if (false == mem_ready()) {
        printf("Device not ready \n");
        return status;
    }

    if (QSPI_STATUS_OK != qspi_device.command_transfer(CMD_RDSR, -1, NULL, 0, status_value, STATUS_REG_SIZE)) {
        printf("Reading Status Register failed \n");
        return status;
    }

    if ((status_value[0] & BIT_WEL)) {
        status = 0;
    }
    return status;
}

static int flash_init()
{
    int status = QSPI_STATUS_OK;
    char status_value[STATUS_REG_SIZE] = {0};

    // Read the Status Register from device
    status =  qspi_device.command_transfer(CMD_RDSR, -1, NULL, 0, status_value, STATUS_REG_SIZE);
    if (status != QSPI_STATUS_OK) {
        printf("Reading Status Register failed: value = 0x%x\n", (int)status_value[0]);
        return status;
    }

    // Send Reset Enable
    status = qspi_device.command_transfer(CMD_RSTEN, -1, NULL, 0, NULL, 0);
    if (status == QSPI_STATUS_OK) {
        printf("Sending RSTEN Success \n");
    } else {
        printf("Sending RSTEN failed \n");
        return status;
    }

    if (false == mem_ready()) {
        printf("Device not ready \n");
        return -1;
    }

    // Send Reset
    status = qspi_device.command_transfer(CMD_RST, -1, NULL, 0, NULL, 0);
    if (status == QSPI_STATUS_OK) {
        printf("Sending RST Success \n");
    } else {
        printf("Sending RST failed \n");
        return status;
    }

    if (false == mem_ready()) {
        printf("Device not ready \n");
        return -1;
    }
    return status;
}

static int sector_erase(unsigned int flash_addr)
{
    if (0 != write_enable()) {
        printf("Write Enabe failed \n");
        return -1;
    }

    if (QSPI_STATUS_OK!= qspi_device.command_transfer(CMD_ERASE, (((int)flash_addr) & 0x00FFF000), NULL, 0, NULL, 0))
    {
        printf("Erase failed\n");
        return -1;
    }

    if (false == mem_ready()) {
        printf("Device not ready \n");
        return -1;
    }

    return 0;
}

int main() {
    char tx_buf[BUF_SIZE] = { 'h', 'e', 'l', 'l', 'o', '\0' };
    char rx_buf[BUF_SIZE] = {0};
    size_t buf_len = sizeof(tx_buf);
    qspi_status_t result;
    uint32_t address = 0x1000;

    result = qspi_device.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_SINGLE,
                                        QSPI_CFG_ADDR_SIZE_24, QSPI_CFG_BUS_SINGLE,
                                        QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_SINGLE, 0);
    if (result != QSPI_STATUS_OK) {
        printf("Config format failed\n");
    }

    if (QSPI_STATUS_OK != flash_init()) {
        printf ("Init failed\n");
        return -1;
    }

    if (0 != sector_erase(address)) {
        return -1;
    }

    if (0 != write_enable()) {
        printf("Write Enabe failed \n");
        return -1;
    }

    result = qspi_device.write(CMD_WRITE, -1, address, tx_buf, &buf_len);
    if (result != QSPI_STATUS_OK) {
        printf("Write failed\n");
        return result;
    }
    printf("Write done: %s \n", tx_buf);

    if (false == mem_ready()) {
        printf("Device not ready \n");
        return -1;
    }

    result = qspi_device.read(CMD_READ, -1, address, rx_buf, &buf_len);
    if (result != QSPI_STATUS_OK) {
        printf("Read failed\n");
        return result;
    }

    printf ("Data Read = %s\n", rx_buf);
    return 0;
}

Important Information for this Arm website

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies. If you are not happy with the use of these cookies, please review our Cookie Policy to learn how they can be disabled. By disabling cookies, some features of the site will not work.