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清零的时候的时候才会触发中断,即只有“写完”之后才会中断,而“读完”之后不会触发中断,这个只是作为初学者的个人理解,也许是错误的,仅供讨论。 开优化////os级别 不知道ICC是不是这样呢 while(EECR & (1 << EEWE));
asm("sbi 0x1C,2"); //EECR |= (1 << EEMWE);
asm("sbi 0x1C,1");//EECR |= (1 << EEWE);
while(EECR & (1 << EEWE)); 学习 我也正想求教winavr的问题,不过我用的是atmega128,在eeprom读写上倒是顺利,而目前是被32K地址限制问题搞死了。winavr不适合做大软件…… 开优化……感觉是老生常谈的一句话了……开优化后就会用位操作和IO访问。 开完贴就睡觉去了。醒来看到了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之后才会出来正确的写操作。
没想到两句之间优化和没有优化的编译结果竟然相差这么多! 回复【2楼】biansf2001 花溅泪
不知道icc是不是这样呢
-----------------------------------------------------------------------
使用手册上的程序ICC应该没有问题吧 回复【1楼】avr_c
开优化////os级别
-----------------------------------------------------------------------
回复【6楼】yyccaa
开优化……感觉是老生常谈的一句话了……开优化后就会用位操作和io访问。
-----------------------------------------------------------------------
虽然接触AVR时间不短,但是由于学业忙和自学的关系,现在还是新手。几乎每一本书每一个教学视频都会告诫新手要慎用优化和熔丝
位,所以才会去寻求其他解决方法而非优化,就如我和那个帖子的楼主,这样说来我发现的所谓BUG说起来倒是有点搞笑了
经过这次发现优化确实很重要,但是对我而言,优化造成的后果是不可预知的,我想问一般开了优化后,会优化哪些东西?而编写程序
该注意那些东西? 开优化主要就是注意正确使用volatile限定变量,不是不管三七二十一每个变量都加限定,而只是适当的变量加。
新手是要慎用优化,但始终不用优化,你在写代码方面就得长期停留在新手层面。
楼主比很多新手好的地方在于能花时间去读懂反汇编后的代码,这对于学习、了解编译器的优化方式很有好处。 回复【10楼】yyccaa
开优化主要就是注意正确使用volatile限定变量,不是不管三七二十一每个变量都加限定,而只是适当的变量加。
新手是要慎用优化,但始终不用优化,你在写代码方面就得长期停留在新手层面。
楼主比很多新手好的地方在于能花时间去读懂反汇编后的代码,这对于学习、了解编译器的优化方式很有好处。
-----------------------------------------------------------------------
争取脱离新手状态。。 奇怪,我使用EEAR编译无法通过,提示EEAR没有定义,使用EEARL即通过。WINAVR。 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操作。 回复【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---???? 哈 楼主被耍了下
那个优化必须要开的就是调试时有些语句优化成几段 C中调试有些步都不走到 乱了
所以出了问题第一个看汇编 另外提一下,gcc对AVR优化一般选-Os,从大量经验来看,这个优化不仅获得的代码尺寸小,多数情况下,甚至速度也比 -O2级别要快。其实对单片机而言,尺寸优先更为重要,毕竟flash空间有限。 mark mark ^^^^^ mark asdfdsa
页:
[1]