加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

STM32 FLASH做EEPROM用

发布时间:2020-12-15 07:06:39 所属栏目:百科 来源:网络整理
导读:STM32? 本身没有自带? EEPROM ,但是? STM32? 具有? IAP (在应用编程)功能,所以我们可以把它的? FLASH? 当成? EEPROM? 来使用 STM32?FLASH? 简介 不同型号的? STM32 ,其? FLASH? 容量也有所不同,最小的只有? 16K? 字节,最大的则达到了 1024K? 字节。战

STM32?本身没有自带?EEPROM,但是?STM32?具有?IAP(在应用编程)功能,所以我们可以把它的?FLASH?当成?EEPROM?来使用

STM32?FLASH?简介

不同型号的?STM32,其?FLASH?容量也有所不同,最小的只有?16K?字节,最大的则达到了1024K?字节。战舰?STM32?开发板选择的?STM32F103ZET6?的?FLASH?容量为?512K?字节,属于大容量产品(另外还有中容量和小容量产品),

STM32?的闪存模块由:主存储器、信息块和闪存存储器接口寄存器等?3?部分组成。

主存储器该部分用来存放代码和数据常数(如?const?类型的数据)。对于大容量产品,其被划分为?256?页,每页?2K?字节。注意,小容量和中容量产品则每页只有?1K?字节。从上图可以看出主存储器的起始地址就是?0X08000000,??B0B1?都接?GND?的时候,就是从?0X08000000开始运行代码的。

信息块,该部分分为?2?个小部分,其中启动程序代码,是用来存储?ST?自带的启动程序,用于串口下载代码,当?B0?接?V3.3B1?接?GND?的时候,运行的就是这部分代码。用户选择字节,则一般用于配置写保护、读保护等功能,

闪存存储器接口寄存器,该部分用于控制闪存读写等,是整个闪存模块的控制机构。

闪存的读取

内置闪存模块可以在通用地址空间直接寻址任何?32?位数据的读操作都能访问闪存模块的内容并得到相应的数据。读接口在闪存端包含一个读控制器,还包含一个?AHB?接口与?CPU?衔接。这个接口的主要工作是产生读闪存的控制信号并预取?CPU?要求的指令块,预取指令块仅用于在?I-Code?总线上的取指操作,数据常量是通过?D-Code?总线访问的。这两条总线的访问目标是相同的闪存模块,访问?D-Code?将比预取指令优先级高

这里要特别留意一个闪存等待时间,因为?CPU?运行速度比?FLASH?快得多,STM32F103的?FLASH?最快访问速度≤24Mhz,如果?CPU?频率超过这个速度,那么必须加入等待时间,比如我们一般使用?72Mhz?的主频,那么?FLASH?等待周期就必须设置为?2,该设置通过?FLASH_ACR寄存器设置。

使用?STM32?的官方固件库操作?FLASH?的几个常用函数。这些函数和定义分布在文件?stm32f10x_flash.c?以及?stm32f10x_flash.h?文件中。

1.??锁定解锁函数

在对?FLASH?进行写操作前必须先解锁,解锁操作也就是必须在?FLASH_KEYR?寄存器写入特定的序列(KEY1?和?KEY2,固件库函数实现很简单:

void?FLASH_Unlock(void)

同样的道理,在对?FLASH?写操作完成之后,我们要锁定?FLASH,使用的库函数是:

FLASH_Lock(void)

2.??写操作函数

固件库提供了三个?FLASH?写函数:

FLASH_Status?FLASH_ProgramWord(uint32_t?Address,?uint32_t?Data);

FLASH_Status?FLASH_ProgramHalfWord(uint32_t?Address,?uint16_t?Data);

FLASH_Status?FLASH_ProgramOptionByteData(uint32_t?Address,?uint8_t?Data);

顾名思义分别为:FLASH_ProgramWord?为??32?位字写入函数其他分别为?16?位半字写入和用户选择字节写入函数。这里需要说明,32?位字节写入实际上是写入的两次?16?位数据,写完第一次后地址+2,这与我们前面讲解的?STM32?闪存的编程每次必须写入?16?位并不矛盾。写入?8位实际也是占用的两个地址了,跟写入?16?位基本上没啥区别。

3.??擦除函数

固件库提供三个?FLASH?擦除函数:

FLASH_Status?FLASH_ErasePage(uint32_t?Page_Address);

FLASH_Status?FLASH_EraseAllPages(void);

FLASH_Status?FLASH_EraSEOptionBytes(void);

这三个函数可以顾名思义了,非常简单。

4.??获取?FLASH?状态

主要是用的函数是:

FLASH_Status?FLASH_GetStatus(void)

返回值是通过枚举类型定义的:

typedef?enum

{?

  FLASH_BUSY?=?1,//忙

  FLASH_ERROR_PG//编程错误   FLASH_ERROR_WRP//写保护错误   FLASH_COMPLETE//操作完成   FLASH_TIMEOUT//操作超时

}FLASH_Status;

从这里面我们可以看到?FLASH?操作的?5?个状态,每个代表的意思我们在后面注释了。

5.??等待操作完成函数

在执行闪存写操作时,任何对闪存的读操作都会锁住总线,在写操作完成后读操作才能正确地进行;既在进行写或擦除操作时,不能进行代码或数据的读取操作。所以在每次操作之前,我们都要等待上一次操作完成这次操作才能开始。使用的函数是:

FLASH_WaitForLastOperation(uint32_t?Timeout)

入口参数为等待时间,返回值是?FLASH?的状态,这个很容易理解,这个函数本身我们在固件库中使用得不多,但是在固件库函数体中间可以多次看到。

6.??读?FLASH?特定地址数据函数

有写就必定有读,而读取?FLASH?指定地址的半字的函数固件库并没有给出来,这里我们自己写的一个函数:

u16?STMFLASH_ReadHalfWord(u32?faddr)

{

return?*(vu16*)faddr;?

}

点击(此处)折叠或打开

  1. //读取指定地址的半字(16位数据)
  2. //faddr:读地址(此地址必须为2的倍数!!)
  3. //返回值:对应数据.
  4. u16 STMFLASH_ReadHalfWord(u32 faddr)
  5. {
  6. ????return?*(vu16)faddr;?
  7. }


  8. #if?STM32_FLASH_WREN????//如果使能了写?
  9. //不检查的写入
  10. //WriteAddr:起始地址
  11. //pBuffer:数据指针
  12. //NumToWrite:半字(16位)数?
  13. void?STMFLASH_Write_NoCheck(u32 WriteAddr,u16?*pBuffer)?
  14. {????????????? ?????????
  15. ????u16 i;
  16. ????for(i=0;i<NumToWrite+)
  17. ????{
  18. ????????FLASH_ProgramHalfWord(WriteAddr[i]);
  19. ???? WriteAddr=2;//地址增加2.
  20. ????}?
  21. }?
  22. //从指定地址开始写入指定长度的数据
  23. //WriteAddr:起始地址(此地址必须为2的倍数!!)
  24. //NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
  25. if?STM32_FLASH_SIZE<256
  26. #define?STM_SECTOR_SIZE 1024?//字节
  27. else?
  28. define?STM_SECTOR_SIZE????2048
  29. endif?????????
  30. u16 STMFLASH_BUF[STM_SECTOR_SIZE/2//最多是2K字节
  31. void?STMFLASH_Write)????
  32. {
  33. ????u32 secpos;?????//扇区地址
  34. ????u16 secoff//扇区内偏移地址(16位字计算)
  35. ????u16 secremain;?//扇区内剩余地址(16位字计算)?????
  36. ?????u16 i;?
  37. ????u32 offaddr//去掉0X08000000后的地址
  38. ????if<STM32_FLASH_BASE|>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZEreturn//非法地址
  39. ????FLASH_Unlock(;????????????????????????//解锁
  40. ????offaddr=WriteAddr-STM32_FLASH_BASE;????????//实际偏移地址.
  41. ????secpos=offaddr/STM_SECTOR_SIZE;????????????//扇区地址 0~127 for STM32F103RBT6
  42. ????secoff(offaddr%STM_SECTOR_SIZE//在扇区内的偏移(2个字节为基本单位.)
  43. ????secremain=STM_SECTOR_SIZE-secoff//扇区剩余空间大小?
  44. ????(NumToWrite<=secremain)secremain=NumToWrite//不大于该扇区范围
  45. ????while(1)?
  46. ????{????
  47. ????????STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASESTM_SECTOR_SIZE//读出整个扇区的内容
  48. ????????<secremain)//校验数据
  49. ????????{
  50. ????????????(STMFLASH_BUF[secoff+i!=0XFFFFbreak//需要擦除 ?????
  51. ????????}
  52. ????????//需要擦除
  53. ????????{
  54. ????????????FLASH_ErasePage//擦除这个扇区
  55. ????????????//复制
  56. ????????????{
  57. ????????????????STMFLASH_BUF+secoff=pBuffer;?????
  58. ????????????}
  59. ????????????STMFLASH_Write_NoCheck//写入整个扇区?
  60. ????????}else?STMFLASH_Write_NoCheck//写已经擦除了的,直接写入扇区剩余区间. ?????????????????
  61. ????????//写入结束了
  62. ????????else//写入未结束
  63. ????????{
  64. ????????????secpos;????????????????//扇区地址增1
  65. ????????????secoff//偏移位置为0 ?????
  66. ???????? ????pBuffer//指针偏移
  67. ????????????WriteAddr;????//写地址偏移?????
  68. ???????? ????NumToWrite-//字节(16位)数递减
  69. ????????????(STM_SECTOR_SIZE//下一个扇区还是写不完
  70. ????????????else?secremain//下一个扇区可以写完了
  71. ????????}?????
  72. ????;????
  73. ????FLASH_Lock//上锁
  74. }
  75. endif


  76. //从指定地址开始读出指定长度的数据
  77. //ReadAddr:起始地址
  78. //NumToWrite:半字(16位)数
  79. void?STMFLASH_Read(u32 ReadAddr)?????
  80. {
  81. ????u16 i<NumToRead{
  82. ????????pBuffer=STMFLASH_ReadHalfWord(ReadAddr//读取2个字节.
  83. ????????ReadAddr//偏移2个字节.????
  84. ????}

  85. //////////////////////////////////////////////////////////////////////////////////////////////////////
  86. //WriteData:要写入的数据
  87. void?Test_Write{
  88. ????STMFLASH_Write&WriteData//写入一个字?
  89. }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读