学习STM32F407的FLASH编程,碰到一个超郁闷的问题,耗了哥2个晚上啊!!!

2019-07-20 04:33发布

昨天搞到3点多,今晚又搞到2半....
终于被我发现问题了.
现象:
如下代码:
//从指定地址开始写入指定长度的数据 //该函数对OTP区域也有效!可以用来写OTP区! //OTP区域地址范围:0X1FFF7800~0X1FFF7A0F //WriteAddr:起始地址(此地址必须为4的倍数!!) //pBuffer:数据指针 //NumToWrite:字(32位)数(就是要写入的32位数据的个数.)  void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite) u8 status=0; u32 addrx=0; u32 endaddr=0;   if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return; //非法地址 STMFLASH_Unlock(); //解锁   addrx=WriteAddr; //写入的起始地址 endaddr=WriteAddr+NumToWrite*4; //写入的结束地址 if(addrx<0X1FFF0000) //只有主存储区,才需要执行擦除操作!! { while(addrx<endaddr) //扫清一切障碍.(对非FFFFFFFF的地方,先擦除) { if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区 {   
                                printf("S"); status=STMFLASH_EraseSector(STMFLASH_GetFlashSector(addrx)); if(status)break; //发生错误了 }else addrx+=4; } if(status==0) { while(WriteAddr<endaddr)//写数据 { if(STMFLASH_WriteWord(WriteAddr,*pBuffer))//写入数据 break; //写入异常 } WriteAddr+=4; pBuffer++; STMFLASH_Lock();//上锁 } 
红 {MOD}的printf,加上,程序运行正常.
红 {MOD}的printf去掉,程序随即进入死循环,死在等待FLASH空闲里面,一旦JTAG仿真,并设置断点在这里,则可以不要printf,也可以正常运行.
非常诡异.

试过的方法:
1,找官方代码替换掉我的代码,结果,失败.
2,把printf,换成延时,失败.
3,把代码结构改了,失败.
4,把printf,换成直接写DR的方式发送,失败.
5,清FLASH->SR标记位,失败.
6,将系统的delay_us,换成i--之类的延时,失败.
7,加多等待FLASH操作结束,失败.
...

总之,2个晚上,就在不停的尝试各种可能的解决方案.不停的刷代码,估计这板子上的F4,都快要被我刷爆了...


最后,眼看着今晚又要3点了,万念俱灰之际,找来stm32f4的编程手册(其实一直在看,寄存器看了N遍了...),发现

这感情十分吻合啊,bus stall...
shit,才想起来,在系统时钟初始化的时候,默认是设置了DATA FETCHES的,仿真看下FLASH->ACR的DCEN位,果然是1.

立即修改代码如下:
//从指定地址开始写入指定长度的数据 //该函数对OTP区域也有效!可以用来写OTP区! //OTP区域地址范围:0X1FFF7800~0X1FFF7A0F //WriteAddr:起始地址(此地址必须为4的倍数!!) //pBuffer:数据指针 //NumToWrite:字(32位)数(就是要写入的32位数据的个数.)  void STMFLASH_Write(u32 WriteAddr,u32 *pBuffer,u32 NumToWrite) u8 status=0; u32 addrx=0; u32 endaddr=0;   if(WriteAddr<STM32_FLASH_BASE||WriteAddr%4)return; //非法地址 STMFLASH_Unlock(); //解锁    FLASH->ACR&=~(1<<10); //FLASH擦除期间,必须禁止数据fetch!!!搞了我两晚上才发现这个问题! addrx=WriteAddr; //写入的起始地址 endaddr=WriteAddr+NumToWrite*4; //写入的结束地址 if(addrx<0X1FFF0000) //只有主存储区,才需要执行擦除操作!! { while(addrx<endaddr) //扫清一切障碍.(对非FFFFFFFF的地方,先擦除) { if(STMFLASH_ReadWord(addrx)!=0XFFFFFFFF)//有非0XFFFFFFFF的地方,要擦除这个扇区 {    status=STMFLASH_EraseSector(STMFLASH_GetFlashSector(addrx)); if(status)break; //发生错误了 }else addrx+=4; } if(status==0) { while(WriteAddr<endaddr)//写数据 { if(STMFLASH_WriteWord(WriteAddr,*pBuffer))//写入数据 break; //写入异常 } WriteAddr+=4; pBuffer++; } FLASH->ACR|=1<<10; //FLASH擦除结束,开启数据fetch STMFLASH_Lock();//上锁 } 
下载,测试....

奇迹出现了...运行正常了.
我勒个去...

两个晚上,换来2行代码.....

诶,说起来都是泪啊,谁怪我没好好看看编程手册,早点看到这里就好了....

本来今晚想早点解决看个电影再睡觉的...
计划赶不上变化...
夜深了,明天还要上班,洗洗睡了....


此文,献给那些和我一样,被一个傻逼的问题搞到傻逼的人....

















































友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。