diff options
-rw-r--r-- | os/ex/Micron/n25q128.c | 292 | ||||
-rw-r--r-- | os/ex/Micron/n25q128.h | 2 | ||||
-rw-r--r-- | os/ex/Micron/n25q128.mk | 5 | ||||
-rw-r--r-- | os/ex/subsystems/mfs/mfs.c | 4 | ||||
-rw-r--r-- | os/ex/subsystems/mfs/mfs.h | 50 | ||||
-rw-r--r-- | os/hal/dox/flash.dox | 75 | ||||
-rw-r--r-- | os/hal/lib/peripherals/flash/hal_flash.c | 75 | ||||
-rw-r--r-- | os/hal/lib/peripherals/flash/hal_flash.h | 121 | ||||
-rw-r--r-- | testhal/STM32/STM32F3xx/SPI-N25Q128/main.c | 2 |
9 files changed, 462 insertions, 164 deletions
diff --git a/os/ex/Micron/n25q128.c b/os/ex/Micron/n25q128.c index 9031ddd3a..9ec25ae8b 100644 --- a/os/ex/Micron/n25q128.c +++ b/os/ex/Micron/n25q128.c @@ -53,19 +53,21 @@ /*===========================================================================*/ static const flash_descriptor_t *get_descriptor(void *instance); -static flash_error_t erase_all(void *instance); -static flash_error_t erase_sector(void *instance, flash_sector_t sector); -static flash_error_t verify_erase(void *instance, flash_sector_t sector); -static flash_error_t program(void *instance, flash_address_t addr, - const uint8_t *pp, size_t n); 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); /** * @brief Virtual methods table. */ static const struct N25Q128DriverVMT n25q128_vmt = { - get_descriptor, erase_all, erase_sector, verify_erase, program, read + get_descriptor, read, program, + start_erase_all, start_erase_sector, query_erase, verify_erase }; /** @@ -105,6 +107,22 @@ void flash_bus_release(N25Q128Driver *devp) { #define flash_bus_release(devp) #endif +static void flash_short_cmd(N25Q128Driver *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(N25Q128Driver *devp, uint8_t cmd) { + uint8_t buf[1]; + + buf[0] = cmd; + spiSend(devp->config->spip, 1, buf); +} + static void flash_send_cmd_addr(N25Q128Driver *devp, uint8_t cmd, flash_address_t addr) { @@ -117,13 +135,6 @@ static void flash_send_cmd_addr(N25Q128Driver *devp, spiSend(devp->config->spip, 4, buf); } -static void flash_send_cmd(N25Q128Driver *devp, uint8_t cmd) { - uint8_t buf[1]; - - buf[0] = cmd; - spiSend(devp->config->spip, 1, buf); -} - static flash_error_t flash_poll_status(N25Q128Driver *devp) { SPIDriver *spip = devp->config->spip; uint8_t sts; @@ -137,17 +148,15 @@ static flash_error_t flash_poll_status(N25Q128Driver *devp) { flash_send_cmd(devp, N25Q128_CMD_READ_FLAG_STATUS_REGISTER); spiReceive(spip, 1, &sts); spiUnselect(spip); - } while ((sts & N25Q128_STS_BUSY) == 0U); + } while ((sts & N25Q128_STS_PROGRAM_ERASE) == 0U); /* Checking for errors.*/ if ((sts & N25Q128_STS_ALL_ERRORS) != 0U) { /* Clearing status register.*/ - spiSelect(spip); flash_send_cmd(devp, N25Q128_CMD_CLEAR_FLAG_STATUS_REGISTER); - spiUnselect(spip); /* Program operation failed.*/ - return FLASH_PROGRAM_FAILURE; + return FLASH_ERROR_PROGRAM; } return FLASH_NO_ERROR; @@ -157,59 +166,144 @@ static const flash_descriptor_t *get_descriptor(void *instance) { N25Q128Driver *devp = (N25Q128Driver *)instance; osalDbgCheck(instance != NULL); - osalDbgAssert(devp->state == FLASH_READY, "invalid state"); + osalDbgAssert((devp->state != FLASH_UNINIT) && (devp->state != FLASH_STOP), + "invalid state"); return &descriptor; } -static flash_error_t erase_all(void *instance) { +static flash_error_t read(void *instance, flash_address_t addr, + uint8_t *rp, size_t n) { N25Q128Driver *devp = (N25Q128Driver *)instance; SPIDriver *spip = devp->config->spip; - flash_error_t err; - osalDbgCheck(instance != NULL); - osalDbgAssert(devp->state == FLASH_READY, "invalid state"); + 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_ERASING; + devp->state = FLASH_READ; - /* Enabling write operation.*/ + /* Read command.*/ spiSelect(spip); - flash_send_cmd(devp, N25Q128_CMD_WRITE_ENABLE); + flash_send_cmd_addr(devp, N25Q128_CMD_READ, addr); + spiReceive(spip, n, rp); spiUnselect(spip); - (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ - /* Bulk erase command.*/ - spiSelect(spip); - flash_send_cmd(devp, N25Q128_CMD_BULK_ERASE); - spiUnselect(spip); + devp->state = FLASH_READY; + flash_bus_release(devp); + return FLASH_NO_ERROR; +} - /* Wait for status and check errors.*/ +static flash_error_t program(void *instance, flash_address_t addr, + const uint8_t *pp, size_t n) { + N25Q128Driver *devp = (N25Q128Driver *)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, N25Q128_CMD_WRITE_ENABLE); + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + + /* Page program command.*/ + spiSelect(spip); + flash_send_cmd_addr(devp, N25Q128_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) { + N25Q128Driver *devp = (N25Q128Driver *)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, N25Q128_CMD_WRITE_ENABLE); (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ - err = flash_poll_status(devp); + + /* Bulk erase command.*/ + flash_short_cmd(devp, N25Q128_CMD_BULK_ERASE); devp->state = FLASH_READY; flash_bus_release(devp); - return err; + return FLASH_NO_ERROR; } -static flash_error_t erase_sector(void *instance, flash_sector_t sector) { +static flash_error_t start_erase_sector(void *instance, flash_sector_t sector) { N25Q128Driver *devp = (N25Q128Driver *)instance; SPIDriver *spip = devp->config->spip; flash_address_t addr = (flash_address_t)(sector * SECTOR_SIZE); - flash_error_t err; osalDbgCheck(instance != NULL); osalDbgCheck(sector < descriptor.sectors_count); - osalDbgAssert(devp->state == FLASH_READY, "invalid state"); + 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_ERASING; + devp->state = FLASH_ERASE; /* Enabling write operation.*/ - spiSelect(spip); - flash_send_cmd(devp, N25Q128_CMD_WRITE_ENABLE); - spiUnselect(spip); + flash_short_cmd(devp, N25Q128_CMD_WRITE_ENABLE); (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ /* Sector erase command.*/ @@ -217,13 +311,9 @@ static flash_error_t erase_sector(void *instance, flash_sector_t sector) { flash_send_cmd_addr(devp, CMD_SECTOR_ERASE, addr); spiUnselect(spip); - /* Wait for status and check errors.*/ - (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ - err = flash_poll_status(devp); - devp->state = FLASH_READY; flash_bus_release(devp); - return err; + return FLASH_NO_ERROR; } static flash_error_t verify_erase(void *instance, flash_sector_t sector) { @@ -233,10 +323,15 @@ static flash_error_t verify_erase(void *instance, flash_sector_t sector) { osalDbgCheck(instance != NULL); osalDbgCheck(sector < descriptor.sectors_count); - osalDbgAssert(devp->state == FLASH_READY, "invalid state"); + 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_READING; + devp->state = FLASH_READ; /* Read command.*/ spiSelect(spip); @@ -244,7 +339,7 @@ static flash_error_t verify_erase(void *instance, flash_sector_t sector) { for (i = SECTOR_SIZE; i > 0U; i--) { if (spiPolledExchange(spip, 0xFF) != 0xFF) { flash_bus_release(devp); - return FLASH_VERIFY_FAILURE; + return FLASH_ERROR_VERIFY; } } spiUnselect(spip); @@ -254,81 +349,56 @@ static flash_error_t verify_erase(void *instance, flash_sector_t sector) { return FLASH_NO_ERROR; } -static flash_error_t program(void *instance, flash_address_t addr, - const uint8_t *pp, size_t n) { +static flash_error_t query_erase(void *instance, uint32_t *msec) { N25Q128Driver *devp = (N25Q128Driver *)instance; SPIDriver *spip = devp->config->spip; + uint8_t sts; - 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, "invalid state"); - - flash_bus_acquire(devp); - devp->state = FLASH_WRITING; - - /* Data is programmed page by page.*/ - while (n > 0U) { - flash_error_t err; + osalDbgCheck(instance != NULL); + osalDbgAssert((devp->state == FLASH_READY) || (devp->state == FLASH_ERASE), + "invalid state"); - /* 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; - } + /* If there is an erase in progress then the device must be checked.*/ + if (devp->state == FLASH_ERASE) { - /* Enabling write operation.*/ - spiSelect(spip); - flash_send_cmd(devp, N25Q128_CMD_WRITE_ENABLE); - spiUnselect(spip); - (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + flash_bus_acquire(devp); - /* Page program command.*/ + /* Read status command.*/ spiSelect(spip); - flash_send_cmd_addr(devp, N25Q128_CMD_PAGE_PROGRAM, addr); - spiSend(spip, chunk, pp); + flash_send_cmd(devp, N25Q128_CMD_READ_FLAG_STATUS_REGISTER); + spiReceive(spip, 1, &sts); 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) { + /* 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); - return err; - } - /* Next page.*/ - addr += chunk; - pp += chunk; - n -= chunk; - } + /* Recommended time before polling again, this is a simplified + implementation.*/ + if (msec != NULL) { + *msec = 1U; + } - devp->state = FLASH_READY; - flash_bus_release(devp); - return FLASH_NO_ERROR; -} + return FLASH_BUSY_ERASING; + } -static flash_error_t read(void *instance, flash_address_t addr, - uint8_t *rp, size_t n) { - N25Q128Driver *devp = (N25Q128Driver *)instance; - SPIDriver *spip = devp->config->spip; + /* The device is ready to accept commands.*/ + devp->state = FLASH_READY; - 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, "invalid state"); + /* Checking for errors.*/ + if ((sts & N25Q128_STS_ALL_ERRORS) != 0U) { + /* Clearing status register.*/ + flash_short_cmd(devp, N25Q128_CMD_CLEAR_FLAG_STATUS_REGISTER); - flash_bus_acquire(devp); - devp->state = FLASH_READING; + /* Program operation failed.*/ + return FLASH_ERROR_ERASE; + } - /* Read command.*/ - spiSelect(spip); - flash_send_cmd_addr(devp, N25Q128_CMD_READ, addr); - spiReceive(spip, n, rp); - spiUnselect(spip); + flash_bus_release(devp); + } - devp->state = FLASH_READY; - flash_bus_release(devp); return FLASH_NO_ERROR; } @@ -372,16 +442,12 @@ void n25q128Start(N25Q128Driver *devp, const N25Q128Config *config) { flash_bus_acquire(devp); /* Reset Enable command.*/ - spiSelect(spip); - flash_send_cmd(devp, N25Q128_CMD_RESET_ENABLE); - spiUnselect(spip); + flash_short_cmd(devp, N25Q128_CMD_RESET_ENABLE); (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ /* Reset Memory command.*/ - spiSelect(spip); - flash_send_cmd(devp, N25Q128_CMD_RESET_MEMORY); - spiUnselect(spip); + flash_short_cmd(devp, N25Q128_CMD_RESET_MEMORY); devp->state = FLASH_READY; flash_bus_release(devp); @@ -428,7 +494,7 @@ void n25q128ReadId(N25Q128Driver *devp, uint8_t *rp, size_t n) { osalDbgAssert(devp->state == FLASH_READY, "invalid state"); flash_bus_acquire(devp); - devp->state = FLASH_READING; + devp->state = FLASH_READ; /* Read Id command.*/ spiSelect(spip); diff --git a/os/ex/Micron/n25q128.h b/os/ex/Micron/n25q128.h index 683d66bb0..c6bff3797 100644 --- a/os/ex/Micron/n25q128.h +++ b/os/ex/Micron/n25q128.h @@ -71,7 +71,7 @@ * @name Status register bits * @{ */ -#define N25Q128_STS_BUSY 0x80U +#define N25Q128_STS_PROGRAM_ERASE 0x80U #define N25Q128_STS_ERASE_SUSPEND 0x40U #define N25Q128_STS_ERASE_ERROR 0x20U #define N25Q128_STS_PROGRAM_ERROR 0x10U diff --git a/os/ex/Micron/n25q128.mk b/os/ex/Micron/n25q128.mk index 15bdcbb6f..2e81cd919 100644 --- a/os/ex/Micron/n25q128.mk +++ b/os/ex/Micron/n25q128.mk @@ -1,6 +1,7 @@ # List of all the N25Q128 device files.
-N25Q128SRC := $(CHIBIOS)/os/ex/Micron/n25q128.c
+N25Q128SRC := $(CHIBIOS)/os/hal/lib/peripherals/flash/hal_flash.c \
+ $(CHIBIOS)/os/ex/Micron/n25q128.c
# Required include directories
N25Q128INC := $(CHIBIOS)/os/hal/lib/peripherals/flash \
- $(CHIBIOS)/os/ex/Micron
\ No newline at end of file + $(CHIBIOS)/os/ex/Micron
\ No newline at end of file diff --git a/os/ex/subsystems/mfs/mfs.c b/os/ex/subsystems/mfs/mfs.c index 7380c34a3..00488db1c 100644 --- a/os/ex/subsystems/mfs/mfs.c +++ b/os/ex/subsystems/mfs/mfs.c @@ -33,6 +33,10 @@ /* Driver local definitions. */ /*===========================================================================*/ +#define MFS_BANK_MAGIC1 0x35A1EC13 +#define MFS_BANK_MAGIC2 0x0FE14991 +#define MFS_HEADER_MAGIC 0x1AC7002E + /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ diff --git a/os/ex/subsystems/mfs/mfs.h b/os/ex/subsystems/mfs/mfs.h index a47c25c47..7abbde0da 100644 --- a/os/ex/subsystems/mfs/mfs.h +++ b/os/ex/subsystems/mfs/mfs.h @@ -62,6 +62,56 @@ typedef enum { } mfs_state_t; /** + * @brief Bank header. + * @note The header resides in the first 16 bytes of a bank extending + * to the next page boundary. + */ +typedef struct { + /** + * @brief Bank magic 1. + */ + uint32_t magic1; + /** + * @brief Bank magic 2. + */ + uint32_t magic2; + /** + * @brief Usage counter of the bank. + */ + uint32_t counter; + /** + * @brief First data element. + */ + flash_address_t next; +} mfs_bank_header_t; + +/** + * @brief Data block header. + */ +typedef union { + struct { + /** + * @brief Data header magic. + */ + uint32_t magic; + /** + * @brief Data identifier. + */ + uint32_t id; + /** + * @brief Data size. + */ + uint32_t size; + /** + * @brief Data CRC. + */ + uint32_t crc; + } fields; + uint8_t h8[16]; + uint32_t h32[4]; +} mfs_data_header_t; + +/** * @brief Type of a MFS configuration structure. */ typedef struct { diff --git a/os/hal/dox/flash.dox b/os/hal/dox/flash.dox new file mode 100644 index 000000000..01b519fff --- /dev/null +++ b/os/hal/dox/flash.dox @@ -0,0 +1,75 @@ +/*
+ ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+/**
+ * @defgroup NOR_FLASH Abstract NOR Flash Class
+ * @brief Generic NOR Flash interface.
+ * @details This module implements a generic class for NOR Flash devices.
+ *
+ * @section flash_1 Driver State Machine
+ * The flash driver implements a state machine internally, not all the driver
+ * functionalities can be used in any moment, any transition not explicitly
+ * shown in the following diagram has to be considered an error and shall
+ * be captured by an assertion (if enabled).
+ * @dot
+ digraph example {
+ rankdir="LR";
+ node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.9", height="0.9"];
+ edge [fontname=Helvetica, fontsize=8];
+ stop [label="FLS_STOP\nLow Power"];
+ uninit [label="FLS_UNINIT", style="bold"];
+ ready [label="FLS_READY\nClock Enabled"];
+ read [label="FLS_READ\nReading"];
+ program [label="FLS_PGM\nProgramming"];
+ erasea [label="FLS_ERASEA\nErasing All"];
+ erases [label="FLS_ERASES\nErasing Sector"];
+ uninit -> stop [label=" flashInit()", constraint=false];
+ stop -> stop [label=" flashStop()"];
+ stop -> ready [label=" flashStart()"];
+ ready -> stop [label=" flashStop()"];
+ ready -> read [label=" flashRead()\nflashVerifyErase()"];
+ read -> ready [label=" return"];
+ ready -> program [label=" flashProgram()"];
+ program -> ready [label=" return"];
+ ready -> erasea [label=" flashEraseAll)"];
+ erasea -> ready [label=" flashQueryErase()\nFLASH_NO_ERROR\nFLASH_ERROR_*"];
+ erasea -> erasea [label=" flashQueryErase()\nflashProgram()\nflashRead()\nFLASH_BUSY_ERASE"];
+ ready -> erases [label=" flashEraseSector()"];
+ erases -> ready [label=" flashQueryErase()\nFLASH_NO_ERROR\nFLASH_ERROR_*"];
+ erases -> erases [label=" flashQueryErase()\nflashProgram()\nflashRead()\nFLASH_BUSY_ERASE"];
+ }
+ * @enddot
+ *
+ * @section flash_2 Flash Operations.
+ * This driver abstracts a generic PWM timer composed of:
+ * - A clock prescaler.
+ * - A main up counter.
+ * - A comparator register that resets the main counter to zero when the limit
+ * is reached. An optional callback can be generated when this happens.
+ * - An array of @p PWM_CHANNELS PWM channels, each channel has an output,
+ * a comparator and is able to invoke an optional callback when a comparator
+ * match with the main counter happens.
+ * .
+ * A PWM channel output can be in two different states:
+ * - <b>IDLE</b>, when the channel is disabled or after a match occurred.
+ * - <b>ACTIVE</b>, when the channel is enabled and a match didn't occur yet
+ * in the current PWM cycle.
+ * .
+ * Note that the two states can be associated to both logical zero or one in
+ * the @p PWMChannelConfig structure.
+ *
+ * @ingroup HAL_INTERFACES
+ */
diff --git a/os/hal/lib/peripherals/flash/hal_flash.c b/os/hal/lib/peripherals/flash/hal_flash.c new file mode 100644 index 000000000..b65ca3768 --- /dev/null +++ b/os/hal/lib/peripherals/flash/hal_flash.c @@ -0,0 +1,75 @@ +/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file hal_flash.c
+ * @brief Generic flash driver class code.
+ *
+ * @addtogroup HAL_FLASH
+ * @{
+ */
+
+#include "hal.h"
+
+#include "hal_flash.h"
+
+/*===========================================================================*/
+/* Driver local definitions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local variables and types. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Waits until the current erase operation is finished.
+ *
+ * @param[in] devp pointer to a @p BaseFlash object
+ * @param[in] cb polling callback or @p NULL
+ */
+flash_error_t flashWaitErase(BaseFlash *devp) {
+
+ while (true) {
+ flash_error_t err;
+ uint32_t msec;
+
+ /* Checking operation state.*/
+ err = flashQueryErase(devp, &msec);
+ if (err != FLASH_BUSY_ERASING) {
+ return err;
+ }
+
+ /* Interval because nice waiting.*/
+ osalThreadSleepMilliseconds(msec);
+ }
+}
+
+/** @} */
diff --git a/os/hal/lib/peripherals/flash/hal_flash.h b/os/hal/lib/peripherals/flash/hal_flash.h index b62f73d66..d0416b353 100644 --- a/os/hal/lib/peripherals/flash/hal_flash.h +++ b/os/hal/lib/peripherals/flash/hal_flash.h @@ -16,7 +16,7 @@ /**
* @file hal_flash.h
- * @brief Generic flash interface header.
+ * @brief Generic flash driver class header.
*
* @addtogroup HAL_FLASH
* @{
@@ -59,10 +59,9 @@ typedef enum { FLASH_UNINIT = 0,
FLASH_STOP = 1,
FLASH_READY = 2,
- FLASH_READING = 3,
- FLASH_WRITING = 4,
- FLASH_ERASING = 5,
- FLASH_SUSPENDED = 6
+ FLASH_READ = 3,
+ FLASH_PGM = 4,
+ FLASH_ERASE = 5
} flash_state_t;
/**
@@ -70,12 +69,12 @@ typedef enum { */
typedef enum {
FLASH_NO_ERROR = 0, /* No error. */
- FLASH_ECC_ERROR = 1, /* ECC error during read operation. */
- FLASH_PROGRAM_FAILURE = 2, /* Program operation failed. */
- FLASH_ERASE_FAILURE = 3, /* Erase operation failed. */
- FLASH_VERIFY_FAILURE = 4, /* Verify operation failed. */
- FLASH_BUSY = 5, /* Attempt to access a sector being erased. */
- FLASH_HW_FAILURE = 6 /* Controller or communication error. */
+ FLASH_BUSY_ERASING = 1, /* Erase operation in progress. */
+ FLASH_ERROR_READ = 2, /* ECC or other error during read operation.*/
+ FLASH_ERROR_PROGRAM = 3, /* Program operation failed. */
+ FLASH_ERROR_ERASE = 4, /* Erase operation failed. */
+ FLASH_ERROR_VERIFY = 5, /* Verify operation failed. */
+ FLASH_ERROR_HW_FAILURE = 6 /* Controller or communication error. */
} flash_error_t;
/**
@@ -144,20 +143,20 @@ typedef struct { #define _base_flash_methods_alone \
/* Get flash device attributes.*/ \
const flash_descriptor_t * (*get_descriptor)(void *instance); \
- /* Erase whole flash device.*/ \
- flash_error_t (*erase_all)(void *instance); \
- /* Erase single sector.*/ \
- flash_error_t (*erase_sector)(void *instance, \
- flash_sector_t sector); \
- /* Erase single sector.*/ \
- flash_error_t (*verify_erase)(void *instance, \
- flash_sector_t sector); \
- /* Write operation.*/ \
- flash_error_t (*program)(void *instance, flash_address_t addr, \
- const uint8_t *pp, size_t n); \
/* Read operation.*/ \
flash_error_t (*read)(void *instance, flash_address_t addr, \
- uint8_t *rp, size_t n);
+ uint8_t *rp, size_t n); \
+ /* Program operation.*/ \
+ flash_error_t (*program)(void *instance, flash_address_t addr, \
+ const uint8_t *pp, size_t n); \
+ /* Erase whole flash device.*/ \
+ flash_error_t (*start_erase_all)(void *instance); \
+ /* Erase single sector.*/ \
+ flash_error_t (*start_erase_sector)(void *instance, \
+ flash_sector_t sector); \
+ flash_error_t (*query_erase)(void *instance, uint32_t *wait_time); \
+ /* Verify erase single sector.*/ \
+ flash_error_t (*verify_erase)(void *instance, flash_sector_t sector);
/**
* @brief @p BaseFlash specific methods with inherited ones.
@@ -211,68 +210,96 @@ typedef struct { (ip)->vmt_baseflash->get_descriptor(ip)
/**
- * @brief Whole device erase operation.
+ * @brief Read operation.
*
* @param[in] ip pointer to a @p BaseFlash or derived class
+ * @param[in] addr flash address
+ * @param[out] rp pointer to the data buffer
+ * @param[in] n number of bytes to be read
* @return An error code.
+ * @retval FLASH_NO_ERROR if there is no erase operation in progress.
+ * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
+ * @retval FLASH_ERROR_READ if the read operation failed.
*
* @api
*/
-#define flashEraseAll(ip) \
- (ip)->vmt_baseflash->erase_all(ip)
+#define flashRead(ip, addr, rp, n) \
+ (ip)->vmt_baseflash->read(ip, addr, rp, n)
/**
- * @brief Erase operation on a sector.
+ * @brief Program operation.
*
* @param[in] ip pointer to a @p BaseFlash or derived class
- * @param[in] sector sector to be erased
+ * @param[in] addr flash address
+ * @param[in] wp pointer to the data buffer
+ * @param[in] n number of bytes to be programmed
* @return An error code.
+ * @retval FLASH_NO_ERROR if there is no erase operation in progress.
+ * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
+ * @retval FLASH_ERROR_PROGRAM if the program operation failed.
*
* @api
*/
-#define flashEraseSector(ip, sector) \
- (ip)->vmt_baseflash->erase_sector(ip, sector)
+#define flashProgram(ip, addr, pp, n) \
+ (ip)->vmt_baseflash->program(ip, addr, pp, n)
/**
- * @brief Returns the erase state of a sector.
+ * @brief Starts a whole-device erase operation.
*
* @param[in] ip pointer to a @p BaseFlash or derived class
- * @param[in] sector sector to be verified
* @return An error code.
+ * @retval FLASH_NO_ERROR if there is no erase operation in progress.
+ * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
*
* @api
*/
-#define flashVerifyErase(ip, sector) \
- (ip)->vmt_baseflash->verify_erase(ip, sector)
+#define flashStartEraseAll(ip) \
+ (ip)->vmt_baseflash->start_erase_all(ip)
/**
- * @brief Write operation.
+ * @brief Starts an sector erase operation.
*
* @param[in] ip pointer to a @p BaseFlash or derived class
- * @param[in] addr flash address
- * @param[in] wp pointer to the data buffer
- * @param[in] n number of bytes to be programmed
+ * @param[in] sector sector to be erased
* @return An error code.
+ * @retval FLASH_NO_ERROR if there is no erase operation in progress.
+ * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
*
* @api
*/
-#define flashProgram(ip, addr, pp, n) \
- (ip)->vmt_baseflash->program(ip, addr, pp, n)
+#define flashStartEraseSector(ip, sector) \
+ (ip)->vmt_baseflash->start_erase_sector(ip, sector)
/**
- * @brief Read operation.
+ * @brief Queries the driver for erase operation progress.
*
* @param[in] ip pointer to a @p BaseFlash or derived class
- * @param[in] addr flash address
- * @param[out] rp pointer to the data buffer
- * @param[in] n number of bytes to be read
+ * @param[out] msec recommended time, in milliseconds, that what should be
+ * spent before calling this function again, can be @p NULL
* @return An error code.
+ * @retval FLASH_NO_ERROR if there is no erase operation in progress.
+ * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
+ * @retval FLASH_ERROR_ERASE if the erase operation failed.
*
* @api
*/
-#define flashRead(ip, addr, rp, n) \
- (ip)->vmt_baseflash->read(ip, addr, rp, n)
+#define flashQueryErase(ip, msec) \
+ (ip)->vmt_baseflash->query_erase(ip, msec)
+/**
+ * @brief Returns the erase state of a sector.
+ *
+ * @param[in] ip pointer to a @p BaseFlash or derived class
+ * @param[in] sector sector to be verified
+ * @return An error code.
+ * @retval FLASH_NO_ERROR if there is no erase operation in progress.
+ * @retval FLASH_BUSY_ERASING if there is an erase operation in progress.
+ * @retval FLASH_ERROR_VERIFY if the verify operation failed.
+ *
+ * @api
+ */
+#define flashVerifyErase(ip, sector) \
+ (ip)->vmt_baseflash->verify_erase(ip, sector)
/** @} */
/*===========================================================================*/
@@ -282,7 +309,7 @@ typedef struct { #ifdef __cplusplus
extern "C" {
#endif
-
+ flash_error_t flashWaitErase(BaseFlash *devp);
#ifdef __cplusplus
}
#endif
diff --git a/testhal/STM32/STM32F3xx/SPI-N25Q128/main.c b/testhal/STM32/STM32F3xx/SPI-N25Q128/main.c index 41c8541e2..021939419 100644 --- a/testhal/STM32/STM32F3xx/SPI-N25Q128/main.c +++ b/testhal/STM32/STM32F3xx/SPI-N25Q128/main.c @@ -129,7 +129,7 @@ int main(void) { err = flashRead(&flash, 0, buffer, 128);
if (err != FLASH_NO_ERROR)
chSysHalt("read error");
- err = flashEraseSector(&flash, 0);
+ err = flashStartEraseSector(&flash, 0);
if (err != FLASH_NO_ERROR)
chSysHalt("erase error");
err = flashVerifyErase(&flash, 0);
|