【图文解说】基于飞思卡尔MC9S12XS的Flash擦除和写入操作
来源:互联网 发布:开淘宝店卖什么比较好 编辑:程序博客网 时间:2024/06/04 18:01
关于Flash的擦除和写入,真的是让我最费力的一部分,网上的相关资料很少,好不容易找到了一点相关代码,却发现程序不能正常的运行,而且更令人无解的是程序本身怎么检查都检查不出错误。好啦,一点一点的说说我的辛酸史。
至于擦除和写入的原理是什么,这个不是我们关心的,我也不去赘述,我主要说明一下相关的具体操作。
我们主要是对飞思卡尔Flash中的PFlash即存放程序段的Flash进行操作。如图:
步骤大概分为:
1、设置Flash分频寄存器:
Flash的操作对频率有一定的要求,过低擦除不成功,过高会损毁Flash,如图为:MC9S12XS128的FCLKDIV寄存器,所有位都是可读的但是只有7位可写入。至于应该如何设置分频数,有一张表格可以参考:
如表格说明,分频数是根据外部时钟来定的,MC9S12XS128的外部时钟是16MHz,所以我选择了0x10作为分频数。
给出一一些具体的代码:
/*********************************************************** ** 名 称:void PFlash_Init(void) ** 功 能:PFlash初始化 ** 入口参数:无 ** 出口参数:无 ** 使用说明:无 ************************************************************/ void PFlash_Init(void){ while(FSTAT_CCIF==0); //等待正在处理的Flash操作,即CCIF=1时,操作完成 FCLKDIV=0x10; //外部晶振为16MHz,Flash时钟设置为1MHz FCNFG=0x00; //禁止中断 while(FCLKDIV_FDIVLD==0); //等待时钟设置成功,即FDIVLD为1时设置成功}这里补充一下对FCLKDIV_FDIVLD的说明
2、FSTAT状态寄存器
在上面的代码中出现了一行“while(FSTAT_CCIF==0);”,这就涉及到一个很重要的寄存器,就是Flash操作的状态寄存器,就像是Flash操作步骤中的“红绿灯”一样,告诉程序什么时候可以执行什么操作,什么时候必须要等待一下。如图:
其中我们比较关心的是CCIF位、ACCERR位和FPVIOL位,这三位也都是可读可写的。
CCIF:指令完成标志位,当CCIF位为1时,表示上一个Flash操作完成了。注意图中的高亮部分,如果想要使当前操作的指令完成,需要手动将CCIF清零(标志位置位就是令标志位为0,但具体操作是令标志位等于1),才能触发指令,令指令完成,也就是前面流程图中说明的,才能launch指令。
ACCERR和FPVIOL:这两位主要标志是否有错误操作发生,当为1时,说明检测到错误。那检测到作物怎么办呢?解决方法也比较奇葩,将两个标志位清零(清零操作如上)就行,,,,,至于什么原理,我也不太明白。数据手册如图,强烈建议还是自己读一下原文,很有好处。
再给出一些具体的代码:
CCIF的操作代码:
FSTAT_CCIF=1; //启动执行命令,即launch指令while(FSTAT_CCIF==0); //等待执行完成
ACCERR和FPVIOL的操作代码:
if(FSTAT_ACCERR) //判断并清除标志位; FSTAT_ACCERR=1; //将标志位清零 if(FSTAT_FPVIOL) //判断并清除标志位; FSTAT_FPVIOL=1; //将标志位清零
注意点:说实话,当时我自己写程序的时候,就对标志位清零操作感到非常的疑惑,说好的清零操作呢,为什么是令标志位为等于1?后来才想明白,对于标志位,写0等效于没有操作,写1代表清零。原因主要有两点:
1) 标志位为1一般表示有什么事情发生啦,对于标志位什么时候为1,应该是单片机根据具体的情况作出自己的判断,是根据实际情况来置1的,而不应该是人为的置1。
2) 如果某次操作我们只想对状态寄存器中的某一位或某几位进行操作,那么对其余位就必须没有任何的影响,如果规定写0时等效于无操作。
3、执行具体的指令
将分频和状态寄存器弄好后,就可以开开心心的执行具体的指令啦。指令具体的指令主要涉及到FCCOBIX寄存器和FCCOB寄存器:
FCCOBIX寄存器和FCCOB寄存器必须要配合使用。FCCOBIX进行选择,然后往FCCOB中写入具体的指令、地址和数据。Flash操作命令表如图:
这里我们只关心P-Flash的擦除和写入操作。
P-Flash的擦除操作:如图,;令CCOBIX为000,往FCCOB中写入0x0A和高地址位,对照指令表,0X0A表示擦除操作,高地址位就是Global address模式下地址的高八位。然后令CCOBIX为001,往FCCOB写入Global address模式下地址的第八位,就可以擦除你想要的擦除的地址片区。
/*********************************************************** ** 名 称:void PFlash_Erase(word ADDR16) ** 功 能:擦除P-FLASH的一个分区 ** 入口参数:无 ** 出口参数:无 ** 使用说明:无 ************************************************************/ void PFlash_Erase(word ADDR16){ while(FSTAT_CCIF==0); if(FSTAT_ACCERR) //判断并清除标志位; FSTAT_ACCERR=1; if(FSTAT_FPVIOL) //判断并清除标志位; FSTAT_FPVIOL=1; FCCOBIX_CCOBIX=0x00; FCCOB=0x0A7E; //写入擦除命令和高位地址,0A是指令,7E是高地址位 FCCOBIX_CCOBIX=0x01; FCCOB=ADDR16; //写入低16位的地址 FSTAT_CCIF=1; //启动执行命令 while(FSTAT_CCIF==0); //等待执行完成 }
P-Flash的写入操作:写入操作和擦除操作是差不多的:
模式是不是和擦除操作很像。CCOBIX为000和001时的含义和擦除操作是完全一样的。主要讲一下CCOBIX为010~101时的含义。因为MC9S12XS128规定Flash写入时,必须一次性写入8个字节,,,是的就是这么蛋疼。不多说啦,直接来一些具体的代码,就很好理解啦。
/*********************************************************** ** 名 称:void PFlash_Write(uint16 ADDR16) ** 功 能:向PFLASH写入数据 ** 入口参数:无 ** 出口参数:无 ** 使用说明:无 ************************************************************/void PFlash_Write(word ADDR16) { byte i,j; //i为Buffer的下标,j为string的下标 for (i=0,j=0;i<4;i++,j++) { Buffer[i]=0x0000; Buffer[i]=Buffer[i]|(string[j]<<8); j++; Buffer[i]=Buffer[i]|string[j]; } while(FSTAT_CCIF==0); if(FSTAT_ACCERR) //判断并清除标志位; FSTAT_ACCERR=1; if(FSTAT_FPVIOL) //判断并清除标志位; FSTAT_FPVIOL=1; FCCOBIX_CCOBIX=0x00; FCCOB=0x067E; //写入命令和高位地址(06是对P-Flash进行固化的指令) FCCOBIX_CCOBIX=0x01; //地址后16位 FCCOB=ADDR16; //写入低16位地址 FCCOBIX_CCOBIX=0x02; //写入第一个数据 FCCOB=Buffer[0]; FCCOBIX_CCOBIX=0x03; //写入第二个数据 FCCOB=Buffer[1]; FCCOBIX_CCOBIX=0x04; //写入第三个数据 FCCOB=Buffer[2]; FCCOBIX_CCOBIX=0x05; //写入第四个数据 FCCOB=Buffer[3]; FSTAT_CCIF=1; //写入执行命令 while(FSTAT_CCIF==0); //等待执行完毕 }这段程序理解起来应该没有问题吧。
4、最后一步:
好啦,看到这里是不是想要自己写一个Flash操作代码尝试一下,然后你单步调制的时候会发现太好啦,终于擦除和写入啦,然后开始全速运行,咦,发现程序跑飞啦,不放弃,接着尝试,然后怎么检查都检查不出错误来,单步运行就是可以,全速运行就是不可以,反复多次,你会感到抓狂,会感到。
好啦好啦,不瞎扯啦,其实这个问题也困扰了我很久,因为我没有系统的学习过单片机,终于,在TI的论坛上,没错,你没有看错,一个飞思卡尔的问题最终在TI论坛上找到了解决方法(吐槽一下,飞思卡尔真是奇葩,资料超少,软件也超贵,相关的论坛也超冷淡。相比来说,TI做的就很好,资料很多,软件免费而且好用,论坛也很火)。
其实原因是,Flash不能对本身就行操作,也就是说在Flash中的代码不能对Flash进行操作,必须转移到RAM中才可以。怎么解决这个问题呢,我自己用的是#pragma关键字,再配合上codewarrior的.prm文件,就可以啦,全速运行下没有问题。
#pragma CODE_SEGFLASH_RAM //在.prm文件中将FLASH_RAM定义在RAM区中
// 对flash进行操作的代码
#pragma CODE_SEG DEFAULF
关于#pragma和.prm怎么用,又是另一个主题啦,在这里就不赘述。
除此之外还有一个方法,就是利用RELOCATE_TO,至于RELOCATE_TO怎么用,也是另外一个话题,在这里给出一些资料,要用到的同学可以自己去看看。
关于RELOCATE_TO的关键定义:
Inthis example, references to functions in CODE_RELOC use addresses from 0x1000to 0x1FFF area, but the code is programmed from 0x8000 to 0x8FFF.
来自http://blog.sina.com.cn/s/blog_83b3bb460100tesw.html
至此,flash的操作就讲完啦,其他操作也都是换汤不换药。
如果
大家如果需要数据手册,可以搜一下“MC9S12XS256RMV1.pdf”,其中就包含了MC9S12XS系列的所有单片机。
你还有什么疑问,可以联系QQ:3463758699
- 【图文解说】基于飞思卡尔MC9S12XS的Flash擦除和写入操作
- 【转载】图文解说:基于飞思卡尔MC9S12XS的Flash擦除和写入操作
- 基于飞思卡尔MC9S12XS的Flash擦除和写入操作
- 关于Msp430 Flash型单片机内部Flash的操作——即片内Flash的擦除、写入、读取
- flash的读写和擦除
- linux下擦除、写入flash的简单编程参考
- flash的读写擦除
- 飞思卡尔 HCS12(x) memory map解说(1)
- 飞思卡尔 HCS12(x) memory map解说之2
- 飞思卡尔 HCS12(x) memory map解说之3
- 飞思卡尔 HCS12(x) memory map解说(1) .
- 飞思卡尔 HCS12(x) memory map解说之2 .
- 飞思卡尔 HCS12(x) memory map解说之3 .
- 飞思卡尔 HCS12(x) memory map解说(1) .
- 飞思卡尔 HCS12(x) memory map解说之2 .
- 飞思卡尔 HCS12(x) memory map解说之3 .
- 归纳STM32 FLASH 擦除(以及如何防止误擦除程序代码)、写入、读取方法
- AMD flash擦除和编程源代码
- Hibernate使用注意
- Java从入门到上天 — — 你不能错过的11本好书
- 被说了很多遍的设计模式---模板方法模式
- 单机版solr6.2.1搭建window
- 响应式设计中的 HTML5
- 【图文解说】基于飞思卡尔MC9S12XS的Flash擦除和写入操作
- 车辆违章查询API 封装
- iOS 解决使用Cell的复用导致视图重叠的问题
- 一个简单的hibernate连接oracle数据库例子
- 第八章上机练习1 自己做的
- linux安装多系统之后启动等待90秒的解决办法
- Windows2008R2+IIS7.5+ASP+SQLServer2008访问慢的原因
- Android Activity启动流程源码全解析(2)
- 粒子群算法