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,96 +166,34 @@ 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; - - /* Enabling write operation.*/ - spiSelect(spip); - flash_send_cmd(devp, N25Q128_CMD_WRITE_ENABLE); - spiUnselect(spip); - (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ - - /* Bulk erase command.*/ - spiSelect(spip); - flash_send_cmd(devp, N25Q128_CMD_BULK_ERASE); - 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; -} - -static flash_error_t 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"); - - flash_bus_acquire(devp); - devp->state = FLASH_ERASING; - - /* Enabling write operation.*/ - spiSelect(spip); - flash_send_cmd(devp, N25Q128_CMD_WRITE_ENABLE); - spiUnselect(spip); - (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ - - /* Sector erase command.*/ - spiSelect(spip); - 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; -} - -static flash_error_t verify_erase(void *instance, flash_sector_t sector) { - N25Q128Driver *devp = (N25Q128Driver *)instance; - SPIDriver *spip = devp->config->spip; - unsigned i; - - osalDbgCheck(instance != NULL); - osalDbgCheck(sector < descriptor.sectors_count); - osalDbgAssert(devp->state == FLASH_READY, "invalid state"); - - flash_bus_acquire(devp); - devp->state = FLASH_READING; + devp->state = FLASH_READ; /* Read command.*/ spiSelect(spip); - flash_send_cmd_addr(devp, N25Q128_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_VERIFY_FAILURE; - } - } + flash_send_cmd_addr(devp, N25Q128_CMD_READ, addr); + spiReceive(spip, n, rp); spiUnselect(spip); devp->state = FLASH_READY; @@ -262,10 +209,15 @@ static flash_error_t program(void *instance, flash_address_t addr, 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"); + 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_WRITING; + devp->state = FLASH_PGM; /* Data is programmed page by page.*/ while (n > 0U) { @@ -278,9 +230,7 @@ static flash_error_t program(void *instance, flash_address_t addr, } /* 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.*/ /* Page program command.*/ @@ -308,23 +258,57 @@ static flash_error_t program(void *instance, flash_address_t addr, return FLASH_NO_ERROR; } -static flash_error_t read(void *instance, flash_address_t addr, - uint8_t *rp, size_t n) { +static flash_error_t start_erase_all(void *instance) { N25Q128Driver *devp = (N25Q128Driver *)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, "invalid state"); + 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_READING; + devp->state = FLASH_ERASE; - /* Read command.*/ + /* Enabling write operation.*/ + flash_short_cmd(devp, N25Q128_CMD_WRITE_ENABLE); + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + + /* Bulk erase command.*/ + flash_short_cmd(devp, N25Q128_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) { + N25Q128Driver *devp = (N25Q128Driver *)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, N25Q128_CMD_WRITE_ENABLE); + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + + /* Sector erase command.*/ spiSelect(spip); - flash_send_cmd_addr(devp, N25Q128_CMD_READ, addr); - spiReceive(spip, n, rp); + flash_send_cmd_addr(devp, CMD_SECTOR_ERASE, addr); spiUnselect(spip); devp->state = FLASH_READY; @@ -332,6 +316,92 @@ static flash_error_t read(void *instance, flash_address_t addr, return FLASH_NO_ERROR; } +static flash_error_t verify_erase(void *instance, flash_sector_t sector) { + N25Q128Driver *devp = (N25Q128Driver *)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, N25Q128_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) { + N25Q128Driver *devp = (N25Q128Driver *)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, N25Q128_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, N25Q128_CMD_CLEAR_FLAG_STATUS_REGISTER); + + /* Program operation failed.*/ + return FLASH_ERROR_ERASE; + } + + flash_bus_release(devp); + } + + return FLASH_NO_ERROR; +} + /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ @@ -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 @@ -61,6 +61,56 @@ typedef enum { MFS_ACTIVE = 3 } 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. */ 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: + * - IDLE, when the channel is disabled or after a match occurred. + * - ACTIVE, 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 . +*/ + +/** + * @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. @@ -210,55 +209,6 @@ typedef struct { #define flashGetDescriptor(ip) \ (ip)->vmt_baseflash->get_descriptor(ip) -/** - * @brief Whole device erase operation. - * - * @param[in] ip pointer to a @p BaseFlash or derived class - * @return An error code. - * - * @api - */ -#define flashEraseAll(ip) \ - (ip)->vmt_baseflash->erase_all(ip) - -/** - * @brief Erase operation on a sector. - * - * @param[in] ip pointer to a @p BaseFlash or derived class - * @param[in] sector sector to be erased - * @return An error code. - * - * @api - */ -#define flashEraseSector(ip, sector) \ - (ip)->vmt_baseflash->erase_sector(ip, sector) - -/** - * @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. - * - * @api - */ -#define flashVerifyErase(ip, sector) \ - (ip)->vmt_baseflash->verify_erase(ip, sector) - -/** - * @brief Write 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 - * @return An error code. - * - * @api - */ -#define flashProgram(ip, addr, pp, n) \ - (ip)->vmt_baseflash->program(ip, addr, pp, n) - /** * @brief Read operation. * @@ -267,12 +217,89 @@ typedef struct { * @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 flashRead(ip, addr, rp, n) \ (ip)->vmt_baseflash->read(ip, addr, rp, n) +/** + * @brief Program 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 + * @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 flashProgram(ip, addr, pp, n) \ + (ip)->vmt_baseflash->program(ip, addr, pp, n) + +/** + * @brief Starts a whole-device erase operation. + * + * @param[in] ip pointer to a @p BaseFlash or derived class + * @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 flashStartEraseAll(ip) \ + (ip)->vmt_baseflash->start_erase_all(ip) + +/** + * @brief Starts an sector erase operation. + * + * @param[in] ip pointer to a @p BaseFlash or derived class + * @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 flashStartEraseSector(ip, sector) \ + (ip)->vmt_baseflash->start_erase_sector(ip, sector) + +/** + * @brief Queries the driver for erase operation progress. + * + * @param[in] ip pointer to a @p BaseFlash or derived class + * @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 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);