首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

请大家帮我看看我这个操作FLASH的代码有什么问题

请大家帮我看看我这个操作FLASH的代码有什么问题

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 */

这个我刚才漏了

0x7E8000global address

0xFA8000logical 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了.

返回列表