飞思卡尔MC9S12G系列单片机flash擦写
飞思卡尔MC9S12G系列单片机flash擦写
- 第一张图:Flash模块功能框图
- 第二张图:寄存器描述
- FCLKDIV(Flash时钟分配寄存器)
- FCCOBIX(Flash CCOB索引寄存器)
- FCCOB(Flash指令寄存器)
- FSTAT(Flash状态寄存器)
- 第三张图:Flash擦写操作流
- Flash的擦写注意事项
- 编码实现
- prm文件设置
- Flash擦写头文件
- Flash擦写源文件
- ROM中程序复制到RAM中函数
最近在学习飞思卡尔MC9S12G系列单片机底层驱动,看了很多,目前理解还不深,处于入门菜鸟级别,仅在此记录下学习心得,后续会在实操中强化底层驱动开发能力,不能老是处于光说不练,搞些假把式。好了,言归正传。本文主要记录笔者基于MC9S12G系列单片机flash擦写,还望各路大神路过时,可指点一番。
Flash本身是非易失性存储,可以通过编程的方式擦写其中的内容,掉电后其内容不会丢失,一般是单片机的程序存储位置。单片机运行时先将Flash中下一条运行的程序读出,然后执行其内容,再读出下一条指令,再执行循环往复。通过擦写flash能够实现单片机应用程序自动更新。
G128系列单片机,查阅芯片手册,获得数据如下:
• 128Kbytes of P-Flash (Program Flash) memory
• 4 Kbytes of EEPROM memory
可以看出,G128系列单片机的Flash存储大小有128KB, 其全局地址范围为: 0x2_0000 - 0x3_FFFF。在这里可通过以下链接,熟悉并理解MC9S12G128内存映射。
MC9S12G128内存映射(本地地址,逻辑地址,全局地址)
第一张图:Flash模块功能框图
上图直接告诉我们,对flash操作其实不是直接对每个Flash存储区进行操作,而是通过控制Flash Interface进行的。具体就是操作Flash Interface的寄存器,再进而操作Flash存储区。那么寄存器有哪些?具体怎么操作?看第二张图。
第二张图:寄存器描述
Flash模块有20个控制和状态寄存器。上图是从芯片手册截取的一部分。但对于Flash模块而言关键寄存器就是图中圈住的几个。下面依次来介绍一下:
FCLKDIV(Flash时钟分配寄存器)
先上图(截取自芯片手册)
上图告诉我们:有三个寄存器需要处理(FDIVLD,FDIVLCK,FDIV):
FDIV寄存器:有六位,通过分频将总线时钟频率分频至1MHz以下从而使Flash控制器可以正常工作。FDIV的值与总线时钟频率有关,根据总线频率的大小确定FDIV的值(见上表),假如当前我的总线频率为16MHz,查表中16MHz在15.6与16.6之间,那么FDIV的值就是0x0F了。当确定好Flash控制器的频率后,需要将其写保护,以防误操作修改了分频寄存器,那么对FDIVLCK写1,当FDIVLCK写入1后,除非重启,否则FDIV的值不能被修改,重启后FDIVLCK的值将重新归零。
由此总结我们Flash控制器的时钟设置步骤如下:
- 根据总线频率设置分频FDIV
- 对分频进行保护,将FDIVLCK置为1
FCCOBIX(Flash CCOB索引寄存器)
先上图(截取自芯片手册)
上图告诉我们,这个寄存器是FCCOB的索引寄存器,CCOBIX[2:0] 只有三位,即8种状态。具体如何索引,看下图:
The CCOBIX bits are used to select which word of the FCCOB register
array is being read or written to.
FCCOBIX的两位决定当前读取或者写入FCCOB的是哪一个word(一般而言一个word在单片机中指两个字节),也就是说FCCOB是一个多word的寄存器,通过FCCOBIX来确定当前操作或者读取的是哪一位。具体如何操作,我们要来看看FCCOB寄存器。FCCOBIN和FCCOB这两个寄存器得结合起来看。
FCCOB(Flash指令寄存器)
上图告诉我们:FCCOB是一个六个word长度的数组,通过FCCOBIX寄存器来定位当前操作的是哪个word。一个word是16位的,前[7:0]位Low,后[15:8]为High。
由于FCCOB只有6个word长,所以FCCOBIX范围为0x00-0x05,也就是说当FCCOBIX = 0x00时,读写FCCOB寄存器操作第0个word的内容,当FCCOBIX = 0x01时,读写FCCOB寄存器操作第1个word的内容,以此类推。也就是说我们操作FCCOB实际内容是由FCCOBIX这个索引寄存器来控制的
FSTAT(Flash状态寄存器)
先上图(截取自芯片手册)
上图告诉我们:
CCIF:用来显示一个Flash指令是否已经执行完成
若CCIF = 0 则表示Flash控制器正在执行指令
若CCIF = 1则表示Flash控制器当前空闲,前一条指令已经执行完毕。
除此以外,CCIF的重要作用就是让Flash控制器开始执行指令,由于Flash控制器的指令内容需要在开始前先行准备到Flash指令寄存器中,当指令准备完成后,通过将CCIF位置1就可以使Flash控制器执行当前写入在指令寄存器中的指令。需要注意的是,当Flash需要执行下一条指令前,务必要检查前一条指令是否已经执行完毕,即CCIF是否为1,若CCIF = 1则再写入1方可执行指令寄存器中的内容。
第三张图:Flash擦写操作流
先上图(截取自芯片手册)
上图告诉我们:
1.FCLKDIV时钟分频寄存器初始化,确定分频因子
2.检查命令缓冲区(FSTAT_CCIF)是否为空
3.对读写错误(FSTAT_ACCER)标志位清零(写1清零)
4.对保护区编程错误(FSTAT_PVIOL)标志位清零(写1清零)
5.对索引寄存器(FCCOBIX)赋值0x00,写入FCCOB编程命令0x06
6.对索引寄存器(FCCOBIX)赋值0x01,写入FCCOB全局地址(写入的首地址)
7.将编程的数据赋值给要编程的Flash地址
8.检查是否还有新的数据需要写入Flash,如有转到第5步
9.等待,直到命令完成标志位(FSTAT_CCIF)置位
Flashde的擦除操作流类似,即将第5步改为如下,去掉第7、8步:
5.对索引寄存器(FCCOBIX)赋值0x00,写入FCCOB擦除命令0x0A
Flash的擦写注意事项
由于在Flash的擦除和写入中,Flash是不能读的,故擦除和写入Flash的程序要放到RAM中去,即:在Flash擦除或写入之前,要把擦除和写入的可执行代码复制到RAM中去,并让程序在RAM中执行。如果没有注意此事项,程序会跑飞。如何解决这个问题,查找资料获知如下:
使用#pragma关键字,配合codewarrior的.prm文件
#pragma CODE_SEGFLASH_RAM //在.prm文件中将FLASH_RAM定义到RAM区中
//对flash进行操作的代码
#pragma CODE_SEG DEFAULT
关于codewarrior的.prm文件的结构可参考如下博主的文章,描述的很清晰:
飞思卡尔MC9S12(X)系列的内存资源分配和.prm文件的结构
编码实现
prm文件设置
NAMES ENDSEGMENTS/* Register space *//* IO_SEG = PAGED 0x0000 TO 0x03FF; intentionally not defined */
/* RAM */ RAM = READ_WRITE 0x2000 TO 0x3BFF; CODE_RAM = READ_WRITE 0x3C00 TO 0x3FFF; /*1 kB for flash read and write*/
/* D-Flash */ DFLASH = READ_ONLY 0x000400 TO 0x0013FF;
/* non-paged FLASHs */ ROM_1400 = READ_ONLY 0x1400 TO 0x1FFF;ROM_BOOT = READ_ONLY 0x4000 TO 0x43FF; ROM_FLASH = READ_ONLY 0X4400 TO 0x47FF RELOCATE_TO 0x3C00; // 1KB for necessary flash operationROM_C000 = READ_ONLY 0xC000 TO 0xFEFF; /* VECTORS = READ_ONLY 0xFF00 TO 0xFFFF; intentionally not defined: used for VECTOR commands below */ //OSVECTORS = READ_ONLY 0xFF80 TO 0xFFFF; /* OSEK interrupt vectors (use your vector.o) */
/* paged FLASH: 0x8000 TO 0xBFFF; addressed through PPAGE */PAGE_08 = READ_ONLY 0x088000 TO 0x08BFFF; PAGE_09 = READ_ONLY 0x098000 TO 0x09BFFF; PAGE_0A = READ_ONLY 0x0A8000 TO 0x0ABFFF; PAGE_0B = READ_ONLY 0x0B8000 TO 0x0BBFFF; PAGE_0C = READ_ONLY 0x0C8000 TO 0x0C93FF; PAGE_0C_A000 = READ_ONLY 0x0CA000 TO 0x0CBFFF; PAGE_0E = READ_ONLY 0x0E8000 TO 0x0EBFFF;
/* PAGE_0D = READ_ONLY 0x0D8000 TO 0x0DBFFF; not used: equivalent to ROM_4000 */
/* PAGE_0F = READ_ONLY 0x0F8000 TO 0x0FBEFF; not used: equivalent to ROM_C000 */
ENDPLACEMENT /* here all predefined and user segments are placed into the SEGMENTS defined above. */ _PRESTART, /* Used in HIWARE format: jump to _Startup at the code start */ STARTUP, /* startup data structures */ ROM_VAR, /* constant variables */ STRINGS, /* string literals */ VIRTUAL_TABLE_SEGMENT, /* C++ virtual table segment */ //.ostext, /* OSEK */NON_BANKED, /* runtime routines which must not be banked */COPY /* copy down information: how to initialize variables */ /* in case you want to use ROM_4000 here as well, make sure that all files (incl. library files) are compiled with the option: -OnB=b */ INTO ROM_C000/*, ROM_1400, ROM_4000*/;BOOTLOADER INTO ROM_BOOT; FLASH_CODE INTO ROM_FLASH;USER_APP INTO PAGE_08; TEST_AREA INTO PAGE_09; /* physical address from 0x2_4000 */DEFAULT_ROM INTO PAGE_0A, PAGE_0B, PAGE_0C, PAGE_0C_A000, PAGE_0E; //.stackstart, /* eventually used for OSEK kernel awareness: Main Stack Start */ SSTACK, /* allocate stack first to avoid overwriting variables on overflow */ //.stackend, /* eventually used for OSEK kernel awareness: Main-Stack End */ DEFAULT_RAM INTO RAM;//.vectors INTO OSVECTORS; /* OSEK */
ENDENTRIES /* keep the following unreferenced variables */ /* OSEK: always allocate the vector table and all dependent objects */ //_vectab OsBuildNumber _OsOrtiStackStart _OsOrtiStart
ENDSTACKSIZE 0x100VECTOR 0 _Startup /* reset vector: this is the default entry point for a C/C++ application. */
//VECTOR 0 Entry /* reset vector: this is the default entry point for an Assembly application. */
//INIT Entry /* for assembly applications: that this is as well the initialization entry point */VECTOR ADDRESS 0xFFD6 SCI0_INT_receive
Flash擦写头文件
在这里插入代码片
Flash擦写源文件
在这里插入代码片
ROM中程序复制到RAM中函数
在这里插入代码片
飞思卡尔MC9S12G系列单片机flash擦写相关推荐
- freescale飞思卡尔 HC9S12 系列单片机 Flash擦写详解(一)之时钟设置
Flash擦写的内容,个人做HC9S12系列单片机时觉得应该是各模块内容中最难而且是最麻烦的一步了.只有能够对Flash进行擦写以后,所做的Bootloader才有真正手段将串口或者其他通讯手段接收到 ...
- freescale飞思卡尔 HC9S12 系列单片机 Flash擦写详解(三)之Flash控制器指令执行
前面我们介绍了Flash主要的几个寄存器,如果还有其他的疑问可以再返回去看看或者直接查阅S12系列单片机的手册中相关的内容.这一节我将介绍Flash控制器指令执行的过程,并举出相关的例子,希望能够起到 ...
- STM32系列内部Flash擦写程序
stm32内部Flash擦写流程,对于FLash必须按页擦写,不同型号的flash页大小不同,需要根据实际修改 #define FLASH_PAGE_SIZE 2048 //定义Flash页大小,RC ...
- 飞思卡尔MKL系列单片机用jlink烧写程序出现的Kinetis (connect): Timeout while halting CPU. CPU does not stop.问题
最近用Jlink烧写飞思卡尔MKL16Z128单片机时发现经常出现不能连接成功的情况,用的是SWD接口,排查了好久后来发现问题在单片机的RESET脚上,因为之前用SWD接口的时候只接4线(SWD.SC ...
- 飞思卡尔Kinetis系列单片机被锁住后,怎么解锁
Kinetis提供了相当可靠地知识产权保护机制:人为的给芯片上锁,这个对量产后的产品是必须的.但是,用户误擦写了芯片内部security的内存部分(0x400~0x40F),从而锁住了芯片:难道芯片就 ...
- 飞思卡尔MC9S12系列单片机地址影射以及分页问题
对于用MCU的人来说,不一定要明白HCS12(x) memory map的机制和联系.因为如果没有系统地学习操作系统和编译原理之类的课程,确实有些难度.并且,对于DG128 XS128这样的MCU,默 ...
- 关于飞思卡尔S12系列单片机SPI通信MODRR配置
MODRR为模块路径选择寄存器,作为CAN0/4与SPI0/1/2映射引脚. 例如选择CAN0为PM0/1引脚,则配置MODRR_MODRR0&1=0.当MODRR_MODRR4=0时,SPI ...
- STM32G0系列将内部FLASH作为EEPROM使用,巧妙编程,可延长Flash擦写寿命上百倍,已用于量产产品。
STM32内部flash可以用作EEPROM,用于保存用户数据. 1.一般来说,stm32的flash擦写寿命只有10万次,如果在同一位置擦写过于频繁,在产品质保期内FLASH就会达到寿命极限,保存数 ...
- 【飞思卡尔 MC9S12】内部Flash读写
上一篇:[飞思卡尔 MC9S12]PRM文件与内存映射(Flash.RAM.EEE) 上一篇讲到PRM文件与内存映射,其中有个重要寄存器叫做GPAGE,可以全局访问所有地址范围,Flash操作也是基于 ...
- ftm模块linux驱动,飞思卡尔k系列_ftm模块详解.doc
飞思卡尔k系列_ftm模块详解 1.5FTM模块1.5.1 FTM模块简介FTM模块是一个多功能定时器模块,主要功能有,PWM输出.输入捕捉.输出比较.定时中断.脉冲加减计数.脉冲周期脉宽测量.在K1 ...
最新文章
- android技术下载
- junit--eclipse插件
- JAVA总结之数组篇
- Iris——整合go-playground/validator参数校验Demo
- centos6系列版本防火墙图形化设置
- ZOJ 1586 QS Network
- Less or Equal(CF-977C)
- python 计算相关系数和决定系数
- Matlab系列教程_基础知识_基本矩阵操作
- Python已经超过了JAVA?
- 大物实验计算弹性模量_什么是材料的杨氏模量?它的定义与计算公式是什么?...
- [Unity]CutScene工具Cinema Suite Rotion 角度不能负数方向旋转的bug修正。
- 信息安全快讯丨桃李满天下,金秋谢师恩——教师节快乐!
- pppo服务器光信号亮红灯,光纤猫光信号闪红灯不能上网怎么办
- js一键复制并调起微信客户端
- 如何治理谐波问题?——有源滤波器
- 面向对象的三大基本特征和六大基本原则
- hyperterminal使用教程_hyperterminal 教程
- pycharm远程连接服务器问题Uploading PyCharm helpers Python Interpreter... Python helpers are not copied yet
- Google Earth 背后的故事