OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 15175|回复: 15

对原子哥“STM32 FLASH模拟EEPROM”官方例程的质疑,强力求助!!!!!!!!!!!!!!!!!

[复制链接]

6

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
65
金钱
65
注册时间
2014-10-27
在线时间
0 小时
发表于 2015-2-6 09:36:26 | 显示全部楼层 |阅读模式
5金钱

void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite) 
{
    u32 secpos;   //扇区地址
    u16 secoff;   //扇区内偏移地址(16位字计算)
    u16 secremain; //扇区内剩余地址(16位字计算)   
   u16 i;    
    u32 offaddr;   //去掉0X08000000后的地址
    if(WriteAddr < STM32_FLASH_BASE || (WriteAddr >= (STM32_FLASH_BASE + 1024*STM32_FLASH_SIZE))) return;//非法地址
    FLASH_Unlock(); //解锁
    offaddr=WriteAddr-STM32_FLASH_BASE; //实际偏移地址.
    secpos=offaddr/STM_SECTOR_SIZE; //扇区地址,即在哪一个扇区  0~127 for STM32F103RBT6
    secoff=(offaddr%STM_SECTOR_SIZE)/2; //在扇区内的偏移(2个字节为基本单位.)
    secremain=STM_SECTOR_SIZE/2-secoff; //扇区剩余空间大小   
    if(NumToWrite<=secremain) secremain=NumToWrite;//不大于该扇区范围
    while(1) 
    { 
        STMFLASH_Read(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE, STMFLASH_BUF, STM_SECTOR_SIZE/2);//读出整个扇区的内容
        for(i=0;i<secremain;i++)//校验数据
        {
            if(STMFLASH_BUF[secoff+i]!=0XFFFF) break;//需要擦除    
        }
        if(i<secremain)//需要擦除
        {
            FLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除这个扇区
            for(i=0;i<secremain;i++)//复制
            {
                STMFLASH_BUF[i+secoff]=pBuffer;  
            }
            STMFLASH_Write_NoCheck(secpos * STM_SECTOR_SIZE + STM32_FLASH_BASE,  STMFLASH_BUF,  STM_SECTOR_SIZE/2);//写入整个扇区  
        }
        else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain); //写已经擦除了的,直接写入扇区剩余区间.   
        if(NumToWrite==secremain) break;//写入结束了
        else//写入未结束
        {
            secpos++; //扇区地址增1
            secoff=0; //偏移位置为0  
            pBuffer+=secremain;   //指针偏移    
            WriteAddr+=secremain; //写地址偏移 ,个人认为此处secremain应该*2   《《-----------------------------------↑
            NumToWrite-=secremain; //字节(16位)数递减                                                                        
            if(NumToWrite > (STM_SECTOR_SIZE/2)) secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完                        
            else secremain=NumToWrite;//下一个扇区可以写完了                                                                                 
        }                                                    
    }                   
    FLASH_Lock();//上锁                
}                  
  
上面这个函数是原子官方例程中stmflash.c文件中的一个函数,总觉得这里有问题----------------------------------------------↑
flash存储的时候都是以每次2个字节的速度存的,secremain表示上一轮存储的半字数,即多少个“2个字节”,所以此处算起始地址时应该为“WriteAddr+=secremain*2”,难道不是这样吗?

求大神解疑???

最佳答案

查看完整内容[请看2#楼]

这里是应该乘以2的,早就有网友提出过这个问题,新版本例程都改过来了 楼主你看的代码是老版本了。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2015-2-6 09:36:27 | 显示全部楼层
这里是应该乘以2的,早就有网友提出过这个问题,新版本例程都改过来了
楼主你看的代码是老版本了。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

58

主题

6293

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11476
金钱
11476
注册时间
2014-4-1
在线时间
1297 小时
发表于 2015-2-6 14:39:01 | 显示全部楼层
没有研究过这个例程,但感觉例程 “不一定” 错,很可能是对的。这种情况比较常见。

地址数值该加多少,按字节操作就该加1,按 2 字节就该加2,这概念没错。

但你可能不知道别的情况,内部硬件很可能再次处理,这个数字最终加在除去A0以外的高位地址上,所以要加1而不是2。

类似的例子还有FSMC的寻址,用到时候注意一下吧。
回复

使用道具 举报

6

主题

21

帖子

0

精华

初级会员

Rank: 2

积分
65
金钱
65
注册时间
2014-10-27
在线时间
0 小时
 楼主| 发表于 2015-2-6 18:51:17 | 显示全部楼层
回复【2楼】xuande:
---------------------------------
      但是就程序而言的话感觉例程计算的值是有误的,就比如一个人走路,走了4个站了,累了停下来休息,第二次继续走的时候不可能从第二个站开始走,肯定是从第4个站开始走的吧。
      这里是修正下一次写的起始地址继续写剩下的数据。假如第一次起始地址为WriteAddr,在第一页里写了secremain个半字,即2*secremain个字节,而还有数据没有写完。那么另起一页的时候地址就应该是“WriteAddr+=2*secremain”,如果以“WriteAddr+=secremain”为起始地址,那肯定是从写过的地方写了,这样难道不会出错吗?
回复

使用道具 举报

58

主题

6293

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11476
金钱
11476
注册时间
2014-4-1
在线时间
1297 小时
发表于 2015-2-6 20:11:59 | 显示全部楼层
事情的根源在于:字节操作、半字操作、字操作,到底是哪种情况。
往前查一下,如果是半字操作,例程就没问题。
回复

使用道具 举报

57

主题

195

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
446
金钱
446
注册时间
2013-2-20
在线时间
1 小时
发表于 2015-3-3 09:16:29 | 显示全部楼层
回复【5楼】正点原子:
---------------------------------
 新版本还是没有改过来呀,亲。。。。
创新超越梦想,拼搏创造奇迹....
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2015-3-3 11:05:53 | 显示全部楼层
回复【6楼】废墟崛起之厦:
---------------------------------
出处?
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

57

主题

195

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
446
金钱
446
注册时间
2013-2-20
在线时间
1 小时
发表于 2015-3-6 23:28:00 | 显示全部楼层
恩 我下载了新的库,还是没有改哦
创新超越梦想,拼搏创造奇迹....
回复

使用道具 举报

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
428
金钱
428
注册时间
2014-1-28
在线时间
8 小时
发表于 2015-7-24 13:00:55 | 显示全部楼层
回复【7楼】正点原子:
回复【8楼】
---------------------------------
我下载的V3版本的新程序,依旧是 WriteAddr+=secremain; //写地址偏移
没有变成 WriteAddr+=secremain*2; //写地址偏移,乘以2

我现在感觉奇怪的是:为什么IAP在线升级的时候,FLASH翻页写入的时候,怎么会没有影响呢?IAP升级很正常。
这是什么原因呢?

谢谢。
回复

使用道具 举报

60

主题

153

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
428
金钱
428
注册时间
2014-1-28
在线时间
8 小时
发表于 2015-7-24 16:43:47 | 显示全部楼层
回复【9楼】LuoKen:
---------------------------------
看了一下,好像找到原因了。

因为IAP时,往FLASH写code的时候,是按照2K字节,1K16位的大小去写的。
APP的写入地址是0x08010000,是64K的位置,2K每页,正好是第32页,0地址偏移。
所以,恰好不涉及FLASH翻页写的问题。

故,不影响IAP在线升级的功能。
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
12
金钱
12
注册时间
2016-11-26
在线时间
2 小时
发表于 2017-5-31 21:24:37 | 显示全部楼层
正点原子 发表于 2015-2-6 09:36
这里是应该乘以2的,早就有网友提出过这个问题,新版本例程都改过来了
楼主你看的代码是老版本了。

STMFLASH_Write(FLASH_SAVE_ADDR,(u16*)TEXT_Buffer,1);
我这样写  读进去的怎么是两位?
回复

使用道具 举报

11

主题

56

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
329
金钱
329
注册时间
2017-3-17
在线时间
83 小时
发表于 2018-2-6 10:40:39 | 显示全部楼层
流泪啊!找了这么久才找到这个原因!又掉到坑里了!!
回复

使用道具 举报

6

主题

315

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1669
金钱
1669
注册时间
2018-1-29
在线时间
160 小时
发表于 2018-2-8 07:50:43 | 显示全部楼层
http://www.openedv.com/forum.php ... 4&fromuid=98045

感谢分析,我之前调试IAP BootLoader代码就是掉到这个坑里了,新库里的STMFLASH.C中是*2的。
直接在BootLoader中就不好使。
我用文件对比工具才找到区别。把*2删除后,IAP程序就好使了!
刚才仔细看了一眼,变量名起的有问题。注释写的很明白:NumToWrite:半字(16位)数(就是要写入的16位数据的个数.)
如果改成WordsToWrite 可能就不会有歧义了吧!
回复

使用道具 举报

5

主题

42

帖子

0

精华

初级会员

Rank: 2

积分
189
金钱
189
注册时间
2014-10-21
在线时间
31 小时
发表于 2018-7-26 17:31:32 | 显示全部楼层
backup2k 发表于 2018-2-8 07:50
http://www.openedv.com/forum.php?mod=redirect&goto=findpost&ptid=46875&pid=319754&fromuid=98045

...

*2才是对的把,那说明IAP程序有问题把
回复

使用道具 举报

1

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
388
金钱
388
注册时间
2020-11-7
在线时间
44 小时
发表于 2020-12-9 21:55:46 | 显示全部楼层
本帖最后由 游走在01的海洋 于 2020-12-21 11:06 编辑
正点原子 发表于 2015-2-6 09:36
这里是应该乘以2的,早就有网友提出过这个问题,新版本例程都改过来了
楼主你看的代码是老版本了。

抱歉,看错代码了
回复

使用道具 举报

1

主题

12

帖子

0

精华

新手上路

积分
37
金钱
37
注册时间
2020-10-25
在线时间
8 小时
发表于 2022-4-18 14:18:27 | 显示全部楼层
即便是*2了,也没有实际意义!因为在每次写数据的同时WriteAddr就已经+2了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-27 14:20

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表