stm32: stm32_flash: add EEPROM writing for STM32L15XX

This commit is contained in:
Juha Niskanen 2017-04-04 07:34:24 -06:00 committed by Gregory Nutt
parent d64d4e02b4
commit 9a29b9a327
3 changed files with 399 additions and 48 deletions

View File

@ -59,16 +59,33 @@
#if defined(CONFIG_STM32_FLASH_CONFIG_DEFAULT)
# if defined(CONFIG_STM32_STM32L15XX)
# if defined(CONFIG_STM32_HIGHDENSITY)
/* The STM32 L15xx/L16xx can support up to 384KB of FLASH. (In reality, supported
* L15xx parts have no more than 128KB). The program memory block is divided into
* 96 sectors of 4 Kbytes each, and each sector is further split up into 16 pages of
* 256 bytes each. The sector is the write protection granularity. In total, the
/* Different STM32L1xxx MCU version are now called by different 'categories' instead
* of 'densities'. Cat.5 MCU can have up to 512KB of FLASH. STM32L1xxx also have
* data EEPROM, up to 16KB.
*/
# define STM32_FLASH_NPAGES 2048
# define STM32_FLASH_PAGESIZE 256
# else
/* The STM32 (< Cat.5) L15xx/L16xx can support up to 384KB of FLASH. (In reality, most
* supported L15xx parts have no more than 128KB). The program memory block is divided
* into 96 sectors of 4 Kbytes each, and each sector is further split up into 16 pages
* of 256 bytes each. The sector is the write protection granularity. In total, the
* program memory block contains 1536 pages.
*/
# define STM32_FLASH_NPAGES 1536
# define STM32_FLASH_PAGESIZE 256
# define STM32_FLASH_NPAGES 1536
# define STM32_FLASH_PAGESIZE 256
# endif
/* Maximum EEPROM size on Cat.5 MCU. TODO: this should be in chip config. */
# ifndef STM32_EEPROM_SIZE
# define STM32_EEPROM_SIZE (16 * 1024)
# endif
# elif defined(CONFIG_STM32_LOWDENSITY)
# define STM32_FLASH_NPAGES 32
@ -201,27 +218,40 @@
# elif defined(CONFIG_STM32_FLASH_CONFIG_I)
# endif
# endif
#endif
#endif /* !defined(CONFIG_STM32_FLASH_CONFIG_DEFAULT) */
#ifdef STM32_FLASH_PAGESIZE
# define STM32_FLASH_SIZE (STM32_FLASH_NPAGES * STM32_FLASH_PAGESIZE)
#endif /* def STM32_FLASH_PAGESIZE */
#endif
/* Register Offsets *****************************************************************/
#define STM32_FLASH_ACR_OFFSET 0x0000
#define STM32_FLASH_KEYR_OFFSET 0x0004
#define STM32_FLASH_OPTKEYR_OFFSET 0x0008
#define STM32_FLASH_SR_OFFSET 0x000c
#define STM32_FLASH_CR_OFFSET 0x0010
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F37XX)
# define STM32_FLASH_AR_OFFSET 0x0014
# define STM32_FLASH_OBR_OFFSET 0x001c
# define STM32_FLASH_WRPR_OFFSET 0x0020
#elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
# define STM32_FLASH_OPTCR_OFFSET 0x0014
#define STM32_FLASH_ACR_OFFSET 0x0000
#if defined(CONFIG_STM32_STM32L15XX)
# define STM32_FLASH_PECR_OFFSET 0x0004
# define STM32_FLASH_PDKEYR_OFFSET 0x0008
# define STM32_FLASH_PEKEYR_OFFSET 0x000c
# define STM32_FLASH_PRGKEYR_OFFSET 0x0010
# define STM32_FLASH_OPTKEYR_OFFSET 0x0014
# define STM32_FLASH_SR_OFFSET 0x0018
# define STM32_FLASH_OBR_OFFSET 0x001c
# define STM32_FLASH_WRPR1_OFFSET 0x0020
# define STM32_FLASH_WRPR2_OFFSET 0x0080
# define STM32_FLASH_WRPR3_OFFSET 0x0084
# define STM32_FLASH_WRPR4_OFFSET 0x0088
#else
# define STM32_FLASH_KEYR_OFFSET 0x0004
# define STM32_FLASH_OPTKEYR_OFFSET 0x0008
# define STM32_FLASH_SR_OFFSET 0x000c
# define STM32_FLASH_CR_OFFSET 0x0010
# if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F37XX)
# define STM32_FLASH_AR_OFFSET 0x0014
# define STM32_FLASH_OBR_OFFSET 0x001c
# define STM32_FLASH_WRPR_OFFSET 0x0020
# elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
# define STM32_FLASH_OPTCR_OFFSET 0x0014
# endif
#endif
#if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429)
@ -230,22 +260,36 @@
/* Register Addresses ***************************************************************/
#define STM32_FLASH_ACR (STM32_FLASHIF_BASE+STM32_FLASH_ACR_OFFSET)
#define STM32_FLASH_KEYR (STM32_FLASHIF_BASE+STM32_FLASH_KEYR_OFFSET)
#define STM32_FLASH_OPTKEYR (STM32_FLASHIF_BASE+STM32_FLASH_OPTKEYR_OFFSET)
#define STM32_FLASH_SR (STM32_FLASHIF_BASE+STM32_FLASH_SR_OFFSET)
#define STM32_FLASH_CR (STM32_FLASHIF_BASE+STM32_FLASH_CR_OFFSET)
#define STM32_FLASH_ACR (STM32_FLASHIF_BASE+STM32_FLASH_ACR_OFFSET)
#if defined(CONFIG_STM32_STM32L15XX)
# define STM32_FLASH_PECR (STM32_FLASHIF_BASE+STM32_FLASH_PECR_OFFSET)
# define STM32_FLASH_PDKEYR (STM32_FLASHIF_BASE+STM32_FLASH_PDKEYR_OFFSET)
# define STM32_FLASH_PEKEYR (STM32_FLASHIF_BASE+STM32_FLASH_PEKEYR_OFFSET)
# define STM32_FLASH_PRGKEYR (STM32_FLASHIF_BASE+STM32_FLASH_PRGKEYR_OFFSET)
# define STM32_FLASH_OPTKEYR (STM32_FLASHIF_BASE+STM32_FLASH_OPTKEYR_OFFSET)
# define STM32_FLASH_SR (STM32_FLASHIF_BASE+STM32_FLASH_SR_OFFSET)
# define STM32_FLASH_OBR (STM32_FLASHIF_BASE+STM32_FLASH_OBR_OFFSET)
# define STM32_FLASH_WRPR1 (STM32_FLASHIF_BASE+STM32_FLASH_WRPR1_OFFSET)
# define STM32_FLASH_WRPR2 (STM32_FLASHIF_BASE+STM32_FLASH_WRPR2_OFFSET)
# define STM32_FLASH_WRPR3 (STM32_FLASHIF_BASE+STM32_FLASH_WRPR3_OFFSET)
# define STM32_FLASH_WRPR4 (STM32_FLASHIF_BASE+STM32_FLASH_WRPR4_OFFSET)
#else
# define STM32_FLASH_KEYR (STM32_FLASHIF_BASE+STM32_FLASH_KEYR_OFFSET)
# define STM32_FLASH_OPTKEYR (STM32_FLASHIF_BASE+STM32_FLASH_OPTKEYR_OFFSET)
# define STM32_FLASH_SR (STM32_FLASHIF_BASE+STM32_FLASH_SR_OFFSET)
# define STM32_FLASH_CR (STM32_FLASHIF_BASE+STM32_FLASH_CR_OFFSET)
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F37XX)
# define STM32_FLASH_AR (STM32_FLASHIF_BASE+STM32_FLASH_AR_OFFSET)
# define STM32_FLASH_OBR (STM32_FLASHIF_BASE+STM32_FLASH_OBR_OFFSET)
# define STM32_FLASH_WRPR (STM32_FLASHIF_BASE+STM32_FLASH_WRPR_OFFSET)
#elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
# define STM32_FLASH_OPTCR (STM32_FLASHIF_BASE+STM32_FLASH_OPTCR_OFFSET)
#endif
#if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429)
# define STM32_FLASH_OPTCR1 (STM32_FLASHIF_BASE+STM32_FLASH_OPTCR1_OFFSET)
# if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
defined(CONFIG_STM32_STM32F33XX) || defined(CONFIG_STM32_STM32F37XX)
# define STM32_FLASH_AR (STM32_FLASHIF_BASE+STM32_FLASH_AR_OFFSET)
# define STM32_FLASH_OBR (STM32_FLASHIF_BASE+STM32_FLASH_OBR_OFFSET)
# define STM32_FLASH_WRPR (STM32_FLASHIF_BASE+STM32_FLASH_WRPR_OFFSET)
# elif defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX)
# define STM32_FLASH_OPTCR (STM32_FLASHIF_BASE+STM32_FLASH_OPTCR_OFFSET)
# endif
# if defined(CONFIG_STM32_STM32F427) || defined(CONFIG_STM32_STM32F429)
# define STM32_FLASH_OPTCR1 (STM32_FLASHIF_BASE+STM32_FLASH_OPTCR1_OFFSET)
# endif
#endif
/* Register Bitfield Definitions ****************************************************/
@ -303,6 +347,34 @@
# define FLASH_SR_PGPERR (1 << 6) /* Bit 6: Programming parallelism error */
# define FLASH_SR_PGSERR (1 << 7) /* Bit 7: Programming sequence error */
# define FLASH_SR_BSY (1 << 16) /* Bit 16: Busy */
#elif defined(CONFIG_STM32_STM32L15XX)
# define FLASH_SR_BSY (1 << 0) /* Bit 0: Busy */
# define FLASH_SR_EOP (1 << 1) /* Bit 1: End of operation */
# define FLASH_SR_ENDHV (1 << 2) /* Bit 2: End of high voltage */
# define FLASH_SR_READY (1 << 3) /* Bit 3: Flash memory module ready after low power mode */
# define FLASH_SR_WRPERR (1 << 8) /* Bit 8: Write protection error */
# define FLASH_SR_PGAERR (1 << 9) /* Bit 9: Programming alignment error */
# define FLASH_SR_SIZERR (1 << 10) /* Bit 10: Size error */
# define FLASH_SR_OPTVERR (1 << 11) /* Bit 11: Option validity error */
# define FLASH_SR_OPTVERRUSR (1 << 12) /* Bit 12: Option UserValidity Error */
# define FLASH_SR_RDERR (1 << 13) /* Bit 13: Read protected error */
#endif
/* Program/Erase Control Register (PECR) */
#if defined(CONFIG_STM32_STM32L15XX)
# define FLASH_PECR_PELOCK (1 << 0) /* Bit 0: PECR and data EEPROM lock */
# define FLASH_PECR_PRGLOCK (1 << 1) /* Bit 1: Program memory lock */
# define FLASH_PECR_OPTLOCK (1 << 2) /* Bit 2: Option bytes block lock */
# define FLASH_PECR_PROG (1 << 3) /* Bit 3: Program memory selection */
# define FLASH_PECR_DATA (1 << 4) /* Bit 4: Data EEPROM selection */
# define FLASH_PECR_FTDW (1 << 8) /* Bit 8: Fixed time data write for Byte, Half Word and Word programming */
# define FLASH_PECR_ERASE (1 << 9) /* Bit 9: Page or Double Word erase mode */
# define FLASH_PECR_FPRG (1 << 10) /* Bit 10: Half Page/Double Word programming mode */
# define FLASH_PECR_PARALLBANK (1 << 15) /* Bit 15: Parallel bank mode */
# define FLASH_PECR_EOPIE (1 << 16) /* Bit 16: End of programming interrupt enable */
# define FLASH_PECR_ERRIE (1 << 17) /* Bit 17: Error interrupt enable */
# define FLASH_PECR_OBL_LAUNCH (1 << 18) /* Bit 18: Launch the option byte loading */
#endif
/* Flash Control Register (CR) */
@ -380,7 +452,6 @@
# define FLASH_OPTCR1_BFB2_SHIFT (4) /* Bits 4: Dual-bank Boot option byte */
# define FLASH_OPTCR1_BFB2_MASK (1 << FLASH_OPTCR_NWRP_SHIFT)
#endif
#if defined(CONFIG_STM32_STM32F446)

View File

@ -59,10 +59,10 @@
#include "up_arch.h"
/* Only for the STM32F[1|3|4]0xx family for now */
/* Only for the STM32F[1|3|4]0xx family and STM32L15xx (EEPROM only) for now */
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
defined (CONFIG_STM32_STM32F40XX)
defined (CONFIG_STM32_STM32F40XX) || defined(CONFIG_STM32_STM32L15XX)
#if defined(CONFIG_STM32_FLASH_CONFIG_DEFAULT) && \
(defined(CONFIG_STM32_STM32F20XX) || defined(CONFIG_STM32_STM32F40XX))
@ -73,15 +73,25 @@
* Pre-processor Definitions
************************************************************************************/
#define FLASH_KEY1 0x45670123
#define FLASH_KEY2 0xCDEF89AB
#if defined(CONFIG_STM32_STM32L15XX)
# define FLASH_KEY1 0x8C9DAEBF
# define FLASH_KEY2 0x13141516
#else
# define FLASH_KEY1 0x45670123
# define FLASH_KEY2 0xCDEF89AB
#endif
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX)
#define FLASH_CR_PAGE_ERASE FLASH_CR_PER
#define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPRT_ERR
# define FLASH_CR_PAGE_ERASE FLASH_CR_PER
# define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPRT_ERR
#elif defined(CONFIG_STM32_STM32F40XX)
#define FLASH_CR_PAGE_ERASE FLASH_CR_SER
#define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPERR
# define FLASH_CR_PAGE_ERASE FLASH_CR_SER
# define FLASH_SR_WRITE_PROTECTION_ERROR FLASH_SR_WRPERR
#endif
#if defined(CONFIG_STM32_STM32L15XX)
# define EEPROM_KEY1 0x89ABCDEF
# define EEPROM_KEY2 0x02030405
#endif
/************************************************************************************
@ -107,6 +117,8 @@ static inline void sem_unlock(void)
sem_post(&g_sem);
}
#if !defined(CONFIG_STM32_STM32L15XX)
static void flash_unlock(void)
{
while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY)
@ -128,6 +140,8 @@ static void flash_lock(void)
modifyreg32(STM32_FLASH_CR, 0, FLASH_CR_LOCK);
}
#endif /* !defined(CONFIG_STM32_STM32L15XX) */
#if defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW)
static void data_cache_disable(void)
{
@ -146,6 +160,183 @@ static void data_cache_enable(void)
}
#endif /* defined(CONFIG_STM32_FLASH_WORKAROUND_DATA_CACHE_CORRUPTION_ON_RWW) */
#if defined(CONFIG_STM32_STM32L15XX)
static void stm32_eeprom_unlock(void)
{
while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY)
{
up_waste();
}
if (getreg32(STM32_FLASH_PECR) & FLASH_PECR_PELOCK)
{
/* Unlock sequence */
putreg32(EEPROM_KEY1, STM32_FLASH_PEKEYR);
putreg32(EEPROM_KEY2, STM32_FLASH_PEKEYR);
}
}
static void stm32_eeprom_lock(void)
{
modifyreg32(STM32_FLASH_PECR, 0, FLASH_PECR_PELOCK);
}
static void flash_unlock(void)
{
if (getreg32(STM32_FLASH_PECR) & FLASH_PECR_PRGLOCK)
{
stm32_eeprom_unlock();
/* Unlock sequence */
putreg32(FLASH_KEY1, STM32_FLASH_PRGKEYR);
putreg32(FLASH_KEY2, STM32_FLASH_PRGKEYR);
}
}
static void flash_lock(void)
{
modifyreg32(STM32_FLASH_PECR, 0, FLASH_PECR_PRGLOCK);
stm32_eeprom_lock();
}
static ssize_t stm32_eeprom_erase_write(size_t addr, const void *buf,
size_t buflen)
{
const char *cbuf = buf;
size_t i;
if (buflen == 0)
{
return 0;
}
/* Check for valid address range */
if (addr >= STM32_EEPROM_BASE)
{
addr -= STM32_EEPROM_BASE;
}
if (addr >= STM32_EEPROM_SIZE)
{
return -EINVAL;
}
/* TODO: Voltage range must be range 1 or 2. Erase/program not allowed in
* range 3.
*/
stm32_eeprom_unlock();
/* Clear pending status flags. */
putreg32(FLASH_SR_WRPERR | FLASH_SR_PGAERR |
FLASH_SR_SIZERR | FLASH_SR_OPTVERR |
FLASH_SR_OPTVERRUSR | FLASH_SR_RDERR, STM32_FLASH_SR);
/* Enable automatic erasing (by disabling 'fixed time' programming). */
modifyreg32(STM32_FLASH_PECR, FLASH_PECR_FTDW, 0);
/* Write buffer to EEPROM data memory. */
addr += STM32_EEPROM_BASE;
i = 0;
while (i < buflen)
{
uint32_t writeval;
size_t left = buflen - i;
if ((addr & 0x03) == 0x00 && left >= 4)
{
/* Read/erase/write word */
writeval = cbuf ? *(uint32_t *)cbuf : 0;
putreg32(writeval, addr);
}
else if ((addr & 0x01) == 0x00 && left >= 2)
{
/* Read/erase/write half-word */
writeval = cbuf ? *(uint16_t *)cbuf : 0;
putreg16(writeval, addr);
}
else
{
/* Read/erase/write byte */
writeval = cbuf ? *(uint8_t *)cbuf : 0;
putreg8(writeval, addr);
}
/* ... and wait to complete. */
while (getreg32(STM32_FLASH_SR) & FLASH_SR_BSY)
{
up_waste();
}
/* Verify */
/* We do not check Options Byte invalid flags FLASH_SR_OPTVERR
* and FLASH_SR_OPTVERRUSR for EEPROM erase/write. They are unrelated
* and STM32L standard library does not check for these either.
*/
if (getreg32(STM32_FLASH_SR) & (FLASH_SR_WRPERR | FLASH_SR_PGAERR |
FLASH_SR_SIZERR | FLASH_SR_RDERR))
{
stm32_eeprom_lock();
return -EROFS;
}
if ((addr & 0x03) == 0x00 && left >= 4)
{
if (getreg32(addr) != writeval)
{
stm32_eeprom_lock();
return -EIO;
}
addr += 4;
i += 4;
cbuf += !!(cbuf) * 4;
}
else if ((addr & 0x01) == 0x00 && left >= 2)
{
if (getreg16(addr) != writeval)
{
stm32_eeprom_lock();
return -EIO;
}
addr += 2;
i += 2;
cbuf += !!(cbuf) * 2;
}
else
{
if (getreg8(addr) != writeval)
{
stm32_eeprom_lock();
return -EIO;
}
addr += 1;
i += 1;
cbuf += !!(cbuf) * 1;
}
}
stm32_eeprom_lock();
return buflen;
}
#endif /* defined(CONFIG_STM32_STM32L15XX) */
/************************************************************************************
* Public Functions
************************************************************************************/
@ -164,6 +355,35 @@ void stm32_flash_lock(void)
sem_unlock();
}
#if defined(CONFIG_STM32_STM32L15XX)
size_t stm32_eeprom_size(void)
{
return STM32_EEPROM_SIZE;
}
size_t stm32_eeprom_getaddress(void)
{
return STM32_EEPROM_BASE;
}
ssize_t stm32_eeprom_write(size_t addr, const void *buf, size_t buflen)
{
if (!buf)
{
return -EINVAL;
}
return stm32_eeprom_erase_write(addr, buf, buflen);
}
ssize_t stm32_eeprom_erase(size_t addr, size_t eraselen)
{
return stm32_eeprom_erase_write(addr, NULL, eraselen);
}
#endif /* defined(CONFIG_STM32_STM32L15XX) */
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX)
size_t up_progmem_pagesize(size_t page)
{
@ -260,6 +480,8 @@ size_t up_progmem_getaddress(size_t page)
#endif /* def CONFIG_STM32_STM32F40XX */
#if !defined(CONFIG_STM32_STM32L15XX)
size_t up_progmem_npages(void)
{
return STM32_FLASH_NPAGES;
@ -271,14 +493,14 @@ bool up_progmem_isuniform(void)
return true;
#else
return false;
#endif /* def STM32_FLASH_PAGESIZE */
#endif
}
ssize_t up_progmem_erasepage(size_t page)
{
#if defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX)
size_t page_address;
#endif /* defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) */
#endif
if (page >= STM32_FLASH_NPAGES)
{
@ -438,5 +660,7 @@ ssize_t up_progmem_write(size_t addr, const void *buf, size_t count)
return written;
}
#endif /* !defined(CONFIG_STM32_STM32L15XX) */
#endif /* defined(CONFIG_STM32_STM32F10XX) || defined(CONFIG_STM32_STM32F30XX) || \
defined (CONFIG_STM32_STM32F40XX) */
defined(CONFIG_STM32_STM32F40XX) || defined(CONFIG_STM32_STM32L15XX) */

View File

@ -46,4 +46,60 @@
#include "chip.h"
#include "chip/stm32_flash.h"
/************************************************************************************
* Public Function Prototypes
************************************************************************************/
/************************************************************************************
* Name: stm32_eeprom_size
*
* Description:
* Get EEPROM data memory size
*
* Returns:
* Length of EEPROM memory region
*
************************************************************************************/
size_t stm32_eeprom_size(void);
/************************************************************************************
* Name: stm32_eeprom_getaddress
*
* Description:
* Get EEPROM data memory address
*
* Returns:
* Address of EEPROM memory region
*
************************************************************************************/
size_t stm32_eeprom_getaddress(void);
/************************************************************************************
* Name: stm32_eeprom_write
*
* Description:
* Write buffer to EEPROM data memory address
*
* Returns:
* Number of written bytes or error code.
*
************************************************************************************/
ssize_t stm32_eeprom_write(size_t addr, const void *buf, size_t buflen);
/************************************************************************************
* Name: stm32_eeprom_erase
*
* Description:
* Erase memory on EEPROM data memory address
*
* Returns:
* Number of erased bytes or error code.
*
************************************************************************************/
ssize_t stm32_eeprom_erase(size_t addr, size_t eraselen);
#endif /* __ARCH_ARM_SRC_STM32_STM32_FLASH_H */