[STM32L5] STM32 内部Flash读写 程序源码

[复制链接]
1540|17
 楼主| 雨果喝水 发表于 2023-11-27 22:47 | 显示全部楼层 |阅读模式
STM32 内部Flash带缓存读写 程序源码
由于STM32 系列Flash的Erase操作很多是按Page擦除,如果往Flash写入的数据或余数不够一个整Page,那么该Page其他数据也会被擦除掉。
所以这种情况想保持其他未操作数据不变的话,就要做缓存读写,既将要擦除Page的数据全读出来,与新写入的数据Merge后,再写入。这一块目前ST没有给出Demo,需要现写。
521566564abfdf4020.png
注意到Programming in the Flash memory performed by word or half-page 所以,Write API使用了按Word写入

 楼主| 雨果喝水 发表于 2023-11-27 22:47 | 显示全部楼层
测试程序使用的单片机为STM32L0系列,PageSize为128B,
481416564ac1be6fcf.png
 楼主| 雨果喝水 发表于 2023-11-27 22:48 | 显示全部楼层
Memory map如下:
36006564ac29bdcbe.png
下面是我以前写的API,首先是相关宏定义:

0 Macro
读写API内部调用的是STM32xx_hal_flash.c中的HAL_FLASH_Program API,如果使用不一样的Hal库,可以直接替换下方的Flash_WriteOneWord宏定义:
  1. #define  TRUE    1
  2. #define  FALSE   0

  3. typedef unsigned char   BOOL;       /* boolean data */
  4. typedef unsigned char   FLAG;       /* boolean data */
  5. typedef unsigned char   U8BIT;      /* unsigned 8 bit data */
  6. typedef unsigned short  U16BIT;     /* unsigned 16 bit data */
  7. typedef unsigned long   U32BIT;     /* unsigned 32 bit data */
  8. typedef unsigned long   WORD;       /* unsigned 32 bit data */

  9. #define PAGE_SIZE              FLASH_PAGE_SIZE  

  10. #define Flash_WriteOneWord(a, b)            HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, a, b)
  11. #define Flash_WriteOneHalfWord(a, b)        HAL_FLASH_Program(FLASH_TYPEPROGRAM_HALFWORD, a, b)

 楼主| 雨果喝水 发表于 2023-11-27 22:48 | 显示全部楼层
1.Flash_Erase
Erase主要负责写入之前清空的操作,由Wirte API判断要Erase多少Page
  1. /*****************************************************************************
  2. [url=home.php?mod=space&uid=139335]@name[/url] : Flash_Erase
  3. [url=home.php?mod=space&uid=247401]@brief[/url] : Erase the whole page by NumtoErase
  4. @Param In : U32BIT StartAddr         
  5.                      uint16_t PageNumtoErase  
  6. @Param Out :
  7. [url=home.php?mod=space&uid=266161]@return[/url] : TURE for Success, FALSE for Failed

  8. History      :
  9.   1.Date   : Tuesday, June 04, 2018
  10.     Author   : Howard Xue

  11. *****************************************************************************/
  12. BOOL Flash_Erase(uint32_t StartAddr, uint16_t PageNumtoErase)
  13. {

  14.         if(HAL_FLASH_Unlock() != HAL_OK)
  15.                 return FALSE;
  16.        
  17.         uint32_t PageError_Tmp = 0;
  18.         FLASH_EraseInitTypeDef Eras;
  19.         Eras.NbPages = PageNumtoErase;
  20.         Eras.PageAddress = StartAddr;
  21.         Eras.TypeErase = FLASH_TYPEERASE_PAGES;
  22.        
  23.         if(HAL_FLASHEx_Erase(&Eras , &PageError_Tmp) != HAL_OK)
  24.                 return FALSE;


  25.         if(HAL_FLASH_Lock() != HAL_OK)
  26.                   return FALSE;

  27.         return TRUE;


  28. }

 楼主| 雨果喝水 发表于 2023-11-27 22:48 | 显示全部楼层
2. Flash_Read_Byte
  1. /*****************************************************************************
  2. @Name : Flash_Read_Byte
  3. @Brief : Read Internal Falsh data by address
  4. @Param In : uint32_t StartAddr         
  5.                       uint8_t  *ReadBuf
  6.                       uint32_t NumToRead
  7. @Param Out :   uint8_t  *ReadBuf
  8. @Return : TURE for Success, FALSE for Failed

  9. History      :
  10.   1.Date   : Tuesday, June 04, 2018
  11.     Author   : Howard Xue

  12. *****************************************************************************/
  13. BOOL Flash_Read_Byte(uint32_t StartAddr, uint8_t  *ReadBuf, uint32_t NumToRead)
  14. {
  15.         if(NumToRead== 0)
  16.                 return FALSE;
  17.                
  18.         uint32_t DataNum = 0;
  19.         uint32_t ReadAddress = StartAddr;
  20.        
  21.         while(DataNum < NumToRead)
  22.         {
  23.                 *(ReadBuf + DataNum) = *(__IO uint8_t  *)ReadAddress++;
  24.                 DataNum++;
  25.         }
  26.                 return TRUE;
  27. }
 楼主| 雨果喝水 发表于 2023-11-27 22:49 | 显示全部楼层
写之前要先Erase,并且Unlock,这种方法是NoBuffer形式,既每次写入都会Erase 一个Page,(因为STM32 Erase都是最低以Page为单位,例如我的芯片是128B,不同的芯片FLASH_PAGE_SIZE 不用,直接copy 不需要修改)
 楼主| 雨果喝水 发表于 2023-11-27 22:49 | 显示全部楼层
3.Flash_Write_NoBuffer
  1. /*****************************************************************************
  2. @Name : Flash_Write_NoBuffer
  3. @Brief : Write Flash without Buffer
  4. @Param In : uint32_t StartAddr         
  5.                       uint32_t  *pBufferToWrite
  6.                       uint32_t NumToWrite
  7. @Param Out :   uint32_t  *pBufferToWrite
  8. @Return : TURE for Success, FALSE for Failed

  9. History      :
  10.   1.Date   : Tuesday, June 04, 2018
  11.     Author   : Howard Xue

  12. *****************************************************************************/
  13. BOOL Flash_Write_NoBuffer(uint32_t StartAddr, uint32_t *pBufferToWrite, uint32_t NumToWrite)
  14. {

  15.         uint32_t PageNumtoErase = 1;//default
  16.     uint32_t i;

  17.         if(NumToWrite == 0)
  18.                 return FALSE;
  19.        
  20.         //GetPageNum to erase
  21.         if(NumToWrite > FLASH_PAGE_SIZE)
  22.         {
  23.                 PageNumtoErase = NumToWrite/FLASH_PAGE_SIZE + 1;
  24.         }
  25.        
  26.         //Erase whole page
  27.         if(Flash_Erase(StartAddr, PageNumtoErase) != TRUE)
  28.                 return FALSE;
  29.        
  30.                 //4.Write Buffer to Flash, Unlock -> write -> lock
  31.         if(HAL_FLASH_Unlock() != HAL_OK)
  32.                 return FALSE;
  33.                
  34.     for ( i = 0 ; i < (NumToWrite/4) ; i++ )
  35.     {
  36.                 if(Flash_WriteOneWord(StartAddr + i * sizeof(uint32_t ), *pBufferToWrite) != HAL_OK)
  37.                         return FALSE;
  38.                        
  39.         pBufferToWrite++;
  40.     }

  41.                  if(HAL_FLASH_Lock() != HAL_OK)
  42.                   return FALSE;

  43.                 return TRUE;

  44. }
 楼主| 雨果喝水 发表于 2023-11-27 22:49 | 显示全部楼层
4.Flash_Write_WithBuffer
BufferWrite其实就是先根据要写多少数据,算出相应需Erase的page数,之后将这些Page的数据全读出来,与新要写入的数据合并覆盖后,再写入。 这样就实现除了要写入的地址数据,其他的数据不被Erase更改。

注意Wite传入参数如果是U8的需要强制转换成U32

  1. /*****************************************************************************
  2. @Name : Flash_Write_WithBuffer
  3. @Brief : Read Buffer from Flash ,Then Merge New Data and Write
  4. @Param In : uint32_t StartAddr         
  5.                       uint32_t  *pBufferToWrite
  6.                       uint32_t NumToWrite
  7. @Param Out :   uint32_t  *pBufferToWrite
  8. @Return : TURE for Success, FALSE for Failed

  9. History      :
  10.   1.Date   : Tuesday, June 04, 2018
  11.     Author   : Howard Xue

  12. *****************************************************************************/
  13. BOOL Flash_Write_WithBuffer(uint32_t StartAddr, uint32_t *pBufferToWrite, uint32_t NumToWrite)
  14. {

  15.         uint8_t PageNumtoErase = 1;//default is erase 1 page.
  16.     uint32_t i;
  17.         uint32_t ReadBuffer_Length = 0;
  18. //        uint8_t ReadBuffer[FLASH_PAGE_SIZE] = {0};

  19.         if(NumToWrite == 0)
  20.                 return FALSE;
  21.        
  22.         //GetPageNum to erase
  23.         if(NumToWrite > FLASH_PAGE_SIZE)
  24.         {
  25.                 PageNumtoErase = NumToWrite/FLASH_PAGE_SIZE + 1;
  26.         }

  27.         ReadBuffer_Length = PageNumtoErase*FLASH_PAGE_SIZE;

  28.         U32BIT *pReadBuffer = (U32BIT *)calloc(1, ReadBuffer_Length);
  29.         U32BIT *pReadBufferCount = pReadBuffer;
  30.        
  31.         //1.Read orginal data from flash
  32.         Flash_Read_Byte(StartAddr,(U8BIT *)pReadBuffer,ReadBuffer_Length);

  33.         //2.Merge New Data for Write
  34.         memcpy(pReadBufferCount,pBufferToWrite,NumToWrite);

  35.         //3.Erase whole page
  36.         if(Flash_Erase(StartAddr, PageNumtoErase) != TRUE)
  37.                 return FALSE;

  38.         //4.Write Buffer to Flash, Unlock -> write -> lock
  39.         if(HAL_FLASH_Unlock() != HAL_OK)
  40.                 return FALSE;
  41.                
  42.     for ( i = 0 ; i < (ReadBuffer_Length/4) ; i++ )
  43.     {
  44.         if(Flash_WriteOneWord(StartAddr + i * sizeof(uint32_t ), *pReadBufferCount) != HAL_OK)
  45.                         return FALSE;
  46.                
  47.                 pReadBufferCount++;
  48.     }

  49.          
  50.         if(HAL_FLASH_Lock() != HAL_OK)
  51.                 return FALSE;

  52.          free(pReadBuffer);
  53.          return TRUE;
  54.        

  55. }

 楼主| 雨果喝水 发表于 2023-11-27 22:50 | 显示全部楼层
5. Test
Test程序中,先Flash_Write_NoBuffer将Data全部写入Flash,然后更改几个下次要写入的数值,只写入更改的数据,这样FlashBufferWrite就会仅更新更改的数值,其他数值不变(如果不使用BufferWrite,Flash同一Page其他数据都会被Erase)
注意Wite传入参数如果是U8的需要强制转换成U32





  1. void FlashTest()
  2. {
  3.         U8BIT Data_W[64] = {0xFA,0xFA,0xFE,0xFE,0xFA,0xFA,0xFE,0xFE,0xFA,0xFA,0xFE,0xFE,0xFA,0xFA,0xFE,0xFE,0xFA,0xFA,0xFE,0xFE,0xFA,0xFA,0xFE,0xFE};
  4.         U8BIT Data_R[64] = {0};
  5.     U32BIT FLASH_DATAZONE_BASE_ADDR = 0x08028000; //Address for test

  6.         Flash_Read_Byte(FLASH_DATAZONE_BASE_ADDR, Data_R,sizeof(Data_R));

  7.         Flash_Write_NoBuffer(FLASH_DATAZONE_BASE_ADDR,(U32BIT *)&Data_W[0],sizeof(Data_W));

  8.         Flash_Read_Byte(FLASH_DATAZONE_BASE_ADDR, Data_R,sizeof(Data_R));

  9.         Data_W[0] = 0;
  10.         Data_W[1] = 1;
  11.         //Merge new data and write, ohter data will contained
  12.         Flash_Write_WithBuffer(FLASH_DATAZONE_BASE_ADDR,(U32BIT *)&Data_W[0],4);
  13.        
  14.         Flash_Read_Byte(FLASH_DATAZONE_BASE_ADDR, Data_R,sizeof(Data_R));
  15. }
Pulitzer 发表于 2024-7-21 07:30 | 显示全部楼层

需要靠近在外部添加一个钳位二极管
童雨竹 发表于 2024-7-21 09:26 | 显示全部楼层

ESD电压通过接地放掉
Wordsworth 发表于 2024-7-21 10:29 | 显示全部楼层

电阻消耗过电压的能量
公羊子丹 发表于 2024-7-21 12:25 | 显示全部楼层

当电路正常工作时,它处于截止状态(高阻态)
万图 发表于 2024-7-21 13:28 | 显示全部楼层

在信号线中串联小电阻其主要目的是对引脚的保护
Uriah 发表于 2024-7-21 14:31 | 显示全部楼层

根据电荷守恒:Qinitial=Qfinal
帛灿灿 发表于 2024-7-21 16:27 | 显示全部楼层

并且衡量电阻受温度影响大小的物理量是温度系数
Bblythe 发表于 2024-7-21 17:30 | 显示全部楼层

需要更大的齐纳二极管来承受能量
周半梅 发表于 2024-7-21 19:26 | 显示全部楼层

就导通接地放掉
您需要登录后才可以回帖 登录 | 注册

本版积分规则

90

主题

1213

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部