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
This commit is contained in:
Giovanni Di Sirio 2016-05-11 11:22:46 +00:00
parent c9387af734
commit c3d1d75f50
9 changed files with 492 additions and 194 deletions

View File

@ -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);

View File

@ -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

View File

@ -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
$(CHIBIOS)/os/ex/Micron

View File

@ -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. */
/*===========================================================================*/

View File

@ -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.
*/

75
os/hal/dox/flash.dox Normal file
View File

@ -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
*/

View File

@ -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);
}
}
/** @} */

View File

@ -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

View File

@ -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);