mbed_example / Mbed OS mbed-os-example-qspi

main.cpp

Committer:
Maciej Bocianski
Date:
2018-09-04
Revision:
5:da509493e3e6
Parent:
2:3165b07182ad
Child:
6:3a643419d247

File content as of revision 5:da509493e3e6:

#include "mbed.h"
#include "QSPI.h"

// The below values are command codes defined in Datasheet for MX25R6435F Macronix Flash Memory
// should work for whole MX25RXX35F chip family

// Command for reading status register
#define QSPI_STD_CMD_RDSR                   0x05
// Command for reading configuration register
#define QSPI_STD_CMD_RDCR                   0x15
// Command for writing status/configuration register
#define QSPI_STD_CMD_WRSR                   0x01
// Command for setting WREN (supported only by some memories)
#define QSPI_STD_CMD_WREN                   0x06
// Command for Sector erase (supported only by some memories)
#define QSPI_STD_CMD_SECT_ERASE             0x20
//
#define QSPI_STD_CMD_WRITE_1IO              0x02   // 1-1-1 mode
#define QSPI_STD_CMD_WRITE_4IO              0x38   // 1-4-4 mode
#define QSPI_STD_CMD_READ_1IO               0x03   // 1-1-1 mode
#define QSPI_STD_CMD_READ_4IO               0xEB   // 1-4-4 mode

#define QSPI_STD_CMD_RSTEN                  0x66
// Command for setting Reset (supported only by some memories)
#define QSPI_STD_CMD_RST                    0x99

#define STATUS_BIT_WIP   (1 << 0)   // write in progress bit
#define STATUS_BIT_QE    (1 << 6)   // Quad Enable

#define QSPI_STATUS_REG_SIZE                1

#define QSPI_READ_4IO_DUMMY_CYCLE           6

#define QSPI_MAX_WAIT_TIME                  1000      // 1000 ms

#define TEST_FLASH_ADDRESS  0x1000

//#define DEBUG_ON 1
#ifdef DEBUG_ON
#define VERBOSE_PRINT(x) printf x
#else
#define VERBOSE_PRINT(x)
#endif

bool InitializeFlashMem(QSPI &qspi);
bool WaitForMemReady(QSPI &qspi);
bool SectorErase(QSPI &qspi, unsigned int flash_addr);
bool WriteReadQuad(QSPI &qspi, unsigned int flash_addr);
bool QuadEnable(QSPI &qspi);
bool QuadDisable(QSPI &qspi);


// main() runs in its own thread in the OS
int main()
{
    printf(">>> Start...\r\n");
    QSPI myQspi((PinName)QSPI_FLASH1_IO0, (PinName)QSPI_FLASH1_IO1, (PinName)QSPI_FLASH1_IO2,
                (PinName)QSPI_FLASH1_IO3, (PinName)QSPI_FLASH1_SCK, (PinName)QSPI_FLASH1_CSN);

    if (false == InitializeFlashMem(myQspi)) {
        printf("[main] Unable to initialize flash memory, tests failed\r\n");
        return -1;
    }

    if (false == WriteReadQuad(myQspi, TEST_FLASH_ADDRESS)) {
        printf("[main] Unable to read/write using QuadSPI\r\n");
        return -1;
    }

    printf("<<< Done...\r\n\r\n");
}

bool WriteReadQuad(QSPI &qspi, unsigned int flash_addr)
{
    int result = 0;
    char tx_buf[] = { 'H', 'E', 'L', 'L', 'O', ' ', 'Q', 'U', 'A', 'D', '-', 'S', 'P', 'I', '!', 0 };
    char rx_buf[16];
    size_t buf_len = sizeof(tx_buf);

    if (false == SectorErase(qspi, flash_addr)) {
        printf("[WriteReadQuad] ERROR: SectorErase failed(addr = 0x%08lX)\r\n", flash_addr);
        return false;
    }

    if (false == QuadEnable(qspi)) {
        printf("[WriteReadQuad] ERROR: Quad enable failed\r\n");
        return false;
    }

    // Send write enable
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_WREN, // command to send
                                                -1,                // no address to transmit
                                                NULL, 0,           // do not transmit
                                                NULL, 0)) {        // do not receive
        VERBOSE_PRINT(("[WriteReadQuad] Sending WREN command success\r\n"));
    } else {
        printf("[WriteReadQuad] ERROR: Sending WREN command failed\r\n");
        return false;
    }

    if (QSPI_STATUS_OK == qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_QUAD, QSPI_CFG_ADDR_SIZE_24,
                                                QSPI_CFG_BUS_QUAD, QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_QUAD, 0)) {
        printf("Configured QSPI driver succesfully: 1-4-4\r\n");
    } else {
        printf("[WriteReadQuad] ERROR: Failed configuring QSPI driver\r\n");
        return -1;
    }

    printf("Writing: %s\r\n", tx_buf);
    result = qspi.write(QSPI_STD_CMD_WRITE_4IO, 0, flash_addr, tx_buf, &buf_len);
    if ((result != QSPI_STATUS_OK) || buf_len != sizeof(tx_buf)) {
        printf("[WriteReadQuad] ERROR: Write failed\r\n");
    }

    if (false == WaitForMemReady(qspi)) {
        printf("[WriteReadQuad] ERROR: Device not ready, tests failed\r\n");
        return false;
    }

    // Set dummy cycle count for read operation
    if (QSPI_STATUS_OK == qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_QUAD, QSPI_CFG_ADDR_SIZE_24,
                                                QSPI_CFG_BUS_QUAD, QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_QUAD, QSPI_READ_4IO_DUMMY_CYCLE)) {
        printf("Configured QSPI driver succesfully: dummy cycle set to 6\r\n");
    } else {
        printf("[WriteReadQuad] ERROR: Failed configuring QSPI driver\r\n");
        return -1;
    }

    memset(rx_buf, 0, sizeof(rx_buf));
    result = qspi.read(QSPI_STD_CMD_READ_4IO, 0, flash_addr, rx_buf, &buf_len);
    if (result != QSPI_STATUS_OK) {
        printf("[WriteReadQuad] ERROR: Read failed\r\n");
        return false;
    }

    if (buf_len != sizeof(rx_buf)) {
        printf("[WriteReadQuad] ERROR: Unable to read the entire buffer\r\n");
        return false;
    }

    if (0 != (memcmp(rx_buf, tx_buf, sizeof(rx_buf)))) {
        printf("[WriteReadQuad] ERROR: Buffer contents are invalid\r\n");
        printf("tx_buf: ");
        for (uint32_t i = 0; i < buf_len; i++) {
            printf("%d ", tx_buf[i]);
        }
        printf("\r\n");
        printf("rx_buf: ");
        for (uint32_t i = 0; i < buf_len; i++) {
            printf("%d ", rx_buf[i]);
        }
        printf("\r\n");
        return false;
    }
    printf("Read: %s\r\n", rx_buf);

    // Reset dummy cycle count
    if (QSPI_STATUS_OK == qspi.configure_format(QSPI_CFG_BUS_SINGLE, QSPI_CFG_BUS_QUAD, QSPI_CFG_ADDR_SIZE_24,
                                                QSPI_CFG_BUS_QUAD, QSPI_CFG_ALT_SIZE_8, QSPI_CFG_BUS_QUAD, 0)) {
        printf("Configured QSPI driver succesfully: dummy cycle set to 0\r\n");
    } else {
        printf("[WriteReadQuad] ERROR: Failed configuring QSPI driver\r\n");
        return -1;
    }

    if (false == QuadDisable(qspi)) {
        printf("[WriteReadQuad] ERROR: Quad disable failed\r\n");
        return false;
    }

    return true;
}

bool InitializeFlashMem(QSPI &qspi)
{
    char reg_data[QSPI_STATUS_REG_SIZE];

    // Read the Status Register from device
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_RDSR,   // command to send
                                                -1,                  // no address to transmit
                                                NULL, 0,             // do not transmit
                                                reg_data, QSPI_STATUS_REG_SIZE)) {
        VERBOSE_PRINT(("[InitializeFlashMem] Reading Status Register Success: value = 0x%02X\r\n", status_value[0]));
    } else {
        printf("[InitializeFlashMem] ERROR: Reading Status Register failed\r\n");
        return false;
    }

    // Send Reset Enable
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_RSTEN,  // command to send
                                                -1,                  // no address to transmit
                                                NULL, 0,             // do not transmit
                                                NULL, 0)) {          // do not receive
        VERBOSE_PRINT(("[InitializeFlashMem] Sending RSTEN Success\r\n"));
    } else {
        printf("[InitializeFlashMem] ERROR: Sending RSTEN failed\r\n");
        return false;
    }

    // Reset device
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_RST,   // command to send
                                                -1,                 // no address to transmit
                                                NULL, 0,            // do not transmit
                                                NULL, 0)) {         // do not receive
        VERBOSE_PRINT(("[InitializeFlashMem] Sending RST Success\r\n"));
    } else {
        printf("[InitializeFlashMem] ERROR: Sending RST failed\r\n");
        return false;
    }

    return true;
}

bool WaitForMemReady(QSPI &qspi)
{
    char status_value[QSPI_STATUS_REG_SIZE];
    Timer timer;

    timer.start();
    do {
        // Read the Status Register from device
        if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_RDSR,                  // command to send
                                                    -1,                                 // no address to transmit
                                                    NULL, 0,                            // do not transmit
                                                    status_value, QSPI_STATUS_REG_SIZE)) {
            VERBOSE_PRINT(("[WaitForMemReady] Readng Status Register Success: value = 0x%02X\r\n", status_value[0]));
        } else {
            printf("[WaitForMemReady] ERROR: Reading Status Register failed\r\n");
        }
    } while ((status_value[0] & STATUS_BIT_WIP) != 0 && timer.read_ms() < QSPI_MAX_WAIT_TIME);

    if ((status_value[0] & STATUS_BIT_WIP) != 0) {
        return false;
    }
    return true;
}

bool SectorErase(QSPI &qspi, unsigned int flash_addr)
{
    //  Set wite enable
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_WREN, // command to send
                                                -1,                 // no address to transmit
                                                NULL, 0,             // do not transmit
                                                NULL, 0)) {   // do not receive
        VERBOSE_PRINT(("[SectorErase] Sending WREN command success\r\n"));
    } else {
        printf("[SectorErase] ERROR: Sending WREN command failed\r\n");
        return false;
    }
    // sector erase
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_SECT_ERASE, // command to send
                                                flash_addr,              // sector address (any address within sector)
                                                NULL, 0,                 // do not transmit
                                                NULL, 0)) {              // do not receive
        VERBOSE_PRINT(("[SectorErase] Sending SECT_ERASE command success\r\n"));
    } else {
        printf("[SectorErase] ERROR: Readng SECT_ERASE command failed\r\n");
        return false;
    }

    if (false == WaitForMemReady(qspi)) {
        printf("[SectorErase] ERROR: Device not ready, tests failed\r\n");
        return false;
    }

    return true;
}

bool QuadEnable(QSPI &qspi)
{
    char reg_data[QSPI_STATUS_REG_SIZE];

    //Read the Status Register from device
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_RDSR,                  // command to send
                                                -1,                                 // no address to transmit
                                                NULL, 0,                            // do not transmit
                                                reg_data, QSPI_STATUS_REG_SIZE)) {
        VERBOSE_PRINT(("[QuadEnable] Reading Status Register Success: value = 0x%02X\r\n", reg_data[0]));
    } else {
        printf("ERROR: Reading Status Register failed\r\n");
        return false;
    }
    //  Set wite enable
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_WREN,  // command to send
                                                -1,                 // no address to transmit
                                                NULL, 0,            // do not transmit
                                                NULL, 0)) {         // do not receive
        VERBOSE_PRINT(("[QuadEnable] Sending WREN command success\r\n"));
    } else {
        printf("[QuadEnable] ERROR: Sending WREN command failed\r\n");
        return false;
    }
    //Set the Status Register to set QE enable bit
    reg_data[0] |= (STATUS_BIT_QE);
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_WRSR,               // command to send
                                                -1,                              // no address to transmit
                                                reg_data, QSPI_STATUS_REG_SIZE,
                                                NULL, 0)) {                      // do not receive
        VERBOSE_PRINT(("[QuadEnable] Writing Status Register Success\r\n"));
    } else {
        printf("[QuadEnable] ERROR: Writing Status Register failed\r\n");
        return false;
    }

    if (false == WaitForMemReady(qspi)) {
        printf("[QuadEnable] ERROR: Device not ready, tests failed\r\n");
        return false;
    }

    return true;
}

bool QuadDisable(QSPI &qspi)
{
    char reg_data[QSPI_STATUS_REG_SIZE];

    // Read the Status Register from device
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_RDSR,  // command to send
                                                -1,                 // no address to transmit
                                                NULL, 0,            // do not transmit
                                                reg_data, QSPI_STATUS_REG_SIZE)) {
        VERBOSE_PRINT(("[QuadDisable] Reading Status Register Success: value = 0x%02X\r\n", reg_data[0]));
    } else {
        printf("[QuadDisable] ERROR: Reading Status Register failed\r\n");
        return false;
    }

    // Set write enable
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_WREN,  // command to send
                                                -1,                 // no address to transmit
                                                NULL, 0,            // do not transmit
                                                NULL, 0)) {         // do not receive
        VERBOSE_PRINT(("[QuadDisable] Sending WREN command success\r\n"));
    } else {
        printf("[QuadDisable] ERROR: Sending WREN command failed\r\n");
        return false;
    }
    //Set the Status Register to reset QE enable bit
    reg_data[0] &= ~(STATUS_BIT_QE);
    if (QSPI_STATUS_OK == qspi.command_transfer(QSPI_STD_CMD_WRSR,               // command to send
                                                -1,                              // no address to transmit
                                                reg_data, QSPI_STATUS_REG_SIZE,
                                                NULL, 0)) {                      // do not receive
        VERBOSE_PRINT(("[QuadDisable] Writing Status Register Success\r\n"));
    } else {
        printf("[QuadDisable] ERROR: Writing Status Register failed\r\n");
        return false;
    }

    if (false == WaitForMemReady(qspi)) {
        printf("[QuadDisable] ERROR: Device not ready, tests failed\r\n");
        return false;
    }

    return true;
}