From 03deeba18703fcaaf3ed34849f400a6ca9499ae1 Mon Sep 17 00:00:00 2001 From: Giovanni Di Sirio Date: Mon, 16 May 2016 14:47:50 +0000 Subject: [PATCH] git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9492 35acf78f-673a-0410-8e92-d51de3d6d3f4 --- os/ex/Micron/m25q.c | 520 ++++++++++++++++++ os/ex/Micron/m25q.h | 233 ++++++++ os/ex/Micron/m25q.mk | 8 + os/ex/Micron/n25q128_spi.c | 2 +- os/ex/Micron/n25q128_spi.h | 2 +- os/hal/lib/peripherals/flash/hal_flash.h | 16 +- .../lib/peripherals/flash/hal_jesd216_flash.h | 10 +- testhal/STM32/STM32L4xx/QSPI-N25Q128/Makefile | 4 +- .../STM32/STM32L4xx/QSPI-N25Q128/halconf.h | 2 +- .../STM32/STM32L4xx/QSPI-N25Q128/mcuconf.h | 2 +- 10 files changed, 783 insertions(+), 16 deletions(-) create mode 100644 os/ex/Micron/m25q.c create mode 100644 os/ex/Micron/m25q.h create mode 100644 os/ex/Micron/m25q.mk diff --git a/os/ex/Micron/m25q.c b/os/ex/Micron/m25q.c new file mode 100644 index 000000000..1d72cdf4f --- /dev/null +++ b/os/ex/Micron/m25q.c @@ -0,0 +1,520 @@ +/* + N25Q128 Flash Driver - Copyright (C) 2016 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 . +*/ + +/** + * @file m25q.c + * @brief Micron serial flash driver code. + * + * @addtogroup m25q + * @{ + */ + +#include "hal.h" + +#include "m25q.h" + +/*===========================================================================*/ +/* Driver local definitions. */ +/*===========================================================================*/ + +#define PAGE_SIZE 256U +#define PAGE_MASK (PAGE_SIZE - 1U) + +#if N25Q128_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. */ +/*===========================================================================*/ + +/*===========================================================================*/ +/* Driver local variables and types. */ +/*===========================================================================*/ + +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); +static flash_error_t program(void *instance, flash_address_t addr, + const uint8_t *pp, size_t n); +static flash_error_t start_erase_all(void *instance); +static flash_error_t start_erase_sector(void *instance, flash_sector_t sector); +static flash_error_t query_erase(void *instance, uint32_t *msec); +static flash_error_t verify_erase(void *instance, flash_sector_t sector); +static flash_error_t read_id(void *instance, uint8_t *rp, size_t n); + +/** + * @brief Virtual methods table. + */ +static const struct M25QDriverVMT m25q_vmt = { + get_descriptor, read, program, + start_erase_all, start_erase_sector, query_erase, verify_erase, + read_id +}; + +/** + * @brief N25Q128 descriptor. + */ +static flash_descriptor_t descriptor = { + .attributes = FLASH_ATTR_ERASED_IS_ONE | FLASH_ATTR_REWRITABLE | + FLASH_ATTR_SUSPEND_ERASE_CAPABLE, + .page_size = 256U, +#if N25Q128_USE_SUB_SECTORS == TRUE + .sectors_count = 4096U, +#else + .sectors_count = 256U, +#endif + .sectors = NULL, + .sectors_size = SECTOR_SIZE, + .address = 0U +}; + +/*===========================================================================*/ +/* Driver local functions. */ +/*===========================================================================*/ + +#if (M25Q_USE_SPI == TRUE) && (M25Q_SHARED_SPI == TRUE) +void flash_bus_acquire(M25QDriver *devp) { + + spiAcquireBus(devp->config->spip); + spiStart(devp->config->spip, devp->config->spicfg); +} + +void flash_bus_release(M25QDriver *devp) { + + spiReleaseBus(devp->config->spip); +} +#else +#define flash_bus_acquire(devp) +#define flash_bus_release(devp) +#endif /* (M25Q_USE_SPI == TRUE) && (M25Q_SHARED_SPI == TRUE) */ + +static void flash_short_cmd(M25QDriver *devp, uint8_t cmd) { + uint8_t buf[1]; + + spiSelect(devp->config->spip); + buf[0] = cmd; + spiSend(devp->config->spip, 1, buf); + spiUnselect(devp->config->spip); +} + +static void flash_send_cmd(M25QDriver *devp, uint8_t cmd) { + uint8_t buf[1]; + + buf[0] = cmd; + spiSend(devp->config->spip, 1, buf); +} + +static void flash_send_cmd_addr(M25QDriver *devp, + uint8_t cmd, + flash_address_t addr) { + uint8_t buf[4]; + + buf[0] = cmd; + buf[1] = (uint8_t)(addr >> 16); + buf[2] = (uint8_t)(addr >> 8); + buf[3] = (uint8_t)(addr >> 0); + spiSend(devp->config->spip, 4, buf); +} + +static flash_error_t flash_poll_status(M25QDriver *devp) { + SPIDriver *spip = devp->config->spip; + uint8_t sts; + + do { +#if N25Q128_NICE_WAITING == TRUE + osalThreadSleepMilliseconds(1); +#endif + /* Read status command.*/ + spiSelect(spip); + flash_send_cmd(devp, M25Q_CMD_READ_FLAG_STATUS_REGISTER); + spiReceive(spip, 1, &sts); + spiUnselect(spip); + } while ((sts & N25Q128_STS_PROGRAM_ERASE) == 0U); + + /* Checking for errors.*/ + if ((sts & N25Q128_STS_ALL_ERRORS) != 0U) { + /* Clearing status register.*/ + flash_send_cmd(devp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER); + + /* Program operation failed.*/ + return FLASH_ERROR_PROGRAM; + } + + return FLASH_NO_ERROR; +} + +static const flash_descriptor_t *get_descriptor(void *instance) { + M25QDriver *devp = (M25QDriver *)instance; + + osalDbgCheck(instance != NULL); + osalDbgAssert((devp->state != FLASH_UNINIT) && (devp->state != FLASH_STOP), + "invalid state"); + + return &descriptor; +} + +static flash_error_t read(void *instance, flash_address_t addr, + uint8_t *rp, size_t n) { + M25QDriver *devp = (M25QDriver *)instance; + SPIDriver *spip = devp->config->spip; + + 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; + } + + flash_bus_acquire(devp); + devp->state = FLASH_READ; + + /* Read command.*/ + spiSelect(spip); + flash_send_cmd_addr(devp, M25Q_CMD_READ, addr); + spiReceive(spip, n, rp); + spiUnselect(spip); + + devp->state = FLASH_READY; + flash_bus_release(devp); + return FLASH_NO_ERROR; +} + +static flash_error_t program(void *instance, flash_address_t addr, + const uint8_t *pp, size_t n) { + M25QDriver *devp = (M25QDriver *)instance; + SPIDriver *spip = devp->config->spip; + + osalDbgCheck((instance != NULL) && (pp != 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; + } + + flash_bus_acquire(devp); + devp->state = FLASH_PGM; + + /* 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)(((addr | PAGE_MASK) + 1U) - addr); + if (chunk > n) { + chunk = n; + } + + /* Enabling write operation.*/ + flash_short_cmd(devp, M25Q_CMD_WRITE_ENABLE); + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + + /* Page program command.*/ + spiSelect(spip); + flash_send_cmd_addr(devp, M25Q_CMD_PAGE_PROGRAM, addr); + spiSend(spip, chunk, pp); + spiUnselect(spip); + + /* Wait for status and check errors.*/ + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + err = flash_poll_status(devp); + if (err != FLASH_NO_ERROR) { + flash_bus_release(devp); + return err; + } + + /* Next page.*/ + addr += chunk; + pp += chunk; + n -= chunk; + } + + devp->state = FLASH_READY; + flash_bus_release(devp); + return FLASH_NO_ERROR; +} + +static flash_error_t start_erase_all(void *instance) { + M25QDriver *devp = (M25QDriver *)instance; + SPIDriver *spip = devp->config->spip; + + osalDbgCheck(instance != NULL); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + if (devp->state == FLASH_ERASE) { + return FLASH_BUSY_ERASING; + } + + flash_bus_acquire(devp); + devp->state = FLASH_ERASE; + + /* Enabling write operation.*/ + flash_short_cmd(devp, M25Q_CMD_WRITE_ENABLE); + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + + /* Bulk erase command.*/ + flash_short_cmd(devp, M25Q_CMD_BULK_ERASE); + + devp->state = FLASH_READY; + flash_bus_release(devp); + return FLASH_NO_ERROR; +} + +static flash_error_t start_erase_sector(void *instance, flash_sector_t sector) { + M25QDriver *devp = (M25QDriver *)instance; + SPIDriver *spip = devp->config->spip; + flash_address_t addr = (flash_address_t)(sector * SECTOR_SIZE); + + osalDbgCheck(instance != NULL); + osalDbgCheck(sector < descriptor.sectors_count); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + if (devp->state == FLASH_ERASE) { + return FLASH_BUSY_ERASING; + } + + flash_bus_acquire(devp); + devp->state = FLASH_ERASE; + + /* Enabling write operation.*/ + flash_short_cmd(devp, M25Q_CMD_WRITE_ENABLE); + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + + /* Sector erase command.*/ + spiSelect(spip); + flash_send_cmd_addr(devp, CMD_SECTOR_ERASE, addr); + spiUnselect(spip); + + devp->state = FLASH_READY; + flash_bus_release(devp); + return FLASH_NO_ERROR; +} + +static flash_error_t verify_erase(void *instance, flash_sector_t sector) { + M25QDriver *devp = (M25QDriver *)instance; + SPIDriver *spip = devp->config->spip; + unsigned i; + + osalDbgCheck(instance != NULL); + osalDbgCheck(sector < descriptor.sectors_count); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); + + if (devp->state == FLASH_ERASE) { + return FLASH_BUSY_ERASING; + } + + flash_bus_acquire(devp); + devp->state = FLASH_READ; + + /* Read command.*/ + spiSelect(spip); + flash_send_cmd_addr(devp, M25Q_CMD_READ, (size_t)(sector * SECTOR_SIZE)); + for (i = SECTOR_SIZE; i > 0U; i--) { + if (spiPolledExchange(spip, 0xFF) != 0xFF) { + flash_bus_release(devp); + return FLASH_ERROR_VERIFY; + } + } + spiUnselect(spip); + + devp->state = FLASH_READY; + flash_bus_release(devp); + return FLASH_NO_ERROR; +} + +static flash_error_t query_erase(void *instance, uint32_t *msec) { + M25QDriver *devp = (M25QDriver *)instance; + SPIDriver *spip = devp->config->spip; + uint8_t sts; + + 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) { + + flash_bus_acquire(devp); + + /* Read status command.*/ + spiSelect(spip); + flash_send_cmd(devp, M25Q_CMD_READ_FLAG_STATUS_REGISTER); + spiReceive(spip, 1, &sts); + spiUnselect(spip); + + /* 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 & N25Q128_STS_PROGRAM_ERASE) == 0U) || + ((sts & N25Q128_STS_ERASE_SUSPEND) != 0U)) { + flash_bus_release(devp); + + /* Recommended time before polling again, this is a simplified + implementation.*/ + if (msec != NULL) { + *msec = 1U; + } + + return FLASH_BUSY_ERASING; + } + + /* The device is ready to accept commands.*/ + devp->state = FLASH_READY; + + /* Checking for errors.*/ + if ((sts & N25Q128_STS_ALL_ERRORS) != 0U) { + /* Clearing status register.*/ + flash_short_cmd(devp, M25Q_CMD_CLEAR_FLAG_STATUS_REGISTER); + + /* Program operation failed.*/ + return FLASH_ERROR_ERASE; + } + + flash_bus_release(devp); + } + + return FLASH_NO_ERROR; +} + +static flash_error_t read_id(void *instance, uint8_t *rp, size_t n) { + + (void)instance; + (void)rp; + (void)n; + + return FLASH_NO_ERROR; +} + +/*===========================================================================*/ +/* 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_baseflash = &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 N25Q128Config *config) { + + osalDbgCheck((devp != NULL) && (config != NULL)); + osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state"); + + if (devp->state == FLASH_STOP) { + SPIDriver *spip = config->spip; + + devp->config = config; + flash_bus_acquire(devp); + + /* Reset Enable command.*/ + flash_short_cmd(devp, M25Q_CMD_RESET_ENABLE); + + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + + /* Reset Memory command.*/ + flash_short_cmd(devp, M25Q_CMD_RESET_MEMORY); + + devp->state = FLASH_READY; + flash_bus_release(devp); + } +} + +/** + * @brief Deactivates the N25Q128 driver. + * + * @param[in] devp pointer to the @p M25QDriver object + * + * @api + */ +void m25qStop(M25QDriver *devp) { + SPIDriver *spip = devp->config->spip; + + osalDbgCheck(devp != NULL); + osalDbgAssert(devp->state != FLASH_UNINIT, "invalid state"); + + if (devp->state != FLASH_STOP) { + flash_bus_acquire(devp); + + spiStop(spip); + + devp->config = NULL; + devp->state = FLASH_STOP; + flash_bus_release(devp); + } +} + +/** + * @brief Reads the device identifier. + * + * @param[in] devp pointer to the @p M25QDriver object + * @param[in] rp pointer to the read buffer + * @param[in] n number of bytes to read (1..17) + * + * @api + */ +void m25qReadId(M25QDriver *devp, uint8_t *rp, size_t n) { + SPIDriver *spip = devp->config->spip; + + osalDbgCheck((devp != NULL) && (rp != NULL) && (n > 0U) && (n <= 17U)); + osalDbgAssert(devp->state == FLASH_READY, "invalid state"); + + flash_bus_acquire(devp); + devp->state = FLASH_READ; + + /* Read Id command.*/ + spiSelect(spip); + flash_send_cmd(devp, M25Q_CMD_READ_ID); + spiReceive(spip, n, rp); + spiUnselect(spip); + + devp->state = FLASH_READY; + flash_bus_release(devp); +} + +/** @} */ diff --git a/os/ex/Micron/m25q.h b/os/ex/Micron/m25q.h new file mode 100644 index 000000000..e732da682 --- /dev/null +++ b/os/ex/Micron/m25q.h @@ -0,0 +1,233 @@ +/* + N25Q128 Flash Driver - Copyright (C) 2016 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 . +*/ + +/** + * @file m25q.h + * @brief Micron serial flash driver header. + * + * @addtogroup m25q + * @{ + */ + +#ifndef M25Q_H +#define M25Q_H + +#include "hal_jesd216_flash.h" + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +/** + * @name Command codes + * @{ + */ +#define M25Q_CMD_RESET_ENABLE 0x66 +#define M25Q_CMD_RESET_MEMORY 0x99 +#define M25Q_CMD_READ_ID 0x9F +#define M25Q_CMD_READ_DISCOVERY_PARAMETER 0x5A +#define M25Q_CMD_READ 0x03 +#define M25Q_CMD_FAST_READ 0x08 +#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 Status register bits + * @{ + */ +#define N25Q128_STS_PROGRAM_ERASE 0x80U +#define N25Q128_STS_ERASE_SUSPEND 0x40U +#define N25Q128_STS_ERASE_ERROR 0x20U +#define N25Q128_STS_PROGRAM_ERROR 0x10U +#define N25Q128_STS_VPP_ERROR 0x08U +#define N25Q128_STS_PROGRAM_SUSPEND 0x04U +#define N25Q128_STS_PROTECTION_ERROR 0x02U +#define N25Q128_STS_RESERVED 0x01U +#define N25Q128_STS_ALL_ERRORS (N25Q128_STS_ERASE_ERROR | \ + N25Q128_STS_PROGRAM_ERROR | \ + N25Q128_STS_VPP_ERROR | \ + N25Q128_STS_PROTECTION_ERROR) +/** @} */ + +/*===========================================================================*/ +/* Driver pre-compile time settings. */ +/*===========================================================================*/ + +/** + * @name Configuration options + * @{ + */ +/** + * @brief SPI fallback switch. + * @details If enabled makes the driver use SPI rather than QSPI. + */ +#if !defined(M25Q_USE_SPI) || defined(__DOXYGEN__) +#define M25Q_USE_SPI FALSE +#endif + +/** + * @brief N25Q128 shared SPI switch. + * @details If set to @p TRUE the device acquires SPI bus ownership + * on each transaction. + * @note The default is @p FALSE. Requires SPI_USE_MUTUAL_EXCLUSION + */ +#if !defined(M25Q_SHARED_SPI) || defined(__DOXYGEN__) +#define M25Q_SHARED_SPI TRUE +#endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the flash waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + * This option is recommended also when the SPI driver does not + * use a DMA channel and heavily loads the CPU. + */ +#if !defined(N25Q128_NICE_WAITING) || defined(__DOXYGEN__) +#define N25Q128_NICE_WAITING TRUE +#endif + +/** + * @brief Uses 4kB sub-sectors rather than 64kB sectors. + */ +#if !defined(N25Q128_USE_SUB_SECTORS) || defined(__DOXYGEN__) +#define N25Q128_USE_SUB_SECTORS FALSE +#endif +/** @} */ + +/*===========================================================================*/ +/* Derived constants and error checks. */ +/*===========================================================================*/ + +#if M25Q_USE_SPI && !HAL_USE_SPI +#error "M25Q_USE_SPI=TRUE requires HAL_USE_SPI" +#endif + +#if !M25Q_USE_SPI && !HAL_USE_QSPI +#error "M25Q_USE_SPI=FALSE requires HAL_USE_QSPI" +#endif + +#if M25Q_USE_SPI && M25Q_SHARED_SPI && !SPI_USE_MUTUAL_EXCLUSION +#error "M25Q_SHARED_SPI requires SPI_USE_MUTUAL_EXCLUSION" +#endif + +/*===========================================================================*/ +/* Driver data structures and types. */ +/*===========================================================================*/ + +/** + * @brief Type of a M25Q configuration structure. + */ +typedef struct { +#if !M25Q_USE_SPI || defined(__DOXYGEN__) + /** + * @brief QSPI driver associated to this instance. + */ + QSPIDriver *qspip; + /** + * @brief QSPI configuration associated to this instance. + */ + const QSPIConfig *qspicfg; +#else + /** + * @brief SPI driver associated to this instance. + */ + SPIDriver *spip; + /** + * @brief SPI configuration associated to this instance. + */ + const SPIConfig *spicfg; +#endif +} 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 JESD216FlashVMT *vmt_baseflash; + _jesd216_flash_data + /** + * @brief Current configuration data. + */ + const M25QConfig *config; +} 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); +#ifdef __cplusplus +} +#endif + +#endif /* M25Q_H */ + +/** @} */ + diff --git a/os/ex/Micron/m25q.mk b/os/ex/Micron/m25q.mk new file mode 100644 index 000000000..78001ba55 --- /dev/null +++ b/os/ex/Micron/m25q.mk @@ -0,0 +1,8 @@ +# List of all the m25Q device files. +M25QSRC := $(CHIBIOS)/os/hal/lib/peripherals/flash/hal_flash.c \ + $(CHIBIOS)/os/hal/lib/peripherals/flash/hal_jesd216_flash.c \ + $(CHIBIOS)/os/ex/Micron/m25q.c + +# Required include directories +M25QINC := $(CHIBIOS)/os/hal/lib/peripherals/flash \ + $(CHIBIOS)/os/ex/Micron \ No newline at end of file diff --git a/os/ex/Micron/n25q128_spi.c b/os/ex/Micron/n25q128_spi.c index 9bc5bf295..3c321cd8d 100644 --- a/os/ex/Micron/n25q128_spi.c +++ b/os/ex/Micron/n25q128_spi.c @@ -417,7 +417,7 @@ void n25q128ObjectInit(N25Q128Driver *devp) { osalDbgCheck(devp != NULL); - devp->vmt_baseflash = &n25q128_vmt; + devp->vmt = &n25q128_vmt; devp->state = FLASH_STOP; devp->config = NULL; } diff --git a/os/ex/Micron/n25q128_spi.h b/os/ex/Micron/n25q128_spi.h index 6a08f9b8a..6f7aa72e5 100644 --- a/os/ex/Micron/n25q128_spi.h +++ b/os/ex/Micron/n25q128_spi.h @@ -178,7 +178,7 @@ typedef struct { /** * @brief BaseFlash Virtual Methods Table. */ - const struct N25Q128DriverVMT *vmt_baseflash; + const struct N25Q128DriverVMT *vmt; _base_flash_data /** * @brief Current configuration data. diff --git a/os/hal/lib/peripherals/flash/hal_flash.h b/os/hal/lib/peripherals/flash/hal_flash.h index 52011a765..b15c18b25 100644 --- a/os/hal/lib/peripherals/flash/hal_flash.h +++ b/os/hal/lib/peripherals/flash/hal_flash.h @@ -184,7 +184,7 @@ struct BaseFlashVMT { */ typedef struct { /** @brief Virtual Methods Table.*/ - const struct BaseFlashVMT *vmt_baseflash; + const struct BaseFlashVMT *vmt; _base_flash_data } BaseFlash; @@ -205,7 +205,7 @@ typedef struct { * @api */ #define flashGetDescriptor(ip) \ - (ip)->vmt_baseflash->get_descriptor(ip) + (ip)->vmt->get_descriptor(ip) /** * @brief Read operation. @@ -222,7 +222,7 @@ typedef struct { * @api */ #define flashRead(ip, addr, rp, n) \ - (ip)->vmt_baseflash->read(ip, addr, rp, n) + (ip)->vmt->read(ip, addr, rp, n) /** * @brief Program operation. @@ -239,7 +239,7 @@ typedef struct { * @api */ #define flashProgram(ip, addr, pp, n) \ - (ip)->vmt_baseflash->program(ip, addr, pp, n) + (ip)->vmt->program(ip, addr, pp, n) /** * @brief Starts a whole-device erase operation. @@ -252,7 +252,7 @@ typedef struct { * @api */ #define flashStartEraseAll(ip) \ - (ip)->vmt_baseflash->start_erase_all(ip) + (ip)->vmt->start_erase_all(ip) /** * @brief Starts an sector erase operation. @@ -266,7 +266,7 @@ typedef struct { * @api */ #define flashStartEraseSector(ip, sector) \ - (ip)->vmt_baseflash->start_erase_sector(ip, sector) + (ip)->vmt->start_erase_sector(ip, sector) /** * @brief Queries the driver for erase operation progress. @@ -282,7 +282,7 @@ typedef struct { * @api */ #define flashQueryErase(ip, msec) \ - (ip)->vmt_baseflash->query_erase(ip, msec) + (ip)->vmt->query_erase(ip, msec) /** * @brief Returns the erase state of a sector. @@ -297,7 +297,7 @@ typedef struct { * @api */ #define flashVerifyErase(ip, sector) \ - (ip)->vmt_baseflash->verify_erase(ip, sector) + (ip)->vmt->verify_erase(ip, sector) /** @} */ /*===========================================================================*/ diff --git a/os/hal/lib/peripherals/flash/hal_jesd216_flash.h b/os/hal/lib/peripherals/flash/hal_jesd216_flash.h index 0c7d1bef6..8e46f71e8 100644 --- a/os/hal/lib/peripherals/flash/hal_jesd216_flash.h +++ b/os/hal/lib/peripherals/flash/hal_jesd216_flash.h @@ -25,6 +25,8 @@ #ifndef HAL_JESD216_FLASH_H #define HAL_JESD216_FLASH_H +#include "hal_flash.h" + /*===========================================================================*/ /* Driver constants. */ /*===========================================================================*/ @@ -66,12 +68,13 @@ */ #define _jesd216_flash_methods_alone \ /* Read SFDP.*/ \ - void (*read_id)(void *instance, uint8_t *rp, size_t max); + flash_error_t (*read_id)(void *instance, uint8_t *rp, size_t max); /** * @brief @p JESD215Flash specific methods with inherited ones. */ #define _jesd216_flash_methods \ + _base_flash_methods \ _jesd216_flash_methods_alone /** @@ -84,14 +87,15 @@ struct JESD215FlashVMT { /** * @brief @p JESD215Flash specific data. */ -#define _jesd216_flash_data +#define _jesd216_flash_data \ + _base_flash_data /** * @brief Base flash class. */ typedef struct { /** @brief Virtual Methods Table.*/ - const struct JESD215FlashVMT *vmt_jesd216flash; + const struct JESD215FlashVMT *vmt; _jesd216_flash_data } JESD215Flash; diff --git a/testhal/STM32/STM32L4xx/QSPI-N25Q128/Makefile b/testhal/STM32/STM32L4xx/QSPI-N25Q128/Makefile index 7a8a46ee0..13da447eb 100644 --- a/testhal/STM32/STM32L4xx/QSPI-N25Q128/Makefile +++ b/testhal/STM32/STM32L4xx/QSPI-N25Q128/Makefile @@ -98,6 +98,7 @@ include $(CHIBIOS)/os/hal/osal/rt/osal.mk include $(CHIBIOS)/os/rt/rt.mk include $(CHIBIOS)/os/common/ports/ARMCMx/compilers/GCC/mk/port_v7m.mk # Other files (optional). +include $(CHIBIOS)/os/ex/Micron/m25q.mk include $(CHIBIOS)/os/hal/lib/streams/streams.mk # Define linker script file here @@ -113,6 +114,7 @@ CSRC = $(STARTUPSRC) \ $(PLATFORMSRC) \ $(BOARDSRC) \ $(STREAMSSRC) \ + $(M25QSRC) \ main.c # C++ sources that can be compiled in ARM or THUMB mode depending on the global @@ -145,7 +147,7 @@ ASMXSRC = $(STARTUPASM) $(PORTASM) $(OSALASM) INCDIR = $(CHIBIOS)/os/license \ $(STARTUPINC) $(KERNINC) $(PORTINC) $(OSALINC) \ - $(HALINC) $(PLATFORMINC) $(BOARDINC) \ + $(HALINC) $(PLATFORMINC) $(BOARDINC) $(M25QINC) \ $(STREAMSINC) $(CHIBIOS)/os/various # diff --git a/testhal/STM32/STM32L4xx/QSPI-N25Q128/halconf.h b/testhal/STM32/STM32L4xx/QSPI-N25Q128/halconf.h index 5ab199774..0dcde8147 100644 --- a/testhal/STM32/STM32L4xx/QSPI-N25Q128/halconf.h +++ b/testhal/STM32/STM32L4xx/QSPI-N25Q128/halconf.h @@ -153,7 +153,7 @@ * @brief Enables the SPI subsystem. */ #if !defined(HAL_USE_SPI) || defined(__DOXYGEN__) -#define HAL_USE_SPI TRUE +#define HAL_USE_SPI FALSE #endif /** diff --git a/testhal/STM32/STM32L4xx/QSPI-N25Q128/mcuconf.h b/testhal/STM32/STM32L4xx/QSPI-N25Q128/mcuconf.h index 4b99a9ce4..1422bc0b6 100644 --- a/testhal/STM32/STM32L4xx/QSPI-N25Q128/mcuconf.h +++ b/testhal/STM32/STM32L4xx/QSPI-N25Q128/mcuconf.h @@ -262,7 +262,7 @@ * SPI driver system settings. */ #define STM32_SPI_USE_SPI1 FALSE -#define STM32_SPI_USE_SPI2 TRUE +#define STM32_SPI_USE_SPI2 FALSE #define STM32_SPI_USE_SPI3 FALSE #define STM32_SPI_SPI1_RX_DMA_STREAM STM32_DMA_STREAM_ID(2, 3) #define STM32_SPI_SPI1_TX_DMA_STREAM STM32_DMA_STREAM_ID(2, 4)