9S12XDT512,BANKED模式。
prm文件的主要设置参数是这样的:
SEGMENTS /* here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. All addresses are 'logical' */
/* Register space */
/* IO_SEG = PAGED 0x0000 TO 0x07FF; intentionally not defined */
/* non-paged EEPROM */
EEPROM = READ_ONLY 0x0C00 TO 0x0FFB;
/* non-paged RAM */
RAM = READ_WRITE 0x2000 TO 0x3FFF;
/* non-banked FLASH */
ROM_4000 = READ_ONLY 0x4000 TO 0x7FFF;
ROM_C000 = READ_ONLY 0xC000 TO 0xFEFF;
/* VECTORS = READ_ONLY 0xFF00 TO 0xFFFF; intentionally not defined: used for VECTOR commands below */
//OSVECTORS = READ_ONLY 0xFF10 TO 0xFFFF; /* OSEK interrupt vectors (use your vector.o) */
/* paged EEPROM 0x0800 TO 0x0BFF; addressed through EPAGE */
EEPROM_FC = READ_ONLY 0xFC0800 TO 0xFC0BFF;
EEPROM_FD = READ_ONLY 0xFD0800 TO 0xFD0BFF;
EEPROM_FE = READ_ONLY 0xFE0800 TO 0xFE0BFF;
/* EEPROM_FF = READ_ONLY 0xFF0800 TO 0xFF0BFF; intentionally not defined: equivalent to EEPROM */
/* paged RAM: 0x1000 TO 0x1FFF; addressed through RPAGE */
RAM_FB = READ_WRITE 0xFB1000 TO 0xFB1FFF;
RAM_FC = READ_WRITE 0xFC1000 TO 0xFC1FFF;
RAM_FD = READ_WRITE 0xFD1000 TO 0xFD1FFF;
/* RAM_FE = READ_WRITE 0xFE1000 TO 0xFE1FFF; intentionally not defined: equivalent to RAM: 0x2000..0x2FFF */
/* RAM_FF = READ_WRITE 0xFF1000 TO 0xFF1FFF; intentionally not defined: equivalent to RAM: 0x3000..0x3FFF */
/* paged FLASH: 0x8000 TO 0xBFFF; addressed through PPAGE */
PAGE_E0 = READ_ONLY 0xE08000 TO 0xE0BFFF;
PAGE_E1 = READ_ONLY 0xE18000 TO 0xE1BFFF;
PAGE_E2 = READ_ONLY 0xE28000 TO 0xE2BFFF;
PAGE_E3 = READ_ONLY 0xE38000 TO 0xE3BFFF;
PAGE_E4 = READ_ONLY 0xE48000 TO 0xE4BFFF;
PAGE_E5 = READ_ONLY 0xE58000 TO 0xE5BFFF;
PAGE_E6 = READ_ONLY 0xE68000 TO 0xE6BFFF;
PAGE_E7 = READ_ONLY 0xE78000 TO 0xE7BFFF;
PAGE_E8 = READ_ONLY 0xE88000 TO 0xE8BFFF;
PAGE_E9 = READ_ONLY 0xE98000 TO 0xE9BFFF;
PAGE_EA = READ_ONLY 0xEA8000 TO 0xEABFFF;
PAGE_EB = READ_ONLY 0xEB8000 TO 0xEBBFFF;
PAGE_EC = READ_ONLY 0xEC8000 TO 0xECBFFF;
PAGE_ED = READ_ONLY 0xED8000 TO 0xEDBFFF;
PAGE_EE = READ_ONLY 0xEE8000 TO 0xEEBFFF;
PAGE_EF = READ_ONLY 0xEF8000 TO 0xEFBFFF;
PAGE_F0 = READ_ONLY 0xF08000 TO 0xF0BFFF;
PAGE_F1 = READ_ONLY 0xF18000 TO 0xF1BFFF;
PAGE_F2 = READ_ONLY 0xF28000 TO 0xF2BFFF;
PAGE_F3 = READ_ONLY 0xF38000 TO 0xF3BFFF;
PAGE_F4 = READ_ONLY 0xF48000 TO 0xF4BFFF;
PAGE_F5 = READ_ONLY 0xF58000 TO 0xF5BFFF;
PAGE_F6 = READ_ONLY 0xF68000 TO 0xF6BFFF;
PAGE_F7 = READ_ONLY 0xF78000 TO 0xF7BFFF;
PAGE_F8 = READ_ONLY 0xF88000 TO 0xF8BFFF;
PAGE_F9 = READ_ONLY 0xF98000 TO 0xF9BFFF;
PAGE_FA = READ_ONLY 0xFA8000 TO 0xFABFFF;
PAGE_FB = READ_ONLY 0xFB8000 TO 0xFBBFFF;
PAGE_FC = READ_ONLY 0xFC8000 TO 0xFCBFFF;
/* PAGE_FD = READ_ONLY 0xFD8000 TO 0xFDBFFF; intentionally not defined: equivalent to ROM_4000 */
PAGE_FE = READ_ONLY 0xFE8000 TO 0xFEBFFF;
/* PAGE_FF = READ_ONLY 0xFF8000 TO 0xFFBFFF; intentionally not defined: equivalent to ROM_C000 */
END
PLACEMENT /* 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, /* eventually OSEK code */
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_4000*/;
DEFAULT_ROM INTO PAGE_FE, PAGE_FB, PAGE_FA, PAGE_F9, PAGE_F8,
PAGE_F7, PAGE_F6, PAGE_F5, PAGE_F4, PAGE_F3, PAGE_F2, PAGE_F1, PAGE_F0,
PAGE_EF, PAGE_EE, PAGE_ED, PAGE_EC, PAGE_EB, PAGE_EA, PAGE_E9, PAGE_E8,
PAGE_E7, PAGE_E6, PAGE_E5, PAGE_E4, PAGE_E3, PAGE_E2, PAGE_E1, PAGE_E0;
//.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 /* all variables, the default RAM location */
INTO RAM;
PAGED_RAM INTO /* when using banked addressing for variable data, make sure to specify
the option -D__FAR_DATA on the compiler command line */
RAM_FB, RAM_FC;
MyRAMSection INTO RAM_FD ; //自定义一个RAM空间
MyFLASHSection INTO PAGE_FC; //自定义一个FLASH空间
//.vectors INTO OSVECTORS; /* OSEK vector table */
END
我的FLASH操作代码如下:
/*************************************************
Flash初始化程序
*************************************************/
void Flash_init(void)
{
FCLKDIV=0x15; // 不采用8分频,因为OSCLK=4M,又为了使FCLK
// 达到190KHZ,所以FDIV=21,即FCLK=4M/21=190.5KHZ
FCNFG=0x00; // 禁止FLASH相关操作的中断
while(FCLKDIV_FDIVLD == 0); // 等待时钟设置成功
FPROT_FPOPEN=1; // 允许对FLASH进行编程与擦除
FPROT_FPHDIS=1; // FLASH保护禁止
FPROT_FPLDIS=1; // FLASH保护禁止
}
#pragma CODE_SEG NON_BANKED
/*************************************************
将指定FLASH页面的指定地址的数据擦除
page:页地址
addr:页中的指定地址
*************************************************/
void flash_erase_word(byte page,word addr)
{
while(!(FCLKDIV & 0x80)); //复位后时钟分频是否做出修改
while(!(FSTAT & 0x80)); //命令缓冲区是否为空
while(FSTAT & 0x30) //判断ACCERR/PVIOL是否为1
FSTAT |= 0x30; //如果是,则写1清标志位
while(!(FPROT & 0x80)); //FLASH是否允许进行编程
PPAGE = page;
page=page&0x0C;
page=page>>2;
FCNFG = 3-page;
*((volatile word *)(addr))=Dump;//写入0xFF,擦除FLASH
FCMD = 0x40; //置擦除命令
FSTAT|=0x80;
while(!(FSTAT & 0x80));
while(!(FSTAT & 0x40)); //命令是否执行完毕
}
/*************************************************
向指定FLASH页面的指定地址写入一个字的数据
page:页地址
addr:页中的指定地址
data:要写入的数据
*************************************************/
void flash_write_word(byte page,word addr,word data)
{
while(!(FCLKDIV & 0x80)); //复位后时钟分频是否做出修改
while(!(FSTAT & 0x80)); //命令缓冲区是否为空
while(FSTAT & 0x30) //判断ACCERR/PVIOL是否为1
FSTAT |= 0x30; //如果是,则写1清标志位
while(!(FPROT & 0x80)); //FLASH是否允许进行编程
PPAGE = page;
page=page&0x0C;
page=page>>2;
FCNFG = 3-page;
*((volatile word *)(addr))=data;//写入0xFF,擦除FLASH
FCMD = 0x20; //置编程命令
FSTAT|=0x80;
while(!(FSTAT & 0x80));
while(!(FSTAT & 0x40)); //命令是否执行完毕
}
#pragma CODE_SEG DEFAULT
但是我调用了
flash_erase_word(0xFA,0x0000);
flash_write_word(0xFA,0x0000,0xaabb);
运行之后,在BDM下,调看memory区,发现0xFA8000地址的数据还是0xFF!
[此贴子已经被作者于2008-9-19 10:52:26编辑过]
你要操作的地址属于IFLASH区的,而你操作的方式是针对D-FLASH的。你是打算把数据存入FLASH中方便以后调用,还是像操作EEPROM一样用来保存可以擦写的数据?
不是很明白这两者之间的差别,不都是往FLASH里写入数据吗?
[此贴子已经被作者于2008-9-19 13:33:38编辑过]
窗口值的范围是从0x8000 到 0xBFFF
固定地址的范围是从0x4000 到 0x7FFF, 0xC000 到 0xFEFF
你操作的地址 page = 0xFA, addr = 0x0000, 这个并不在FLASH的地址范围内。
从你的PRM文件来看,操作的时候最好把数据写在固定地址 0x4000 - 0x7FFF 这个区域里,因为这个区域现在没有分配,烧程序时这一块不会被占用,可以安全的存放数据。
另外一点,如果你要查看地址的话,注意用本地地址的方式来查看,举个例子,0x4000这个地址对应的本地地址为" 0xFD8000'L ",即 page = 0xFD, addr = 0x8000
[此贴子已经被作者于2008-9-19 15:27:31编辑过]
PAGE_FA = READ_ONLY 0xFA8000 TO 0xFABFFF;
这个不就是FLASH的分页地址吗? page = 0xFA, addr = 0x0000不就表示地址是0xFA页的第0个地址.
另外,固定页面的FLASH操作我都试过了,没问题,我只是想试下操作分页的FLASH空间.
分页的话你就把地址改一下,你写的0x0000这个地址是 local address, 寻址的话这个地址对应的是寄存器区,你找一个分页的区号试一下,记得从prm文件里把那个区分出来。
你改成这样试试
flash_erase_word(0xFA,0x8000);
flash_write_word(0xFA,0x8000,0xaabb);
prm文件里
DEFAULT_ROM INTO PAGE_FE, PAGE_FB, /*PAGE_FA, */PAGE_F9, PAGE_F8,
PAGE_F7, PAGE_F6, PAGE_F5, PAGE_F4, PAGE_F3, PAGE_F2, PAGE_F1, PAGE_F0,
PAGE_EF, PAGE_EE, PAGE_ED, PAGE_EC, PAGE_EB, PAGE_EA, PAGE_E9, PAGE_E8,
PAGE_E7, PAGE_E6, PAGE_E5, PAGE_E4, PAGE_E3, PAGE_E2, PAGE_E1, PAGE_E0;
local address 是这样分配的
0000~07FF ----- REGISTERS
0800~0BFF ----- EEPROM window
0C00~0FFF ----- EEPROM window
1000~1FFF ----- RAM window
2000~2FFF ----- RAM fix
3000~3FFF ----- RAM fix
4000~7FFF ----- FLASH fix
8000~BFFF ----- FLASH window
C000~FFFF ----- FLASH fix
只有在地址属于window这一段内,才需要PAGE寄存器来判断是具体哪个地址
谢谢楼上大虾的耐心回复.你指出的地址空间分配我是清楚的.现在我是想知道如何操作页寻址的空间.
已经将PAGE_FA从DEFAULT_ROM 中屏蔽掉了,这个确实是应该屏蔽掉的。
但是,0x0000这个地址不是 local address!而是每页里的相对地址,如果写成
flash_erase_word(0xFA,0x8000);
flash_write_word(0xFA,0x8000,0xaabb);
刚刚试了,程序无法运行,死掉了!
写成flash_erase_word(0xFA,0x0000); 则实际操作的地址应该就是0xFA8000
[此贴子已经被作者于2008-9-19 16:03:33编辑过]
PAGE_F8 = READ_ONLY 0xF88000 TO 0xF8BFFF;
PAGE_F9 = READ_ONLY 0xF98000 TO 0xF9BFFF;
/*PAGE_FA = READ_ONLY 0xFA8000 TO 0xFABFFF; */
PAGE_FB = READ_ONLY 0xFB8000 TO 0xFBBFFF;
PAGE_FC = READ_ONLY 0xFC8000 TO 0xFCBFFF;
/* PAGE_FD = READ_ONLY 0xFD8000 TO 0xFDBFFF; intentionally not defined: equivalent to ROM_4000 */
PAGE_FE = READ_ONLY 0xFE8000 TO 0xFEBFFF;
/* PAGE_FF = READ_ONLY 0xFF8000 TO 0xFFBFFF; intentionally not defined: equivalent to ROM_C000 */
这个我刚才漏了
0x7E8000 是 global address
0xFA8000 是 logical address
logical address = ( 0xFA( page ) << 16 ) + ( 0x8000( local address ) )
先谢谢fayefayehoo 的热心解答。但是我按照你说的方法试了,结果程序死掉了!我把工程文件发上来,请帮我看看吧!
[attach]5137[/attach]
void Flash_init(void)
{
if( !FCLKDIV_FDIVLD )
{
FCLKDIV_PRDIV8 = 0;
FCLKDIV = 21;
FCNFG = 0;
}
FPROT_FPOPEN=1;
FPROT_FPHDIS=1;
FPROT_FPLDIS=1;
}
void flash_write_word(byte page,word addr,word data)
{
FSTAT = 0x30;
PPAGE = page;
*((word *)addr) = data;
FCMD = 0x20;
FSTAT = 0x80;
while( !FSTAT_CBEIF );
while( !FSTAT_CCIF );
}
换上去试一下,我这边没有这块片子,调试不了
[此贴子已经被作者于2008-9-24 15:36:51编辑过]
fayefayehoo,非常感谢你的耐心解答。
现在又有新的发现,如果在BDM下使用单步调试,程序能够运行下去,并且0xFA8000地址的FLASH区能够写入数据!但是,一旦点了"RUN",或者是将芯片复位,程序就死掉了!
一起学习,共同进步嘛。
能不能脱离BDM来调试,通过SCI或者CAN来读取0xFA8000地址的数据,以此确定是否正确写入数据,我在用BDM调试烧写FLASH时也遇到类似问题。我试一下看看是不是用BDM才会有问题?
单步可以点RUN就不行可能是因为flash读写是在高于芯片电源电压下进行的.这样会导致程序运行不稳定.你可以试一下将 // FSTAT=0x80; while(!(FSTAT&0x40));这两句转成机器码放入RAM中运行.
这是这两句的机器码const INT8U P[18] = {0x18,0x0B,0x80,0x01,0x05,0xF6,0x01,0x05,0x87,
0x87,0xC4,0x40,0x8C,0x00,0x00,0x27,0xF4,0x3D}. RAM中的这些机器码放入一数组中,flash擦写时调用就行了for (i=0; i<18; i++) PrgOfRam = P;当要执行 FSTAT=0x80; while(!(FSTAT&0x40));这两句时就换成asm("JSR PrgOfRam);就ok了.
首先谢谢luojun2005,按照你说的方法,程序运行正常了!
只是const INT8U P[18] 应该改为INT8U P[18],因为const是定义FLASH的,而这里应该把数组定义到RAM中吧
也就是说将对FLASH读写的操作代码放到RAM中去执行。但是我不明白为什么会有这种情况出现,FLASH读写的特殊性在芯片的文档里有提到过吗?这算不算是CW的一个BUG呢?
《嵌入式系统--使用HCS12微控制器的设计与应用》
Flash在线编程时提供一下两种方案:
1 将擦除与写入程序放在不包含要擦/写区域的Flash块中,这样进行擦/写操作时,擦/写程序就可以直接在Flash中运行,不需要移到RAM中运行。
2 将擦除与写入程序放在包含要擦/写区域的Flash块中,这样进行擦/写操作时,擦/写程序不能直接在Flash中运行,需要移到RAM中运行。
我的问题是,对于XEP100系列的单片机,是不是在操作FLASH时也必须按以上方案来执行?
但是我是把对FLASH操作的代码放在NON_BANKED块的,而要操作的FLASH地址(0xFA8800)与操作代码并不在同一个FLASH块啊!
这里的块应该是指BLOCK,不是指PAGE,不过不知道哪些PAGE是划分在BLOCK0,哪些是划分在BLOCK1中的,这个数据手册上我还没找到。
这里的块应该是指BLOCK,不是指PAGE,不过不知道哪些PAGE是划分在BLOCK0,哪些是划分在BLOCK1中的,这个数据手册上我还没找到。
对啊,我只在文档上看到过分成4个BLOCK,但是具体怎么划分的就不知道了!
把代码数组改了半天,终于在XEP100上面也能正常编程FLASH了
const U08 P[18] = { 0x18, 0x0B, 0x80, 0x01, 0x06, 0xF6, 0x01, 0x06, 0x87, 0x87, 0xC4, 0x80, 0x8C, 0x00, 0x00, 0x27, 0xF4, 0x3D };
[此贴子已经被作者于2008-10-7 16:28:22编辑过]
收益颇多啊,我现在正在写这方面代码
欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) | Powered by Discuz! 7.0.0 |