catnull 发表于 2012-7-19 08:30:23

关于Atmega8L的bootloader的基于源代码的重新编译

我做了一个DIY 的基于Atmega8L的arduino的板子,参考了阿古(宫微宏老师)的博客介绍。我外接了8Mhz的晶振,因为Atmega8L手册上说,只允许最大加到8Mhz.
用avr编程器写入的bootloader,一个系列是由optiboot编译而来,这个版本做了一些优化,得到的bootloder跑不起来。思路回到arduino 自带源代码的Atmega8版本的bootloader , 就是在arduino-1.0-windows\arduino-1.0\hardware\arduino\bootloaders\atmega8文件夹内,



可以看到Makefile自动编译配置文件,一个生成的bootloader文件AtmegaBOOT.hex ,还有AtMegaBOOT.c,这个目录就是我们编译所需要的源代码目录。
下面开始配置编译的环境,编译器是arduino自带的avr-gcc(avr-g++)编译器,这一套编译器组件的目录类似arduino-1.0-windows\arduino-1.0\hardware\tools\avr,实际上是winavr(读作whenever :-))的20081205版本,更多的版本在sourceforge上有,从20021111的第一版到最新的20101100都有,请goole一下。这里我们就不麻烦了,直接用arduino 的。为了方便命令行运行make命令,可以在path 中加入这个编译器的两个可执行文件目录,一个是arduino-1.0-windows\arduino-1.0\hardware\tools\avr\utils\bin,这个目录就包含了一些工具软件,例如make.exe就在这里头。还有一个可执行文件目录arduino-1.0-windows\arduino-1.0\hardware\tools\avr\bin,这里头是编译器的各个环节的工具,比如avr-gcc.exe等。下面说说怎么加path,我使用的是winxp,其它的类似。
1、先右击桌面“我的电脑”图标,点击属性



2、选择“高级”标签页,点击下方的环境变量



3、选择当前用户的PATH 变量选项,并点击编辑



4、在变量值内,我们可以看到系统原有的一些目录的路径,各个路径之间用分号隔开,所以,我们在最后增加一个分号,然后再在后面加上我们的两个目录,arduino-1.0-windows\arduino-1.0\hardware\tools\avr\utils\bin;arduino-1.0-windows\arduino-1.0\hardware\tools\avr\bin;注意,方括号内的内容改成你自己的arduino 目录。加好后,点击确定。这样环境变量就改好了。



接下来测试编译环境是否正常,点击开始——》运行,输入"cmd.exe",打开命令行窗口。输入命令"make --version"和“avr-gcc--version",注意后面的参数之间用空格隔开。可以看到下面的图。




好了,编译环境设置好了,下面回到刚才的源代码目录。
介绍一下这次编译的目标,使bootloader的运行的晶振频率从默认的16Mzh更改为8Mhz,波特率保持官方的19200不变。这个需要修改Makefile 文件了。
需要做3个地方的改动:
1、修改变量DIRAVR, 只需要加入这一行就可以:"DIRAVR = D://arduino/arduinosoftware/arduino-1.0-windows/arduino-1.0/hardware/tools/avr 。 说明:这是编译器组件所在的目录,我们使用的是arduino-1.0-windows所自带的winavr20081205版本,因为avr-gcc 的工具链来自gun平台,目录的斜杆尊重unix的传统,是"/",而不是windows 和dos 的传统"\"。
2、修改晶振频率,找到DEFS       = -DF_CPU=16000000 -DBAUD_RATE=19200这一行,
修改为DEFS       = -DF_CPU=8000000 -DBAUD_RATE=19200 。说明:这里设置频率为8Mhz,波特率为19200,没有更改。
3、修改优化参数,这是最重要的一步,也是整篇文章最关键的地方。winavr从20021111版到现在的最新的20100110版,gcc的内核版本,从原来的gcc-3.4.2,发展到了现在的gcc-4.3.2版本。而这个Atmega8BOOT.c 编写于2003年,Makefile的最新版本是2004年,年代太久远了。所以需要修改优化参数。如果不修改,生成的中间代码太大了,然后链接不成最后的hex文件。找到
OPTIMIZE   = -Os , 修改为OPTIMIZE   = -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls 。说明:-fno-inline-small-functions 这个优化选项是最重要的,意思是告诉gcc编译器,不要把一些短函数,变成inline的处理.inline 处理的原理是,把一些短小的函数,不是编译成rjmp,rcall之类的汇编指令,而是把这个短函数的代码,变成了不用回调的顺序执行码,安放到汇编代码所调用的位置。gcc 是想把速度提高起来,因为回调用到堆栈操作啊啥的,比较慢,可是代码却臃肿了,到处都是重复的代码。所以,加上了这个优化选项,等于是告诉gcc编译器,我不要速度了,我要的是魔鬼身材:-)。编译后得到的hex的代码有2718字节的大小,大约3K。

修改后的Makefile的内容如下:
# Makefile for ATmegaBOOT
# E.Lins, 2004-10-14

# program name should not be changed...
PROGRAM    = ATmegaBOOT

PRODUCT=atmega8

# enter the parameters for the UISP isp tool
ISPPARAMS= -dprog=stk500 -dserial=$(SERIAL) -dspeed=115200


#DIRAVR = /usr/local/avr
DIRAVR = D://arduino/arduinosoftware/arduino-1.0-windows/arduino-1.0/hardware/tools/avr
DIRAVRBIN = $(DIRAVR)/bin
DIRAVRUTILS = $(DIRAVR)/utils/bin
DIRINC = $(DIRAVR)/include
DIRLIB = $(DIRAVR)/avr/lib


MCU_TARGET = atmega8
LDSECTION= --section-start=.text=0x1c00
FUSE_L   = 0xdf
FUSE_H   = 0xca
ISPFUSES   = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --wr_fuse_l=$(FUSE_L) --wr_fuse_h=$(FUSE_H)
ISPFLASH   = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --erase --upload if=$(PROGRAM).hex -v


OBJ      = $(PROGRAM).o
#OPTIMIZE   = -Os   ;old version ,this trig for optimize,will lead to a too big bin file ,which will get out the region of .text ,we need to optimize more.the reason is this Make file is too old ,and should compiled under the winavr20040720 toolchain. but now we use the winavr20081205 toolchain.
OPTIMIZE   = -Os -fno-inline-small-functions -fno-split-wide-types -mshort-calls

#DEFS       = -DF_CPU=16000000 -DBAUD_RATE=19200   ; old version , the next is new ,which turn the crystal frequency from 16Mhz to 8 Mhz
DEFS       = -DF_CPU=8000000 -DBAUD_RATE=19200   
LIBS       =

CC         = $(DIRAVRBIN)/avr-gcc


# Override is only needed by avr-lib build system.

override CFLAGS      = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -D$(PRODUCT) $(DEFS) -I$(DIRINC)
override LDFLAGS       = -Wl,-Map,$(PROGRAM).map,$(LDSECTION)

OBJCOPY      = $(DIRAVRBIN)/avr-objcopy
OBJDUMP      = $(DIRAVRBIN)/avr-objdump
SIZE         = $(DIRAVRBIN)/avr-size

all: $(PROGRAM).elf lst text asm size

isp: $(PROGRAM).hex
        $(ISPFUSES)
        $(ISPFLASH)

$(PROGRAM).elf: $(OBJ)
        $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)

clean:
        rm -rf *.s
        rm -rf *.o *.elf
        rm -rf *.lst *.map

asm: $(PROGRAM).s

%.s: %.c
        $(CC) -S $(CFLAGS) -g1 $^

lst:$(PROGRAM).lst

%.lst: %.elf
        $(OBJDUMP) -h -S $< > $@

size: $(PROGRAM).hex
        $(SIZE) $^

# Rules for building the .text rom images

text: hex bin srec

hex:$(PROGRAM).hex
bin:$(PROGRAM).bin
srec: $(PROGRAM).srec

%.hex: %.elf
        $(OBJCOPY) -j .text -j .data -O ihex $< $@

%.srec: %.elf
        $(OBJCOPY) -j .text -j .data -O srec $< $@

%.bin: %.elf
        $(OBJCOPY) -j .text -j .data -O binary $< $@

准备了这么多,就是见证奇迹的时刻了:)
接下来,就是进行编译的过程了。
1、在打开命令行窗口,修改当前目录到所在的盘。介绍一下Dos 命令,默认打开的命令行窗口是C盘,我们要切换到保持源文件的盘,比如我的是D:盘,在命令行中输入"D:" ,按回车键。更改目录 ,输入" cd[\arduino\arduinosoftware\]arduino-1.0-windows\arduino-1.0\hardware\arduino\bootloaders\atmega8" 。方括号内请你自己改成自己的目录。

2、在atmega8目录下输入命令"make clean" ,这是把以前编译过程的中间代码,结果代码等.o .a .hex 扩展名文件全部清空,为新的编译清理空间。

3、输入命令"make” ,是不是太容易了:)刷刷,编译过程一下子过了,最后生成AtmegaBOOT.hex文件等等,是不是特兴奋?



打开Atmega8目录,可以看到我们自己搞出来的hex了吧,呵呵。

之后的事情,我想大家各显神通,用编程器把这个hex烧到Atmega8L芯片里头吧。
这个芯片写好了我们自制的bootloader,已经是arduino 的家族成员了。
下面还有一个工作要做,就是把我们的信息加到arduino 的board的参数选项中。打开D:\arduino\arduinosoftware\arduino-1.0-windows\arduino-1.0\hardware\arduino文件夹的boards.txt 文件,进行修改,修改的模板用ATmega8的直接复制修改。参考看下面的代码:##############################################################

atmega8.name=catnull modified w/ ATmega8L

atmega8.upload.protocol=arduino
atmega8.upload.maximum_size=7168
atmega8.upload.speed=19200

atmega8.bootloader.low_fuses=0xdf
atmega8.bootloader.high_fuses=0xca
atmega8.bootloader.path=atmega8
atmega8.bootloader.file=ATmegaBOOT.hex
atmega8.bootloader.unlock_bits=0x3F
atmega8.bootloader.lock_bits=0x0F

atmega8.build.mcu=atmega8
atmega8.build.f_cpu=8000000L
atmega8.build.core=arduino
atmega8.build.variant=standard说明:其实就把16000000L改成8000000L。
之后的事情,arduino 人都知道了。


思考题:1、编译过程中出现了一个警告,你打算如何把这个警告消除呢?是不是遵从GPL2.0的标准,改一下AtmegaBOOT.c的代码?
2、烧写bootloader时,avr芯片的熔丝位Hfuse 和Lfuse的数值在哪里可以找到?

最终生成的bootloader,在arduino1.0版测试通过,在arduino-0200版本测试通过,在1.0.1最新版测试通不过:(
经过一个下午的努力,在RXD 和TXD(2、3)脚和VCC之间接1K OM的电阻后,在1.0.1版本测试也正常了:)

弘毅 发表于 2012-7-19 10:44:27

好贴。。。强烈加精。。。

Randy 发表于 2012-7-19 10:47:54

真的不错,写的狠详细,希望楼主继续努力!

catnull 发表于 2012-7-19 18:27:12

本帖最后由 catnull 于 2012-7-19 18:30 编辑

自制的板,很多原理不是很清楚。我的设计是,把max232的电平转换小板单独出来,这样板子可以整洁一点,也便于仪器的重复利用:)。但是参考原来的原理图,以及Arduino NG的USB转串口的原理图,USB转串口芯片和M8的2、3脚RXD,TXD 之间的220OM 的电阻,以为是用来保护的。后面发现,我的数据板一掉电,arduino 的启动就不正常,如果数据板一上电,arduino启动就正常了。
这个非常诡异,以为我费了老大劲搞出来的Atmega8L的bootloader跑飞了。
后面冷静一想,靠,这不是硬件问题吗?
一定是数据口的问题。我看一般指示灯都可以用LED串470OM电阻,接在RXD 和VCC之间,起到指示灯作用,我不用LED,我用1KOM的电阻,把RXD 和TXD两个脚上拉到VCC好了。
结果一测试,正的是这个上拉的电阻在搞怪。
记得以前读过一个嵌入式的文章,里面作者就谈到了一个上拉电阻让程序通信失灵的故事。这次我用上了。
只能说, Atmel 真的很小气,在数据口集成一个上拉电阻,要费老大的劲吗?
希望愿意自己DIY的朋友们可以成功。附上我的NG图,



还有一个Free NG图,后面这个是搞了max232芯片的。真的很方便自己DIY.


上面的带232芯片的,有一个自动复位的电路,就是232的8、9j脚组合的电路,真的很给力,

这是修改的上拉电阻的部分

ysit1990 发表于 2012-7-26 11:49:48

这贴 非常有质量 有营养!
关于自动复位电路那里 有点疑问
就是串口线的DTR为什么不是像官方直接
       DTR->104电容->RST
而是 DTR->R2IN->R2OUT->104电容->RST
望指教

catnull 发表于 2012-7-26 20:57:37

ysit1990 发表于 2012-7-26 11:49 static/image/common/back.gif
这贴 非常有质量 有营养!
关于自动复位电路那里 有点疑问
就是串口线的DTR为什么不是像官方直接


应该是利用232电平转换的功能吧。直接接的话不好,电脑的串口的电平标准不一样。

ninjiafan 发表于 2012-10-11 19:21:19

非常感谢,很有含金量的帖子.

迷你强 发表于 2012-10-11 19:30:34

:funk:好贴。

ttyp 发表于 2012-10-22 09:38:10

好东西啊,哪天改改试试看:lol

天天向上/tp 发表于 2013-4-20 23:51:59

还是没怎么看懂~~~~~~~~~~~~·

FutureMaker 发表于 2014-1-15 10:33:16

这个问题是怎么回事啊?

kingqb 发表于 2014-3-25 16:04:34

收获不少:)

catnull 发表于 2014-5-7 16:11:34

本帖最后由 catnull 于 2015-4-14 16:34 编辑

FutureMaker 发表于 2014-1-15 10:33 static/image/common/back.gif
这个问题是怎么回事啊?

画红线部分的目录的分隔符是"\",这是和unix标准不相容的,需要在makefile里的DIRAVR变量里修改为"/"。这是斜杠,方向不同的两个斜杠,所以提醒说文件不存在。

正确的应该改成:

qzhyjd 发表于 2014-9-27 12:50:05

非常有质量 有营养!:):):)

ofourme 发表于 2015-4-16 21:52:05

mark,准备做的mega8的arduino系统。
页: [1] 2
查看完整版本: 关于Atmega8L的bootloader的基于源代码的重新编译