MC68HC908QY4单片机FLASH模拟EEPROM的方法
- UID
- 104673
- 性别
- 男
|
MC68HC908QY4单片机FLASH模拟EEPROM的方法
MC68HC908QY4单片机FLASH模拟EEPROM的方法
田云锋
MC68HC908QY4是飞思卡尔半导体针对车身控制低端市场推出的低成本高性能的一款单片机。它有4K FLASH,128字节RAM,2通道16位具有输入捕捉,输出比较以及PWM功能的定时器,内部晶振,4通道8位AD转换,具有低电压禁止功能,看门狗,大电流I/O端口,键盘中断,13路双向I/O端口以及1路输入端口。它有16引脚DIP,SOIC,TSSOP三种封装形式。
MC68HC908QY4主要应用于车身控制,比如对天窗,雨刮,电动车窗,后视镜的控制。由于越来越多的汽车厂商针对车身控制大量采用LIN总线,所以MC68HC908QY4常常用来做LIN网络中的一个从节点。用户可以用定时器来模拟串口实现LIN通讯功能。飞思卡尔也提供了针对QY系列的LIN驱动程序。用户可到飞思卡尔网站上下载LIN驱动程序。
在实际的应用中,用户经常会遇到在程序运行过程中保存一些数据,比如天窗的行程,后视镜的位置等。这些数据在工作中经常会变化,所以需要及时地进行存储。存储这些数据常用的办法是用EEPROM。MC68HC908QY4虽然本身不带EEPROM,但是却可以用FLASH来模拟EEPROM,这样不仅简化了设计,而且降低了成本。
MC68HC908QY4的FLASH写入10个字节,仅需1ms,是EEPROM的10倍。它的擦除时间为4ms。它的擦写次数为1万次。
MC68HC908QY4的FLASH是以页为单位,每页64字节。它允许写入单个字节,但是擦除时,必须整页擦除。在一页内,可以依次将数据写入FLASH,当写满一页后,再全部擦除整页。比如每次写入4字节数据块,一页可以写16个数据块,写满后,再全部擦除。这样在某个页内对数据块的擦写次数可以提高16倍,即16万次。数据块的大小最好是2的n次方,并且小于32字节。这样可以一页64字节就可以全部利用。如果大于32字节,每写一次,就要擦除整页。
一般的要想对FLASH在应用编程,必须将FLASH的擦写程序拷贝到RAM中执行,但是由于MC68HC908QY4的RAM只有128字节,而且FLASH空间也有限,所以飞思卡尔把对FLASH擦写的程序在出厂前固化到了监控ROM区中。用户如需对FLASH进行编程,只需调用这几个函数即可。
----------------------------------------------------------------------------------------------------------
ERARNGE 0x2806 //擦除函数入口地址
PGRRNGE 0x2809 //编程函数入口地址
表1 固化在ROM内的函数的入口地址
------------------------------------------------------------------------------------------------------------
调用编程函数时,这些函数需要访问几个固定RAM区,因此需要先对这几个RAM区赋值。如图2所示。注意:用户的应用程序中的变量不要放在这个区域内。在调用PGRRNGE时,需要编程的FLASH的起始地址需要放在变址寄存器H:X中,所以不需要在RAM区来存储。
------------------------------------------------------------------------------------------------------------
入口参数 RAM地址 字节数 用途
CTRLBYT $88 1 控制位
CPUSPD $89 1 总线速度(单位:0.25MHz)
LSTADDR $8A-8B 2 FLASH中数据块的末尾地址
BFRSTRT $8C => 数据块的大小 数据缓冲区即要编程的数据
表2 固化在ROM内的函数用到的RAM区的地址
------------------------------------------------------------------------------------------------------------
另外需要注意的是CTRLBYT用来告诉擦除函数时页擦除,还是整体擦除。这里因为用户程序需要保留,所以应该选择页擦除。CPUSPD要告诉这两个函数总线的速度,以保证这些函数在执行时延时准确。在调用这两个函数时,要禁止所有的中断,在调用结束后,再打开中断。下面代码是使用示例,编程环境为codewarriorHC08 V3.1。
------------------------------------------------------------------------------------------------------------
#include /* for EnableInterrupts macro */
#include /* include peripheral declarations */
#define FBUS 3200000 //总线速度
#define ERARNGE() {__asm jsr 0x2806;} //跳到0x2806执行
#define PGRRNGE() {__asm jsr 0x2809;} //跳到0x2809执行
#define CTRLBYT (*(volatile unsigned char*) (0x88)) //存放控制位的RAM地址
#define CPUSPD (*(volatile unsigned char*) (0x89)) //存总线速度的RAM地址
//LADDRH,LADDRL存储FLASH编程末尾地址的RAM地址
#define LADDRH (*(volatile unsigned char*) (0x8A))
#define LADDRL (*(volatile unsigned char*) (0x8B))
#define OSC_CONST FBUS/250000 //总线速度(单位:0.25MHz)
#define FLASH_TEST_ADDRESS 0xFD40 //存放数据的FLASH页的首地址
#define RECEIVE_LENGTH 2 //编程数据的长度
unsigned char My_Receive[RECEIVE_LENGTH]@0x8C; //存储编程数据的RAM区
void ProgramRange(word *_ini, byte _num) //FLASH编程函数
{
word _first;
_first = *_ini; //要编程的起始地址
CPUSPD = OSC_CONST; //总线速度
LADDRH = ((_first + _num -1) & 0xFF00) >> 8;
LADDRL = ((_first + _num -1) & 0x00FF); //要编程的末尾地址
__asm ldhx _first; //将要编程的地址装入H,X寄存器
PGRRNGE(); //调用编程函数
return;
}
void EraseRow(word *_row) //FLASH擦除函数
{
word _address;
_address = *_row; //要擦除的起始地址
CPUSPD = OSC_CONST; //总线速度
CTRLBYT &= 0xBF; //控制字,页擦除
__asm ldhx _address; //将要擦除的地址装入H,X寄存器
ERARNGE(); //调用擦除函数
return;
}
void main(void)
{
word address;
word *ptr;
address = FLASH_TEST_ADDRESS;
EraseRow(&address); //擦除地址从FLASH_TEST_ADDRESS开始的一页
My_Receive[0] = 0x18; //要写入FLASH中的数据
My_Receive[1] = 0x08; //要写入FLASH中的数据
//从FLASH_TEST_ADDRESS开始写入RECEIVE_LENGTH个字节
ProgramRange (&address, RECEIVE_LENGTH);
EnableInterrupts; /* enable interrupts */
for(;;)
{
ptr=(word *) (0xFD40)); //把FLASH中刚写入的值读出来
....
}
}
FLASH模拟EEPROM使用实例
------------------------------------------------------------------------------------------------------------
上面的例子只是介绍了一种基本的FLASH模拟EEPROM的方法,用户如果想写满整页之后,再擦除,可以采用查询方式,从页的首地址开始,如果FLASH的内容等于$FF,则表示为空,然后在该地址内写入数据,一直到写满。不过此时用户的数据不能等于$FF,否则会发生错误。另外,还可以采用标志位,在保存的数据后面加一个标志位,如果查到标志位,就说明此地址内已有数据,然后继续往后查询,直到最后一个标志位,此时后面的FLASH空间内可以写数据。
如果用户需要保存历史数据,则可以采用两页FLASH来存储数据,一页存放当前数据,另一页存放历史数据。当前数据页存满以后,把数据全部转移到历史数据页中,然后在擦除当前数据页,继续写入新数据。
另外用户的应用程序为了避免意外的被擦除,应该把存放用户程序的FLASH保护起来。寄存器FLBPR可以用来保护从某一特定地址以上的FLASH区。因此用来存放数据的FLASH区应该尽量从地址开始,用户程序放在高地址。FLBPR寄存器的赋值需要对采用FLASH的编程方法写入。
在应用中,系统可能在编程中掉电,或由于其他原因程序中止,这样已经写入的数据可能是无效的或错误的,用户在开发阶段要考虑到这一点,尽量减少这种情况的发生,或者可以考虑采用数据恢复机制。不过由于FLASH的擦写速度快,所以发生这种情况时,它比EEPROM就更具有优势。
本文介绍的MC68HC908QY4单片机FLASH模拟EEPROM的这种方法,只是起到抛砖引玉的作用。用户可以根据自己的实际情况,灵活应用满足系统要求。
参考文献
1. MC68HC908QY4/D, technical data sheet
2. Application Note AN2346, “EEPROM Emulation Using FLASH in MC68HC908QY/QT MCUs”
3. Application Note AN1831, “Using MC68HC908 On-chip FLASH Programming Routines”
4. Application Note AN2183, “Using FLASH as EEPROM on the MC68HC908GP32”
5. Engineering Bulletin EB398, “Techniques to Protect MCU Applications
Against Malfunction due to Code Run-away” |
|
|
|
|
|
- UID
- 114430
- 性别
- 男
|
|
|
|
|
|
- UID
- 140841
- 性别
- 男
|
楼主:你好!我试过了,第一次能写,第二次再写的话就有问题,发现问题是在擦除上,我调试过,擦除不正确,带来写入不正确,我用的是内部晶振3.2M,不知道是什么原因,请楼主赐教,因为我刚好要用,非常感谢! |
|
|
|
|
|
- UID
- 104380
- 性别
- 男
|
|
|
|
|
|
- UID
- 122756
- 性别
- 男
|
能给一个相关资料的具体网址吗?
要是可以的话把你的资料给我发一份,谢谢!
另外,有没有用C语言编写的相关程序。 |
|
|
|
|
|
- UID
- 112879
- 性别
- 男
|
Freescale 有份应用笔记 AN2346,有QT/QY利用内部ROM程序模拟EEPROM,网站都可以下载 |
|
|
|
|
|