diff options
| -rw-r--r-- | os/ex/Micron/m25q.c | 181 | ||||
| -rw-r--r-- | os/ex/Micron/m25q.h | 27 | ||||
| -rw-r--r-- | os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c | 16 | ||||
| -rw-r--r-- | os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h | 22 | ||||
| -rw-r--r-- | testhal/STM32/STM32L4xx/QSPI-N25Q128/debug/QSPI-N25Q128 (OpenOCD, Flash and Run).launch | 2 | ||||
| -rw-r--r-- | testhal/STM32/STM32L4xx/QSPI-N25Q128/main.c | 10 | 
6 files changed, 227 insertions, 31 deletions
diff --git a/os/ex/Micron/m25q.c b/os/ex/Micron/m25q.c index 9a170a17f..84a67f2cc 100644 --- a/os/ex/Micron/m25q.c +++ b/os/ex/Micron/m25q.c @@ -25,8 +25,9 @@   * @{   */ -#include "hal.h" +#include <string.h> +#include "hal.h"  #include "m25q.h"  /*===========================================================================*/ @@ -82,11 +83,7 @@ static flash_descriptor_t descriptor = {    .attributes       = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE |                        FLASH_ATTR_SUSPEND_ERASE_CAPABLE,    .page_size        = 256U, -#if M25Q_USE_SUB_SECTORS == TRUE -  .sectors_count    = 4096U, -#else -  .sectors_count    = 256U, -#endif +  .sectors_count    = 0U,           /* It is overwritten.*/    .sectors          = NULL,    .sectors_size     = SECTOR_SIZE,    .address          = 0U @@ -209,9 +206,11 @@ static const uint8_t evconf_value[1] = {0xCF};  #elif M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI2L  static const uint8_t evconf_value[1] = {0x8F};  #else -static const uint8_t evconf_value[1] = {0xCF};//{0x4F}; +static const uint8_t evconf_value[1] = {0x4F};  #endif +static const uint8_t flash_status[1] = {(M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU}; +  #endif /* M25Q_BUS_MODE != M25Q_BUS_MODE_SPI */  /*===========================================================================*/ @@ -314,6 +313,39 @@ static void flash_cmd_receive(M25QDriver *devp,  #endif  } +static void flash_cmd_send(M25QDriver *devp, +                           uint8_t cmd, +                           size_t n, +                           const uint8_t *p) { +#if M25Q_BUS_MODE != M25Q_BUS_MODE_SPI +  qspi_command_t mode; + +  mode.cfg = QSPI_CFG_CMD(cmd) | +#if M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI1L +             QSPI_CFG_CMD_MODE_ONE_LINE | +             QSPI_CFG_DATA_MODE_ONE_LINE; +#elif M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI2L +             QSPI_CFG_CMD_MODE_TWO_LINES | +             QSPI_CFG_DATA_MODE_TWO_LINES; +#else +             QSPI_CFG_CMD_MODE_FOUR_LINES | +             QSPI_CFG_DATA_MODE_FOUR_LINES; + +#endif +  mode.addr = 0U; +  mode.alt  = 0U; +  qspiSend(devp->config->qspip, &mode, n, p); +#else +  uint8_t buf[1]; + +  spiSelect(devp->config->spip); +  buf[0] = cmd; +  spiSend(devp->config->spip, 1, buf); +  spiSend(devp->config->spip, n, p); +  spiUnselect(devp->config->spip); +#endif +} +  static void flash_cmd_addr(M25QDriver *devp,                             uint8_t cmd,                             flash_address_t addr) { @@ -437,6 +469,42 @@ static void flash_cmd_addr_receive(M25QDriver *devp,  #endif  } +#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) || defined(__DOXYGEN__) +static void flash_cmd_addr_dummy_receive(M25QDriver *devp, +                                         uint8_t cmd, +                                         flash_address_t addr, +                                         uint8_t dummy, +                                         size_t n, +                                         uint8_t *p) { +  qspi_command_t mode; + +  mode.cfg = QSPI_CFG_CMD(cmd) | +#if M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI1L +             QSPI_CFG_CMD_MODE_ONE_LINE | +             QSPI_CFG_ADDR_MODE_ONE_LINE | +             QSPI_CFG_ADDR_SIZE_24 | +             QSPI_CFG_DUMMY_CYCLES(dummy) | +             QSPI_CFG_DATA_MODE_ONE_LINE; +#elif M25Q_BUS_MODE == M25Q_BUS_MODE_QSPI2L +             QSPI_CFG_CMD_MODE_TWO_LINES | +             QSPI_CFG_ADDR_MODE_TWO_LINES | +             QSPI_CFG_ADDR_SIZE_24 | +             QSPI_CFG_DUMMY_CYCLES(dummy) | +             QSPI_CFG_DATA_MODE_TWO_LINES; +#else +             QSPI_CFG_CMD_MODE_FOUR_LINES | +             QSPI_CFG_ADDR_MODE_FOUR_LINES | +             QSPI_CFG_ADDR_SIZE_24 | +             QSPI_CFG_DUMMY_CYCLES(dummy) | +             QSPI_CFG_DATA_MODE_FOUR_LINES; + +#endif +  mode.addr = addr; +  mode.alt  = 0U; +  qspiReceive(devp->config->qspip, &mode, n, p); +} +#endif /* M25Q_BUS_MODE != M25Q_BUS_MODE_SPI */ +  static flash_error_t flash_poll_status(M25QDriver *devp) {    return FLASH_NO_ERROR; @@ -454,6 +522,38 @@ static const flash_descriptor_t *get_descriptor(void *instance) {  static flash_error_t read(void *instance, flash_address_t addr,                            uint8_t *rp, size_t n) { +  M25QDriver *devp = (M25QDriver *)instance; + +  osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U)); +  osalDbgCheck((size_t)addr + n <= (size_t)descriptor.sectors_count * +                                   (size_t)descriptor.sectors_size); +  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), +                "invalid state"); + +  if (devp->state == FLASH_ERASE) { +    return FLASH_BUSY_ERASING; +  } + +  /* Bus acquired.*/ +  flash_bus_acquire(devp); + +  /* FLASH_READY state while the operation is performed.*/ +  devp->state = FLASH_READ; + +#if M25Q_BUS_MODE != M25Q_BUS_MODE_SPI +  /* Fast read command in QSPI mode.*/ +  flash_cmd_addr_dummy_receive(devp, M25Q_CMD_FAST_READ, +                               addr, M25Q_READ_DUMMY_CYCLES, +                               n, rp); +#else +  /* Normal read command in SPI mode.*/ +#endif + +  /* Ready state again.*/ +  devp->state = FLASH_READY; + +  /* Bus released.*/ +  flash_bus_release(devp);    return FLASH_NO_ERROR;  } @@ -516,6 +616,18 @@ void m25qObjectInit(M25QDriver *devp) {  #endif  } +static const qspi_command_t cmd_test_reset_enable_4 = { +  .cfg              = QSPI_CFG_ALT_MODE_FOUR_LINES, +  .addr             = 0, +  .alt              = M25Q_CMD_RESET_ENABLE +}; + +static const qspi_command_t cmd_test_reset_memory_4 = { +  .cfg              = QSPI_CFG_ALT_MODE_FOUR_LINES, +  .addr             = 0, +  .alt              = M25Q_CMD_RESET_MEMORY +}; +  /**   * @brief   Configures and activates N25Q128 driver.   * @@ -532,7 +644,6 @@ void m25qStart(M25QDriver *devp, const M25QConfig *config) {    devp->config = config;    if (devp->state == FLASH_STOP) { -    uint8_t id[3];      /* Bus acquisition.*/      flash_bus_acquire(devp); @@ -546,46 +657,62 @@ void m25qStart(M25QDriver *devp, const M25QConfig *config) {      /* QSPI initialization.*/      qspiStart(devp->config->qspip, devp->config->qspicfg); +    /* Reading device ID and unique ID.*/ +  #if M25Q_SWITCH_WIDTH == TRUE -    /* Attempting a device reset with decreasing bus widths, commands +    /* Attempting a device reset with different bus widths, commands         shorter than 8 bits are ignored.*/ -    qspiCommand(devp->config->qspip, &cmd_reset_enable_4); -    qspiCommand(devp->config->qspip, &cmd_reset_memory_4); -    qspiCommand(devp->config->qspip, &cmd_reset_enable_2); -    qspiCommand(devp->config->qspip, &cmd_reset_memory_2);      qspiCommand(devp->config->qspip, &cmd_reset_enable_1);      qspiCommand(devp->config->qspip, &cmd_reset_memory_1); +    qspiCommand(devp->config->qspip, &cmd_reset_enable_2); +    qspiCommand(devp->config->qspip, &cmd_reset_memory_2); +    qspiCommand(devp->config->qspip, &cmd_reset_enable_4); +    qspiCommand(devp->config->qspip, &cmd_reset_memory_4);  #endif -    /* Reading device ID.*/ -    qspiReceive(devp->config->qspip, &cmd_read_id, 3, id); +    /* Reading device ID and unique ID.*/ +    qspiReceive(devp->config->qspip, &cmd_read_id, +                sizeof devp->device_id, devp->device_id);  #endif /* M25Q_BUS_MODE != M25Q_BUS_MODE_SPI */      /* Checking if the device is white listed.*/ -    osalDbgAssert(find_id(manufacturer_ids, sizeof manufacturer_ids, id[0]), +    osalDbgAssert(find_id(manufacturer_ids, +                          sizeof manufacturer_ids, +                          devp->device_id[0]),                    "invalid manufacturer id"); -    osalDbgAssert(find_id(memory_type_ids, sizeof memory_type_ids, id[1]), +    osalDbgAssert(find_id(memory_type_ids, +                          sizeof memory_type_ids, +                          devp->device_id[1]),                    "invalid memory type id");  #if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) && (M25Q_SWITCH_WIDTH == TRUE)      /* Setting up final bus width.*/      qspiCommand(devp->config->qspip, &cmd_write_enable);      qspiSend(devp->config->qspip, &cmd_write_evconf, 1, evconf_value); -#endif -    flash_cmd_receive(devp, M25Q_CMD_READ_ID, 3, id); +    { +      uint8_t id[3]; -    flash_cmd_receive(devp, M25Q_CMD_READ_ID, 3, id); +      /* Reading ID again for confirmation.*/ +      flash_cmd_receive(devp, M25Q_CMD_MULTIPLE_IO_READ_ID, 3, id); -    /* Reading device ID.*/ -    qspiReceive(devp->config->qspip, &cmd_read_id, 3, id); +      /* Checking if the device is white listed.*/ +      osalDbgAssert(memcmp(id, devp->device_id, 3) == 0, +                    "id confirmation failed"); +    } +#endif -    /* Reset Enable command.*/ -//    flash_short_cmd(devp, M25Q_CMD_RESET_ENABLE); +    /* Setting up the device size.*/ +    descriptor.sectors_count = (1U << (size_t)devp->device_id[2]) / SECTOR_SIZE; -    /* Reset Memory command.*/ -//    flash_short_cmd(devp, M25Q_CMD_RESET_MEMORY); +#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) +    /* Setting up the dummy cycles to be used for rast read operations.*/ +    flash_cmd(devp, M25Q_CMD_WRITE_ENABLE); +    flash_cmd_send(devp, M25Q_CMD_WRITE_V_CONF_REGISTER, +                   1, flash_status); +#endif +    /* Driver in ready state.*/      devp->state = FLASH_READY;      /* Bus release.*/ @@ -617,6 +744,8 @@ void m25qStop(M25QDriver *devp) {  #endif      devp->config = NULL; + +    /* Driver stopped.*/      devp->state = FLASH_STOP;      /* Bus release.*/ diff --git a/os/ex/Micron/m25q.h b/os/ex/Micron/m25q.h index 27ee06afc..865cc32ea 100644 --- a/os/ex/Micron/m25q.h +++ b/os/ex/Micron/m25q.h @@ -41,9 +41,10 @@  #define M25Q_CMD_RESET_ENABLE                       0x66  #define M25Q_CMD_RESET_MEMORY                       0x99  #define M25Q_CMD_READ_ID                            0x9F +#define M25Q_CMD_MULTIPLE_IO_READ_ID                0xAF  #define M25Q_CMD_READ_DISCOVERY_PARAMETER           0x5A  #define M25Q_CMD_READ                               0x03 -#define M25Q_CMD_FAST_READ                          0x08 +#define M25Q_CMD_FAST_READ                          0x0B  #define M25Q_CMD_WRITE_ENABLE                       0x06  #define M25Q_CMD_WRITE_DISABLE                      0x04  #define M25Q_CMD_READ_STATUS_REGISTER               0x05 @@ -112,6 +113,15 @@  #endif  /** + * @brief   Number of dummy cycles for fast read (1..15). + * @details This is the number of dummy cycles to be used for fast read + *          operations. + */ +#if !defined(M25Q_READ_DUMMY_CYCLES) || defined(__DOXYGEN__) +#define M25Q_READ_DUMMY_CYCLES              8 +#endif + +/**   * @brief   Switch QSPI bus width on initialization.   * @details A bus width initialization is performed by writing the   *          Enhanced Volatile Configuration Register. If the flash @@ -185,6 +195,17 @@  #error "M25Q_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION"  #endif +#if (M25Q_BUS_MODE != M25Q_BUS_MODE_SPI) &&                                 \ +    (M25Q_BUS_MODE != M25Q_BUS_MODE_QSPI1L) &&                              \ +    (M25Q_BUS_MODE != M25Q_BUS_MODE_QSPI2L) &&                              \ +    (M25Q_BUS_MODE != M25Q_BUS_MODE_QSPI4L) +#error "invalid M25Q_BUS_MODE selected" +#endif + +#if (M25Q_READ_DUMMY_CYCLES < 1) || (M25Q_READ_DUMMY_CYCLES > 15) +#error "invalid M25Q_READ_DUMMY_CYCLES value (1..15)" +#endif +  /*===========================================================================*/  /* Driver data structures and types.                                         */  /*===========================================================================*/ @@ -250,6 +271,10 @@ typedef struct {     */    uint32_t                      qspi_mode;  #endif +  /** +   * @brief   Device ID and unique ID. +   */ +  uint8_t                       device_id[20];  } M25QDriver;  /*===========================================================================*/ diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c index 40df845db..f914b6163 100644 --- a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c +++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.c @@ -211,6 +211,22 @@ void qspi_lld_stop(QSPIDriver *qspip) {   */
  void qspi_lld_command(QSPIDriver *qspip, const qspi_command_t *cmdp) {
 +#if STM32_USE_STM32_D1_WORKAROUND == TRUE
 +  /* If it is a command without address and alternate phases then the command
 +     is sent as an alternate byte, the command phase is suppressed.*/
 +  if ((cmdp->cfg & (QSPI_CFG_ADDR_MODE_MASK | QSPI_CFG_ALT_MODE_MASK)) == 0U) {
 +    uint32_t cfg;
 +
 +    /* The command mode field is copied in the alternate mode field. All
 +       other fields are not used in this scenario.*/
 +    cfg = (cmdp->cfg  & QSPI_CFG_CMD_MODE_MASK) << 6U;
 +
 +    qspip->qspi->DLR = 0U;
 +    qspip->qspi->ABR = cmdp->cfg & QSPI_CFG_CMD_MASK;
 +    qspip->qspi->CCR = cfg;
 +    return;
 +  }
 +#endif
    qspip->qspi->DLR = 0U;
    qspip->qspi->ABR = cmdp->alt;
    qspip->qspi->CCR = cmdp->cfg;
 diff --git a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h index c3a82d690..4465755bf 100644 --- a/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h +++ b/os/hal/ports/STM32/LLD/QUADSPIv1/hal_qspi_lld.h @@ -31,6 +31,17 @@  /* Driver constants.                                                         */
  /*===========================================================================*/
 +/**
 + * @name    DCR register options
 + * @{
 + */
 +#define STM32_DCR_CK_MODE                   (1U << 0U)
 +#define STM32_DCR_CSHT_MASK                 (7U << 8U)
 +#define STM32_DCR_CSHT(n)                   ((n) << 8U)
 +#define STM32_DCR_FSIZE_MASK                (31U << 16U)
 +#define STM32_DCR_FSIZE(n)                  ((n) << 16U)
 +/** @} */
 +
  /*===========================================================================*/
  /* Driver pre-compile time settings.                                         */
  /*===========================================================================*/
 @@ -85,6 +96,17 @@  #if !defined(STM32_QSPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
  #define STM32_QSPI_DMA_ERROR_HOOK(qspip)    osalSysHalt("DMA failure")
  #endif
 +
 +/**
 + * @brief   Enables a workaround for a STM32L476 QUADSPI errata.
 + * @details The document DM00111498 states: "QUADSPI_BK1_IO1 is always an
 + *          input when the command is sent in dual or quad SPI mode".
 + *          This workaround makes commands without address or data phases
 + *          to be sent as alternate bytes.
 + */
 +#if !defined(STM32_USE_STM32_D1_WORKAROUND) || defined(__DOXYGEN__)
 +#define STM32_USE_STM32_D1_WORKAROUND       TRUE
 +#endif
  /** @} */
  /*===========================================================================*/
 diff --git a/testhal/STM32/STM32L4xx/QSPI-N25Q128/debug/QSPI-N25Q128 (OpenOCD, Flash and Run).launch b/testhal/STM32/STM32L4xx/QSPI-N25Q128/debug/QSPI-N25Q128 (OpenOCD, Flash and Run).launch index 5c5c982a2..573a54f12 100644 --- a/testhal/STM32/STM32L4xx/QSPI-N25Q128/debug/QSPI-N25Q128 (OpenOCD, Flash and Run).launch +++ b/testhal/STM32/STM32L4xx/QSPI-N25Q128/debug/QSPI-N25Q128 (OpenOCD, Flash and Run).launch @@ -33,7 +33,7 @@  <intAttribute key="org.eclipse.cdt.launch.ATTR_BUILD_BEFORE_LAUNCH_ATTR" value="2"/>
  <stringAttribute key="org.eclipse.cdt.launch.COREFILE_PATH" value=""/>
  <stringAttribute key="org.eclipse.cdt.launch.DEBUGGER_REGISTER_GROUPS" value=""/>
 -<stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?><contentList><content id="id[2]-id-m25qStart-(format)" val="4"/><content id="id[1]-id-m25qStart-(format)" val="4"/><content id="id[0]-id-m25qStart-(format)" val="4"/><content id="cr2-adc_lld_start_conversion-(format)" val="4"/><content id="CR2-adc-null-port_wait_for_interrupt-(format)" val="4"/><content id="CR2-adc-adcp-adc_lld_start_conversion-(format)" val="4"/><content id="cfg-cmdp-qspiSend-(format)" val="4"/><content id="CR-qspi-qspip-qspi_lld_send-(format)" val="4"/><content id="CCR-qspi-qspip-qspi_lld_send-(format)" val="4"/><content id="cfg-cmdp-qspiReceive-(format)" val="4"/><content id="r2-(format)" val="4"/></contentList>"/>
 +<stringAttribute key="org.eclipse.cdt.launch.FORMAT" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?><contentList><content id="CCR-qspi-qspip-qspi_lld_receive-(format)" val="4"/><content id="cfg-cmdp-qspi_lld_receive-(format)" val="4"/><content id="id[2]-id-m25qStart-(format)" val="4"/><content id="id[1]-id-m25qStart-(format)" val="4"/><content id="id[0]-id-m25qStart-(format)" val="4"/><content id="AFRL-gpiop-initgpio-(format)" val="4"/><content id="AFRH-gpiop-initgpio-(format)" val="4"/><content id="ODR-gpiop-initgpio-(format)" val="4"/><content id="IDR-gpiop-initgpio-(format)" val="4"/><content id="PUPDR-gpiop-initgpio-(format)" val="4"/><content id="OSPEEDR-gpiop-initgpio-(format)" val="4"/><content id="MODER-gpiop-initgpio-(format)" val="4"/><content id="afrh-config-initgpio-(format)" val="4"/><content id="moder-config-initgpio-(format)" val="4"/><content id="config-initgpio-(format)" val="4"/><content id="r2-(format)" val="4"/><content id="cfg-cmdp-qspiReceive-(format)" val="4"/><content id="CCR-qspi-qspip-qspi_lld_send-(format)" val="4"/><content id="CR-qspi-qspip-qspi_lld_send-(format)" val="4"/><content id="cfg-cmdp-qspiSend-(format)" val="4"/><content id="CR2-adc-adcp-adc_lld_start_conversion-(format)" val="4"/><content id="CR2-adc-null-port_wait_for_interrupt-(format)" val="4"/><content id="cr2-adc_lld_start_conversion-(format)" val="4"/><content id="cmd-flash_cmd_receive-(format)" val="4"/></contentList>"/>
  <stringAttribute key="org.eclipse.cdt.launch.GLOBAL_VARIABLES" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<globalVariableList/>
"/>
  <stringAttribute key="org.eclipse.cdt.launch.MEMORY_BLOCKS" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<memoryBlockExpressionList/>
"/>
  <stringAttribute key="org.eclipse.cdt.launch.PROGRAM_NAME" value="./build/ch.elf"/>
 diff --git a/testhal/STM32/STM32L4xx/QSPI-N25Q128/main.c b/testhal/STM32/STM32L4xx/QSPI-N25Q128/main.c index 5e57497fa..51abd65cd 100644 --- a/testhal/STM32/STM32L4xx/QSPI-N25Q128/main.c +++ b/testhal/STM32/STM32L4xx/QSPI-N25Q128/main.c @@ -21,7 +21,7 @@  const QSPIConfig qspicfg1 = {
    NULL,
 -  0
 +  STM32_DCR_FSIZE(24) | STM32_DCR_CSHT(1)
  };
  qspi_command_t cmd_read_id = {
 @@ -63,6 +63,7 @@ static THD_FUNCTION(Thread1, arg) {   * Application entry point.
   */
  int main(void) {
 +  flash_error_t err;
    /*
     * System initializations.
 @@ -89,8 +90,11 @@ int main(void) {     */
    m25qObjectInit(&m25q);
    m25qStart(&m25q, &m25qcfg1);
 -//  qspiStart(&QSPID1, &qspicfg1);
 -//  qspiReceive(&QSPID1, &cmd_read_id, 17, buffer);
 +
 +  /* Reading it back.*/
 +  err = flashRead(&m25q, 0, buffer, 128);
 +  if (err != FLASH_NO_ERROR)
 +    chSysHalt("read error");
    /*
     * Normal main() thread activity, in this demo it does nothing.
  | 
