|
Atmel 的AVR M8 的I2C/TWI BootLoader终于稳定了,真的还有不少问题呢。下面总结一下,希望对后来人有帮助。
我的目的是,将整个BootLoader都放到M8自带的BootLoader段内,然后加电时从BootLoader启动,再由程序通过I2C总线上传新固件或者引导BootLoader启动程序。
看起来并不复杂,将整个BootLoader的代码都编译进BootLoader段也很容易。通过在调用的函数前加上BOOTLOADER_SECTION,这个是在<avr/boot.h>里定义的一个宏。告诉编译器这个函数要放到bootloader段里。最后的实际编译效果可以查看那个.map文件。
这里有一点比较麻烦,就是必须将主函数放到最前面,否则加电后可能先执行某个子程序去了。通过将所有调用的函数前加上static就可以做到这点。
以上步骤都相对容易,设置bootloader的段地址也可以在网上找到相关资料。但下面就郁闷了。
经过这样的过程,Bootloader可以被引导,但有的时候不正常。我在测试中加了一个灯的闪烁代码,结果发现有时候灯闪烁的速度很慢。当时不知道原因,以为编译器的问题、内置晶振的不稳定问题、加电电压不稳损坏了代码、芯片损坏等等原因。足足查了4天啊,真是痛苦。3个芯片,同样的代码,有一个怎么都好使,另外2个时好时坏。
最后,在网上找到老外的一个BootLoader,也是I2C的,终于发现问题所在。
原来设置成从BootLoader区引导后,必须在进入C的main前设置好堆栈。以前这部编译器帮我完成了,所以我从没注意。但这回就需要自己来写了。于是一段比较简单的汇编代码后,终于我的BootLoader可以正常执行了。
vectors.S 文件内容:
#include <avr/io.h>
#if __AVR_MEGA__
#define XJMP jmp
#define XCALL call
#else
#define XJMP rjmp
#define XCALL rcall
#endif
.section .boot_vectors,"ax",@progbits
XJMP start
.word 0 // pad (vector 7)
.word 0 // pad (vector 8)
// 中断向量表,我们没有调用中断,所以都是空。
// 保留这个向量表的意识是,一旦我们需要调用中断了
// 可以加在下面。
//vector __vector_9 // OverFlow0
.word 0
//vector __vector_10
.word 0
//vector __vector_11 // OverFlow0
.word 0
//vector __vector_12
.word 0
//vector __vector_13
.word 0
//vector __vector_14
.word 0
//vector __vector_15
.word 0
//vector __vector_16 // OverFlow0
.word 0
//vector __vector_17 // TWI
.word 0
//vector __vector_18
.word 0
//vector __vector_19 // TWI
.word 0
//vector __vector_20
.word 0
//vector __vector_21
.word 0
//vector __vector_22
.word 0
//vector __vector_23
.word 0
//vector __vector_24 // TWI
.word 0
//vector __vector_25
.word 0
//vector __vector_26
.word 0
//vector __vector_27
.word 0
//vector __vector_28
.word 0
//vector __vector_29
.word 0
//vector __vector_30
.word 0
//vector __vector_31
.word 0
//vector __vector_32
.word 0
//vector __vector_33 // TWI
.word 0
// We don't need any vectors higher than 33, so don't waste the flash
#define __zero_reg__ r1
// 全局的__stack变量
.global __stack
.set __stack, RAMEND
start:
// 设置堆栈,这个非常重要!
// 必须在进入C程序前设置好
clr __zero_reg__
out _SFR_IO_ADDR(SREG), __zero_reg__
ldi r28,lo8(__stack)
ldi r29,hi8(__stack)
out _SFR_IO_ADDR(SPH), r29
out _SFR_IO_ADDR(SPL), r28
ldi r24,lo8(0)
ldi r25,hi8(0)
XJMP main
修改了老外的引导代码,简化了一些。这个是针对M8芯片的。
由于换文件后如果有同名的section,编译器会在后面自动加一个.1。所以这里用了2个section。
.bootloader 0xc25,这个是给C的程序用的。偏移了0x25个字节,因为那个汇编编译后生成了这么多的代码。
.boot_vectors 0xc00,这个是给这个汇编用的。
需要在Project Options的Memory Settings里设置好。
[ 本帖最后由 c_nmusic 于 2009-2-26 18:39 编辑 ] |
|