搜索
bottom↓
回复: 74

stm32做PVD掉电检测保存数据到flash

  [复制链接]

出0入0汤圆

发表于 2014-3-7 10:49:28 | 显示全部楼层 |阅读模式
我用STM32做掉电检测,在检测到掉电后保存数据到flash,我已经检测到掉电了,而且已经进入PVD中断了,保存数据的函数也是执行完了的,但为什么就是数据没有保存成功呢?求大神指点!

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

发表于 2014-3-7 11:05:45 来自手机 | 显示全部楼层
靠这么点时间是不行的,flash写入时间较长

出0入0汤圆

 楼主| 发表于 2014-3-7 11:07:34 | 显示全部楼层
myxiaonia 发表于 2014-3-7 11:05
靠这么点时间是不行的,flash写入时间较长

不是的哟,写入flash的函数是已经执行完了的,我写在那个函数后面的代码都是执行了的哟!但就是没有保存成功!我就纠结了。

出0入0汤圆

发表于 2014-3-7 11:17:45 | 显示全部楼层
这个得看手册,另外,flash写入,掉电时,写入过程中电压要满足工作条件

出0入0汤圆

发表于 2014-3-7 11:25:10 | 显示全部楼层
flash写入电压有条件

出0入0汤圆

 楼主| 发表于 2014-3-7 11:37:09 | 显示全部楼层
amnumber 发表于 2014-3-7 11:25
flash写入电压有条件

我怎么没看到啊,有什么条件呢?我PVD的监测阀值设的是2.9v

出0入0汤圆

发表于 2014-3-7 11:41:25 | 显示全部楼层
Llinuxu 发表于 2014-3-7 11:37
我怎么没看到啊,有什么条件呢?我PVD的监测阀值设的是2.9v

1\ 你一次性写入多少个字?
2\ 你的FLASH读写函数是否测试过?是否OK;
3\ 如果在掉电函数中,你如何能仿出来掉电的瞬间,难道你用打印?打印可是很耗时间的啊!

出0入0汤圆

 楼主| 发表于 2014-3-7 11:45:27 | 显示全部楼层
kinsno 发表于 2014-3-7 11:41
1\ 你一次性写入多少个字?
2\ 你的FLASH读写函数是否测试过?是否OK;
3\ 如果在掉电函数中,你如何能仿出来 ...

是这样的:
首先对FLASH的读写是没有问题的,因为在正常的使用中,对FLASH的读写完全OK,只是在PVD中断中没有保存成功。
其次是不管写多少字节,我在写完后用串口向PC打印数据,串口的数据都是发送出来了的,所以写函数是执行完了的。

出0入0汤圆

发表于 2014-3-7 11:46:40 | 显示全部楼层
Llinuxu 发表于 2014-3-7 11:45
是这样的:
首先对FLASH的读写是没有问题的,因为在正常的使用中,对FLASH的读写完全OK,只是在PVD中断中 ...

这个可真有点奇怪啊,我一般不用这个PVD的,因为它不通用,你可以用外部中断来做数据保存;
一个光藕搞定.  比所谓的电压稳定多了.

出0入0汤圆

 楼主| 发表于 2014-3-7 11:49:00 | 显示全部楼层
kinsno 发表于 2014-3-7 11:46
这个可真有点奇怪啊,我一般不用这个PVD的,因为它不通用,你可以用外部中断来做数据保存;
一个光藕搞定.   ...

这个!!对pcb板也是要求很高的,我这PCB已经不能再改了!尺寸原因!

出0入0汤圆

发表于 2014-3-7 11:53:25 | 显示全部楼层
Llinuxu 发表于 2014-3-7 11:49
这个!!对pcb板也是要求很高的,我这PCB已经不能再改了!尺寸原因!

可以把每个字节是否写成功,也打印出来啊,  操作LFASH读写的时候,不是有个返回值的吗,可以打印看看吗?  执行了写函数,未必就能写成功!  其次,是否开锁啊? unLock()  

出0入0汤圆

 楼主| 发表于 2014-3-7 12:05:10 | 显示全部楼层
kinsno 发表于 2014-3-7 11:53
可以把每个字节是否写成功,也打印出来啊,  操作LFASH读写的时候,不是有个返回值的吗,可以打印看看吗?  执 ...

写函数没有返回值吧!开锁我都是写到写函数里面的!!

出0入0汤圆

发表于 2014-3-7 12:06:00 | 显示全部楼层
Llinuxu 发表于 2014-3-7 12:05
写函数没有返回值吧!开锁我都是写到写函数里面的!!

有返回值,你查一下,写函数是有返回值的啊,返回值表示是否成功或不成功的? 你可以去看一下STM32的写函数原型;

出0入0汤圆

 楼主| 发表于 2014-3-7 12:07:50 | 显示全部楼层
kinsno 发表于 2014-3-7 12:06
有返回值,你查一下,写函数是有返回值的啊,返回值表示是否成功或不成功的? 你可以去看一下STM32的写函数原 ...

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;        //写地址偏移          
                           NumToWrite-=secremain;        //字节(16位)数递减
                        if(NumToWrite>(STM_SECTOR_SIZE/2))
                        {
                                secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
                        }
                        else
                        {
                                secremain=NumToWrite;//下一个扇区可以写完了
                        }
                }         
        }       
        FLASH_Lock();//上锁
}

出0入0汤圆

发表于 2014-3-7 12:22:35 | 显示全部楼层
Llinuxu 发表于 2014-3-7 12:07
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)       
{
        u32 secpos;           //扇区地址

不是指这个,是指你这个函数里面调用的库函数,是有返回值的?  比如那个擦降xxxxerase(),比如那个写  halfwordwirte(),我说的是库函数写或擦除,是有返回值的哦!不是指你写的写函数;

出0入0汤圆

发表于 2014-3-7 12:54:20 | 显示全部楼层
可以手工模拟掉电信号,然后示波器看下总的时间。再看写的对不对

出0入0汤圆

 楼主| 发表于 2014-3-7 13:23:19 | 显示全部楼层
xjtyOnly51 发表于 2014-3-7 12:54
可以手工模拟掉电信号,然后示波器看下总的时间。再看写的对不对

我想过这样干哟,但是让单片机长时间工作在低电压下是不好的,我怕给烧坏了!

出0入0汤圆

发表于 2014-3-7 13:45:25 | 显示全部楼层
估计是时间不够长,我以前做别的单片机的时候也遇到过。

出0入4汤圆

发表于 2014-3-7 14:34:34 | 显示全部楼层
把电解电容加大一点呗

出0入12汤圆

发表于 2014-3-7 14:49:10 | 显示全部楼层
电池,写BKP

出0入0汤圆

发表于 2014-3-7 16:15:08 | 显示全部楼层
我是说电压先正常,模拟掉电信号。然后测试自己的掉电处理程序,看看backup和restore是否OK

出0入0汤圆

发表于 2014-3-7 16:40:20 来自手机 | 显示全部楼层
kinsno 发表于 2014-3-7 12:22
不是指这个,是指你这个函数里面调用的库函数,是有返回值的?  比如那个擦降xxxxerase(),比如那个写  halfw ...

对,这几个是基本的flash操作函数,只有他们返回成功才能继续写,看看这里先。。。或者把写入内容再读取回来并串口打印

出100入85汤圆

发表于 2014-3-7 21:30:02 | 显示全部楼层

似乎是这样,要电池,没电池保存不了的

出0入0汤圆

发表于 2014-3-8 07:30:29 | 显示全部楼层
Llinuxu 发表于 2014-3-7 13:23
我想过这样干哟,但是让单片机长时间工作在低电压下是不好的,我怕给烧坏了! ...

兄弟啊,你看你程序中写入用的是  STMFLASH_Write_NoCheck     这个函数,无检查表明你都不知道有没有写对,这是不对的,无效的写入还不如不写的,使用有检查的写入试试

出0入0汤圆

发表于 2014-3-8 08:59:43 | 显示全部楼层
“检测到掉电后保存到flash”和“数据没有保存成功”这个互相矛盾吧,感觉你没有把你现在的现象描述清楚

出0入0汤圆

 楼主| 发表于 2014-3-14 14:29:48 | 显示全部楼层
怎么还是没搞明白以前到底是什么原因,不过现在已经好了。虽然中间还是遇到了些问题,但现在都解决了。谢谢各位大神的帮忙!

出0入0汤圆

发表于 2014-4-8 23:50:22 | 显示全部楼层
现在已经好

出0入0汤圆

发表于 2014-4-9 00:41:59 来自手机 | 显示全部楼层
是什么问题呀?

出0入0汤圆

 楼主| 发表于 2014-4-12 18:57:18 | 显示全部楼层
wsh 发表于 2014-4-9 00:41
是什么问题呀?

具体我也不知道!可能是在保存前没有察除,察除flash是很费时间的!

出0入0汤圆

发表于 2014-4-24 15:33:49 | 显示全部楼层
也想学习下PVD检测掉电,方便分享下程序吗,谢谢!

出0入0汤圆

发表于 2014-4-24 15:51:18 | 显示全部楼层
2.9V....能完成这么多事啊.
我在外部供电到直流14V的时候开始保存,也只能正常保存两个扇区,
还是上电时先擦除了,掉电只做写动作.

出0入0汤圆

 楼主| 发表于 2014-4-24 17:03:56 | 显示全部楼层
wenunit 发表于 2014-4-24 15:51
2.9V....能完成这么多事啊.
我在外部供电到直流14V的时候开始保存,也只能正常保存两个扇区,
还是上电时先擦 ...

掉电的时候本来就基本只能写,但是写起来还是很快地~~根本不费时间,所以还是可以写很多的

出0入0汤圆

 楼主| 发表于 2014-4-24 17:08:02 | 显示全部楼层
tuowai 发表于 2014-4-24 15:33
也想学习下PVD检测掉电,方便分享下程序吗,谢谢!

void PVD_NVIC(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;
  
  /* Configure one bit for preemption priority */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  
  /* Enable the PVD Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);
}

void PVD_Init(void)
{
        EXTI_InitTypeDef EXTI_InitStructure;
        PWR_PVDLevelConfig(PWR_PVDLevel_2V9); // 设定监控的阀值
    PWR_PVDCmd(ENABLE); // 使能PVD
      
    EXTI_InitStructure.EXTI_Line = EXTI_Line16; // PVD连接到中断线16上
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //使能中断模式
    //EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//表示电压从低上升到高于阀值时产生中断
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//表示电压从高下降到低于阀值时产生中断
        //EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//表示电压上升或下降越过设定阀值时都产生中断
        EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能中断线
    EXTI_Init(&EXTI_InitStructure); // 初始化exti寄存器
}

上面的是初始化,在用的时候一定不要忘了RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
这些都做好好就可以直接在PVD_IRQHandler() 函数中调用,希望对你有帮助,如果还有不懂的再问我吧~

出0入0汤圆

 楼主| 发表于 2014-4-24 17:09:31 | 显示全部楼层
Llinuxu 发表于 2014-4-24 17:08
void PVD_NVIC(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;

不是在 PVD_IRQHandler() 中调用,而是在这个函数中干自己想干的事情~

出0入0汤圆

发表于 2014-4-26 09:21:28 | 显示全部楼层
Llinuxu 发表于 2014-4-24 17:08
void PVD_NVIC(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;

谢谢,到时去测试下,一直想着flash频繁写,会影响寿命的问题,这方法要可靠的话,可以减少很多麻烦了

出0入0汤圆

 楼主| 发表于 2014-4-28 09:19:19 | 显示全部楼层
tuowai 发表于 2014-4-26 09:21
谢谢,到时去测试下,一直想着flash频繁写,会影响寿命的问题,这方法要可靠的话,可以减少很多麻烦了 ...

我就是为了延长flash的寿命才这样做的~

出0入0汤圆

发表于 2014-4-28 14:56:31 | 显示全部楼层
Llinuxu
想请问下,看了看手册,STM32好象是检测VDD/VDDA,但VDD和VDDA一般都是稳压后的的吧,这样检测到掉电后,还够时间保存数据吗,我的数据会比较多?以前有用过STC的,那时数据量不大,且有专门的引脚检测,用的是检测稳压前的电源,那时数据不多,可以正常保存

出0入0汤圆

 楼主| 发表于 2014-4-30 14:29:28 | 显示全部楼层
tuowai 发表于 2014-4-28 14:56
Llinuxu
想请问下,看了看手册,STM32好象是检测VDD/VDDA,但VDD和VDDA一般都是稳压后的的吧,这样检测到掉 ...

保存数据其实是很快的,主要是擦出flash很费时间,所以你在程序中要处理,在掉电之前你要保证掉电保存数据的块是已经被擦出了的,光写数据可以写很多进去。再就是你可以把检测电平设置的高一点。当然如果你要保存的数据实在太大就只有想其他办法了~

出50入0汤圆

发表于 2014-4-30 15:02:12 | 显示全部楼层
要想检测到掉电并保存到FALSH,或者EEPROM,就别想了,都不可靠。

出0入0汤圆

 楼主| 发表于 2014-5-21 17:01:06 | 显示全部楼层
ground 发表于 2014-4-30 15:02
要想检测到掉电并保存到FALSH,或者EEPROM,就别想了,都不可靠。

那是因为做得不够完美或者需要保存的数据实在太多!

出0入0汤圆

发表于 2014-8-21 00:21:24 | 显示全部楼层
Llinuxu 发表于 2014-5-21 17:01
那是因为做得不够完美或者需要保存的数据实在太多!


stm8s 用外部电压检测IC搞过,数据量也不大,没有问题!
现在手上有个stm32也要这么搞,并且用自身的pvd,只是还没有测试不知道是否可行,希望不要出什么岔子!
ps:用是1500uF的电容

出0入0汤圆

发表于 2014-8-21 08:42:26 | 显示全部楼层
Junsea 发表于 2014-8-21 00:21
stm8s 用外部电压检测IC搞过,数据量也不大,没有问题!
现在手上有个stm32也要这么搞,并且用自身的pvd ...

你随便用一个外部中断就能完成这个活的,并且不需要特别的电容,有个普通的470啊220啊,也够了,至少足够我保存50个BYTE了;

出0入0汤圆

 楼主| 发表于 2014-9-1 15:52:51 | 显示全部楼层
kinsno 发表于 2014-8-21 08:42
你随便用一个外部中断就能完成这个活的,并且不需要特别的电容,有个普通的470啊220啊,也够了,至少足够我保 ...

外部中断!!没做过,不过好像你说得很有道理,关键是用外部中断你是怎么判断电压值的!

出100入101汤圆

发表于 2014-9-1 20:28:45 | 显示全部楼层
写flash时间过长

出0入0汤圆

 楼主| 发表于 2014-9-2 14:54:28 | 显示全部楼层

是你写太多了吧

出0入0汤圆

发表于 2014-9-2 15:16:59 | 显示全部楼层
flash写入 之前是需要先把对应的PAGE擦除的,擦除的时间比较长,还有可以用后备寄存器试一下

出0入0汤圆

发表于 2015-8-20 13:48:06 | 显示全部楼层
你的电容用的多大的啊?

出0入0汤圆

发表于 2015-8-20 21:31:39 | 显示全部楼层
要先解锁,擦除,然后等着进中断,中断里面只写,尽可能的短。

出0入0汤圆

 楼主| 发表于 2015-8-20 22:13:18 | 显示全部楼层
xld826 发表于 2015-8-20 21:31
要先解锁,擦除,然后等着进中断,中断里面只写,尽可能的短。

主要是要先擦除,中断中只要不擦出还是没问题的,谢谢

出0入0汤圆

发表于 2015-8-21 09:14:11 | 显示全部楼层
Llinuxu 发表于 2015-8-20 22:13
主要是要先擦除,中断中只要不擦出还是没问题的,谢谢

搞定了?

出0入0汤圆

 楼主| 发表于 2015-8-22 21:47:55 | 显示全部楼层

嗯,去年就搞定了

出0入0汤圆

发表于 2015-8-23 09:58:41 | 显示全部楼层
Mark一下,学习了

出0入0汤圆

发表于 2015-8-23 11:23:53 | 显示全部楼层
说明电压太低写入没有成功,要做掉电保存数据必须加大电容

出0入0汤圆

发表于 2015-8-23 20:19:41 来自手机 | 显示全部楼层
估计是电压问题

出0入0汤圆

发表于 2016-5-29 22:42:05 | 显示全部楼层
本帖最后由 gaoxiaohu110 于 2016-5-29 22:43 编辑
Llinuxu 发表于 2014-3-14 14:29
怎么还是没搞明白以前到底是什么原因,不过现在已经好了。虽然中间还是遇到了些问题,但现在都解决了。谢谢 ...


楼主这个问题是怎么解决的,我现在也是遇到了跟你相同的问题,搞得我头都大了,我用的是原子的写FLASH函数,能进掉电中断,但是始终不能成功写FLASH,我用的电容是0.2f的法拉电容,电容的容量应该不是问题。

出0入0汤圆

发表于 2016-5-29 22:56:19 | 显示全部楼层
mark!!这个写入函数不错!

出0入0汤圆

 楼主| 发表于 2016-5-30 13:51:02 | 显示全部楼层
gaoxiaohu110 发表于 2016-5-29 22:42
楼主这个问题是怎么解决的,我现在也是遇到了跟你相同的问题,搞得我头都大了,我用的是原子的写FLASH函 ...

1、看看在正常情况下你的flash操作是否正常
2、写入的数据是否过大
3、在掉电中断中千万不要有察除动作,也就是你得在程序其他地方将你要在掉电中断中要用到的flash先进行察除,在中断中只写

出0入0汤圆

发表于 2016-5-30 15:30:08 | 显示全部楼层
Llinuxu 发表于 2016-5-30 13:51
1、看看在正常情况下你的flash操作是否正常
2、写入的数据是否过大
3、在掉电中断中千万不要有察除动作, ...

怎样,将摖除函数和写函数分开?能分享程序吗?

出0入0汤圆

发表于 2016-5-30 16:20:34 | 显示全部楼层
弱弱问一句,PVD没有硬件对应的接口吧,不需要端口配置?

出0入0汤圆

发表于 2016-5-30 16:54:13 | 显示全部楼层
zeroXone 发表于 2016-5-30 16:45
没有硬件接口,直接检测vdd,但是有个阈值判定设置:PWR_PVDLevelConfig(),在【stm32f10x_pwr.c】库文件里 ...

其实初始化,楼主已经给出了。楼主说过摖除和中断写分开。我自己分开有问题,会保存不了数据。所以想问问楼主怎么实现。比如楼主的写程序如下:怎么分开操作。


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;        //写地址偏移           
                           NumToWrite-=secremain;        //字节(16位)数递减
                        if(NumToWrite>(STM_SECTOR_SIZE/2))
                        {
                                secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完
                        }
                        else
                        {
                                secremain=NumToWrite;//下一个扇区可以写完了
                        }
                }         
        }        
        FLASH_Lock();//上锁
}

出0入0汤圆

发表于 2016-5-30 17:05:56 | 显示全部楼层
zeroXone 发表于 2016-5-30 16:59
要不,你检查下你器件的型号,还有你操作的地址???。。。看是不是因为鞭长莫及 ...

之前试过用线性电源供电慢慢调小供电电压,断电,重新上电,可以保存到数据。但是立刻断电,再上电就保存不到数据。楼主那种方法可以实现立刻断电保存到数据。他说需要分开摖除,然后在中断写数据。。。想问怎么分开摖除和写入?

出0入0汤圆

发表于 2016-5-30 20:40:27 | 显示全部楼层
zeroXone 发表于 2016-5-30 16:59
要不,你检查下你器件的型号,还有你操作的地址???。。。看是不是因为鞭长莫及 ...

擦除和写入的函数如何分开,另外我用示波器检测,掉电瞬间电容放电,直接给mcu提供电源,会发现,电源不稳,毛刺特别大,大概过500ms,电压才正常,但此时,电压已经降到1.6v,还能完成写入吗?
能否贴出你的掉电检测电路,参考一下?

出0入0汤圆

 楼主| 发表于 2016-5-31 14:01:32 | 显示全部楼层
raydsp 发表于 2016-5-30 15:30
怎样,将摖除函数和写函数分开?能分享程序吗?

程序不敢分享的!我可是签了保密协议的

出0入0汤圆

 楼主| 发表于 2016-5-31 14:04:36 | 显示全部楼层
raydsp 发表于 2016-5-30 16:20
弱弱问一句,PVD没有硬件对应的接口吧,不需要端口配置?

初始化和一切配置好像我在前面是给出了的!写函数里面的察除只是做判断,你要自己之前先察除,然后写函数里面判断后就不会做察除动作

出0入0汤圆

发表于 2016-6-1 10:37:16 | 显示全部楼层
Llinuxu 发表于 2016-5-31 14:04
初始化和一切配置好像我在前面是给出了的!写函数里面的察除只是做判断,你要自己之前先察除,然后写函数 ...

摖除函数使用整页摖除FLASH_ErasePage(uint32_t Page_Address)还是FLASH_EraseOptionBytes(void)摖除?

出0入0汤圆

发表于 2016-6-3 08:11:49 | 显示全部楼层
本帖最后由 gaoxiaohu110 于 2016-6-3 08:13 编辑
zeroXone 发表于 2016-5-30 20:55
系统运行起来一段时候之后才启用掉电检测和Flash功能呀,这样就很好避免你这个类似上电不稳定的情况啊。
...


关键不是上电电压不稳,是掉电,5.5v法拉电容通过一个3.3V的稳压芯片,当电压在1.8V附近时,文波有120MV,会出现电压不稳的情况,中断里做个LED灯翻转,会看到led在不停的闪烁

出0入0汤圆

发表于 2016-6-3 10:47:32 | 显示全部楼层
zeroXone 发表于 2016-6-3 09:29
你是说程序还在挣扎,然后不停的进中断,然而你本意只进一次?进了中断搞个变量判断一下,宕机之前不再处 ...

这是一个方法,但是为什么会宕机呢,很奇怪的现象,在5.5v电容两端并联个10uf的电容滤波也不起作用?

出0入0汤圆

发表于 2016-6-3 11:34:49 | 显示全部楼层
经过几天调试,写出可以使用的STM32  PVD掉电存储数据,目前只能一个扇区内存储数据,不过应该够用。希望可以帮助有需要的人。代码可能不是很严谨,需自己改进。
写入数据修改(摖除与写入分开):
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)        //摖除
{
       
       
         
        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;                //实际偏移地址.0X08034000-0X08000000=0X00034000
        secpos=offaddr/STM_SECTOR_SIZE;                        //扇区地址  0~127 for STM32F103RBT6   16
        secoff=(offaddr%STM_SECTOR_SIZE)/2;                //在扇区内的偏移(2个字节为基本单位.)616
        secremain=STM_SECTOR_SIZE/2-secoff;                //扇区剩余空间大小   408
        if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围 4
        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[i];          
                        }
               
                }       
if(NumToWrite==secremain)break;//摖除跳出
        }       
                                 
}
void STMFLASH_Writego(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)        //中断写入
{
       
                         STMFLASH_Write_NoCheck(WriteAddr,pBuffer,NumToWrite);//写已经擦除了的,直接写入扇区剩余区间.
       FLASH_Lock();//上锁                         
}


PVD初始化与中断函数:
void NVIC_pvdConfiguration(void)
{ static u16 TEXT_Buffer[4];
  NVIC_InitTypeDef NVIC_InitStructure;

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//PVD
  NVIC_InitStructure.NVIC_IRQChannel = PVD_IRQn;//PVD_IRQChannel;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
  NVIC_Init(&NVIC_InitStructure);  


                    last_data[0]=lastNM;last_data[1]=lastNM2;//摖除之前需要将掉电存储到的数据转移到其他地方
                                                         STMFLASH_Write(FLASH_SAVE_LAST,(u16*)TEXT_Buffer,4);        
}
void ExterLineInterrupt(void)
{
    EXTI_InitTypeDef EXTI_InitStructure;
    EXTI_DeInit();
    EXTI_StructInit(&EXTI_InitStructure);
     PWR_PVDLevelConfig(PWR_PVDLevel_2V9); // ???????
    PWR_PVDCmd(ENABLE); // ??PVD
    EXTI_InitStructure.EXTI_Line = EXTI_Line16;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
}
void PVD_IRQHandler(void)
{
        static u16 TEXT_Buffer[4];
       

        LCD_LED=0;
                EXTI_ClearITPendingBit(EXTI_Line16);//clear bit;
          
                                                 STMFLASH_Writego(FLASH_SAVE_LAST,(u16*)TEXT_Buffer,4); //写入需要保存的数据

   if (PWR_GetFlagStatus(PWR_FLAG_PVDO)== SET) {
                 PWR_ClearFlag(PWR_FLAG_PVDO);
   
    }
  
}

出0入4汤圆

发表于 2019-3-20 09:10:32 | 显示全部楼层
供电电压影响flash读写,可以降低读写速度设置,调低flash电压等级,测试下。

出0入0汤圆

发表于 2019-3-20 10:20:09 | 显示全部楼层
最好加个电池。

出0入0汤圆

发表于 2020-9-7 06:00:34 | 显示全部楼层
Llinuxu 发表于 2014-3-7 11:07
不是的哟,写入flash的函数是已经执行完了的,我写在那个函数后面的代码都是执行了的哟!但就是没有保存 ...

flash写入没错的话估计是保存的flash地址错误
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-2 07:34

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

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