aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiovanni Di Sirio <gdisirio@gmail.com>2016-05-11 11:22:46 +0000
committerGiovanni Di Sirio <gdisirio@gmail.com>2016-05-11 11:22:46 +0000
commitc3d1d75f50ecfe9ae36f58de67d2baf57be1be39 (patch)
tree5058c433916b6f3bc21914ec12ea0d14d3a5f474
parentc9387af734393984b01a356314ed856e699cde93 (diff)
downloadChibiOS-c3d1d75f50ecfe9ae36f58de67d2baf57be1be39.tar.gz
ChibiOS-c3d1d75f50ecfe9ae36f58de67d2baf57be1be39.tar.bz2
ChibiOS-c3d1d75f50ecfe9ae36f58de67d2baf57be1be39.zip
Added smart polling and preparation for erase suspend.
git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@9463 35acf78f-673a-0410-8e92-d51de3d6d3f4
-rw-r--r--os/ex/Micron/n25q128.c292
-rw-r--r--os/ex/Micron/n25q128.h2
-rw-r--r--os/ex/Micron/n25q128.mk5
-rw-r--r--os/ex/subsystems/mfs/mfs.c4
-rw-r--r--os/ex/subsystems/mfs/mfs.h50
-rw-r--r--os/hal/dox/flash.dox75
-rw-r--r--os/hal/lib/peripherals/flash/hal_flash.c75
-rw-r--r--os/hal/lib/peripherals/flash/hal_flash.h121
-rw-r--r--testhal/STM32/STM32F3xx/SPI-N25Q128/main.c2
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);