freescale飞思卡尔 HC9S12 系列单片机 Flash擦写详解(三)之Flash控制器指令执行
前面我们介绍了Flash主要的几个寄存器,如果还有其他的疑问可以再返回去看看或者直接查阅S12系列单片机的手册中相关的内容。这一节我将介绍Flash控制器指令执行的过程,并举出相关的例子,希望能够起到举一反三的效果。
在手册中FCCOB寄存器下面,介绍了Flash寄存器执行指令的过程是这样的:
我们解释下:NVM执行指令时将通过FCCOB寄存器向存储控制器提供一个指令码还有其相关的参数,也就是说先根据指令码对FCCOB寄存器进行设置,然后通过对FSTAT寄存器中的CCIF位写入1从而使Flash控制器开始执行FCCOB中的指令(当向CCIF写1后,读取CCIF时其值将为0)。当用户向CCIF中写1后,FCCOB指令寄存器内的内容将被锁定直到此次指令执行结束。如果该指令码有返回值,则返回信息将会在FCCOB寄存器内。
我们稍微总结下Flash寄存器执行指令的过程:
1. 先通过调整FCCOBIX寄存器向FCCOB寄存器各个word中写入指令码与相关的参数
2. 向FSTAT的CCIF位中写入1,开始指令执行
3. 读取CCIF的值直到指令执行结束,若指令码有返回值则读取并返回(还有FSTAT中的其他位可能表示了写入过程中的错误信息)
这样就可以让Flashi控制器完成一次指令的执行了。下面我们看一下一个手册中的典型FCCOB寄存器的用法:
在上面的典型用法表中我们可以看到向Flash中写入8个Byte的过程应该如下方程序所示:
1 unsigned long address = 0x020000 //将要在Flash中写入的数据首地址(全局地址) 2 unsigned int *ptr = data // word长度的数据指针 3 byte i 4 5 // 读取CCIF的值来判断Flash 6 while ((FSTAT & FSTAT_CCIF_MASK) == 0); 7 8 9 // 按照格式要求选择0x00 10 FCCOBIX = 0x00; // choose the 000 FCCOB 11 12 /* 000 FCCOB HI is 8 bits commands and LO is physical address Highest byte*/ 13 /* command 0x06 means program flash */ 14 /* warning: before program, the area must be erased*/ 15 FCCOB = 0x0600 | ((address & 0x00030000) >> 16); 16 17 FCCOBIX = 0x01; //choose the 001 FCCOB 18 /* 001 FCCOB is the least 16bits physical address*/ 19 FCCOB = (address & 0x0000FFFF); 20 21 /* 0x02 - 0x05 FCCOB are 4x2 bytes write data*/ 22 for (i = 2; i < 6; i++) 23 { 24 FCCOBIX = i; 25 FCCOB = *ptr; /* 2 bytes data each FCCOB */ 26 ptr ++; /* next 2 bytes */ 27 } 28 29 FSTAT = 0x80; /* set CCIF to clear CCIF and launch command */ 30 while ((FSTAT & FSTAT_CCIF_MASK) == 0); /* wait command done */ 31
请仔细阅读上方的代码,在代码中我使用了向Flash中写入8个Byte的指令码0x06,完成的效果就是将上方表格所示的FCCOB中的内容设置满,然后启动并执行指令,直到指令被完全执行成功。
这里有四点需要强调,
首先是不同的指令码对应着FCCOB中不同的内容要求,具体设置情况根据需要,参照手册中对每个指令码的要求来编写。
其次是Flash的操作地址模式为全局地址,也就是上面表格中Global address,先把全局地址与分页地址的关系搞清楚了再做Flash的操作。
第三是Flash的擦写程序必须要复制到RAM中执行才可以执行,复制代码到RAM中执行前要在prm文件中使用RELOCATE_TO关键词,将代码拷贝至内存中运行(在bootloader详解教程中有写如何将ROM中的代码拷贝至RAM中),这是因为Flash的操作不能读写同步的,当Flash控制器在执行指令时,单片机无法从Flash读出指令,一定要先将Flash擦写的代码拷贝至RAM中运行才可以。
第四是,在写入Flash之前,务必要确定该片Flash区域已经被擦除了,否则会出现写入错误。
后面我还会展示一点代码,对于初学者,将下面的代码每一句都弄懂,对照着器件手册理解了,基本上Flash这部分内容就算是勉强出师了。其间涉及到了错误信息的处理,在手册里查一查都有的。
还想说一下本人写这个教程的初衷,因为首先自己搞的时候确实很头大,这样把过程写出来十分畅快,其次就是在下目前在下的环境,完全不参与什么行业竞争,这些只是需要读一读器件手册就能完成的事情,发出来对大家有用就好。下面贴代码,代码包括prm文件设置,Flash擦写头文件与实现,还有个将ROM中程序复制到RAM中运行的程序。要是根据我这个教程将Flash调通的,在教程下评论下吧,并不是要推荐,只是想看看帮到了多少人。
prm文件设置
1 NAMES END 2 3 SEGMENTS 4 /* Register space */ 5 /* IO_SEG = PAGED 0x0000 TO 0x03FF; intentionally not defined */ 6 7 /* RAM */ 8 RAM = READ_WRITE 0x2000 TO 0x3BFF; 9 CODE_RAM = READ_WRITE 0x3C00 TO 0x3FFF; /*1 kB for flash read and write*/ 10 11 /* D-Flash */ 12 DFLASH = READ_ONLY 0x000400 TO 0x0013FF; 13 14 /* non-paged FLASHs */ 15 ROM_1400 = READ_ONLY 0x1400 TO 0x1FFF; 16 17 ROM_BOOT = READ_ONLY 0x4000 TO 0x43FF; // 1KB for boot loader 18 ROM_FLASH = READ_ONLY 0X4400 TO 0x47FF RELOCATE_TO 0x3C00; // 1KB for necessary flash operation 19 20 ROM_C000 = READ_ONLY 0xC000 TO 0xFEFF; 21 /* VECTORS = READ_ONLY 0xFF00 TO 0xFFFF; intentionally not defined: used for VECTOR commands below */ 22 //OSVECTORS = READ_ONLY 0xFF80 TO 0xFFFF; /* OSEK interrupt vectors (use your vector.o) */ 23 24 /* paged FLASH: 0x8000 TO 0xBFFF; addressed through PPAGE */ 25 PAGE_08 = READ_ONLY 0x088000 TO 0x08BFFF; 26 PAGE_09 = READ_ONLY 0x098000 TO 0x09BFFF; 27 PAGE_0A = READ_ONLY 0x0A8000 TO 0x0ABFFF; 28 PAGE_0B = READ_ONLY 0x0B8000 TO 0x0BBFFF; 29 PAGE_0C = READ_ONLY 0x0C8000 TO 0x0C93FF; 30 PAGE_0C_A000 = READ_ONLY 0x0CA000 TO 0x0CBFFF; 31 PAGE_0E = READ_ONLY 0x0E8000 TO 0x0EBFFF; 32 /* PAGE_0D = READ_ONLY 0x0D8000 TO 0x0DBFFF; not used: equivalent to ROM_4000 */ 33 /* PAGE_0F = READ_ONLY 0x0F8000 TO 0x0FBEFF; not used: equivalent to ROM_C000 */ 34 END 35 36 PLACEMENT /* here all predefined and user segments are placed into the SEGMENTS defined above. */ 37 _PRESTART, /* Used in HIWARE format: jump to _Startup at the code start */ 38 STARTUP, /* startup data structures */ 39 ROM_VAR, /* constant variables */ 40 STRINGS, /* string literals */ 41 VIRTUAL_TABLE_SEGMENT, /* C++ virtual table segment */ 42 //.ostext, /* OSEK */ 43 NON_BANKED, /* runtime routines which must not be banked */ 44 COPY /* copy down information: how to initialize variables */ 45 /* in case you want to use ROM_4000 here as well, make sure 46 that all files (incl. library files) are compiled with the 47 option: -OnB=b */ 48 INTO ROM_C000/*, ROM_1400, ROM_4000*/; 49 50 BOOTLOADER INTO ROM_BOOT; 51 FLASH_CODE INTO ROM_FLASH; 52 53 54 USER_APP INTO PAGE_08; 55 TEST_AREA INTO PAGE_09; /* physical address from 0x2_4000 */ 56 DEFAULT_ROM INTO PAGE_0A, PAGE_0B, PAGE_0C, PAGE_0C_A000, PAGE_0E ; 57 58 //.stackstart, /* eventually used for OSEK kernel awareness: Main-Stack Start */ 59 SSTACK, /* allocate stack first to avoid overwriting variables on overflow */ 60 //.stackend, /* eventually used for OSEK kernel awareness: Main-Stack End */ 61 DEFAULT_RAM INTO RAM; 62 63 //.vectors INTO OSVECTORS; /* OSEK */ 64 END 65 66 ENTRIES /* keep the following unreferenced variables */ 67 /* OSEK: always allocate the vector table and all dependent objects */ 68 //_vectab OsBuildNumber _OsOrtiStackStart _OsOrtiStart 69 END 70 71 STACKSIZE 0x100 72 73 VECTOR 0 _Startup /* reset vector: this is the default entry point for a C/C++ application. */ 74 //VECTOR 0 Entry /* reset vector: this is the default entry point for an Assembly application. */ 75 //INIT Entry /* for assembly applications: that this is as well the initialization entry point */ 76 77 VECTOR ADDRESS 0xFFD6 SCI0_INT_receive
View Code
Flash擦写头文件
1 #ifndef _FLASH_LIB_H 2 #define _FLASH_LIB_H 3 4 #include <mc9s12g128.h> 5 6 typedef enum 7 { 8 NoError = 0, 9 FlashProgramError = 1, 10 FlashEraseError = 2 11 } FlashMsg; 12 13 #pragma CODE_SEG BOOTLOASER 14 15 void Init_Flash(void); 16 17 #pragma CODE_SEG DEFAULT 18 19 #pragma CODE_SEG FLASH_CODE 20 21 FlashMsg Flash_Program(unsigned long address, unsigned int *ptr); 22 23 FlashMsg Flash_EraseSector(unsigned long address); 24 25 26 #pragma CODE_SEG DEFAULT 27 28 #endif
View Code
Flash擦写实现
1 #include "FLASH_LIB.h" 2 3 /* a sector contains 512 bytes */ 4 #define FLASH_SECTOR_SIZE 0x200 5 6 7 #pragma CODE_SEG BOOTLOASER 8 9 void Init_Flash(void) 10 { 11 // bus clock is 8MHz 12 // read the manual reference get the respective value 13 14 // check if the flash controller is busy or not 15 while ((FSTAT & FSTAT_CCIF_MASK) == 0); 16 17 // set the clock divider according to bus clock 18 FCLKDIV = 0x07; 19 20 // lock the divider 21 FCLKDIV_FDIVLCK = 1; 22 23 } 24 25 #pragma CODE_SEG DEFAULT 26 27 28 #pragma CODE_SEG FLASH_CODE 29 30 FlashMsg Flash_Program(unsigned long address, unsigned int *ptr) 31 { 32 byte i; 33 34 /*CCIF is the 7th bit of FSTAT 35 CCIF is 0, the flash controller is busy 36 wait until CCIF become 1*/ 37 while ((FSTAT & FSTAT_CCIF_MASK) == 0); 38 39 /*clear ACCERR (flash access error) 5th bit 40 clear PVIOL (protection violation error) 4th bit 41 , or the CCIF cannot be cleared*/ 42 FSTAT = 0x30; 43 44 /*write flash command, operation address and input parameters*/ 45 FCCOBIX = 0x00; // choose the 000 FCCOB 46 47 /* 000 FCCOB HI is 8 bits commands and LO is physical address Highest byte*/ 48 /* command 0x06 means program flash */ 49 /* warning: before program, the area must be erased*/ 50 FCCOB = 0x0600 | ((address & 0x00030000) >> 16); 51 52 FCCOBIX = 0x01; //choose the 001 FCCOB 53 /* 001 FCCOB is the least 16bits physical address*/ 54 FCCOB = (address & 0x0000FFFF); 55 56 /* 0x02 - 0x05 FCCOB are 4x2 bytes write data*/ 57 for (i = 2; i < 6; i++) 58 { 59 FCCOBIX = i; 60 FCCOB = *ptr; /* 2 bytes data each FCCOB */ 61 ptr ++; /* next 2 bytes */ 62 } 63 64 FSTAT = 0x80; /* set CCIF to clear CCIF and launch command */ 65 while ((FSTAT & FSTAT_CCIF_MASK) == 0); /* wait command done */ 66 67 /*read the error flag and return error message*/ 68 if ((FSTAT & (FSTAT_ACCERR_MASK | FSTAT_FPVIOL_MASK)) != 0) 69 return FlashProgramError; 70 else 71 return NoError; 72 73 } 74 75 FlashMsg Flash_EraseSector(unsigned long address) 76 { 77 while ((FSTAT & FSTAT_CCIF_MASK) == 0); 78 FSTAT = 0x30; 79 80 /* command 0x0A means erased all address in the sector*/ 81 FCCOBIX = 0x00; 82 FCCOB = 0x0A00 | ((address & 0x00030000) >> 16); 83 84 FCCOBIX = 0x01; 85 FCCOB = (address & 0x0000FFF8); /*get the sector*/ 86 87 FSTAT = 0x80; /* launch command*/ 88 while ((FSTAT & FSTAT_CCIF_MASK) == 0); /*wait for done*/ 89 90 if ((FSTAT & (FSTAT_ACCERR_MASK | FSTAT_FPVIOL_MASK | 91 FSTAT_MGSTAT_MASK)) != 0) 92 return FlashEraseError; 93 else 94 return NoError; 95 } 96 97 98 #pragma CODE_SEG DEFAULT
View Code
ROM中内容复制到RAM中函数
void MoveCodeIntoRam(byte *source, byte *dest, unsigned int size) {while (size --){*dest ++ = *source ++;} }
View Code
对应本prm文件调用复制函数
MoveCodeIntoRam((byte *)0x4400, (byte *)0x3C00, 0x400);
本节内容小结:
1. 通过实例展示了S12系列单片机通过Flash指令寄存器让Flash控制器执行操作的过程
2. 给出了在擦写Flash的四个重要问题
3. 给出了可以调用的实例程序
注: 本系列文章均为原创,如有转载引用请标明来源
转载于:https://www.cnblogs.com/15821216114sw/p/9690450.html
freescale飞思卡尔 HC9S12 系列单片机 Flash擦写详解(三)之Flash控制器指令执行相关推荐
- freescale飞思卡尔 HC9S12 系列单片机 Flash擦写详解(一)之时钟设置
Flash擦写的内容,个人做HC9S12系列单片机时觉得应该是各模块内容中最难而且是最麻烦的一步了.只有能够对Flash进行擦写以后,所做的Bootloader才有真正手段将串口或者其他通讯手段接收到 ...
- 飞思卡尔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),从而锁住了芯片:难道芯片就 ...
- ADSP-21489的开发详解:SPIflash的硬件设计及程序烧写详解(含Flash驱动源码)
硬件准备 ADSP-21489EVB:ADI 21489处理器的开发板 AD-HP530ICE:ADI DSP专用仿真器 USBi:ADI SigmaDSP和SHARC DSP的图形化编程调试器 软件 ...
- 飞思卡尔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 ...
- NOR Flash擦写和原理分析
http://www.cnblogs.com/jason-lu/archive/2013/03/13/2957399.html NOR Flash擦写和原理分析 NOR Flash擦写和原理分析 一. ...
- 痞子衡嵌入式:飞思卡尔Kinetis系列MCU启动那些事(1)- KBOOT架构
大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔Kinetis系列MCU的KBOOT架构. Bootloader是嵌入式MCU开发里很常见的一种专用的应用程序,在一个没有Boo ...
- ftm模块linux驱动,飞思卡尔k系列_ftm模块详解.doc
飞思卡尔k系列_ftm模块详解 1.5FTM模块1.5.1 FTM模块简介FTM模块是一个多功能定时器模块,主要功能有,PWM输出.输入捕捉.输出比较.定时中断.脉冲加减计数.脉冲周期脉宽测量.在K1 ...
最新文章
- Linux_ISCSI服务器
- 熵(Entropy),交叉熵(Cross-Entropy),KL-松散度(KL Divergence),似然(Likelihood)
- Call for Papers | IEEE/IAPR IJCB 2022 会议
- mysql连接字符串 .net_.net MYSQL连接字符串参数详细解析
- java架构师证书_java架构师证书怎么考?做架构师有什么要求?
- OpManager12——一个完整的网络管理解决方案
- SketchUp LayOut 剪贴簿制作技巧
- 八种抽样技术的科学指南
- win7计算机图标排列,win7系统每次开机桌面图标都会重新排列的方法
- 数据结构大作-学生信息管理系统
- Nginx服务器软件学习记录
- SyntaxError: Non-UTF-8 code starting with '\xb5' in file“问题解决办法
- Oracle实现递归查询
- python匿名函数里用for_Python基础之(内置函数、匿名函数、递归)
- java并查集_一个非常实用而且精妙的算法-并查集(java语言实现)
- 查互联网ip(公网ip)
- memcached的基础
- win11添加右键在此处打开命令窗口
- Unifier项目实施系列:02项目实施方法论
- 计算机网络(英文版 第2版),计算机网络(原书第2版)(二).pdf
热门文章
- 编程图记(2): 学用PHP框架Laravel
- VUE 实现滑块验证 ①
- Nature:一份全球综合报告显示生物多样性的丧失是生态系统变化的一个主要驱动因素
- java做的企业网站源码 java开发的公司网站源码 java ssm框架开发的门户网站源码 java 企业官网源代码公司门户网站模板源码带后台SSM框架开发建设
- 约瑟夫环问题 —— 算法
- 详解Bresenham算法原理(1)
- 如何 禁掉 Hyper-V 如何解决禁不掉 Hyper-V 的问题
- 学习:从入门到精通,Java学习路线导航
- 机器学习 | 回归问题
- What is COM, COM+? (什么是COM, COM+?)