witnessiz 发表于 2010-9-28 03:26:55

WINAVR关于片内eeprom写操作的一个BUG。。。

今天被mega16片内eeprom烦了一天,程序错误莫名其妙。让我感到抓狂的是我的程序是直接复制了用户手册上的C程序。程序如下:(Page19)

void EEPROM_write(unsigned int uiAddress, unsigned char ucData)
{
while(EECR & (1<<EEWE));    /* 等待上一次写操作结束 */

EEAR = uiAddress;         /* 设置地址和数据寄存器*/

EEDR = ucData;            /* 置位EEMWE */

EECR |= (1<<EEMWE);         /* 置位EEWE 以启动写操作*/

EECR |= (1<<EEWE);
}

去网上找资料,多为推荐使用winavr自带的函数。后来反复修改编译烧写一度使我的M16擦写寿命少了一百多次,依然无果。

后来再仿真的时候,忽然发现EEMWE和EEWE永远不可能会同时置位,也就是说,EEWE置位永远在EEMWE清零之后。

不管改成 EECR |= (1<<EEMWE)|(1<<EEWE);还是将两者换位都不行;
(虽然资料上说在EEMWE置位后4个周期就会被清零,所以EEWE必须在EEMWE置位后立即将EEWE置位,但是大家注意上面的程序这两句是上下行的。。)

于是上网搜类似的情况,终于发现有位仁兄和我有同样的疑问 http://bbs.avrvi.com/simple/t16903.html

按照他的说法“于是变半信半疑的用AVR Simulator看看EECR|=_BV(EEWE)这条语句所消耗的时间,一看发现其用了5个时钟周期,这时我便豁然开朗了,但是我还是想不通为什么EECR|=_BV(EEWE)这条语句会要5个时钟周期这么长,于是便看了这条语句的反汇编,发现Winavr读写I/O寄存器(包括EECR)全是用的LDI,STD指令,即把I/O寄存器当做SRAM处理,而没有用OUT指令,导致其需要花费5个时钟周期,这里要提醒大家注意,Winavr把所有的I/O寄存器都当做SRAM来处理,其花费的时钟周期较长。至此问题已经找出,于是便开始想解决办法,我想到的是在C里面嵌入汇编来做。”

就上下两行的程序,编译之后竟然要花大于4周期的时间。。。。。

于是我根据他的程序做了点修改,嵌入汇编,程序如下:

void EEPROM_Write(uint waddr,uchar wdata)
{
        while(EECR & (1 << EEWE));
        EEAR = waddr;
        EEDR = wdata;                                                                       
       
        asm volatile("PUSH R16" "\n\t"                       
                  "LDI R16,0x04" "\n\t"
                  "OUT 0x1C,R16" "\n\t"                //EECR |= (1 << EEMWE);
                  "LDI R16,0x06" "\n\t"
                  "OUT 0x1C,R16" "\n\t"                //EECR |= (1 << EEWE);
                  "POP R16");
}

就可以用了,由于没有学过AVR的指令集,结合了一些51的汇编,先将R16原来的压栈保护再谈栈,也不知写没写对,反正编译通过,可以正确写操作。说这个是BUG也许不恰当,但是对于初学者来说是相当悲剧的,明明是用户手册上的程序,写在ICC、IAR上可以用,在GCC上就不行给人一种编译器有问题的感觉、、、

关于eeprom的中断,做了之后发现,eeprom的中断貌似仅限于写操作的中断,假设I和EERIE置一后,只有当EEWE清零的时候的时候才会触发中断,即只有“写完”之后才会中断,而“读完”之后不会触发中断,这个只是作为初学者的个人理解,也许是错误的,仅供讨论。

avr_c 发表于 2010-9-28 03:32:37

开优化////os级别

biansf2001 发表于 2010-9-28 08:52:16

不知道ICC是不是这样呢

sharpufo 发表于 2010-9-28 09:12:46

while(EECR & (1 << EEWE));
asm("sbi 0x1C,2"); //EECR |= (1 << EEMWE);
asm("sbi 0x1C,1");//EECR |= (1 << EEWE);
while(EECR & (1 << EEWE));

whyjld 发表于 2010-9-28 10:22:04

学习

yyy71cj 发表于 2010-9-28 10:33:11

我也正想求教winavr的问题,不过我用的是atmega128,在eeprom读写上倒是顺利,而目前是被32K地址限制问题搞死了。winavr不适合做大软件……

yyccaa 发表于 2010-9-28 11:11:11

开优化……感觉是老生常谈的一句话了……开优化后就会用位操作和IO访问。

witnessiz 发表于 2010-9-28 11:57:09

开完贴就睡觉去了。醒来看到了1楼和6楼的回答,马上试了一下。

看了一下程序的汇编后。。。。

http://cache.amobbs.com/bbs_upload782111/files_33/ourdev_586169MLLN5X.jpg
优化-00的汇编 (原文件名:-00.jpg)

http://cache.amobbs.com/bbs_upload782111/files_33/ourdev_586170YHB49P.jpg
优化-01的汇编 (原文件名:-01.jpg)

http://cache.amobbs.com/bbs_upload782111/files_33/ourdev_586171CND987.jpg
优化-02以后的汇编 (原文件名:-02.jpg)

在测试之后发现-01似乎也不行,只有在优化-02及-02之后才会出来正确的写操作。

没想到两句之间优化和没有优化的编译结果竟然相差这么多!

witnessiz 发表于 2010-9-28 11:59:41

回复【2楼】biansf2001 花溅泪
不知道icc是不是这样呢
-----------------------------------------------------------------------

使用手册上的程序ICC应该没有问题吧

witnessiz 发表于 2010-9-28 12:10:02

回复【1楼】avr_c
开优化////os级别
-----------------------------------------------------------------------

回复【6楼】yyccaa
开优化……感觉是老生常谈的一句话了……开优化后就会用位操作和io访问。
-----------------------------------------------------------------------

虽然接触AVR时间不短,但是由于学业忙和自学的关系,现在还是新手。几乎每一本书每一个教学视频都会告诫新手要慎用优化和熔丝

位,所以才会去寻求其他解决方法而非优化,就如我和那个帖子的楼主,这样说来我发现的所谓BUG说起来倒是有点搞笑了

经过这次发现优化确实很重要,但是对我而言,优化造成的后果是不可预知的,我想问一般开了优化后,会优化哪些东西?而编写程序

该注意那些东西?

yyccaa 发表于 2010-9-28 13:21:33

开优化主要就是注意正确使用volatile限定变量,不是不管三七二十一每个变量都加限定,而只是适当的变量加。
新手是要慎用优化,但始终不用优化,你在写代码方面就得长期停留在新手层面。
楼主比很多新手好的地方在于能花时间去读懂反汇编后的代码,这对于学习、了解编译器的优化方式很有好处。

witnessiz 发表于 2010-9-28 17:22:58

回复【10楼】yyccaa
开优化主要就是注意正确使用volatile限定变量,不是不管三七二十一每个变量都加限定,而只是适当的变量加。
新手是要慎用优化,但始终不用优化,你在写代码方面就得长期停留在新手层面。
楼主比很多新手好的地方在于能花时间去读懂反汇编后的代码,这对于学习、了解编译器的优化方式很有好处。
-----------------------------------------------------------------------

争取脱离新手状态。。

wsygb 发表于 2010-11-16 14:14:08

奇怪,我使用EEAR编译无法通过,提示EEAR没有定义,使用EEARL即通过。WINAVR。

wsygb 发表于 2010-11-16 14:28:39

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=717674&bbs_page_no=1&search_mode=1&search_text=EEPROM&bbs_id=1000
m48只对EEARL操作。

easier 发表于 2010-11-16 22:13:08

回复【5楼】yyy71cj
我也正想求教winavr的问题,不过我用的是atmega128,在eeprom读写上倒是顺利,而目前是被32k地址限制问题搞死了。winavr不适合做大软件……
-----------------------------------------------------------------------
ATmega128(L)-
      doc2467.pdf


– 128K Bytes of In-System Reprogrammable Flash
Endurance: 10,000 Write/Erase Cycles
– Optional Boot Code Section with Independent Lock Bits
In-System Programming by On-chip Boot Program
True Read-While-Write Operation
– 4K Bytes EEPROM
Endurance: 100,000 Write/Erase Cycles
– 4K Bytes Internal SRAM


– Up to 64K Bytes Optional External Memory Space---????

qq_zhs 发表于 2010-11-20 19:56:33

哈 楼主被耍了下
那个优化必须要开的就是调试时有些语句优化成几段 C中调试有些步都不走到 乱了
所以出了问题第一个看汇编

elecboy 发表于 2010-11-20 20:29:48

另外提一下,gcc对AVR优化一般选-Os,从大量经验来看,这个优化不仅获得的代码尺寸小,多数情况下,甚至速度也比 -O2级别要快。其实对单片机而言,尺寸优先更为重要,毕竟flash空间有限。

walshao 发表于 2011-12-23 14:19:49

mark

tomy 发表于 2012-1-10 14:38:40

mark ^^^^^

weiyix 发表于 2012-9-19 08:58:47

mark asdfdsa
页: [1]
查看完整版本: WINAVR关于片内eeprom写操作的一个BUG。。。