STM32 内部FLASH用作用户数据区Byte操作函数设计 (HAL)

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. 如果写入的首页和尾页数据,不是一整页,则需要把原有页内数据读出,再和要写入的数据组合后,作为整理后的一整页数据写入。
  2. 中间的页面,是整页数据,可以直接擦除后覆盖写入。
  3. 最终实现从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-

猜你喜欢

转载自blog.csdn.net/hwytree/article/details/103907992