aboutsummaryrefslogtreecommitdiff
path: root/spiflash_n25q128.c
diff options
context:
space:
mode:
Diffstat (limited to 'spiflash_n25q128.c')
-rw-r--r--spiflash_n25q128.c91
1 files changed, 63 insertions, 28 deletions
diff --git a/spiflash_n25q128.c b/spiflash_n25q128.c
index 6e35a41..c23f244 100644
--- a/spiflash_n25q128.c
+++ b/spiflash_n25q128.c
@@ -43,6 +43,14 @@
#define _n25q128_deselect(ctx) HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_SET);
+#define N25Q128_NUM_BYTES (N25Q128_PAGE_SIZE * N25Q128_NUM_PAGES)
+
+#if N25Q128_SECTOR_SIZE * N25Q128_NUM_SECTORS != N25Q128_NUM_BYTES || \
+ N25Q128_SUBSECTOR_SIZE * N25Q128_NUM_SUBSECTORS != N25Q128_NUM_BYTES
+#error Inconsistant definitions for pages / sectors / subsectors
+#endif
+
+
int _n25q128_get_wel_flag(struct spiflash_ctx *ctx);
@@ -208,18 +216,30 @@ int n25q128_get_wip_flag(struct spiflash_ctx *ctx)
return (spi_rx[1] & 1);
}
+/* Wait until the flash memory is done writing (wip = Write In Progress) */
+inline int _wait_while_wip(struct spiflash_ctx *ctx, uint32_t timeout)
+{
+ int i;
+ while (timeout--) {
+ i = n25q128_get_wip_flag(ctx);
+ if (i < 0) return 0;
+ if (! i) break;
+ HAL_Delay(10);
+ }
+ return 1;
+}
-int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset)
+static int n25q128_erase_something(struct spiflash_ctx *ctx, uint8_t command, uint32_t byte_offset)
{
+ // check offset
+ if (byte_offset >= N25Q128_NUM_BYTES) return 0;
+
// tx buffer
uint8_t spi_tx[4];
// result
HAL_StatusTypeDef ok;
- // check offset
- if (sector_offset >= N25Q128_NUM_SECTORS) return 0;
-
// enable writing
spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE;
@@ -236,14 +256,11 @@ int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset)
int wel = _n25q128_get_wel_flag(ctx);
if (wel != 1) return 0;
- // calculate byte address
- sector_offset *= N25Q128_SECTOR_SIZE;
-
- // send ERASE SUBSECTOR command
- spi_tx[0] = N25Q128_COMMAND_ERASE_SECTOR;
- spi_tx[1] = (uint8_t)(sector_offset >> 16);
- spi_tx[2] = (uint8_t)(sector_offset >> 8);
- spi_tx[3] = (uint8_t)(sector_offset >> 0);
+ // send command (ERASE SECTOR or ERASE SUBSECTOR)
+ spi_tx[0] = command;
+ spi_tx[1] = (uint8_t)(byte_offset >> 16);
+ spi_tx[2] = (uint8_t)(byte_offset >> 8);
+ spi_tx[3] = (uint8_t)(byte_offset >> 0);
// activate, send command, deselect
_n25q128_select(ctx);
@@ -254,11 +271,29 @@ int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset)
// check
if (ok != HAL_OK) return 0;
+ // wait for erase to finish
+
+ if (! _wait_while_wip(ctx, 2000)) return 0;
+
// done
return 1;
}
+int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset)
+{
+ return n25q128_erase_something(ctx, N25Q128_COMMAND_ERASE_SECTOR,
+ sector_offset * N25Q128_SECTOR_SIZE);
+}
+
+
+int n25q128_erase_subsector(struct spiflash_ctx *ctx, uint32_t subsector_offset)
+{
+ return n25q128_erase_something(ctx, N25Q128_COMMAND_ERASE_SUBSECTOR,
+ subsector_offset * N25Q128_SUBSECTOR_SIZE);
+}
+
+
int _n25q128_get_wel_flag(struct spiflash_ctx *ctx)
{
// tx, rx buffers
@@ -284,21 +319,8 @@ int _n25q128_get_wel_flag(struct spiflash_ctx *ctx)
return ((spi_rx[1] >> 1) & 1);
}
-/* Wait until the flash memory is done writing (wip = Write In Progress) */
-inline int _wait_while_wip(struct spiflash_ctx *ctx, uint32_t timeout)
-{
- int i;
- while (timeout--) {
- i = n25q128_get_wip_flag(ctx);
- if (i < 0) return 0;
- if (! i) break;
- HAL_Delay(10);
- }
- return 1;
-}
-
/* This function performs erasure if needed, and then writing of a number of pages to the flash memory */
-int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len)
+int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len, const int auto_erase)
{
uint32_t page;
@@ -306,8 +328,15 @@ int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t
if ((offset % N25Q128_PAGE_SIZE) != 0) return -1;
if ((len % N25Q128_PAGE_SIZE) != 0) return -2;
- if ((offset % N25Q128_SECTOR_SIZE) == 0) {
- /* first page in sector, need to erase sector */
+ if (auto_erase && (offset % N25Q128_SECTOR_SIZE) == 0) {
+ /*
+ * first page in sector, need to erase sector
+ *
+ * So why do we only do this when the buffer starts on the
+ * sector, as opposed to performing this check for every page?
+ * Also, might be better to do this by subsectors rather than
+ * sectors.
+ */
if (! _wait_while_wip(ctx, 1000)) return -3;
@@ -330,6 +359,12 @@ int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t
*/
}
+ /*
+ * Wait until last write finishes.
+ */
+
+ if (! _wait_while_wip(ctx, 1000)) return -7;
+
return 1;
}