stm32wl5: add support for internal FLASH
This patch adds corrected implementation of FLASH memory to be used with progmem driver for use with mtd filesystems like nxffs or smartfs. Signed-off-by: Michał Łyszczek <michal.lyszczek@bofc.pl>
This commit is contained in:
parent
845e259ac7
commit
5490f8964f
@ -40,6 +40,7 @@ RCC Yes All registers defined, not all peripherals enabled
|
||||
SYSCFG Yes All registers defined, GPIO EXTI works, remapping not tested
|
||||
USART Yes
|
||||
LPUART Yes full speed with HSE works, low power mode with LSE not implemented
|
||||
FLASH Yes Progmem imlementation - mtd filesystems like smartfs or nxffs work
|
||||
DMA No
|
||||
SRAM2 No
|
||||
SPI No
|
||||
@ -133,6 +134,15 @@ interrupt first goes through EXTI and is then forwarded to main NVIC.
|
||||
|
||||
EXTI for gpio can be enabled via `stm32wl5_gpiosetevent` function.
|
||||
|
||||
FLASH
|
||||
-----
|
||||
|
||||
Place where program code lives. Part of flash can also be used to create
|
||||
small filesystems like nxffs or smartfs to hold persistant data between
|
||||
reboots without the need of attaching external flash or mmc card. Since
|
||||
flash has limited number of erases (writes) it's best to hold there only
|
||||
data that is no frequently updated (so, configuration is ok, logs are not).
|
||||
|
||||
Supported Boards
|
||||
================
|
||||
|
||||
|
@ -45,8 +45,6 @@
|
||||
* STM32WL5xxx has only single bank flash and page size 2KiB
|
||||
*/
|
||||
|
||||
#define _K(x) ((x)*1024)
|
||||
|
||||
#if !defined(CONFIG_STM32WL5_FLASH_OVERRIDE_DEFAULT) && \
|
||||
!defined(CONFIG_STM32WL5_FLASH_OVERRIDE_8) && \
|
||||
!defined(CONFIG_STM32WL5_FLASH_OVERRIDE_B) && \
|
||||
@ -207,7 +205,7 @@
|
||||
|
||||
#define FLASH_CR_START (1 << 16) /* Bit 16: Start Erase */
|
||||
#define FLASH_CR_OPTSTRT (1 << 17) /* Bit 17: Options modification Start */
|
||||
#define FLASH_CR_FSTPG (1 << 23) /* Bit 23: Fast programming */
|
||||
#define FLASH_CR_FSTPG (1 << 18) /* Bit 18: Fast programming */
|
||||
#define FLASH_CR_EOPIE (1 << 24) /* Bit 24: End of operation interrupt enable */
|
||||
#define FLASH_CR_ERRIE (1 << 25) /* Bit 25: Error interrupt enable */
|
||||
#define FLASH_CR_RDERRIE (1 << 26) /* Bit 26: PCROP read error interrupt enable */
|
||||
@ -217,8 +215,8 @@
|
||||
|
||||
/* Flash ECC Register (ECCR) */
|
||||
|
||||
#define FLASH_ECCR_ADDR_ECC_SHIFT (0) /* Bits 0-15: Read protect */
|
||||
# define FLASH_ECCR_ADDR_ECC_MASK (0xffff << FLASH_ECCR_ADDR_ECC_SHIFT)
|
||||
#define FLASH_ECCR_ADDR_ECC_SHIFT (0) /* Bits 0-16: ECC fail address */
|
||||
# define FLASH_ECCR_ADDR_ECC_MASK (0x1ffff << FLASH_ECCR_ADDR_ECC_SHIFT)
|
||||
#define FLASH_ECCR_SYSF_ECC (1 << 20) /* Bit 20: System Flash ECC fail */
|
||||
#define FLASH_ECCR_ECCCIE (1 << 24) /* Bit 24: ECC correction interrupt enable */
|
||||
#define FLASH_ECCR_CPUID_SHIFT (26)
|
||||
|
@ -34,17 +34,17 @@
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/progmem.h>
|
||||
#include <nuttx/semaphore.h>
|
||||
|
||||
#include <semaphore.h>
|
||||
#include <assert.h>
|
||||
#include <debug.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "stm32wl5_rcc.h"
|
||||
#include "stm32wl5_waste.h"
|
||||
#include "stm32wl5_flash.h"
|
||||
|
||||
#include "arm_internal.h"
|
||||
|
||||
#if !defined(CONFIG_STM32WL5_FLASH_OVERRIDE_DEFAULT)
|
||||
@ -57,6 +57,7 @@
|
||||
|
||||
#define FLASH_KEY1 0x45670123
|
||||
#define FLASH_KEY2 0xCDEF89AB
|
||||
#define FLASH_ERASEDVALUE 0xffu
|
||||
|
||||
#define OPTBYTES_KEY1 0x08192A3B
|
||||
#define OPTBYTES_KEY2 0x4C5D6E7F
|
||||
@ -64,15 +65,7 @@
|
||||
#define FLASH_PAGE_SIZE STM32WL5_FLASH_PAGESIZE
|
||||
#define FLASH_PAGE_WORDS (FLASH_PAGE_SIZE / 4)
|
||||
#define FLASH_PAGE_MASK (FLASH_PAGE_SIZE - 1)
|
||||
#if FLASH_PAGE_SIZE == 2048
|
||||
# define FLASH_PAGE_SHIFT (11) /* 2**11 = 2048B */
|
||||
#elif FLASH_PAGE_SIZE == 4096
|
||||
# define FLASH_PAGE_SHIFT (12) /* 2**12 = 4096B */
|
||||
#elif FLASH_PAGE_SIZE == 8192
|
||||
# define FLASH_PAGE_SHIFT (13) /* 2**13 = 8192B */
|
||||
#else
|
||||
# error Unsupported STM32WL5_FLASH_PAGESIZE
|
||||
#endif
|
||||
#define FLASH_PAGE_SHIFT (11) /* 2**11 = 2048B */
|
||||
#define FLASH_BYTE2PAGE(o) ((o) >> FLASH_PAGE_SHIFT)
|
||||
|
||||
#define FLASH_CR_PAGE_ERASE FLASH_CR_PER
|
||||
@ -99,23 +92,9 @@ static uint32_t g_page_buffer[FLASH_PAGE_WORDS];
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
static inline void sem_lock(void)
|
||||
static inline int sem_lock(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
/* Take the semaphore (perhaps waiting) */
|
||||
|
||||
ret = nxsem_wait(&g_sem);
|
||||
|
||||
/* The only case that an error should occur here is if the wait was
|
||||
* awakened by a signal.
|
||||
*/
|
||||
|
||||
DEBUGASSERT(ret == OK || ret == -EINTR);
|
||||
}
|
||||
while (ret == -EINTR);
|
||||
return nxsem_wait_uninterruptible(&g_sem);
|
||||
}
|
||||
|
||||
static inline void sem_unlock(void)
|
||||
@ -168,10 +147,11 @@ static inline void flash_optbytes_lock(void)
|
||||
|
||||
static inline void flash_erase(size_t page)
|
||||
{
|
||||
finfo("erase page %u\n", page);
|
||||
finfo("erase page %u\n", (unsigned int)page);
|
||||
|
||||
modifyreg32(STM32WL5_FLASH_CR, 0, FLASH_CR_PAGE_ERASE);
|
||||
modifyreg32(STM32WL5_FLASH_CR, FLASH_CR_PNB_MASK, FLASH_CR_PNB(page));
|
||||
modifyreg32(STM32WL5_FLASH_CR, FLASH_CR_PNB_MASK,
|
||||
FLASH_CR_PNB(page & 0xff));
|
||||
modifyreg32(STM32WL5_FLASH_CR, 0, FLASH_CR_START);
|
||||
|
||||
while (getreg32(STM32WL5_FLASH_SR) & FLASH_SR_BSY)
|
||||
@ -186,18 +166,36 @@ static inline void flash_erase(size_t page)
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
void stm32wl5_flash_unlock(void)
|
||||
int stm32wl5_flash_unlock(void)
|
||||
{
|
||||
sem_lock();
|
||||
int ret;
|
||||
|
||||
ret = sem_lock();
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
flash_unlock();
|
||||
sem_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void stm32wl5_flash_lock(void)
|
||||
int stm32wl5_flash_lock(void)
|
||||
{
|
||||
sem_lock();
|
||||
int ret;
|
||||
|
||||
ret = sem_lock();
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
flash_lock();
|
||||
sem_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@ -220,6 +218,7 @@ void stm32wl5_flash_lock(void)
|
||||
uint32_t stm32wl5_flash_user_optbytes(uint32_t clrbits, uint32_t setbits)
|
||||
{
|
||||
uint32_t regval;
|
||||
int ret;
|
||||
|
||||
/* To avoid accidents, do not allow setting RDP via this function.
|
||||
* Remove these asserts if want to enable changing the protection level.
|
||||
@ -229,19 +228,24 @@ uint32_t stm32wl5_flash_user_optbytes(uint32_t clrbits, uint32_t setbits)
|
||||
DEBUGASSERT((clrbits & FLASH_OPTR_RDP_MASK) == 0);
|
||||
DEBUGASSERT((setbits & FLASH_OPTR_RDP_MASK) == 0);
|
||||
|
||||
sem_lock();
|
||||
ret = sem_lock();
|
||||
if (ret < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
flash_optbytes_unlock();
|
||||
|
||||
/* Modify Option Bytes in register. */
|
||||
|
||||
regval = getreg32(STM32WL5_FLASH_OPTR);
|
||||
|
||||
finfo("Flash option bytes before: 0x%x\n", (unsigned)regval);
|
||||
finfo("Flash option bytes before: 0x%" PRIx32 "\n", regval);
|
||||
|
||||
regval = (regval & ~clrbits) | setbits;
|
||||
putreg32(regval, STM32WL5_FLASH_OPTR);
|
||||
|
||||
finfo("Flash option bytes after: 0x%x\n", (unsigned)regval);
|
||||
finfo("Flash option bytes after: 0x%" PRIx32 "\n", regval);
|
||||
|
||||
/* Start Option Bytes programming and wait for completion. */
|
||||
|
||||
@ -260,13 +264,11 @@ uint32_t stm32wl5_flash_user_optbytes(uint32_t clrbits, uint32_t setbits)
|
||||
|
||||
size_t up_progmem_pagesize(size_t page)
|
||||
{
|
||||
(void)page;
|
||||
return STM32WL5_FLASH_PAGESIZE;
|
||||
}
|
||||
|
||||
size_t up_progmem_erasesize(size_t block)
|
||||
{
|
||||
(void)block;
|
||||
return STM32WL5_FLASH_PAGESIZE;
|
||||
}
|
||||
|
||||
@ -305,33 +307,10 @@ bool up_progmem_isuniform(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t up_progmem_ispageerased(size_t page)
|
||||
{
|
||||
size_t addr;
|
||||
size_t count;
|
||||
size_t bwritten = 0;
|
||||
|
||||
if (page >= STM32WL5_FLASH_NPAGES)
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Verify */
|
||||
|
||||
for (addr = up_progmem_getaddress(page), count = up_progmem_pagesize(page);
|
||||
count; count--, addr++)
|
||||
{
|
||||
if (getreg8(addr) != 0xff)
|
||||
{
|
||||
bwritten++;
|
||||
}
|
||||
}
|
||||
|
||||
return bwritten;
|
||||
}
|
||||
|
||||
ssize_t up_progmem_eraseblock(size_t block)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (block >= STM32WL5_FLASH_NPAGES)
|
||||
{
|
||||
return -EFAULT;
|
||||
@ -339,7 +318,12 @@ ssize_t up_progmem_eraseblock(size_t block)
|
||||
|
||||
/* Erase single block */
|
||||
|
||||
sem_lock();
|
||||
ret = sem_lock();
|
||||
if (ret < 0)
|
||||
{
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
|
||||
flash_unlock();
|
||||
|
||||
flash_erase(block);
|
||||
@ -359,6 +343,31 @@ ssize_t up_progmem_eraseblock(size_t block)
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t up_progmem_ispageerased(size_t page)
|
||||
{
|
||||
size_t addr;
|
||||
size_t count;
|
||||
size_t bwritten = 0;
|
||||
|
||||
if (page >= STM32WL5_FLASH_NPAGES)
|
||||
{
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
/* Verify */
|
||||
|
||||
for (addr = up_progmem_getaddress(page), count = up_progmem_pagesize(page);
|
||||
count; count--, addr++)
|
||||
{
|
||||
if (getreg8(addr) != FLASH_ERASEDVALUE)
|
||||
{
|
||||
bwritten++;
|
||||
}
|
||||
}
|
||||
|
||||
return bwritten;
|
||||
}
|
||||
|
||||
ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
|
||||
{
|
||||
uint32_t *dest;
|
||||
@ -367,6 +376,7 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
|
||||
size_t xfrsize;
|
||||
size_t offset;
|
||||
size_t page;
|
||||
bool set_pg_bit = false;
|
||||
int i;
|
||||
int ret = OK;
|
||||
|
||||
@ -393,7 +403,11 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
|
||||
dest = (uint32_t *)((uint8_t *)addr - offset);
|
||||
written = 0;
|
||||
|
||||
sem_lock();
|
||||
ret = sem_lock();
|
||||
if (ret < 0)
|
||||
{
|
||||
return (ssize_t)ret;
|
||||
}
|
||||
|
||||
/* Get flash ready and begin flashing. */
|
||||
|
||||
@ -445,6 +459,7 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
|
||||
/* Write the page. Must be with double-words. */
|
||||
|
||||
modifyreg32(STM32WL5_FLASH_CR, 0, FLASH_CR_PG);
|
||||
set_pg_bit = true;
|
||||
|
||||
for (i = 0; i < FLASH_PAGE_WORDS; i += 2)
|
||||
{
|
||||
@ -460,7 +475,6 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
|
||||
|
||||
if (getreg32(STM32WL5_FLASH_SR) & FLASH_SR_WRITE_PROTECTION_ERROR)
|
||||
{
|
||||
modifyreg32(STM32WL5_FLASH_CR, FLASH_CR_PG, 0);
|
||||
ret = -EROFS;
|
||||
goto out;
|
||||
}
|
||||
@ -468,13 +482,13 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
|
||||
if (getreg32(dest - 1) != *(src - 1) ||
|
||||
getreg32(dest - 2) != *(src - 2))
|
||||
{
|
||||
modifyreg32(STM32WL5_FLASH_CR, FLASH_CR_PG, 0);
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
modifyreg32(STM32WL5_FLASH_CR, FLASH_CR_PG, 0);
|
||||
set_pg_bit = false;
|
||||
|
||||
/* Adjust pointers and counts for the next time through the loop */
|
||||
|
||||
@ -487,15 +501,20 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t buflen)
|
||||
}
|
||||
|
||||
out:
|
||||
/* If there was an error, clear all error flags in status
|
||||
* register (rc_w1 register so do this by writing the
|
||||
* error bits).
|
||||
if (set_pg_bit)
|
||||
{
|
||||
modifyreg32(STM32WL5_FLASH_CR, FLASH_CR_PG, 0);
|
||||
}
|
||||
|
||||
/* If there was an error, clear all error flags in status register (rc_w1
|
||||
* register so do this by writing the error bits).
|
||||
*/
|
||||
|
||||
if (ret != OK)
|
||||
{
|
||||
ferr("flash write error: %d, status: 0x%x\n", ret,
|
||||
(unsigned)getreg32(STM32WL5_FLASH_SR));
|
||||
ferr("flash write error: %d, status: 0x%" PRIx32 "\n",
|
||||
ret, getreg32(STM32WL5_FLASH_SR));
|
||||
|
||||
modifyreg32(STM32WL5_FLASH_SR, 0, FLASH_SR_ALLERRS);
|
||||
}
|
||||
|
||||
@ -503,3 +522,8 @@ out:
|
||||
sem_unlock();
|
||||
return (ret == OK) ? written : ret;
|
||||
}
|
||||
|
||||
uint8_t up_progmem_erasestate(void)
|
||||
{
|
||||
return FLASH_ERASEDVALUE;
|
||||
}
|
||||
|
@ -26,14 +26,16 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/config.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "hardware/stm32wl5_flash.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
* Public Functions Prototypes
|
||||
****************************************************************************/
|
||||
|
||||
void stm32wl5_flash_lock(void);
|
||||
void stm32wl5_flash_unlock(void);
|
||||
int stm32wl5_flash_lock(void);
|
||||
int stm32wl5_flash_unlock(void);
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32wl5_flash_user_optbytes
|
||||
|
Loading…
x
Reference in New Issue
Block a user