aboutsummaryrefslogtreecommitdiffstats
path: root/os/ex/Micron
diff options
context:
space:
mode:
Diffstat (limited to 'os/ex/Micron')
-rw-r--r--os/ex/Micron/n25q128.c292
-rw-r--r--os/ex/Micron/n25q128.h2
-rw-r--r--os/ex/Micron/n25q128.mk5
3 files changed, 183 insertions, 116 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