STM32 内部FLASH用作用户数据区Byte操作函数设计 (HAL)
说明
STM32内部的FLASH空间,主要用作代码存储空间。在IAP模式,分为boot和app两个区,boot区可以由JTAG/SWD和ISP方式写入,app区通过选定的接口接收数据后写入FLASH, 在这种模式下, app的首地址一般是FLASH的页对齐地址,无论是擦除还是写入,都没有之前的数据信息保护需要考虑。
当用户把一块(通常靠后)的FLASH空间,用作第三个区,作为数据区使用,则在擦除和写入时,需要对原有数据,本次不改写的部分,进行保护。
STM32内部FLASH只支持32位字地址写入,不支持字节和半字地址写入;而读操作不受限制,可以读取字节,半字和字地址数据。在把FLASH空间用作数据区时,操作灵活性上要求能够进行字节为单位的写入和读取,故基于下述规则设计了STM32内部FLASHByte操作函数。
规则
- 如果写入的首页和尾页数据,不是一整页,则需要把原有页内数据读出,再和要写入的数据组合后,作为整理后的一整页数据写入。
- 中间的页面,是整页数据,可以直接擦除后覆盖写入。
- 最终实现从1个byte到任意byte(在一个页内或跨多个页)的写入读取,不影响其它地址的数据。
STM32内部FLASH WORD读写函数
以STM32L0为例,先了解下WORD的读写函数, FLASH写入前需要进行解锁和页擦除:
HAL库STM32L0xx_hal_flash.h里有Flash空间和页面空间的定义:
#define FLASH_SIZE (uint32_t)((*((uint32_t *)FLASHSIZE_BASE)&0xFFFF) * 1024U)
#define FLASH_PAGE_SIZE ((uint32_t)128U) /*!< FLASH Page Size in bytes */
字操作的读函数可如下编写:
//Word read
HAL_StatusTypeDef FLASH_READ_WORD(uint32_t addr, uint32_t *data, uint32_t Size)
{
uint32_t d32;
for(uint32_t i = 0;i< Size ;i++)
{
d32 = *(__IO uint32_t*)(addr + i * 4);
*(data+i * 4) = d32;
}
return HAL_OK;
}
字操作的写函数可如下编写:
//Word write
HAL_StatusTypeDef FLASH_WRITE_WORD(uint32_t addr, uint32_t *data, uint32_t Size)
{
uint8_t HAL_STATUS = 0;
uint32_t PageError = 0;
HAL_FLASH_Unlock(); //unlock
FLASH_EraseInitTypeDef fe;
fe.TypeErase = FLASH_TYPEERASE_PAGES;
fe.PageAddress = addr;
fe.NbPages = 1;
HAL_FLASHEx_Erase(&fe, &PageError); //Erase page
uint32_t d32 = 0;
for(uint32_t i = 0;i< Size ;i++)
{
d32 = (*(data+i*4));
HAL_STATUS += HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD , addr + i * 4, d32);
}
HAL_FLASH_Lock();
if (HAL_STATUS==0) return HAL_OK;
else return HAL_ERROR;
}
STM32内部FLASH BYTE读函数
字节读函数可编写如下,相对比较容易:
//Byte read
HAL_StatusTypeDef FLASH_READ_BYTE(uint32_t addr, uint8_t *data, uint32_t Size)
{
uint8_t d8;
for(uint32_t i = 0;i< Size ;i++)
{
d8 = *(__IO uint8_t*)(addr + i);
*(data+i) = d8;
}
return HAL_OK;
}
STM32内部FLASH BYTE写函数
字节写函数的设计分为3种页面情况,只在1页写,只在2页写和超过2页写。具体的函数设计如下:
//Byte write:written by Pegasus Yu 2019/01/09
HAL_StatusTypeDef FLASH_WRITE_BYTE(uint32_t addr, uint8_t *data, uint32_t Size)
{
HAL_StatusTypeDef HAL_STATUS = HAL_ERROR;
uint32_t PageError = 0;
extern FLASH_ProcessTypeDef pFlash;
uint32_t pstart = 0; //address number in first page
uint32_t pn = 0; //total page number
uint32_t pstop = 0; //address number in last page
uint8_t fpage[FLASH_PAGE_SIZE] = {0};
uint8_t lpage[FLASH_PAGE_SIZE] = {0};
uint32_t icount;
uint32_t d32;
assert_param(IS_FLASH_PROGRAM_ADDRESS(addr));// Check the parameters
if (Size>(FLASH_PAGE_SIZE-(addr%FLASH_PAGE_SIZE)))
{
pstart =(FLASH_PAGE_SIZE-(addr%FLASH_PAGE_SIZE));
pn = (Size-((pstart==FLASH_PAGE_SIZE)?FLASH_PAGE_SIZE:pstart))/FLASH_PAGE_SIZE + ((((Size-((pstart==FLASH_PAGE_SIZE)?FLASH_PAGE_SIZE:pstart))%FLASH_PAGE_SIZE)==0)?0:1) + 1; //total page number
pstop = Size-pstart-(pn-2)*FLASH_PAGE_SIZE; //address number in last page
}
else
{
pn = 1;
pstart = Size;
pstop = Size;
}
HAL_FLASH_Unlock(); //unlock
if (pn==1)
{
for (icount = 0; icount<FLASH_PAGE_SIZE; icount++)
{
fpage[icount]=*((uint8_t *)((addr/FLASH_PAGE_SIZE)*FLASH_PAGE_SIZE+icount));
}
for (icount = 0; icount< pstart; icount++)
{
fpage[(addr%FLASH_PAGE_SIZE) + icount]= *(data+icount);
}
FLASH_EraseInitTypeDef fe;
fe.TypeErase = FLASH_TYPEERASE_PAGES;
fe.PageAddress = addr;
fe.NbPages = 1;
HAL_FLASHEx_Erase(&fe, &PageError); //Erase page
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
__HAL_LOCK(&pFlash); // Process Locked
for (icount = 0; icount< (FLASH_PAGE_SIZE/4); icount++)
{
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE; // Clean the error context
*(uint32_t *)((addr/FLASH_PAGE_SIZE)*FLASH_PAGE_SIZE+icount*4) = *(uint32_t *)(fpage+icount*4);
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
}
__HAL_UNLOCK(&pFlash); /* Process Unlocked */
HAL_FLASH_Lock();
}
else if (pn==2)
{
for (icount = 0; icount<FLASH_PAGE_SIZE; icount++)
{
fpage[icount]=*((uint8_t *)((addr/FLASH_PAGE_SIZE)*FLASH_PAGE_SIZE+icount));
}
for (icount = 0; icount< pstart; icount++)
{
fpage[(addr%FLASH_PAGE_SIZE) + icount]= *(data+icount);
}
for (icount = 0; icount<FLASH_PAGE_SIZE; icount++)
{
lpage[icount]=*((uint8_t *)((addr/FLASH_PAGE_SIZE+1)*FLASH_PAGE_SIZE+icount));
}
for (icount = 0; icount< pstop; icount++)
{
lpage[icount]= *(data+(FLASH_PAGE_SIZE-(addr%FLASH_PAGE_SIZE))+icount);
}
FLASH_EraseInitTypeDef fe;
fe.TypeErase = FLASH_TYPEERASE_PAGES;
fe.PageAddress = addr;
fe.NbPages = 2;
HAL_FLASHEx_Erase(&fe, &PageError); //Erase page
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE*2);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
__HAL_LOCK(&pFlash); // Process Locked
for (icount = 0; icount< (FLASH_PAGE_SIZE/4); icount++)
{
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE; // Clean the error context
*(uint32_t *)((addr/FLASH_PAGE_SIZE)*FLASH_PAGE_SIZE+icount*4) = *(uint32_t *)(fpage+icount*4);
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
}
for (icount = 0; icount< (FLASH_PAGE_SIZE/4); icount++)
{
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
*(uint32_t *)((addr/FLASH_PAGE_SIZE+1)*FLASH_PAGE_SIZE+icount*4) = *(uint32_t *)(lpage+icount*4);
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
}
__HAL_UNLOCK(&pFlash); /* Process Unlocked */
HAL_FLASH_Lock();
}
else
{
if (pstart != FLASH_PAGE_SIZE)
{
for (icount = 0; icount<FLASH_PAGE_SIZE; icount++)
{
fpage[icount]=*((uint8_t *)((addr/FLASH_PAGE_SIZE)*FLASH_PAGE_SIZE+icount));
}
for (icount = 0; icount< pstart; icount++)
{
fpage[(addr%FLASH_PAGE_SIZE) + icount]= *(data+icount);
}
}
if (pstop != FLASH_PAGE_SIZE)
{
for (icount = 0; icount<FLASH_PAGE_SIZE; icount++)
{
lpage[icount]=*((uint8_t *)((addr/FLASH_PAGE_SIZE+pn-1)*FLASH_PAGE_SIZE+icount));
}
for (icount = 0; icount< pstop; icount++)
{
lpage[icount]= *(data+(Size-pstop)+icount);
}
}
FLASH_EraseInitTypeDef fe;
fe.TypeErase = FLASH_TYPEERASE_PAGES;
fe.PageAddress = addr;
fe.NbPages = pn;
HAL_FLASHEx_Erase(&fe, &PageError); //Erase page
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE*pn);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
__HAL_LOCK(&pFlash); // Process Locked
if (pstart!=FLASH_PAGE_SIZE)
{
for (icount = 0; icount< (FLASH_PAGE_SIZE/4); icount++)
{
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE; // Clean the error context
*(uint32_t *)((addr/FLASH_PAGE_SIZE)*FLASH_PAGE_SIZE+icount*4) = *(uint32_t *)(fpage+icount*4);
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
}
}
else
{
for (icount = 0; icount< (FLASH_PAGE_SIZE/4); icount++)
{
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE; // Clean the error context
d32 = (*(data+icount*4)) + ((*(data+icount*4+1))<<8) + ((*(data+icount*4+2))<<16) + ((*(data+icount*4+3))<<24);
*(uint32_t *)((addr/FLASH_PAGE_SIZE)*FLASH_PAGE_SIZE+icount*4) = *(uint32_t *)(data+icount*4);
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
}
}
for (icount = 0; icount < (pn-2)*(FLASH_PAGE_SIZE/4); icount++)
{
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
d32 = (*(data+pstart+icount*4)) + ((*(data+pstart+icount*4+1))<<8) + ((*(data+pstart+icount*4+2))<<16) + ((*(data+pstart+icount*4+3))<<24);
*(uint32_t *)((addr+pstart)+icount*4) = d32;
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
}
if (pstop != FLASH_PAGE_SIZE)
{
for (icount = 0; icount< (FLASH_PAGE_SIZE/4); icount++)
{
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
*(uint32_t *)((addr/FLASH_PAGE_SIZE+pn-1)*FLASH_PAGE_SIZE+icount*4) = *(uint32_t *)(lpage+icount*4);
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
}
}
else
{
for (icount = 0; icount< (FLASH_PAGE_SIZE/4); icount++)
{
pFlash.ErrorCode = HAL_FLASH_ERROR_NONE;
d32 = (*(data+(Size-pstop)+icount*4)) + ((*(data+(Size-pstop)+icount*4+1))<<8) + ((*(data+(Size-pstop)+icount*4+2))<<16) + ((*(data+(Size-pstop)+icount*4+3))<<24);
*(uint32_t *)((addr/FLASH_PAGE_SIZE+pn-1)*FLASH_PAGE_SIZE+icount*4) = d32;
HAL_STATUS = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);// Wait for last operation to be completed
if (HAL_STATUS!=HAL_OK) return HAL_STATUS;
}
}
__HAL_UNLOCK(&pFlash); /* Process Unlocked */
HAL_FLASH_Lock();
}
return HAL_STATUS;
}
经过验证,首地址为奇数或偶数地址,写半页字节数据,一页半字节数据,两页半字节数据,读回字节都正确,且未操作的地址,字节数据未被擦除破坏。
-End-