飞思卡尔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控制器的时钟设置步骤如下:

  1. 根据总线频率设置分频FDIV
  2. 对分频进行保护,将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擦写相关推荐

  1. freescale飞思卡尔 HC9S12 系列单片机 Flash擦写详解(一)之时钟设置

    Flash擦写的内容,个人做HC9S12系列单片机时觉得应该是各模块内容中最难而且是最麻烦的一步了.只有能够对Flash进行擦写以后,所做的Bootloader才有真正手段将串口或者其他通讯手段接收到 ...

  2. freescale飞思卡尔 HC9S12 系列单片机 Flash擦写详解(三)之Flash控制器指令执行

    前面我们介绍了Flash主要的几个寄存器,如果还有其他的疑问可以再返回去看看或者直接查阅S12系列单片机的手册中相关的内容.这一节我将介绍Flash控制器指令执行的过程,并举出相关的例子,希望能够起到 ...

  3. STM32系列内部Flash擦写程序

    stm32内部Flash擦写流程,对于FLash必须按页擦写,不同型号的flash页大小不同,需要根据实际修改 #define FLASH_PAGE_SIZE 2048 //定义Flash页大小,RC ...

  4. 飞思卡尔MKL系列单片机用jlink烧写程序出现的Kinetis (connect): Timeout while halting CPU. CPU does not stop.问题

    最近用Jlink烧写飞思卡尔MKL16Z128单片机时发现经常出现不能连接成功的情况,用的是SWD接口,排查了好久后来发现问题在单片机的RESET脚上,因为之前用SWD接口的时候只接4线(SWD.SC ...

  5. 飞思卡尔Kinetis系列单片机被锁住后,怎么解锁

    Kinetis提供了相当可靠地知识产权保护机制:人为的给芯片上锁,这个对量产后的产品是必须的.但是,用户误擦写了芯片内部security的内存部分(0x400~0x40F),从而锁住了芯片:难道芯片就 ...

  6. 飞思卡尔MC9S12系列单片机地址影射以及分页问题

    对于用MCU的人来说,不一定要明白HCS12(x) memory map的机制和联系.因为如果没有系统地学习操作系统和编译原理之类的课程,确实有些难度.并且,对于DG128 XS128这样的MCU,默 ...

  7. 关于飞思卡尔S12系列单片机SPI通信MODRR配置

    MODRR为模块路径选择寄存器,作为CAN0/4与SPI0/1/2映射引脚. 例如选择CAN0为PM0/1引脚,则配置MODRR_MODRR0&1=0.当MODRR_MODRR4=0时,SPI ...

  8. STM32G0系列将内部FLASH作为EEPROM使用,巧妙编程,可延长Flash擦写寿命上百倍,已用于量产产品。

    STM32内部flash可以用作EEPROM,用于保存用户数据. 1.一般来说,stm32的flash擦写寿命只有10万次,如果在同一位置擦写过于频繁,在产品质保期内FLASH就会达到寿命极限,保存数 ...

  9. 【飞思卡尔 MC9S12】内部Flash读写

    上一篇:[飞思卡尔 MC9S12]PRM文件与内存映射(Flash.RAM.EEE) 上一篇讲到PRM文件与内存映射,其中有个重要寄存器叫做GPAGE,可以全局访问所有地址范围,Flash操作也是基于 ...

  10. ftm模块linux驱动,飞思卡尔k系列_ftm模块详解.doc

    飞思卡尔k系列_ftm模块详解 1.5FTM模块1.5.1 FTM模块简介FTM模块是一个多功能定时器模块,主要功能有,PWM输出.输入捕捉.输出比较.定时中断.脉冲加减计数.脉冲周期脉宽测量.在K1 ...

最新文章

  1. android技术下载
  2. junit--eclipse插件
  3. JAVA总结之数组篇
  4. Iris——整合go-playground/validator参数校验Demo
  5. centos6系列版本防火墙图形化设置
  6. ZOJ 1586 QS Network
  7. Less or Equal(CF-977C)
  8. python 计算相关系数和决定系数
  9. Matlab系列教程_基础知识_基本矩阵操作
  10. Python已经超过了JAVA?
  11. 大物实验计算弹性模量_什么是材料的杨氏模量?它的定义与计算公式是什么?...
  12. [Unity]CutScene工具Cinema Suite Rotion 角度不能负数方向旋转的bug修正。
  13. 信息安全快讯丨桃李满天下,金秋谢师恩——教师节快乐!
  14. pppo服务器光信号亮红灯,光纤猫光信号闪红灯不能上网怎么办
  15. js一键复制并调起微信客户端
  16. 如何治理谐波问题?——有源滤波器
  17. 面向对象的三大基本特征和六大基本原则
  18. hyperterminal使用教程_hyperterminal 教程
  19. pycharm远程连接服务器问题Uploading PyCharm helpers Python Interpreter... Python helpers are not copied yet
  20. Google Earth 背后的故事

热门文章

  1. 除了WhatsApp以外,还有哪些即时聊天软件?
  2. 高效制作期刊论文三线表格教程
  3. 【升级版】和秋叶一起学Office
  4. selenium原理
  5. Java架构师知识体系图谱
  6. postgresql 查询sql字符串拼接相关
  7. matlab xrd,波导光学大作业-论文-matlab模拟xrd及分析.doc
  8. Javashop 7.0 商城Https协议修改部分
  9. PE制作-004.UEFI和Legacy双启动之修改定制Win10PE
  10. DeepFaceLab AI换脸使用教程(1.安装及分解视频)