diff options
Diffstat (limited to 'os')
-rw-r--r-- | os/ex/Micron/n25q128.c | 59 | ||||
-rw-r--r-- | os/ex/Micron/n25q128.h | 30 | ||||
-rw-r--r-- | os/hal/lib/peripherals/flash/hal_flash.h | 6 |
3 files changed, 86 insertions, 9 deletions
diff --git a/os/ex/Micron/n25q128.c b/os/ex/Micron/n25q128.c index 079a565a7..03ebd6cc2 100644 --- a/os/ex/Micron/n25q128.c +++ b/os/ex/Micron/n25q128.c @@ -93,6 +93,13 @@ static void spi_send_cmd_addr(N25Q128Driver *devp, spiSend(devp->config->spip, 4, buf); } +static void spi_send_cmd(N25Q128Driver *devp, uint8_t cmd) { + uint8_t buf[1]; + + buf[0] = cmd; + spiSend(devp->config->spip, 1, buf); +} + static const flash_descriptor_t *get_attributes(void *instance) { N25Q128Driver *devp = (N25Q128Driver *)instance; SPIDriver *spip = devp->config->spip; @@ -149,6 +156,7 @@ 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; + flash_error_t err; osalDbgAssert(devp->state == FLASH_READY, "invalid state"); @@ -158,31 +166,69 @@ static flash_error_t program(void *instance, flash_address_t addr, #endif devp->state = FLASH_ACTIVE; - while (n > 0) { + while (n > 0U) { + uint8_t sts; + + /* 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.*/ spiSelect(spip); + spi_send_cmd(devp, N25Q128_CMD_WRITE_ENABLE); + spiUnselect(spip); + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + /* Page program command.*/ + spiSelect(spip); spi_send_cmd_addr(devp, N25Q128_CMD_PAGE_PROGRAM, addr); spiSend(spip, chunk, pp); - spiUnselect(spip); + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + /* Operation end waiting.*/ + do { +#if N25Q128_NICE_WAITING == TRUE + osalThreadSleepMilliseconds(1); +#endif + /* Read status command.*/ + spiSelect(spip); + spi_send_cmd(devp, N25Q128_CMD_READ_STATUS_REGISTER); + spiReceive(spip, 1, &sts); + spiUnselect(spip); + } while ((sts & N25Q128_STS_BUSY) != 0U); + + /* Checking for errors.*/ + if ((sts & N25Q128_STS_ALL_ERRORS) != 0U) { + /* Clearing status register.*/ + (void) spiPolledExchange(spip, 0xFF); /* One frame delay.*/ + spiSelect(spip); + spi_send_cmd(devp, N25Q128_CMD_CLEAR_FLAG_STATUS_REGISTER); + spiUnselect(spip); + + /* Program operation failed.*/ + err = FLASH_PROGRAM_FAILURE; + goto exit_error; + } + + /* Next page.*/ addr += chunk; pp += chunk; n -= chunk; } - devp->state = FLASH_READY; + /* Program operation succeeded.*/ + err = FLASH_NO_ERROR; + /* Common exit path for this function.*/ +exit_error: + devp->state = FLASH_READY; #if N25Q128_SHARED_SPI == TRUE spiReleaseBus(spip); #endif - - return FLASH_NO_ERROR; + return err; } static flash_error_t read(void *instance, flash_address_t addr, @@ -198,17 +244,16 @@ static flash_error_t read(void *instance, flash_address_t addr, #endif devp->state = FLASH_ACTIVE; + /* Read command.*/ spiSelect(spip); spi_send_cmd_addr(devp, N25Q128_CMD_READ, addr); spiReceive(spip, n, rp); spiUnselect(spip); devp->state = FLASH_READY; - #if N25Q128_SHARED_SPI == TRUE spiReleaseBus(spip); #endif - return FLASH_NO_ERROR; } diff --git a/os/ex/Micron/n25q128.h b/os/ex/Micron/n25q128.h index bdc500463..b86cfefc7 100644 --- a/os/ex/Micron/n25q128.h +++ b/os/ex/Micron/n25q128.h @@ -67,6 +67,24 @@ #define N25Q128_CMD_PROGRAM_OTP_ARRAY 0x42 /** @} */ +/** + * @name Status register bits + * @{ + */ +#define N25Q128_STS_BUSY 0x80U +#define N25Q128_STS_ERASE_SUSPEND 0x40U +#define N25Q128_STS_ERASE_ERROR 0x20U +#define N25Q128_STS_PROGRAM_ERROR 0x10U +#define N25Q128_STS_VPP_ERROR 0x08U +#define N25Q128_STS_PROGRAM_SUSPEND 0x04U +#define N25Q128_STS_PROTECTION_ERROR 0x02U +#define N25Q128_STS_RESERVED 0x01U +#define N25Q128_STS_ALL_ERRORS (N25Q128_STS_ERASE_ERROR | \ + N25Q128_STS_PROGRAM_ERROR | \ + N25Q128_STS_VPP_ERROR | \ + N25Q128_STS_PROTECTION_ERROR) +/** @} */ + /*===========================================================================*/ /* Driver pre-compile time settings. */ /*===========================================================================*/ @@ -84,6 +102,18 @@ #if !defined(N25Q128_SHARED_SPI) || defined(__DOXYGEN__) #define N25Q128_SHARED_SPI TRUE #endif + +/** + * @brief Delays insertions. + * @details If enabled this options inserts delays into the flash waiting + * routines releasing some extra CPU time for the threads with + * lower priority, this may slow down the driver a bit however. + * This option is recommended also when the SPI driver does not + * use a DMA channel and heavily loads the CPU. + */ +#if !defined(N25Q128_NICE_WAITING) || defined(__DOXYGEN__) +#define N25Q128_NICE_WAITING TRUE +#endif /** @} */ /*===========================================================================*/ diff --git a/os/hal/lib/peripherals/flash/hal_flash.h b/os/hal/lib/peripherals/flash/hal_flash.h index 4c497e508..c3559a732 100644 --- a/os/hal/lib/peripherals/flash/hal_flash.h +++ b/os/hal/lib/peripherals/flash/hal_flash.h @@ -69,8 +69,10 @@ typedef enum { FLASH_PARAMETER_ERROR = 1, /* Error in a function parameter. */
FLASH_ADDRESS_ERROR = 2, /* Operation overlaps invalid addresses. */
FLASH_ECC_ERROR = 3, /* ECC error during read operation. */
- FLASH_VERIFY_FAILURE = 4, /* Write or erase operation failed. */
- FLASH_HW_FAILURE = 5 /* Controller or communication error. */
+ FLASH_PROGRAM_FAILURE = 4, /* Program operation failed. */
+ FLASH_ERASE_FAILURE = 5, /* Erase operation failed. */
+ FLASH_VERIFY_FAILURE = 6, /* Verify operation failed. */
+ FLASH_HW_FAILURE = 7 /* Controller or communication error. */
} flash_error_t;
/**
|