在线时间1 小时
UID61275
注册时间2008-7-25
NXP金币0
该用户从未签到
注册会员

- 积分
- 121
- 最后登录
- 1970-1-1
|
情景:用Flash模拟EEPROM保存预设参数
问题:每次开机时程序并没有使用设置后的新值,而是仍然用初始值运行。
分析:读Flash,参数已经被写入了Flash。但是看来程序并没有使用Flash中的参数运行。
原来程序中相关的部分如下。目的是从Flash的F000~F003地址处取出参数,并放到变量“DRTU”和“DRTL”中。
#define RTU 501 /* input pulse standard up value */
#define RTL 251 /* input pulse standard low value */
uint16 DRTU;
uint16 DRTL;
#pragma DATA_SEG EEE_DATA /* 这是Flash中用来模拟EEPROM的地址空间 */
const uint8 CRTUH @0x0000F000 = (uint8)(RTU/256);
const uint8 CRTUL @0x0000F001 = (uint8)(RTU&0x00FF);
const uint8 CRTLH @0x0000F002 = (uint8)(RTL/256);
const uint8 CRTLL @0x0000F003 = (uint8)(RTL&0x00FF);
#pragma DATA_SEG DEFAULT
DRTU = CRTUH*256+CRTUL;
DRTL = CRTLH*256+CRTLL;
反汇编代码如下。发现汇编代码并没有从Flash地址取数,而是直接用立即数给变量赋值。看来“聪明”的编译器找到了更“优化”的赋值方法。我们当然不能怪编译器,它只是按照人的指令去工作。
445: DRTU = CRTUH*256+CRTUL;
007c 4501f5 [3] LDHX #501
007f 3500 [5] STHX DRTU
446: DRTL = CRTLH*256+CRTLL;
0081 aefb [2] LDX #-5
0083 8c [1] CLRH
0084 3500 [5] STHX DRTL
解决方法:这里用到了这个貌似怪异的声明“const volatile”。没错,既“const”又“volatile”。“const”表示这个值为只读。“volatile”则告诉编译器每次用到这个值都要去老老实实的到相应的地址去读一下,不能“偷懒”。比较典型的应用是用来声明硬件相关的状态寄存器。我们这里Flash中存储的参数值对程序来说是只读的,而这块Flash是通过特殊的操作步骤模拟EEPROM使用的。修改后的声明如下。
#pragma DATA_SEG EEE_DATA /* 这是Flash中用来模拟EEPROM的地址空间 */
const volatile uint8 CRTUH @0x0000F000 = (uint8)(RTU/256);
const volatile uint8 CRTUL @0x0000F001 = (uint8)(RTU&0x00FF);
const volatile uint8 CRTLH @0x0000F002 = (uint8)(RTL/256);
const volatile uint8 CRTLL @0x0000F003 = (uint8)(RTL&0x00FF);
#pragma DATA_SEG DEFAULT
反汇编,这回是我们想要的代码了。
445: DRTU = CRTUH*256+CRTUL;
007c c60000 [4] LDA CRTUL
007f b701 [3] STA DRTU:1
0081 c60000 [4] LDA CRTUH
0084 b700 [3] STA DRTU
446: DRTL = CRTLH*256+CRTLL;
0086 c60000 [4] LDA CRTLL
0089 b701 [3] STA DRTL:1
008b c60000 [4] LDA CRTLH
008e b700 [3] STA DRTL
**************************************************
情景:用Flash模拟EEPROM保存预设参数
问题:在DATA_SEG EEE_DATA段中声明的数组会被初始化为全零,而我的应用里想让它保持“FF”状态。
解决方法:将EEE_STORAGE的属性改为NO_INIT。注意,这样此段中声明的其他变量也不可以赋初值。下面是工程中.prm文件的内容。
SEGMENTS /* Here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. */
Z_RESERVE = READ_WRITE 0x0060 TO 0x0064;
Z_RAM = READ_WRITE 0x0065 TO 0x00FF;
RAMFUNC = READ_WRITE 0x0100 TO 0x011F;
RAM = READ_WRITE 0x0120 TO 0x015F;
EEE_STORAGE = NO_INIT 0xF000 TO 0xF1FF;
ROM = READ_ONLY 0xF200 TO 0xFFA9;
ROM1 = READ_ONLY 0xFFC0 TO 0xFFCF;
/* INTVECTS = READ_ONLY 0xFFD0 TO 0xFFFF; Reserved for Interrupt Vectors */
END
PLACEMENT /* Here all predefined and user segments are placed into the SEGMENTS defined above. */
DEFAULT_RAM /* non-zero page variables */
INTO RAM;
_PRESTART, /* startup code */
STARTUP, /* startup data structures */
ROM_VAR, /* constant variables */
STRINGS, /* string literals */
VIRTUAL_TABLE_SEGMENT, /* C++ virtual table segment */
DEFAULT_ROM,
COPY /* copy down information: how to initialize variables */
INTO ROM; /* ,ROM1: To use "ROM1" as well, pass the option -OnB=b to the compiler */
EEE_DATA
INTO EEE_STORAGE;
_DATA_ZEROPAGE, /* zero page variables */
MY_ZEROPAGE INTO Z_RAM;
CODE_IN_RAM INTO RAMFUNC;
PASS_IN_RAM INTO Z_RESERVE;
END
|
|