打印

EEPROM问题,请张教主救命啊.

[复制链接]
3054|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
win2000_li|  楼主 | 2008-5-9 11:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这个程序是按照张教主的改了一点点.
但是不能用啊.我是用在MC9S08SG8上的.
一运行,程序就会死机,总线频率发生频繁变化.后重启.
我主要是拿来用,在底层操作也不熟.请张教主指点.请大家帮我一下.

看一看这个程序哪里出了问题的.
/* This is a linker parameter file for the mc9s08sg8 */

NAMES END /* CodeWarrior will pass all the needed files to the linker by command line. But here you may add your own files too. */

SEGMENTS /* Here all RAM/ROM areas of the device are listed. Used in PLACEMENT below. */
    EEPROM                   =  READ_ONLY    0xE000 TO 0xE3FF;
    Z_RAM                    =  READ_WRITE   0x0080 TO 0x00FF;
    RAM                      =  READ_WRITE   0x0100 TO 0x027F;
    ROM                      =  READ_ONLY    0xE400 TO 0xFFAD;
 /* INTVECTS                 =  READ_ONLY    0xFFC0 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; 

    _DATA_ZEROPAGE,                     /* zero page variables */
    MY_ZEROPAGE                         INTO  Z_RAM;
END


STACKSIZE 0x50

VECTOR 0 _Startup /* Reset vector: this is the default entry point for an application. */





#include"DSD.h"
#include"MC9S08SG8.h"

#define SIZE_FUNC_RAM 50           //擦写在RAM中的空间.

//函数类型声明
void WriteEE(byte*, byte*, byte);   //写一串数据字节到E2
void EraseEE(byte*);                //擦除E2数据页

#pragma CONST_SEG EEPROM
const byte EE_Data[1023];           //保留一页Flash空间作为E2模拟
//==============================================================
// Following data are declared in the direct addressing area
// for fast access (address < 0x100)
//==============================================================
#pragma DATA_SEG SHORT MY_ZEROPAGE //direct addressing data segment
byte testData[8] = "12345678";     //测试时被写入E2的数据

//==============================================================
// Following data are declared in the common data area
// (address >= 0x100)
//==============================================================
#pragma DATA_SEG DEFALUT          //default data segment

//MCU初始化子程序
void MCU_init(void)
{
    SOPT1 = 0x00;
    SOPT2 = 0x00;
    
    ICSC1_CLKS  = 0;
    ICSC1_IREFS = 1;
    ICSC1_RDIV  = 0;
    ICSC2_BDIV  = 2;
    ICSTRM      = 0xB5; //自调整  0x96
    // 配置时钟频率
    FCDIV_PRDIV8 = 0;
    FCDIV_DIV = 19; //set FCLK base on 8MHz Fbus  200K
}


//下面这段代码是专门为启动Flash编程命令然后查询编程结束标志
//在执行之前必须被拷贝到RAM区(任意地址),然后从RAM中运行
//=============================================================================
byte ExecEePrgCmd(byte cmd)
{
    FCMD = cmd;        //set command
    FSTAT_FCBEF = 1;   //command launched and FCBEF cleared
    _asm NOP;          //wait at least 4 nop
    _asm NOP;
    _asm NOP;
    _asm NOP;
    if(FSTAT_FPVIOL || FSTAT_FACCERR)   //exit if encounter any error
    {  
        return(0);                       //return with error flag
    }
    
    while(!FSTAT_FCCF)                   //wait for FCCF=1
    {                
        __RESET_WATCHDOG(); 
    }
    return(1);                           //return with success
}


//定义上面一段代码的长度,编译后不超过50字节
//写一串数据到模拟E2区,大部分代码是在Flash区内运行的,只是上面关键的一小段代码必须拷贝到RAM区才能运行
void WriteEE(byte* eeAddr, byte* datBuff, byte byteCount)
{
    byte i;
    byte *srcPtr;
    byte codeBuff[SIZE_FUNC_RAM]; //buffer size is slightly bigger than the length of ExecEePrgCmd function

    //这里示范的是将关键代码拷贝到局部变量(堆栈)区。用户可以将代码拷贝到静态数据区,一样使用
    //Copy ExecEePrgCmd code into RAM
    srcPtr = (byte*)ExecEePrgCmd;          //function entry in Flash
    for(i=0;i<SIZE_FUNC_RAM;i++)
    {                                      //do byte copy
        codeBuff = srcPtr;
    }

    FSTAT_FACCERR = 1;                      //clear any pending Flash error flag

    while (byteCount)
    {
        *eeAddr++ = *datBuff++;             //latch data byte and memory address
        Disable_Interrupts;                 //禁止任何中断,很重要!!!
        ((byte (*)(byte))codeBuff)(0x20);   //编程一个字节 在前面加 (void)就没有了报警 -C1420
        Enable_Interrupts;
        byteCount--;
    }
}


//擦除E2页面,原理基本同上//=============================================================================
// Erase a page of EEPROM (Flash emulated)
//=============================================================================
void EraseEE(byte* eeAddr)
{
    byte i;
    byte *srcPtr;
    byte codeBuff[SIZE_FUNC_RAM];       //buffer size is slightly bigger than the length of ExecEePrgCmd function

    //Copy ExecEePrgCmd code into RAM
    srcPtr = (byte*)ExecEePrgCmd;       //function entry in Flash
    for(i = 0; i < SIZE_FUNC_RAM; i++)  //do byte copy
    { 
        codeBuff = srcPtr;
    }

    FSTAT_FACCERR = 1;                   //clear any pending Flash error flag

    *eeAddr = 0;                         //latch memory address
    Disable_Interrupts;
    ((byte (*)(byte))codeBuff)(0x40);    //do page erase在前面加 (void)就没有了报警 -C1420
    Enable_Interrupts;
}

//主程序入口
void main(void)
{
    MCU_init();
    Enable_Interrupts;
    EraseEE((byte*)EE_Data);
    WriteEE((byte*)EE_Data, testData, 8);
    for(;;) 
    {
        _asm NOP
        _asm NOP
        __RESET_WATCHDOG(); // feeds the dog
    }
}


相关帖子

沙发
张明峰| | 2008-5-9 13:52 | 只看该作者

好像漏了点什么

prm文件中的placement部分没有看到EEPROM段的指派。

PLACEMENT /* Here all predefined and user segments are placed into the SEGMENTS defined above. */
   ...
   MyEEData    INTO   EEPROM;
END

#pragma CONST_SEG MyEEData
const byte EE_Data[1023];           //保留一页Flash空间作为E2模拟

使用特权

评论回复
板凳
win2000_li|  楼主 | 2008-5-9 14:14 | 只看该作者

谢谢,继续请教.

好的,我把以下这两条不要就可以了
//#pragma CONST_SEG EEPROM
//const byte EE_Data[1023];           //保留一页Flash空间作为E2模拟

调用函数时是这样
EraseEE((byte*)0xE000);
WriteEE((byte*)0xE000, testData, 8);

我看了结果,在0xE000处开始确时写了8个测试字节.

问题1:
如果加与不加有什么区别呢???


问题2:
#define SIZE_FUNC_RAM 50           //擦写在RAM中的空间.

这个数字为什么不能改啊??

我一改到就会死机啊.

因为我想写EEPROM时少占用些RAM资源.
 
我的单片机里只有256.


问题3:
这条语句怎么理解不到,请老师指点.
((byte (*)(byte))codeBuff)(0x40);


问题4:
我的应用还要读函数,想请教在如何写**(思路)


诚心请教张教主.

使用特权

评论回复
地板
win2000_li|  楼主 | 2008-5-9 14:50 | 只看该作者

顶起!!!

对了,我刚刚做了实验,用您的方式来做的.

是正确的.

使用特权

评论回复
5
张明峰| | 2008-5-9 17:22 | 只看该作者

回答如下:

问题1:
源程序中用#pragma声明的段并不是直接对应到prm文件中的SEGMENTS中定义的各段。它必须通过PLACEMENT声明将两者联系起来。如果PLACEMENT中没有指派用户定义的特殊段具体到哪一个内存段,则将被放到缺省段中。对于你定义的const类型变量,会和程序代码合在一起存放。你在擦除EE数据时把部分代码也擦除了,当然一起全乱了;

问题2:
50这个数据可以改。你可以把它改大,保证不出问题。但如果改小,就会有问题(改成49应该没有问题)这个数据只是确定把Flash区的代码拷贝到RAM去的长度。具体长度是函数ExecEePrgCmd编译后的代码长度。我得到50这个数是看了最终该函数的代码字节大概是40多字节,故放50。如果数据太小拷贝不完整,RAM中的代码就无法执行了。

问题3:
这是标准C语言中对函数指针的定义方式。ramBuff在定义时是普通数据数组。代码被拷贝到这里后要在这里运行,所以数组的首地址就成了函数入口。为了使编译器能产生正确的代码,需将数据指针强制转换为函数指针。看来兄弟C语言学艺不精啊。

问题4:
读Flash中模拟的EE数据再简单不过,就象读RAM中的数据一模一样。飞思卡尔的8位单片机架构决定了RAM和Flash属于同一线性寻址空间。

使用特权

评论回复
6
yewuyi| | 2008-5-11 19:59 | 只看该作者

FLASH模拟EE~~

使用特权

评论回复
7
win2000_li|  楼主 | 2008-5-12 22:11 | 只看该作者

谢谢张工的答复.

谢谢张工的回复,让我明白很多.

我再仔细读一下PDF,在你的这些函数加一些其它功能.

如计算偏移量,计算EEPROM剩余空间.读取函数等.

继续努力,加强学习.哈哈!!

谢谢张工指点.

最后还是想说点,如果把flash写成一个标准的API,我想用起来会更好。

尤其是像我这种初学者来说,那就太好。加一些说明,更有注于理解。

使用特权

评论回复
8
yewuyi| | 2008-5-21 21:59 | 只看该作者

今日再次进来看到此帖,对张工的这段有点疑问!

张工在5楼回复内容的一段如下:
问题1:
源程序中用#pragma声明的段并不是直接对应到prm文件中的SEGMENTS中定义的各段。它必须通过PLACEMENT声明将两者联系起来。如果PLACEMENT中没有指派用户定义的特殊段具体到哪一个内存段,则将被放到缺省段中。对于你定义的const类型变量,会和程序代码合在一起存放。你在擦除EE数据时把部分代码也擦除了,当然一起全乱了;


问题:
LZ在连接文件因为没有指定const byte EE_Data[1023]的定位地址,所以编译器把EE_Data[1023]强制放到DEFAULT中去了,从而导致程序代码和代码合在一起存放,但使用FLASH模拟EEPROM,这两个数据段本来就都是共同都放在ROM段中的啊?!这样解释擦除EE数据时会冲掉部分代码是不是不太合适?

呵呵,我没怎么用过FSL,也没用过FSL的FLASH模拟EE,但我猜测这样解释是不是更完整一点:
因为FLASH的特性,擦除是按页操作的,所以在用FLASH模拟EE的时候要注意把EE的连接定位放到一个单独的ROM上,并且在这个页上不应该有应用程序代码,如果不在连接文件中单独划出一个页做EE模拟,那么按照编译连接的规则,其最终的连接定位是连续的,一般用FLASH模拟EE区的时候,MCU会先执行一个擦除整页操作,所以整个页上的数据都会被KILL掉,如果应用程序代码中的有那么一段不开眼的‘闯入者’自然也难以幸免,从而导致用户应用代码丢失的故障现象。

呵呵,请张工指教一下,晚上翻FSL的选型手册,看到QG系列的低功耗特性时非常兴奋,还想着明天早上找FREETECH问问价格好不好的,但仔细一翻,没有LCD驱动,呵呵,白忙乎了^^^

使用特权

评论回复
9
hotpower| | 2008-5-21 22:14 | 只看该作者

学习学习~~~没实战过没资格发表见解~~~

使用特权

评论回复
10
张明峰| | 2008-5-22 09:26 | 只看该作者

8楼正解, 100%

感谢yewuyi朋友精准的补充说明。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

142

主题

718

帖子

1

粉丝