diff options
| -rw-r--r-- | os/hal/lib/complex/m25q/devices/micron_n25q/m25q_flash.c | 547 | ||||
| -rw-r--r-- | os/hal/lib/complex/m25q/devices/micron_n25q/m25q_flash.h | 152 | ||||
| -rw-r--r-- | os/hal/lib/complex/m25q/devices/micron_n25q/micron_n25q.mk | 14 | ||||
| -rw-r--r-- | os/hal/lib/complex/m25q/m25q.c | 447 | ||||
| -rw-r--r-- | os/hal/lib/complex/m25q/m25q.h | 185 | ||||
| -rw-r--r-- | testex/STM32/STM32F3xx/I2C-LSM303DLHC/.project | 2 | 
6 files changed, 1346 insertions, 1 deletions
diff --git a/os/hal/lib/complex/m25q/devices/micron_n25q/m25q_flash.c b/os/hal/lib/complex/m25q/devices/micron_n25q/m25q_flash.c new file mode 100644 index 000000000..7aeae9065 --- /dev/null +++ b/os/hal/lib/complex/m25q/devices/micron_n25q/m25q_flash.c @@ -0,0 +1,547 @@ +/*
 +    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
 +
 +    This file is part of ChibiOS.
 +
 +    ChibiOS is free software; you can redistribute it and/or modify
 +    it under the terms of the GNU General Public License as published by
 +    the Free Software Foundation; either version 3 of the License, or
 +    (at your option) any later version.
 +
 +    ChibiOS is distributed in the hope that it will be useful,
 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +    GNU General Public License for more details.
 +
 +    You should have received a copy of the GNU General Public License
 +    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +/**
 + * @file    m25q_flash.c
 + * @brief   Micron N25Q serial flash driver code.
 + *
 + * @addtogroup MICRON_N25Q
 + * @ingroup M25Q
 + * @{
 + */
 +
 +#include <string.h>
 +
 +#include "hal.h"
 +#include "m25q.h"
 +
 +/*===========================================================================*/
 +/* Driver local definitions.                                                 */
 +/*===========================================================================*/
 +
 +#define PAGE_SIZE                           256U
 +#define PAGE_MASK                           (PAGE_SIZE - 1U)
 +
 +#if M25Q_USE_SUB_SECTORS == TRUE
 +#define SECTOR_SIZE                         0x00001000U
 +#define CMD_SECTOR_ERASE                    M25Q_CMD_SUBSECTOR_ERASE
 +#else
 +#define SECTOR_SIZE                         0x00010000U
 +#define CMD_SECTOR_ERASE                    M25Q_CMD_SECTOR_ERASE
 +#endif
 +
 +/*===========================================================================*/
 +/* Driver exported variables.                                                */
 +/*===========================================================================*/
 +
 +/**
 + * @brief   N25Q128 descriptor.
 + */
 +flash_descriptor_t m25q_descriptor = {
 +  .attributes       = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE |
 +                      FLASH_ATTR_SUSPEND_ERASE_CAPABLE,
 +  .page_size        = 256U,
 +  .sectors_count    = 0U,           /* It is overwritten.*/
 +  .sectors          = NULL,
 +  .sectors_size     = SECTOR_SIZE,
 +  .address          = 0U
 +};
 +
 +/*===========================================================================*/
 +/* Driver local variables and types.                                         */
 +/*===========================================================================*/
 +
 +#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
 +/* Initial M25Q_CMD_READ_ID command.*/
 +static const qspi_command_t m25q_cmd_read_id = {
 +  .cfg              = QSPI_CFG_CMD(M25Q_CMD_READ_ID) |
 +#if M25Q_SWITCH_WIDTH == TRUE
 +                      QSPI_CFG_CMD_MODE_ONE_LINE     |
 +                      QSPI_CFG_DATA_MODE_ONE_LINE,
 +#else
 +#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
 +                      QSPI_CFG_CMD_MODE_ONE_LINE   |
 +                      QSPI_CFG_DATA_MODE_ONE_LINE,
 +#elif JESD216_BUS_MODE == JESD216_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
 +#endif
 +  .addr             = 0,
 +  .alt              = 0
 +};
 +
 +/* Initial M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER command.*/
 +static const qspi_command_t m25q_cmd_write_evconf = {
 +  .cfg              = QSPI_CFG_CMD(M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER) |
 +#if M25Q_SWITCH_WIDTH == TRUE
 +                      QSPI_CFG_CMD_MODE_ONE_LINE     |
 +                      QSPI_CFG_DATA_MODE_ONE_LINE,
 +#else
 +#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
 +                      QSPI_CFG_CMD_MODE_ONE_LINE   |
 +                      QSPI_CFG_DATA_MODE_ONE_LINE,
 +#elif JESD216_BUS_MODE == JESD216_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
 +#endif
 +  .addr             = 0,
 +  .alt              = 0
 +};
 +
 +/* Initial M25Q_CMD_WRITE_ENABLE command.*/
 +static const qspi_command_t m25q_cmd_write_enable = {
 +  .cfg              = QSPI_CFG_CMD(M25Q_CMD_WRITE_ENABLE) |
 +#if M25Q_SWITCH_WIDTH == TRUE
 +                      QSPI_CFG_CMD_MODE_ONE_LINE,
 +#else
 +#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
 +                      QSPI_CFG_CMD_MODE_ONE_LINE,
 +#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
 +                      QSPI_CFG_CMD_MODE_TWO_LINES,
 +#else
 +                      QSPI_CFG_CMD_MODE_FOUR_LINES,
 +#endif
 +#endif
 +  .addr             = 0,
 +  .alt              = 0
 +};
 +
 +/* Bus width initialization.*/
 +#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
 +static const uint8_t m25q_evconf_value[1] = {0xCF};
 +#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
 +static const uint8_t m25q_evconf_value[1] = {0x8F};
 +#else
 +static const uint8_t m25q_evconf_value[1] = {0x4F};
 +#endif
 +#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
 +
 +/*===========================================================================*/
 +/* Driver local functions.                                                   */
 +/*===========================================================================*/
 +
 +static bool m25q_find_id(const uint8_t *set, size_t size, uint8_t element) {
 +  size_t i;
 +
 +  for (i = 0; i < size; i++) {
 +    if (set[i] == element) {
 +      return true;
 +    }
 +  }
 +  return false;
 +}
 +
 +static flash_error_t m25q_poll_status(M25QDriver *devp) {
 +  uint8_t sts;
 +
 +  do {
 +#if M25Q_NICE_WAITING == TRUE
 +    osalThreadSleepMilliseconds(1);
 +#endif
 +    /* Read status command.*/
 +    jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_FLAG_STATUS_REGISTER,
 +                        1, &sts);
 +  } while ((sts & M25Q_FLAGS_PROGRAM_ERASE) == 0U);
 +
 +  /* Checking for errors.*/
 +  if ((sts & M25Q_FLAGS_ALL_ERRORS) != 0U) {
 +    /* Clearing status register.*/
 +    jesd216_cmd(devp->config->busp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER);
 +
 +    /* Program operation failed.*/
 +    return FLASH_ERROR_PROGRAM;
 +  }
 +
 +  return FLASH_NO_ERROR;
 +}
 +
 +#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
 +static void m25q_reset_memory(M25QDriver *devp) {
 +
 +  /* 1x M25Q_CMD_RESET_ENABLE command.*/
 +  static const qspi_command_t cmd_reset_enable_1 = {
 +    .cfg              = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
 +                        QSPI_CFG_CMD_MODE_ONE_LINE,
 +    .addr             = 0,
 +    .alt              = 0
 +  };
 +
 +  /* 1x M25Q_CMD_RESET_MEMORY command.*/
 +  static const qspi_command_t cmd_reset_memory_1 = {
 +    .cfg              = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
 +                        QSPI_CFG_CMD_MODE_ONE_LINE,
 +    .addr             = 0,
 +    .alt              = 0
 +  };
 +
 +  /* If the device is in one bit mode then the following commands are
 +     rejected because shorter than 8 bits. If the device is in multiple
 +     bits mode then the commands are accepted and the device is reset to
 +     one bit mode.*/
 +#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI4L
 +  /* 4x M25Q_CMD_RESET_ENABLE command.*/
 +  static const qspi_command_t cmd_reset_enable_4 = {
 +    .cfg              = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
 +                        QSPI_CFG_CMD_MODE_FOUR_LINES,
 +    .addr             = 0,
 +    .alt              = 0
 +  };
 +
 +  /* 4x M25Q_CMD_RESET_MEMORY command.*/
 +  static const qspi_command_t cmd_reset_memory_4 = {
 +    .cfg              = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
 +                        QSPI_CFG_CMD_MODE_FOUR_LINES,
 +    .addr             = 0,
 +    .alt              = 0
 +  };
 +
 +  qspiCommand(devp->config->busp, &cmd_reset_enable_4);
 +  qspiCommand(devp->config->busp, &cmd_reset_memory_4);
 +#else
 +  /* 2x M25Q_CMD_RESET_ENABLE command.*/
 +  static const qspi_command_t cmd_reset_enable_2 = {
 +    .cfg              = QSPI_CFG_CMD(M25Q_CMD_RESET_ENABLE) |
 +                        QSPI_CFG_CMD_MODE_TWO_LINES,
 +    .addr             = 0,
 +    .alt              = 0
 +  };
 +
 +  /* 2x M25Q_CMD_RESET_MEMORY command.*/
 +  static const qspi_command_t cmd_reset_memory_2 = {
 +    .cfg              = QSPI_CFG_CMD(M25Q_CMD_RESET_MEMORY) |
 +                        QSPI_CFG_CMD_MODE_TWO_LINES,
 +    .addr             = 0,
 +    .alt              = 0
 +  };
 +
 +  qspiCommand(devp->config->busp, &cmd_reset_enable_2);
 +  qspiCommand(devp->config->busp, &cmd_reset_memory_2);
 +#endif
 +
 +  /* Now the device should be in one bit mode for sure and we perform a
 +     device reset.*/
 +  qspiCommand(devp->config->busp, &cmd_reset_enable_1);
 +  qspiCommand(devp->config->busp, &cmd_reset_memory_1);
 +}
 +#endif /* #if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
 +
 +static const uint8_t m25q_manufacturer_ids[] = M25Q_SUPPORTED_MANUFACTURE_IDS;
 +static const uint8_t m25q_memory_type_ids[] = M25Q_SUPPORTED_MEMORY_TYPE_IDS;
 +
 +/*===========================================================================*/
 +/* Driver exported functions.                                                */
 +/*===========================================================================*/
 +
 +void m25q_device_init(M25QDriver *devp) {
 +
 +#if JESD216_BUS_MODE == JESD216_BUS_MODE_SPI
 +  /* Reading device ID.*/
 +  jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_ID,
 +                      sizeof devp->device_id, devp->device_id);
 +
 +#else /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
 +  /* Attempting a reset of the XIP mode, it could be in an unexpected state
 +     because a CPU reset does not reset the memory too.*/
 +  m25q_reset_xip(devp);
 +
 +  /* Attempting a eeset of the device, it could be in an unexpected state
 +     because a CPU reset does not reset the memory too.*/
 +  m25q_reset_memory(devp);
 +
 +  /* Reading device ID and unique ID.*/
 +  qspiReceive(devp->config->busp, &m25q_cmd_read_id,
 +              sizeof devp->device_id, devp->device_id);
 +#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
 +
 +  /* Checking if the device is white listed.*/
 +  osalDbgAssert(m25q_find_id(m25q_manufacturer_ids,
 +                             sizeof m25q_manufacturer_ids,
 +                             devp->device_id[0]),
 +                "invalid manufacturer id");
 +  osalDbgAssert(m25q_find_id(m25q_memory_type_ids,
 +                             sizeof m25q_memory_type_ids,
 +                             devp->device_id[1]),
 +                "invalid memory type id");
 +
 +#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) && (M25Q_SWITCH_WIDTH == TRUE)
 +  /* Setting up final bus width.*/
 +  qspiCommand(devp->config->busp, &m25q_cmd_write_enable);
 +  qspiSend(devp->config->busp, &m25q_cmd_write_evconf, 1, m25q_evconf_value);
 +
 +  {
 +    uint8_t id[3];
 +
 +    /* Reading ID again for confirmation.*/
 +    jesd216_cmd_receive(devp->config->busp, M25Q_CMD_MULTIPLE_IO_READ_ID,
 +                        3, id);
 +
 +    /* Checking if the device is white listed.*/
 +    osalDbgAssert(memcmp(id, devp->device_id, 3) == 0,
 +                  "id confirmation failed");
 +  }
 +#endif
 +
 +  /* Setting up the device size.*/
 +  m25q_descriptor.sectors_count = (1U << (size_t)devp->device_id[2]) /
 +                                  SECTOR_SIZE;
 +
 +#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI)
 +  {
 +    static const uint8_t flash_conf[1] = {
 +      (M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU
 +    };
 +
 +    /* Setting up the dummy cycles to be used for fast read operations.*/
 +    jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
 +    jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
 +                     1, flash_conf);
 +  }
 +#endif
 +}
 +
 +const flash_descriptor_t *m25q_get_descriptor(void *instance) {
 +  M25QDriver *devp = (M25QDriver *)instance;
 +
 +  osalDbgCheck(instance != NULL);
 +  osalDbgAssert((devp->state != FLASH_UNINIT) && (devp->state != FLASH_STOP),
 +                "invalid state");
 +
 +  return &m25q_descriptor;
 +}
 +
 +flash_error_t m25q_device_read(M25QDriver *devp, flash_offset_t offset,
 +                               size_t n, uint8_t *rp) {
 +
 +#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
 +  /* Fast read command in QSPI mode.*/
 +  jesd216_cmd_addr_dummy_receive(devp->config->busp, M25Q_CMD_FAST_READ,
 +                                 offset, M25Q_READ_DUMMY_CYCLES, n, rp);
 +#else
 +  /* Normal read command in SPI mode.*/
 +  jesd216_cmd_addr_receive(devp->config->busp, M25Q_CMD_READ,
 +                           offset, n, rp);
 +#endif
 +
 +  return FLASH_NO_ERROR;
 +}
 +
 +flash_error_t m25q_device_program(M25QDriver *devp, flash_offset_t offset,
 +                                  size_t n, const uint8_t *pp) {
 +
 +  /* Data is programmed page by page.*/
 +  while (n > 0U) {
 +    flash_error_t err;
 +
 +    /* Data size that can be written in a single program page operation.*/
 +    size_t chunk = (size_t)(((offset | PAGE_MASK) + 1U) - offset);
 +    if (chunk > n) {
 +      chunk = n;
 +    }
 +
 +    /* Enabling write operation.*/
 +    jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
 +
 +    /* Page program command.*/
 +    jesd216_cmd_addr_send(devp->config->busp, M25Q_CMD_PAGE_PROGRAM, offset,
 +                          chunk, pp);
 +
 +    /* Wait for status and check errors.*/
 +    err = m25q_poll_status(devp);
 +    if (err != FLASH_NO_ERROR) {
 +
 +      /* Bus released.*/
 +      jesd216_bus_release(devp->config->busp);
 +
 +      return err;
 +    }
 +
 +    /* Next page.*/
 +    offset += chunk;
 +    pp     += chunk;
 +    n      -= chunk;
 +  }
 +
 +  return FLASH_NO_ERROR;
 +}
 +
 +flash_error_t m25q_device_start_erase_all(M25QDriver *devp) {
 +
 +  /* Enabling write operation.*/
 +  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
 +
 +  /* Bulk erase command.*/
 +  jesd216_cmd(devp->config->busp, M25Q_CMD_BULK_ERASE);
 +
 +  return FLASH_NO_ERROR;
 +}
 +
 +flash_error_t m25q_device_start_erase_sector(M25QDriver *devp,
 +                                             flash_sector_t sector) {
 +  flash_offset_t offset = (flash_offset_t)(sector * SECTOR_SIZE);
 +
 +  /* Enabling write operation.*/
 +  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
 +
 +  /* Sector erase command.*/
 +  jesd216_cmd_addr(devp->config->busp, M25Q_CMD_SECTOR_ERASE, offset);
 +
 +  return FLASH_NO_ERROR;
 +}
 +
 +flash_error_t m25q_device_verify_erase(M25QDriver *devp,
 +                                       flash_sector_t sector) {
 +  uint8_t cmpbuf[M25Q_COMPARE_BUFFER_SIZE];
 +  flash_offset_t offset;
 +  size_t n;
 +
 +  /* Read command.*/
 +  offset = (flash_offset_t)(sector * SECTOR_SIZE);
 +  n = SECTOR_SIZE;
 +  while (n > 0U) {
 +    uint8_t *p;
 +
 +#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
 +   jesd216_cmd_addr_dummy_receive(devp->config->busp, M25Q_CMD_FAST_READ,
 +                                  offset, M25Q_READ_DUMMY_CYCLES,
 +                                  sizeof cmpbuf, cmpbuf);
 +#else
 +   /* Normal read command in SPI mode.*/
 +   jesd216_cmd_addr_receive(devp->config->busp, M25Q_CMD_READ,
 +                            offset, sizeof cmpbuf, cmpbuf);
 +#endif
 +
 +    /* Checking for erased state of current buffer.*/
 +    for (p = cmpbuf; p < &cmpbuf[M25Q_COMPARE_BUFFER_SIZE]; p++) {
 +      if (*p != 0xFFU) {
 +        /* Ready state again.*/
 +        devp->state = FLASH_READY;
 +
 +        return FLASH_ERROR_VERIFY;
 +      }
 +    }
 +
 +    offset += sizeof cmpbuf;
 +    n -= sizeof cmpbuf;
 +  }
 +
 +  return FLASH_NO_ERROR;
 +}
 +
 +flash_error_t m25q_device_query_erase(M25QDriver *devp, uint32_t *msec) {
 +  uint8_t sts;
 +
 +  /* Read status command.*/
 +  jesd216_cmd_receive(devp->config->busp, M25Q_CMD_READ_FLAG_STATUS_REGISTER,
 +                      1, &sts);
 +
 +  /* If the P/E bit is zero (busy) or the flash in a suspended state then
 +     report that the operation is still in progress.*/
 +  if (((sts & M25Q_FLAGS_PROGRAM_ERASE) == 0U) ||
 +      ((sts & M25Q_FLAGS_ERASE_SUSPEND) != 0U)) {
 +
 +    /* Recommended time before polling again, this is a simplified
 +       implementation.*/
 +    if (msec != NULL) {
 +      *msec = 1U;
 +    }
 +
 +    return FLASH_BUSY_ERASING;
 +  }
 +
 +  /* Checking for errors.*/
 +  if ((sts & M25Q_FLAGS_ALL_ERRORS) != 0U) {
 +
 +    /* Clearing status register.*/
 +    jesd216_cmd(devp->config->busp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER);
 +
 +    /* Erase operation failed.*/
 +    return FLASH_ERROR_ERASE;
 +  }
 +
 +  return FLASH_NO_ERROR;
 +}
 +
 +flash_error_t m25q_device_read_sfdp(M25QDriver *devp, flash_offset_t offset,
 +                                    size_t n, uint8_t *rp) {
 +
 +  (void)devp;
 +  (void)rp;
 +  (void)offset;
 +  (void)n;
 +
 +  return FLASH_NO_ERROR;
 +}
 +
 +#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
 +void m25q_activate_xip(M25QDriver *devp) {
 +  static const uint8_t flash_status_xip[1] = {
 +    (M25Q_READ_DUMMY_CYCLES << 4U) | 0x07U
 +  };
 +
 +  /* Activating XIP mode in the device.*/
 +  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
 +  jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
 +                   1, flash_status_xip);
 +}
 +
 +void m25q_reset_xip(M25QDriver *devp) {
 +  static const uint8_t flash_conf[1] = {
 +    (M25Q_READ_DUMMY_CYCLES << 4U) | 0x0FU
 +  };
 +  qspi_command_t cmd;
 +  uint8_t buf[1];
 +
 +  /* Resetting XIP mode by reading one byte without XIP confirmation bit.*/
 +  cmd.alt  = 0xFF;
 +  cmd.addr = 0;
 +  cmd.cfg  = QSPI_CFG_CMD_MODE_NONE |
 +             QSPI_CFG_ADDR_SIZE_24 |
 +#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
 +             QSPI_CFG_ADDR_MODE_ONE_LINE |
 +             QSPI_CFG_DATA_MODE_ONE_LINE |
 +#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
 +             QSPI_CFG_ADDR_MODE_TWO_LINES |
 +             QSPI_CFG_DATA_MODE_TWO_LINES |
 +#else
 +             QSPI_CFG_ADDR_MODE_FOUR_LINES |
 +             QSPI_CFG_DATA_MODE_FOUR_LINES |
 +#endif
 +             QSPI_CFG_ALT_MODE_FOUR_LINES |  /* Always 4 lines, note.*/
 +             QSPI_CFG_ALT_SIZE_8 |
 +             QSPI_CFG_DUMMY_CYCLES(M25Q_READ_DUMMY_CYCLES - 2);
 +  qspiReceive(devp->config->busp, &cmd, 1, buf);
 +
 +  /* Enabling write operation.*/
 +  jesd216_cmd(devp->config->busp, M25Q_CMD_WRITE_ENABLE);
 +
 +  /* Rewriting volatile configuration register.*/
 +  jesd216_cmd_send(devp->config->busp, M25Q_CMD_WRITE_V_CONF_REGISTER,
 +                   1, flash_conf);
 +}
 +#endif /* #if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
 +
 +/** @} */
 diff --git a/os/hal/lib/complex/m25q/devices/micron_n25q/m25q_flash.h b/os/hal/lib/complex/m25q/devices/micron_n25q/m25q_flash.h new file mode 100644 index 000000000..5948f068b --- /dev/null +++ b/os/hal/lib/complex/m25q/devices/micron_n25q/m25q_flash.h @@ -0,0 +1,152 @@ +/*
 +    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
 +
 +    This file is part of ChibiOS.
 +
 +    ChibiOS is free software; you can redistribute it and/or modify
 +    it under the terms of the GNU General Public License as published by
 +    the Free Software Foundation; either version 3 of the License, or
 +    (at your option) any later version.
 +
 +    ChibiOS is distributed in the hope that it will be useful,
 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +    GNU General Public License for more details.
 +
 +    You should have received a copy of the GNU General Public License
 +    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +/**
 + * @file    n25q_flash.h
 + * @brief   Micron N25Q serial flash driver header.
 + *
 + * @addtogroup MICRON_N25Q
 + * @ingroup M25Q
 + * @{
 + */
 +
 +#ifndef MICRON_N25Q_H
 +#define MICRON_N25Q_H
 +
 +#include "hal_jesd216_flash.h"
 +#include "m25q_flash.h"
 +
 +/*===========================================================================*/
 +/* Driver constants.                                                         */
 +/*===========================================================================*/
 +
 +/**
 + * @name    Device identification
 + * @{
 + */
 +#define M25Q_SUPPORTED_MANUFACTURE_IDS      {0x20}
 +#define M25Q_SUPPORTED_MEMORY_TYPE_IDS      {0xBA, 0xBB}
 +/** @} */
 +
 +/**
 + * @name    Command codes
 + * @{
 + */
 +#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                          0x0B
 +#define M25Q_CMD_WRITE_ENABLE                       0x06
 +#define M25Q_CMD_WRITE_DISABLE                      0x04
 +#define M25Q_CMD_READ_STATUS_REGISTER               0x05
 +#define M25Q_CMD_WRITE_STATUS_REGISTER              0x01
 +#define M25Q_CMD_READ_LOCK_REGISTER                 0xE8
 +#define M25Q_CMD_WRITE_LOCK_REGISTER                0xE5
 +#define M25Q_CMD_READ_FLAG_STATUS_REGISTER          0x70
 +#define M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER         0x50
 +#define M25Q_CMD_READ_NV_CONFIGURATION_REGISTER     0xB5
 +#define M25Q_CMD_WRITE_NV_CONFIGURATION_REGISTER    0xB1
 +#define M25Q_CMD_READ_V_CONF_REGISTER               0x85
 +#define M25Q_CMD_WRITE_V_CONF_REGISTER              0x81
 +#define M25Q_CMD_READ_ENHANCED_V_CONF_REGISTER      0x65
 +#define M25Q_CMD_WRITE_ENHANCED_V_CONF_REGISTER     0x61
 +#define M25Q_CMD_PAGE_PROGRAM                       0x02
 +#define M25Q_CMD_SUBSECTOR_ERASE                    0x20
 +#define M25Q_CMD_SECTOR_ERASE                       0xD8
 +#define M25Q_CMD_BULK_ERASE                         0xC7
 +#define M25Q_CMD_PROGRAM_ERASE_RESUME               0x7A
 +#define M25Q_CMD_PROGRAM_ERASE_SUSPEND              0x75
 +#define M25Q_CMD_READ_OTP_ARRAY                     0x4B
 +#define M25Q_CMD_PROGRAM_OTP_ARRAY                  0x42
 +/** @} */
 +
 +/**
 + * @name    Flags status register bits
 + * @{
 + */
 +#define M25Q_FLAGS_PROGRAM_ERASE                    0x80U
 +#define M25Q_FLAGS_ERASE_SUSPEND                    0x40U
 +#define M25Q_FLAGS_ERASE_ERROR                      0x20U
 +#define M25Q_FLAGS_PROGRAM_ERROR                    0x10U
 +#define M25Q_FLAGS_VPP_ERROR                        0x08U
 +#define M25Q_FLAGS_PROGRAM_SUSPEND                  0x04U
 +#define M25Q_FLAGS_PROTECTION_ERROR                 0x02U
 +#define M25Q_FLAGS_RESERVED                         0x01U
 +#define M25Q_FLAGS_ALL_ERRORS                   (M25Q_FLAGS_ERASE_ERROR |   \
 +                                                 M25Q_FLAGS_PROGRAM_ERROR | \
 +                                                 M25Q_FLAGS_VPP_ERROR |     \
 +                                                 M25Q_FLAGS_PROTECTION_ERROR)
 +/** @} */
 +
 +/*===========================================================================*/
 +/* Driver pre-compile time settings.                                         */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* Derived constants and error checks.                                       */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* Driver data structures and types.                                         */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* Driver macros.                                                            */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* External declarations.                                                    */
 +/*===========================================================================*/
 +
 +#if !defined(__DOXYGEN__)
 +extern flash_descriptor_t m25q_descriptor;
 +#endif
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +void m25q_device_init(M25QDriver *devp);
 +const flash_descriptor_t *m25q_get_descriptor(void *instance);
 +flash_error_t m25q_device_read(M25QDriver *devp, flash_offset_t offset,
 +                               size_t n, uint8_t *rp);
 +flash_error_t m25q_device_program(M25QDriver *devp, flash_offset_t offset,
 +                                  size_t n, const uint8_t *pp);
 +flash_error_t m25q_device_start_erase_all(M25QDriver *devp);
 +flash_error_t m25q_device_start_erase_sector(M25QDriver *devp,
 +                                             flash_sector_t sector);
 +flash_error_t m25q_device_verify_erase(M25QDriver *devp,
 +                                       flash_sector_t sector);
 +flash_error_t m25q_device_query_erase(M25QDriver *devp, uint32_t *msec);
 +flash_error_t m25q_device_read_sfdp(M25QDriver *devp, flash_offset_t offset,
 +                                    size_t n, uint8_t *rp);
 +#if JESD216_BUS_MODE != JESD216_BUS_MODE_SPI
 +  void m25q_activate_xip(M25QDriver *devp);
 +  void m25q_reset_xip(M25QDriver *devp);
 +#endif
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* MICRON_N25Q_H */
 +
 +/** @} */
 +
 diff --git a/os/hal/lib/complex/m25q/devices/micron_n25q/micron_n25q.mk b/os/hal/lib/complex/m25q/devices/micron_n25q/micron_n25q.mk new file mode 100644 index 000000000..5a5e0ea49 --- /dev/null +++ b/os/hal/lib/complex/m25q/devices/micron_n25q/micron_n25q.mk @@ -0,0 +1,14 @@ +# List of all the Micron N25Q device files.
 +M25QSRC := $(CHIBIOS)/os/hal/lib/peripherals/flash/hal_flash.c \
 +           $(CHIBIOS)/os/hal/lib/peripherals/flash/hal_jesd216_flash.c \
 +           $(CHIBIOS)/os/hal/lib/complex/m25q/m25q.c \
 +           $(CHIBIOS)/os/hal/lib/complex/m25q/devices/micron_n25q/m25q_flash.c
 +
 +# Required include directories
 +M25QINC := $(CHIBIOS)/os/hal/lib/peripherals/flash \
 +           $(CHIBIOS)/os/hal/lib/complex/m25q \
 +           $(CHIBIOS)/os/hal/lib/complex/m25q/devices/micron_n25q
 +
 +# Shared variables
 +ALLCSRC += $(M25QSRC)
 +ALLINC  += $(M25QINC)
 diff --git a/os/hal/lib/complex/m25q/m25q.c b/os/hal/lib/complex/m25q/m25q.c new file mode 100644 index 000000000..a2e75f3fd --- /dev/null +++ b/os/hal/lib/complex/m25q/m25q.c @@ -0,0 +1,447 @@ +/*
 +    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
 +
 +    This file is part of ChibiOS.
 +
 +    ChibiOS is free software; you can redistribute it and/or modify
 +    it under the terms of the GNU General Public License as published by
 +    the Free Software Foundation; either version 3 of the License, or
 +    (at your option) any later version.
 +
 +    ChibiOS is distributed in the hope that it will be useful,
 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +    GNU General Public License for more details.
 +
 +    You should have received a copy of the GNU General Public License
 +    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +/**
 + * @file    m25q.c
 + * @brief   M25Q serial flash driver code.
 + *
 + * @addtogroup M25Q
 + * @ingroup M25Q
 + * @{
 + */
 +
 +#include "hal.h"
 +#include "m25q.h"
 +
 +/*===========================================================================*/
 +/* Driver local definitions.                                                 */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* Driver exported variables.                                                */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* Driver local variables and types.                                         */
 +/*===========================================================================*/
 +
 +static flash_error_t m25q_read(void *instance, flash_offset_t offset,
 +                               size_t n, uint8_t *rp);
 +static flash_error_t m25q_program(void *instance, flash_offset_t offset,
 +                                  size_t n, const uint8_t *pp);
 +static flash_error_t m25q_start_erase_all(void *instance);
 +static flash_error_t m25q_start_erase_sector(void *instance,
 +                                             flash_sector_t sector);
 +static flash_error_t m25q_verify_erase(void *instance,
 +                                       flash_sector_t sector);
 +static flash_error_t m25q_query_erase(void *instance, uint32_t *msec);
 +static flash_error_t m25q_read_sfdp(void *instance, flash_offset_t offset,
 +                                    size_t n, uint8_t *rp);
 +
 +/**
 + * @brief   Virtual methods table.
 + */
 +static const struct M25QDriverVMT m25q_vmt = {
 +  (size_t)0,
 +  m25q_get_descriptor, m25q_read, m25q_program,
 +  m25q_start_erase_all, m25q_start_erase_sector,
 +  m25q_query_erase, m25q_verify_erase,
 +  m25q_read_sfdp
 +};
 +
 +/*===========================================================================*/
 +/* Driver local functions.                                                   */
 +/*===========================================================================*/
 +
 +static flash_error_t m25q_read(void *instance, flash_offset_t offset,
 +                               size_t n, uint8_t *rp) {
 +  M25QDriver *devp = (M25QDriver *)instance;
 +  flash_error_t err;
 +
 +  osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
 +  osalDbgCheck((size_t)offset + n <= (size_t)m25q_descriptor.sectors_count *
 +                                     (size_t)m25q_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.*/
 +  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +  /* FLASH_READY state while the operation is performed.*/
 +  devp->state = FLASH_READ;
 +
 +  /* Actual read implementation.*/
 +  err = m25q_device_read(devp, offset, n, rp);
 +
 +  /* Ready state again.*/
 +  devp->state = FLASH_READY;
 +
 +  /* Bus released.*/
 +  jesd216_bus_release(devp->config->busp);
 +
 +  return err;
 +}
 +
 +static flash_error_t m25q_program(void *instance, flash_offset_t offset,
 +                                  size_t n, const uint8_t *pp) {
 +  M25QDriver *devp = (M25QDriver *)instance;
 +  flash_error_t err;
 +
 +  osalDbgCheck((instance != NULL) && (pp != NULL) && (n > 0U));
 +  osalDbgCheck((size_t)offset + n <= (size_t)m25q_descriptor.sectors_count *
 +                                     (size_t)m25q_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.*/
 +  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +  /* FLASH_PGM state while the operation is performed.*/
 +  devp->state = FLASH_PGM;
 +
 +  /* Actual program implementation.*/
 +  err = m25q_device_program(devp, offset, n, pp);
 +
 +  /* Ready state again.*/
 +  devp->state = FLASH_READY;
 +
 +  /* Bus released.*/
 +  jesd216_bus_release(devp->config->busp);
 +
 +  return err;
 +}
 +
 +static flash_error_t m25q_start_erase_all(void *instance) {
 +  M25QDriver *devp = (M25QDriver *)instance;
 +  flash_error_t err;
 +
 +  osalDbgCheck(instance != NULL);
 +  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
 +                "invalid state");
 +
 +  if (devp->state == FLASH_ERASE) {
 +    return FLASH_BUSY_ERASING;
 +  }
 +
 +  /* Bus acquired.*/
 +  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +  /* FLASH_ERASE state while the operation is performed.*/
 +  devp->state = FLASH_ERASE;
 +
 +  /* Actual erase implementation.*/
 +  err = m25q_device_start_erase_all(devp);
 +
 +  /* Ready state again.*/
 +  devp->state = FLASH_READY;
 +
 +  /* Bus released.*/
 +  jesd216_bus_release(devp->config->busp);
 +
 +  return err;
 +}
 +
 +static flash_error_t m25q_start_erase_sector(void *instance,
 +                                             flash_sector_t sector) {
 +  M25QDriver *devp = (M25QDriver *)instance;
 +  flash_error_t err;
 +
 +  osalDbgCheck(instance != NULL);
 +  osalDbgCheck(sector < m25q_descriptor.sectors_count);
 +  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
 +                "invalid state");
 +
 +  if (devp->state == FLASH_ERASE) {
 +    return FLASH_BUSY_ERASING;
 +  }
 +
 +  /* Bus acquired.*/
 +  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +  /* FLASH_ERASE state while the operation is performed.*/
 +  devp->state = FLASH_ERASE;
 +
 +  /* Actual erase implementation.*/
 +  err = m25q_device_start_erase_sector(devp, sector);
 +
 +  /* Bus released.*/
 +  jesd216_bus_release(devp->config->busp);
 +
 +  return err;
 +}
 +
 +static flash_error_t m25q_verify_erase(void *instance,
 +                                       flash_sector_t sector) {
 +  M25QDriver *devp = (M25QDriver *)instance;
 +  flash_error_t err;
 +
 +  osalDbgCheck(instance != NULL);
 +  osalDbgCheck(sector < m25q_descriptor.sectors_count);
 +  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
 +                "invalid state");
 +
 +  if (devp->state == FLASH_ERASE) {
 +    return FLASH_BUSY_ERASING;
 +  }
 +
 +  /* Bus acquired.*/
 +  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +  /* FLASH_READY state while the operation is performed.*/
 +  devp->state = FLASH_READ;
 +
 +  /* Actual verify erase implementation.*/
 +  err = m25q_device_verify_erase(devp, sector);
 +
 +  /* Ready state again.*/
 +  devp->state = FLASH_READY;
 +
 +  /* Bus released.*/
 +  jesd216_bus_release(devp->config->busp);
 +
 +  return err;
 +}
 +
 +static flash_error_t m25q_query_erase(void *instance, uint32_t *msec) {
 +  M25QDriver *devp = (M25QDriver *)instance;
 +  flash_error_t err;
 +
 +  osalDbgCheck(instance != NULL);
 +  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
 +                "invalid state");
 +
 +  /* If there is an erase in progress then the device must be checked.*/
 +  if (devp->state == FLASH_ERASE) {
 +
 +    /* Bus acquired.*/
 +    jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +    /* Actual query erase implementation.*/
 +    err = m25q_device_query_erase(devp, msec);
 +
 +    /* The device is ready to accept commands.*/
 +    if (err == FLASH_NO_ERROR) {
 +      devp->state = FLASH_READY;
 +    }
 +
 +    /* Bus released.*/
 +    jesd216_bus_release(devp->config->busp);
 +  }
 +  else {
 +    err = FLASH_NO_ERROR;
 +  }
 +
 +  return err;
 +}
 +
 +static flash_error_t m25q_read_sfdp(void *instance, flash_offset_t offset,
 +                                    size_t n, uint8_t *rp) {
 +  M25QDriver *devp = (M25QDriver *)instance;
 +  flash_error_t err;
 +
 +  osalDbgCheck((instance != NULL) && (rp != NULL) && (n > 0U));
 +  osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE),
 +                "invalid state");
 +
 +  if (devp->state == FLASH_ERASE) {
 +    return FLASH_BUSY_ERASING;
 +  }
 +
 +  /* Bus acquired.*/
 +  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +  /* Actual read SFDP implementation.*/
 +  err = m25q_device_read_sfdp(devp, offset, n, rp);
 +
 +  /* The device is ready to accept commands.*/
 +  if (err == FLASH_NO_ERROR) {
 +    devp->state = FLASH_READY;
 +  }
 +
 +  /* Bus released.*/
 +  jesd216_bus_release(devp->config->busp);
 +
 +  return err;
 +}
 +
 +/*===========================================================================*/
 +/* Driver exported functions.                                                */
 +/*===========================================================================*/
 +
 +/**
 + * @brief   Initializes an instance.
 + *
 + * @param[out] devp     pointer to the @p M25QDriver object
 + *
 + * @init
 + */
 +void m25qObjectInit(M25QDriver *devp) {
 +
 +  osalDbgCheck(devp != NULL);
 +
 +  devp->vmt         = &m25q_vmt;
 +  devp->state       = FLASH_STOP;
 +  devp->config      = NULL;
 +}
 +
 +/**
 + * @brief   Configures and activates N25Q128 driver.
 + *
 + * @param[in] devp      pointer to the @p M25QDriver object
 + * @param[in] config    pointer to the configuration
 + *
 + * @api
 + */
 +void m25qStart(M25QDriver *devp, const M25QConfig *config) {
 +
 +  osalDbgCheck((devp != NULL) && (config != NULL));
 +  osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state");
 +
 +  devp->config = config;
 +
 +  if (devp->state == FLASH_STOP) {
 +
 +    /* Bus acquisition.*/
 +    jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +    /* Device identification and initialization.*/
 +    m25q_device_init(devp);
 +
 +    /* Driver in ready state.*/
 +    devp->state = FLASH_READY;
 +
 +    /* Bus release.*/
 +    jesd216_bus_release(devp->config->busp);
 +  }
 +} 
 +
 +/**
 + * @brief   Deactivates the N25Q128 driver.
 + *
 + * @param[in] devp      pointer to the @p M25QDriver object
 + *
 + * @api
 + */
 +void m25qStop(M25QDriver *devp) {
 +
 +  osalDbgCheck(devp != NULL);
 +  osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state");
 +
 +  if (devp->state != FLASH_STOP) {
 +
 +    /* Bus acquisition.*/
 +    jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +    /* Stopping bus device.*/
 +    jesd216_stop(devp->config->busp);
 +
 +    /* Deleting current configuration.*/
 +    devp->config = NULL;
 +
 +    /* Driver stopped.*/
 +    devp->state = FLASH_STOP;
 +
 +    /* Bus release.*/
 +    jesd216_bus_release(devp->config->busp);
 +  }
 +}
 +
 +#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
 +#if (QSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
 +/**
 + * @brief   Enters the memory Mapping mode.
 + * @details The memory mapping mode is only available when the QSPI mode
 + *          is selected and the underlying QSPI controller supports the
 + *          feature.
 + *
 + * @param[in] devp      pointer to the @p M25QDriver object
 + * @param[out] addrp    pointer to the memory start address of the mapped
 + *                      flash or @p NULL
 + *
 + * @api
 + */
 +void m25qMemoryMap(M25QDriver *devp, uint8_t **addrp) {
 +  qspi_command_t cmd;
 +
 +  /* Bus acquisition.*/
 +  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +  /* Activating XIP mode in the device.*/
 +  m25q_activate_xip(devp);
 +
 +  /* Putting the QSPI driver in memory mapped mode.*/
 +  cmd.cfg = QSPI_CFG_CMD(M25Q_CMD_FAST_READ) |
 +            QSPI_CFG_ADDR_SIZE_24 |
 +#if JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI1L
 +            QSPI_CFG_CMD_MODE_ONE_LINE |
 +            QSPI_CFG_ADDR_MODE_ONE_LINE |
 +            QSPI_CFG_DATA_MODE_ONE_LINE |
 +#elif JESD216_BUS_MODE == JESD216_BUS_MODE_QSPI2L
 +            QSPI_CFG_CMD_MODE_TWO_LINES |
 +            QSPI_CFG_ADDR_MODE_TWO_LINES |
 +            QSPI_CFG_DATA_MODE_TWO_LINES |
 +#else
 +            QSPI_CFG_CMD_MODE_FOUR_LINES |
 +            QSPI_CFG_ADDR_MODE_FOUR_LINES |
 +            QSPI_CFG_DATA_MODE_FOUR_LINES |
 +#endif
 +            QSPI_CFG_ALT_MODE_FOUR_LINES |  /* Always 4 lines, note.*/
 +            QSPI_CFG_ALT_SIZE_8 |
 +            QSPI_CFG_SIOO |
 +            QSPI_CFG_DUMMY_CYCLES(M25Q_READ_DUMMY_CYCLES - 2);
 +
 +  /* Starting QSPI memory mapped mode.*/
 +  qspiMapFlash(devp->config->busp, &cmd, addrp);
 +
 +  /* Bus release.*/
 +  jesd216_bus_release(devp->config->busp);
 +}
 +
 +/**
 + * @brief   Leaves the memory Mapping mode.
 + *
 + * @param[in] devp      pointer to the @p M25QDriver object
 + *
 + * @api
 + */
 +void m25qMemoryUnmap(M25QDriver *devp) {
 +
 +  /* Bus acquisition.*/
 +  jesd216_bus_acquire(devp->config->busp, devp->config->buscfg);
 +
 +  /* Stopping QSPI memory mapped mode.*/
 +  qspiUnmapFlash(devp->config->busp);
 +
 +  m25q_reset_xip(devp);
 +
 +  /* Bus release.*/
 +  jesd216_bus_release(devp->config->busp);
 +}
 +#endif /* QSPI_SUPPORTS_MEMMAP == TRUE */
 +#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
 +
 +/** @} */
 diff --git a/os/hal/lib/complex/m25q/m25q.h b/os/hal/lib/complex/m25q/m25q.h new file mode 100644 index 000000000..5ddf9d532 --- /dev/null +++ b/os/hal/lib/complex/m25q/m25q.h @@ -0,0 +1,185 @@ +/*
 +    ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio.
 +
 +    This file is part of ChibiOS.
 +
 +    ChibiOS is free software; you can redistribute it and/or modify
 +    it under the terms of the GNU General Public License as published by
 +    the Free Software Foundation; either version 3 of the License, or
 +    (at your option) any later version.
 +
 +    ChibiOS is distributed in the hope that it will be useful,
 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +    GNU General Public License for more details.
 +
 +    You should have received a copy of the GNU General Public License
 +    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +*/
 +
 +/**
 + * @file    m25q.h
 + * @brief   M25Q serial flash driver header.
 + *
 + * @addtogroup M25Q
 + * @ingroup M25Q
 + * @{
 + */
 +
 +#ifndef M25Q_H
 +#define M25Q_H
 +
 +#include "hal_jesd216_flash.h"
 +
 +/*===========================================================================*/
 +/* Driver constants.                                                         */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* Driver pre-compile time settings.                                         */
 +/*===========================================================================*/
 +
 +/**
 + * @name    Configuration options
 + * @{
 + */
 +/**
 + * @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
 + *          device is configured using the Non Volatile Configuration
 + *          Register then this option is not required.
 + * @note    This option is only valid in QSPI bus modes.
 + */
 +#if !defined(M25Q_SWITCH_WIDTH) || defined(__DOXYGEN__)
 +#define M25Q_SWITCH_WIDTH                   TRUE
 +#endif
 +
 +/**
 + * @brief   Delays insertions.
 + * @details If enabled this options inserts delays into the flash waiting
 + *          routines releasing some extra CPU time for threads with lower
 + *          priority, this may slow down the driver a bit however.
 + */
 +#if !defined(M25Q_NICE_WAITING) || defined(__DOXYGEN__)
 +#define M25Q_NICE_WAITING                   TRUE
 +#endif
 +
 +/**
 + * @brief   Uses 4kB sub-sectors rather than 64kB sectors.
 + */
 +#if !defined(M25Q_USE_SUB_SECTORS) || defined(__DOXYGEN__)
 +#define M25Q_USE_SUB_SECTORS                FALSE
 +#endif
 +
 +/**
 + * @brief   Size of the compare buffer.
 + * @details This buffer is allocated in the stack frame of the function
 + *          @p flashVerifyErase() and its size must be a power of two.
 + *          Larger buffers lead to better verify performance but increase
 + *          stack usage for that function.
 + */
 +#if !defined(M25Q_COMPARE_BUFFER_SIZE) || defined(__DOXYGEN__)
 +#define M25Q_COMPARE_BUFFER_SIZE            32
 +#endif
 +/** @} */
 +
 +/*===========================================================================*/
 +/* Derived constants and error checks.                                       */
 +/*===========================================================================*/
 +
 +#if (M25Q_READ_DUMMY_CYCLES < 1) || (M25Q_READ_DUMMY_CYCLES > 15)
 +#error "invalid M25Q_READ_DUMMY_CYCLES value (1..15)"
 +#endif
 +
 +#if (M25Q_COMPARE_BUFFER_SIZE & (M25Q_COMPARE_BUFFER_SIZE - 1)) != 0
 +#error "invalid M25Q_COMPARE_BUFFER_SIZE value"
 +#endif
 +
 +/*===========================================================================*/
 +/* Driver data structures and types.                                         */
 +/*===========================================================================*/
 +
 +/**
 + * @brief   Type of a M25Q configuration structure.
 + */
 +typedef struct {
 +  _jesd216_config
 +} M25QConfig;
 +
 +/**
 + * @brief   @p M25Q specific methods.
 + */
 +#define _m25q_methods                                                       \
 +  _jesd216_flash_methods
 +
 +/**
 + * @extends JESD216FlashVMT
 + *
 + * @brief   @p M25Q virtual methods table.
 + */
 +struct M25QDriverVMT {
 +  _m25q_methods
 +};
 +  
 +/**
 + * @extends JESD216Flash
 + *
 + * @brief   Type of M25Q flash class.
 + */
 +typedef struct {
 +  /**
 +   * @brief   M25QDriver Virtual Methods Table.
 +   */
 +  const struct M25QDriverVMT    *vmt;
 +  _jesd216_flash_data
 +  /**
 +   * @brief   Current configuration data.
 +   */
 +  const M25QConfig              *config;
 +  /**
 +   * @brief   Device ID and unique ID.
 +   */
 +  uint8_t                       device_id[20];
 +} M25QDriver;
 +
 +/*===========================================================================*/
 +/* Driver macros.                                                            */
 +/*===========================================================================*/
 +
 +/*===========================================================================*/
 +/* External declarations.                                                    */
 +/*===========================================================================*/
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +  void m25qObjectInit(M25QDriver *devp);
 +  void m25qStart(M25QDriver *devp, const M25QConfig *config);
 +  void m25qStop(M25QDriver *devp);
 +#if (JESD216_BUS_MODE != JESD216_BUS_MODE_SPI) || defined(__DOXYGEN__)
 +#if (QSPI_SUPPORTS_MEMMAP == TRUE) || defined(__DOXYGEN__)
 +  void m25qMemoryMap(M25QDriver *devp, uint8_t ** addrp);
 +  void m25qMemoryUnmap(M25QDriver *devp);
 +#endif /* QSPI_SUPPORTS_MEMMAP == TRUE */
 +#endif /* JESD216_BUS_MODE != JESD216_BUS_MODE_SPI */
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +/* Device-specific implementations.*/
 +#include "m25q_flash.h"
 +
 +#endif /* M25Q_H */
 +
 +/** @} */
 +
 diff --git a/testex/STM32/STM32F3xx/I2C-LSM303DLHC/.project b/testex/STM32/STM32F3xx/I2C-LSM303DLHC/.project index 94d8e5c66..73e5a83ea 100644 --- a/testex/STM32/STM32F3xx/I2C-LSM303DLHC/.project +++ b/testex/STM32/STM32F3xx/I2C-LSM303DLHC/.project @@ -27,7 +27,7 @@  		<link>
  			<name>board</name>
  			<type>2</type>
 -			<locationURI>CHIBIOS/os/hal/boards/ST_STM32F3_DISCOVERY_REVC</locationURI>
 +			<locationURI>CHIBIOS/os/hal/boards/ST_STM32F3_DISCOVERY</locationURI>
  		</link>
  		<link>
  			<name>os</name>
  | 
