你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F7--->Internal Flash

[复制链接]
STMCU小助手 发布时间:2021-12-11 12:00
Flash
闪存模块


bc19fd5ce8ca4f108678471a9994d1d1.png


模块组织表如上,可见STM32F767IGT6由:主存储器、系统存储器、OPT区域、选项字节4部分组成。
STM32F767的Flash访问路径有两条:AXIM和ICTM,一般使用AXIM接口访问Falsh,其其实地址为0X08000000

主存储器
存放代码和数据常量(const常量数据)。它可以分为1个Bank(默认)和2个Bank,可以通过选项字节nDBank位来设置。
在单Bank模式下,STM32F767的主存储器被分为8个扇区,前4个扇区为32kb大小,第五个山扇区为128kb大小,剩下的3个扇区都是256kb大小,共1MB

系统存储器
存放Bootloader代码,此代码是出厂时就固化的,用来给主存储器下载代码,当B0接3.3v时默认从系统存储器启动

OTP区域
一次性可编程区域,共1056byte,被划分为16个64字节的OTP数据块和1个16字节的OTP锁定块。锁定块决定了数据块是否可编程。

选项字节

闪存的读取
为了准确的读取Flash数据,需要根据CPU时钟(HCLK)的频率和器件电源电压设置FLSH的存取控制寄存器(FLASH_ACR)中的等待周期数(LATENCY),CPU频率与FLASH等待周期数的对应关系如图:

8a2f2b2dd84e4a57a4f63ee69b5dbe6b.png


等待周期通过FLASH_ACR寄存器的LATENCY[3:0]来设置,系统复位后,系统时钟为内部的16MRC振荡器,LATENCY默认是0(1个等待周期)。供电电压一般默认为3.3,所以在设置216Mhz频率作为CPU时钟之前,必须先设置LATENCY为7(8个CPU周期),否则FLASH读写可能会出错导致死机。
STM23F7的 FLASH 读取是很简单的。例如,我们要从地址 addr ,读取一个字(一个字为32 位),可以通过如下的语句读取:
              data=(vu32)addr;
将addr 强制转换为 vu32 指针,然后取该指针所指向的地址的值,即得到了 addr 地址的值。
类似的,将上面的 vu32 改为 vu8 ,即可读取指定地址的一个字节。

闪存的编程和擦除
执行任何Flash的编程操作(擦除或编程)时,CPU时钟频率(HCLK)不能低于1Mhz。如果在Flash操作期间期间器件发生复位,无法保证Flash的内容。
在对Flash执行写入或擦除操作期间,任何读取Flash的尝试都会导致总线阻塞。只有在完成编程操作后才能正确处理读操作。
STM32F767的闪存编程由7个32位寄存器控制,如下

T85`2XMT@0~([S{862MVQMV.png


STM32F767复位后,Flash的编程操作是被保护的,不能写入FLASH_CR寄存器;通过写入特定的序列(0X45670123 和 0XCDEF89AB)到FLASH_KEYR寄存器才可解除写保护,只有在写保护被解除后,才能操作相关寄存器。
STM32F767的编程位数通过FLASH_CR的PSIZE字段配置,PSIZE的设置必须和电源电压匹配,见表,使用3.3v供电时,PSIZE必须设置为10,擦除护着编程都必须以32位为基础。

5d10e1e0f2de471fa642a60b4893a091.png


FLASH在编程的时候,也必须要求其写入地址的FLASH是被擦除了的(值必须是0XFFFFFFFF),否则无法写入。

STM32F767的标准编程步骤
检查Flash_SR的BSY位,确定当前未执行任何Flash操作;
将Flash_CR寄存器中的PG位置1,激活Flash编程;
针对所需存储器地址(主存储器块或OTP区域内)执行数据写入操作(PSIZE需要已经设置)
等待BSY位清,完成一次编程。
以上四步操作就可以完成一次FLASH编程操作,需要注意几点:
确保编程地址已擦除
需要先解锁FLASH_CR,操作完后要上锁
变成操作对OPT区域也一样


STM32F767的擦除
扇区擦除
检查FLASH_CR是否解锁,未解锁先解锁
检查FLASH_SR的BSY位,确保当前未执行任何FLASH操作
将FLASH_CR的SER位置1,并从主存储块的12个扇区中选择要擦除的扇区(SNB)
将FLASH_CR的STRT置1,触发擦除操作
等待BSY位清零
整片擦除
附录
代码
依赖于HAL库

  1. #include "stmflash.h"
  2. #include "delay.h"

  3. //读取指定地址的字(32位数据)
  4. //faddr:读地址
  5. //返回值:对应数据.
  6. u32 STMFLASH_ReadWord(u32 faddr)
  7. {
  8.     return *(__IO uint32_t *)faddr;
  9. }

  10. //获取某个地址所在的flash扇区
  11. //addr:flash地址
  12. //返回值:0~11,即addr所在的扇区
  13. uint16_t STMFLASH_GetFlashSector(u32 addr)
  14. {
  15.     if(addr<ADDR_FLASH_SECTOR_1)return FLASH_SECTOR_0;
  16.     else if(addr<ADDR_FLASH_SECTOR_2)return FLASH_SECTOR_1;
  17.     else if(addr<ADDR_FLASH_SECTOR_3)return FLASH_SECTOR_2;
  18.     else if(addr<ADDR_FLASH_SECTOR_4)return FLASH_SECTOR_3;
  19.     else if(addr<ADDR_FLASH_SECTOR_5)return FLASH_SECTOR_4;
  20.     else if(addr<ADDR_FLASH_SECTOR_6)return FLASH_SECTOR_5;
  21.     else if(addr<ADDR_FLASH_SECTOR_7)return FLASH_SECTOR_6;
  22.     return FLASH_SECTOR_7;   
  23. }

  24. //从指定地址开始写入指定长度的数据
  25. //特别注意:因为STM32F7的扇区实在太大,没办法本地保存扇区数据,所以本函数
  26. //         写地址如果非0XFF,那么会先擦除整个扇区且不保存扇区数据.所以
  27. //         写非0XFF的地址,将导致整个扇区数据丢失.建议写之前确保扇区里
  28. //         没有重要数据,最好是整个扇区先擦除了,然后慢慢往后写.
  29. //该函数对OTP区域也有效!可以用来写OTP区!
  30. //OTP区域地址范围:0X1FF0F000~0X1FF0F41F
  31. //WriteAddr:起始地址(此地址必须为4的倍数!!)
  32. //pBuffer:数据指针
  33. //NumToWrite:字(32位)数(就是要写入的32位数据的个数.)
  34. void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite)   
  35. {
  36.     FLASH_EraseInitTypeDef FlashEraseInit;
  37.     HAL_StatusTypeDef FlashStatus=HAL_OK;
  38.     u32 SectorError=0;
  39.     u32 addrx=0;
  40.     u32 endaddr=0;   
  41.     if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return;    //非法地址

  42.     HAL_FLASH_Unlock();             //解锁
  43.     addrx=WriteAddr;                //写入的起始地址
  44.     endaddr=WriteAddr+NumToWrite*4;    //写入的结束地址

  45.     if(addrx<0X1FF00000)
  46.     {
  47.         while(addrx<endaddr)        //扫清一切障碍.(对非FFFFFFFF的地方,先擦除)
  48.         {
  49.             if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区
  50.             {   
  51.                 FlashEraseInit.TypeErase=FLASH_TYPEERASE_SECTORS;       //擦除类型,扇区擦除
  52.                 FlashEraseInit.Sector=STMFLASH_GetFlashSector(addrx);   //要擦除的扇区
  53.                 FlashEraseInit.NbSectors=1;                             //一次只擦除一个扇区
  54.                 FlashEraseInit.VoltageRange=FLASH_VOLTAGE_RANGE_3;      //电压范围,VCC=2.7~3.6V之间!!
  55.                 if(HAL_FLASHEx_Erase(&FlashEraseInit,&SectorError)!=HAL_OK)
  56.                 {
  57.                     break;//发生错误了   
  58.                 }
  59.                 SCB_CleanInvalidateDCache();                            //清除无效的D-Cache
  60.             }else addrx+=4;
  61.             FLASH_WaitForLastOperation(FLASH_WAITETIME);                //等待上次操作完成
  62.         }
  63.     }
  64.     FlashStatus=FLASH_WaitForLastOperation(FLASH_WAITETIME);            //等待上次操作完成
  65.     if(FlashStatus==HAL_OK)
  66.     {
  67.         while(WriteAddr<endaddr)//写数据
  68.         {
  69.             if(HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD,WriteAddr,*pBuffer)!=HAL_OK)//写入数据
  70.             {
  71.                 break;    //写入异常
  72.             }
  73.             WriteAddr+=4;
  74.             pBuffer++;
  75.         }
  76.     }
  77.     HAL_FLASH_Lock();           //上锁
  78. }

  79. //从指定地址开始读出指定长度的数据
  80. //ReadAddr:起始地址
  81. //pBuffer:数据指针
  82. //NumToRead:字(32位)数
  83. void STMFLASH_Read(u32 ReadAddr,u32 *pBuffer,u32 NumToRead)      
  84. {
  85.     u32 i;
  86.     for(i=0;i<NumToRead;i++)
  87.     {
  88.         pBuffer<i>=STMFLASH_ReadWord(ReadAddr);//读取4个字节.
  89.         ReadAddr+=4;//偏移4个字节.   
  90.     }
  91. }

  92. </i>
复制代码


收藏 评论0 发布时间:2021-12-11 12:00

举报

0个回答
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版