请选择 进入手机版 | 继续访问电脑版

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

STM32F103C8T6 读写内部FLASH报错

1+1=2 提问时间:2021-9-15 16:27 /
最近在使用STM32F103C8T6这款芯片,在读写内部flash的时候,读出数据没有问题,但是当写入数据的时候出现问题
我的代码如下(参考的正点原子例程)
不校验的情况下写入数据的数据
  1. void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)   
  2. {                                           
  3.         u16 i;
  4.         for(i=0;i<NumToWrite;i++)
  5.         {
  6.                 FLASH_ProgramHalfWord(WriteAddr,pBuffer[i]);
  7.             WriteAddr+=2;//地址增加2.
  8.         }  
  9. }
复制代码


  1. u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节
  2. void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)       
  3. {
  4.         u32 secpos;           //扇区地址
  5.         u16 secoff;           //扇区内偏移地址(16位字计算)
  6.         u16 secremain; //扇区内剩余地址(16位字计算)          
  7.         u16 i;   
  8.         u32 offaddr;   //去掉0X08000000后的地址
  9.         if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址
  10.         FLASH_Unlock();                                                //解锁
  11.         offaddr=WriteAddr-STM32_FLASH_BASE;                //实际偏移地址.
  12.         secpos=offaddr/STM_SECTOR_SIZE;                        //扇区地址  0~127 for STM32F103RBT6
  13.         secoff=(offaddr%STM_SECTOR_SIZE)/2;                //在扇区内的偏移(2个字节为基本单位.)
  14.         secremain=STM_SECTOR_SIZE/2-secoff;                //扇区剩余空间大小   
  15.         if(NumToWrite<=secremain)
  16.         {
  17.           secremain=NumToWrite;//不大于该扇区范围
  18.         }
  19.         while(1)
  20.         {       
  21.                 STMFLASH_Read(((secpos*STM_SECTOR_SIZE)+STM32_FLASH_BASE),STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容
  22.                 for(i=0;i<secremain;i++)//校验数据
  23. //                for(i=0;i<(STM_SECTOR_SIZE/2);i++)//校验数据
  24.                 {
  25.                         if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除  
  26. //        if(STMFLASH_BUF[i]!=0XFFFF)break;//需要擦除                        
  27.                 }
  28.                 if(i<secremain)//需要擦除
  29. //                if(i<(STM_SECTOR_SIZE/2))//需要擦除
  30.                 {
  31.                         FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);

  32.                         FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区
  33.                         for(i=0;i<secremain;i++)//复制
  34.                         {
  35.                                 STMFLASH_BUF[i+secoff]=pBuffer[i];          
  36.                         }
  37.                         STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//写入整个扇区  
  38.                 }else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                   
  39.                 if(NumToWrite==secremain)break;//写入结束了
  40.                 else//写入未结束
  41.                 {
  42.                                 secpos++;                                //扇区地址增1
  43.                                 secoff=0;                                //偏移位置为0          
  44.                            pBuffer+=secremain;          //指针偏移
  45.                                 WriteAddr+=secremain;        //写地址偏移          
  46.                            NumToWrite-=secremain;        //字节(16位)数递减
  47.                                 if(NumToWrite>(STM_SECTOR_SIZE/2))
  48.                                 {
  49.                                   secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
  50.                                 }
  51.                                 else
  52.                                 {
  53.                                   secremain=NumToWrite;//下一个扇区可以写完了
  54.                                 }
  55.                 }         
  56.         }       
  57.         FLASH_Lock();//上锁
  58. }
复制代码


主函数调用
  1. for(u16 i=0;i<6;i++)
  2.         {
  3.     flash_buff_write[i]=i;
  4.         }
  5.    for(u8 i=0;i<88;i++)
  6.         {
  7.      STMFLASH_Write(((0x08005000)+(i*12)),flash_buff_write,6);
  8.     if(i>80)
  9.    {
  10.        receive_num=1;
  11.      }
  12.          }
复制代码


寄存器数值

寄存器数值

写完第一页了,该写第二页了,报错

写完第一页了,该写第二页了,报错
收藏 评论14 发布时间:2021-9-15 16:27

举报

14个回答
1+1=2 最优答案 回答时间:2021-9-16 16:12:55
结贴了,最终给大家回复一下是怎么解决的吧,因为我STM32F429和STM32F103读写内部FLASH的例程都是根据正点原子的例子写的,其实是他们的例子有问题截屏给大家看一下就明白了,还有一点需要注意的地方就是,如果遇到写入前需要先清除异常标志也就是调用这个函数
  1. FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);
复制代码



最好是把这个放到库函数中,因为每次写入前都清除一次异常标志,要不然如果写错一个,再继续写的话就全部都是错误的,不管你写的是什么,也不管后面是不是0XFF都会出问题
2()`(8$IG7%9STJJM6N]BA3.png
xmshao 回答时间:2021-9-15 16:53:17
对于STM32F1系列的flash编程,仅支持半字编程,即每次写入16位半字,不支持别的格式。再就是注意下地址边界、编程流程,比方开锁、上锁之类的。你可以参考下手册PM0075.同时STM32F1的标准库或Cube库都有相关例程可以参考。
1+1=2 回答时间:2021-9-15 21:09:02
xmshao 发表于 2021-9-15 16:53
对于STM32F1系列的flash编程,仅支持半字编程,即每次写入16位半字,不支持别的格式。再就是注意下地址边界 ...

是半字编程啊,您看我都是每次写16位的数进去,单独写的话没事儿,但是当跨页的时候如果遇到新页是0XFFFF的话是不进行擦除的,这样的话写入会有问题,是不是字节对齐的原因?

1+1=2 回答时间:2021-9-15 21:09:42
xmshao 发表于 2021-9-15 16:53
对于STM32F1系列的flash编程,仅支持半字编程,即每次写入16位半字,不支持别的格式。再就是注意下地址边界 ...

而且您说的PM0075搜索不到啊
1+1=2 回答时间:2021-9-15 21:15:25
xmshao 发表于 2021-9-15 16:53
对于STM32F1系列的flash编程,仅支持半字编程,即每次写入16位半字,不支持别的格式。再就是注意下地址边界 ...

我用的是标准库,例程参考的正点原子的例子,其中他们缺少的清除异常标志位,我也是添加到代码内的,如果不跨页写的话是没问题的
每次写入6个半字


1+1=2 回答时间:2021-9-15 21:18:14
xmshao 发表于 2021-9-15 16:53
对于STM32F1系列的flash编程,仅支持半字编程,即每次写入16位半字,不支持别的格式。再就是注意下地址边界 ...

每次写入6个半字 一页是512个半字,所以只能写入85个半字 剩下两个半字,这一页写入是完全正确的 但是写入剩下4个半字的时候就出错了,第二页是没有经过擦除的,因为第二页起始位置是4个0xFFFF按照手册上是可以写入的,但实际情况是写入后会出现异常,通过memory查看对应地址上的数据,确实没有改变,能解释一下是为什么吗?

1+1=2 回答时间:2021-9-15 21:41:22
xmshao 发表于 2021-9-15 16:53
对于STM32F1系列的flash编程,仅支持半字编程,即每次写入16位半字,不支持别的格式。再就是注意下地址边界 ...
  1. /* Porgram FLASH Bank1 ********************************************************/      
  2.   /* Unlock the Flash Bank1 Program Erase controller */
  3.   FLASH_UnlockBank1();

  4.   /* Define the number of page to be erased */
  5.   NbrOfPage = (BANK1_WRITE_END_ADDR - BANK1_WRITE_START_ADDR) / FLASH_PAGE_SIZE;

  6.   /* Clear All pending flags */
  7.   FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_PGERR | FLASH_FLAG_WRPRTERR);       

  8.   /* Erase the FLASH pages */
  9.   for(EraseCounter = 0; (EraseCounter < NbrOfPage) && (FLASHStatus == FLASH_COMPLETE); EraseCounter++)
  10.   {
  11.     FLASHStatus = FLASH_ErasePage(BANK1_WRITE_START_ADDR + (FLASH_PAGE_SIZE * EraseCounter));
  12.   }
  13.   
  14.   /* Program Flash Bank1 */
  15.   Address = BANK1_WRITE_START_ADDR;

  16.   while((Address < BANK1_WRITE_END_ADDR) && (FLASHStatus == FLASH_COMPLETE))
  17.   {
  18.     FLASHStatus = FLASH_ProgramWord(Address, Data);
  19.     Address = Address + 4;
  20.   }

  21.   FLASH_LockBank1();
  22.   
  23.   /* Check the correctness of written data */
  24.   Address = BANK1_WRITE_START_ADDR;

  25.   while((Address < BANK1_WRITE_END_ADDR) && (MemoryProgramStatus != FAILED))
  26.   {
  27.     if((*(__IO uint32_t*) Address) != Data)
  28.     {
  29.       MemoryProgramStatus = FAILED;
  30.     }
  31.     Address += 4;
  32.   }
复制代码
这个是标准库里的例子,只不过这个是整字写入,我是半字写入,其他无区别


xmshao 回答时间:2021-9-16 10:35:55
1+1=2 发表于 2021-9-15 21:41
这个是标准库里的例子,只不过这个是整字写入,我是半字写入,其他无区别

不管用哪个库都是可以的。

PM0075是专门介绍STM32F1系列flash编程的用户手册,实在找不到我可以发给你。当然,对于你眼前
问题有没有它或许没有决定性作用,但是了解下基本编程规程为宜。需要的话 可以留下你的邮箱。

你跨页写的话,之前应是被erased过。同时 还要注意地址对齐方面的问题。


xmshao 回答时间:2021-9-16 10:37:26
1+1=2 发表于 2021-9-15 21:18
每次写入6个半字 一页是512个半字,所以只能写入85个半字 剩下两个半字,这一页写入是完全正确的 但是写 ...

确认下地址对不对,另外,有无对齐方面的问题。
1+1=2 回答时间:2021-9-16 11:28:01
xmshao 发表于 2021-9-16 10:35
不管用哪个库都是可以的。

PM0075是专门介绍STM32F1系列flash编程的用户手册,实在找不到我可以发给你。 ...

您好,PM0075我找到了,里面说的是在写入前确认被擦除过,因为在烧写前,我选择的是全片擦除,所以肯定是擦除了的 ,还是有地址肯定是对的,对齐的话是按照半字写入的,应该不存在没有对齐的情况
1+1=2 回答时间:2021-9-16 11:28:31
xmshao 发表于 2021-9-16 10:37
确认下地址对不对,另外,有无对齐方面的问题。

仿真,一步一步走,地址是没有问题的
1+1=2 回答时间:2021-9-16 11:45:10
xmshao 发表于 2021-9-16 10:37
确认下地址对不对,另外,有无对齐方面的问题。

这个情况,以前在STM32F429上遇到过,当时没注意,这次是想搞明白怎么回事儿,读写过程肯定是没有问题的,只是不清楚为啥写不进去的
1+1=2 回答时间:2021-9-16 11:46:05
xmshao 发表于 2021-9-16 10:37
确认下地址对不对,另外,有无对齐方面的问题。

我还做过一个实验,就是无论什么情况下,都在写入前擦除一次,这样的情况是,每次都能正确的写进去,能解释一下这是为什么吗?
xmshao 回答时间:2021-9-16 17:05:03
1+1=2 发表于 2021-9-16 16:12
结贴了,最终给大家回复一下是怎么解决的吧,因为我STM32F429和STM32F103读写内部FLASH的例程都是根据正点 ...

嗯 看来根本原因还是地址出了问题。
关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版