[交流]AVR32 UC3专题学习:细说AVR32 UC3 启动[2009-2-20 Updated]
[闲扯两句]仔细算来,鄙人在ATMEL当山寨AE已经快有3个月了,虽说工资一分没有,但好歹也混了口饭吃。
其间,仔细研究了Software Framework、AVR32 Studio、温习了我那半通不通的外语、体验了一下
越洋会议,也见识了来自世界各地关于AVR和AVR32的各种让人啼笑皆非的问题。而且也从法国老大
的老大那里学到了一个难得的单词:RTFM……
/*
(
据说对那些数据手册都不看,什么都要提问的家伙,就可以这样在心理骂一句RTFM,然后还要把脸一抹,
做微笑状,再键盘上敲下:
If you have any question Please let us known.
Best Regards
XXXX Support team
);
*/
其间,最有意思的一系列事情就是弄清楚AVR32 UC3的启动过程,以及AVR32 Studio里面众多与启动
有关的设置。本人多喜欢卖弄,无奈论坛里面一直没有人提出类似的疑问,只好耐心等待,耐心等待,
终于,在春花烂漫之时,有人注意到trampoline.x和crt0.x这两个可疑的东西。
yeah!yeah!yeah!yeah~~今天天气不错,挺风和日丽的,我们下午不上班,这心情挺爽的……
<font color=red>
以下内容请顺次阅读,跳跃将导致某些内容“理解不能”
A、UC3基本启动流程 完成
B、都是UDF惹的祸…… 完成
C、trampoline.x和UDF的秘密协定 完成
D、AVR32 Studio的Startup和Software Framework的Startup 最新更新filter的内容
<font color=blue>看这个帖子的人一定要再看这个帖子:
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3338552&bbs_page_no=6&bbs_id=1030 >> UC3基本启动流程 <font color=brown>
A、所有AVR32 UC3的程序都是在0x80000000地址开始运行的。
B、如果你的程序因为堆栈溢出,导致PC指针跑飞到0x80000000以前的地址,
并且恰好那个地址上的数据是一个无效的OPCODE时,你会发现程序死机,
如果使用跟踪的方式进行调试,会发现程序总是进入_unhandled exception
的异常处理程序中。如果你运气更糟糕,说不定连_unhanled exception
都无法进入,UC3直接失去和仿真器(mkII或者AVR ONE)的联系……当然
这实际上不是你运气不好,而是因为基本的启动程序中少了一些必要的内容。
C、你可以忘记B点,但一定不要怀疑A所说的内容。我们所有编译的代码都
应该被放置在0x80000000地址。如果你使用BatchISP进行下载,那么请
务必正确填写Offset设置(即0x80000000),因为BatchISP是通过Offset
来判断用户要下载的存储器究竟是SRAM、FLASH还是EEPROM的。如果你使用
mkII、Dragon或者AVR ONE,那么Offset可以保持为默认的0x0。
That`s all,顺便说一下,如果你懂汇编,你会发现UC3几乎不用任何启动代码
也能正常工作。当然,对大部分使用AVR32 Studio的人来说,灾难才刚刚开始。 >> 都是UDF惹的祸
我们知道,ATMEL为了降低用户开发成本,在每一个AVR32 UC3芯片出厂时,都烧入了一个USB Bootloader,
一般被称为UDF。用户只需要借助一根USB线就可以完成对芯片的供电和下载,而无须借助专用的编程或仿真工
具,实际测试中,UDF的下载速度要比mkII编程快得多(AVR32 Studio环境下测试)。但是,UC3系列芯片和AVR
不同:AVR芯片可以通过烧写熔丝的方式为Bootloader程序单独指定一个程序启动地址,即系统复位时都自动从
该地址执行程序,因此普通的用户程序可以放置在固定的0x0000地址上;AVR32 UC3没有这样的熔丝,所有的程
序都从唯一的一个地址0x80000000开始执行,如果Bootloader占用了这一地址,那么它就必须为用户应用程序
制造一个新的虚拟起始地址。另一方面,如果要保留芯片上的Bootloader,用户应用程序也必须绕开Bootloader
所占用的空间——从0x80000000开始的2048个字节,如果用户应用程序没有做专门的处理绕开Bootloader区域,
那么只有两个结果:
1、使用编程器下载程序,将先被迫执行Chiperase将Bootloader区域擦除,然后将用户
应用程序放置在0x80000000起始的位置上。这种做法显然破坏了UDF,这也是很多初学者都遇到
过的情况。幸好现在有很多方法和途径都可以方便的恢复UDF。(恢复UDF的方法请参照附录)
2、使用BatchISP,也就是USB Bootloader下载程序。用户会看到一个提示说,用户的应用
程序和Bootloader Overlap了,并且此时用户的应用程序总也无法正确执行,仿佛打了水漂……
下图就是USB Bootloader的结构,它在自己占用0x8000,0000起始的2048个字节以后,为用户建立了一个
虚假的入口地址0x8000,0200。系统复位时,USB Bootloader程序被运行(即便发生Reset异常,异常处理程序
也会指向0x80000000地址),此时,UDF检测指定引脚的电平是否为指定值,如果检测结果为真,则执行剩下
的IAP代码,计算机将检测到一个USB设备,用户可以通过BatchISP来下载程序;如果检测结果为假,UDF将跳转
到虚拟入口地址处执行,一般为0x80000200,也就是用户程序的入口地址。
一个无视了UDF的用户应用程序,一定是认为自己从0x80000000开始执行的,当该程序通过BatchISP下载
时,0x80000000到0x80000200之间的代码会被UDF直接忽略。那么此时的用户程序就是一个无头僵尸……很难
想象此时在0x80000200处的代码会导致什么意外的结果……
AVR UC3 Address Space -
\
\___ | . . . . . . . |
| |
|--.reset-----------------| 0x8000,0000 Internal Flash
|USB Bootloader | 内部FLASH起始地址
|-------|"lda.w pc, _stext" |
|
| . . . . . . .
|
| | |
|------>|-- _stext----------------|0x8000,0200 User Application Start Address
|User Application | 用户应用程序起始地址
| . . . . . . . |
<font color=blue>附录 如何使用Snail mkII DEMO恢复UDF
1、下载AVR Snail 0.112版,更新Snail mkII DEMO
[该链接经过有效恢复]
点击此处下载 ourdev_418143.rar(文件大小:2.55M) (原文件名:Snail Bootloader.rar)
2、安装最新的AVR32 Studio2.1
3、正确设置Snail mkII DEMO(请参考以往的帖子)
4、在菜单中选择:
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_418144.JPG
(原文件名:1.JPG)
选择UDF版本
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_418145.JPG
(原文件名:2.JPG)
设置UDF启动IAP时检测的引脚,引脚的编号与引脚名称的对应关系可以从头文件uc3xxxxx.h中找到,例如13在UC3B0256中
对应的引脚可以在uc3b0256.h中找到。
其中 ISP_IO_COND_PIN用以选择引脚,ISP_IO_COND_LEVEL用以选择启动启动IAP的有效电平。
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_418146.JPG
(原文件名:3.JPG)
等待完成
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_418147.JPG
(原文件名:4.JPG) >> trampoline.x和UDF的秘密协定
任意打开一个UDF的Example,我们都能在src文件夹下看到这样两个文件:
<font color=blue>trampoline.x和boot.x
http://cache.amobbs.com/bbs_upload782111/files_11/ourdev_418148.GIF
trampoline.x
#include "conf_isp.h"
// 这个section必须被放置在0x80000000地址上
.section.reset, "ax", @progbits
//定义了一个类似void _trampoline(void)的全局函数。
.global _trampoline
.type _trampoline, @function
_trampoline:
// 跳转到 program start.代码段
rjmp program_start
//这句话意思是说接下来的代码program_start:将放置在宏PROGRAM_START_OFFSET所在的地址偏移上,
//而这一偏移是相对整个.section的
.orgPROGRAM_START_OFFSET
program_start:
// 跳转到用户应用程序(Startup代码段所在的内容)
lda.w pc, _stext
trampoline.x等效结构图
AVR UC3 Address Space -
\
\___ | . . . . . . . |
| |
|--.reset-----------------| 0x8000,0000 Internal Flash
-------|"rjmp program_start"| 内部FLASH起始地址
| | Maybe Nothings here |
|
| . . . . . . .
|
| | |
------>|-- program_start---------|0x8000,0200 trampoline.x在用户程序入口做了一个劫持,
-------|"lda.w pc, _stext" | 这样用户的_stext就可以存在于FLASH的任意
| | . . . . . . . | 地址,而不用人为的定位了。
|
|
| | |
------>|-- _stext----------------|Any address in User Application Area
boot.x
#include <avr32/io.h>
#include "conf_isp.h"
……
//定义了一个.reset段
.section.reset, "ax", @progbits
.balign 2
// Reset vector: This must be linked @ 0x80000000.
//定义了一个类似void _start(void)的全局函数。这个函数将被放置在0x8000000000上。
.global _start
.type _start, @function
_start:
mov.w r8, ISP_KEY_ADDRESS
mov.w r9, AVR32_WDT_ADDRESS
mov.w r10, AVR32_FLASHC_ADDRESS
mov.w r11, AVR32_PM_ADDRESS
……
//相对_start开始的一个子函数,用于跳转到虚拟入口地址,也就是用户应用程序区域去执行
start_program_no_isp_key:
……
lddpc pc, program_start_address
//这是一个UDF放置在用户应用程序区的代码片断,其功能是截获复位异常,并将PC指针重新指向
//_start,也就是0x80000000所在的位置执行。这也可以解释为什么重新恢复了UDF的芯片不用操作
//专门的按键时序就可以进入IAP模式——PC机立即认出一个设备。因为刚恢复了UDF的芯片,其用
//户代码区放置的就是下面的代码,这个代码又把程序goto回了UDF的入口处,就好比形成了一个
//大循环。一旦真正的用户程序覆盖了这一部分,循环就被破坏了。
program_start_address:
.word PROGRAM_START_ADDRESS
.section.evba, "ax", @progbits
.balign 2
//定义系统事件 _evba段,详细解释参照论坛的相关专题
// Start of exception vector table: Unrecoverable exception.
.global _evba
.type _evba, @function
_evba:
//将_start的地址送入r8寄存器,也就是将立即数0x80000000送入寄存器r8
lda.w r8, _start
//将对SR寄存器的设置内容送入寄存器R9,也就是将
//AVR32_SR_GM_MASK | AVR32_SR_EM_MASK | (AVR32_SR_M_SUP << AVR32_SR_M_OFFSET)指定的
//立即数送入寄存器r9
mov.w r9, AVR32_SR_GM_MASK | AVR32_SR_EM_MASK | (AVR32_SR_M_SUP << AVR32_SR_M_OFFSET)
//设置sp指针,使其指向堆栈段_estack - 6 * 4的位置
mov sp, _estack - 6 * 4
//将r8~r9的内容压入堆栈
pushm r8-r9
//伪造一个从异常处理程序中返回的操作,rete会自动从堆栈中pop出两个32位数字分别送入pc和sr寄存器
//实际上就完成了让程序返回_start的功能
rete
boot.x等效结构图
AVR UC3 Address Space -
\
\___ | . . . . . . . |
| |
----------------->|--.reset(_start)---------------------| 0x8000,0000 Internal Flash
| |"mov.w r8, ISP_KEY_ADDRESS" | 内部FLASH起始地址
| |"mov.w r9, AVR32_WDT_ADDRESS" |
| | . . . . . . . |
| |-- start_program_no_isp_key----------| start_program_no_isp_key 子程序
| | . . . . . . . |
| |-------|"lddpc pc, program_start_address"|
| |
| | . . . . . . .
| |
| | | |
| |------>|-- _evba-----------------------------|0x8000,0200 User Application Start Address
| | . . . . . . . | 用户应用程序起始地址
------------------| "rete" |
Boot.x约定了UDF的程序流程:从0x80000000进入,假设不满足ISP条件,则通过一个
公共子程序start_program_no_isp_key跳转到0x80000200地址,也就是用户应用程序的实际
入口。同时UDF在用户应用程序做了一个劫持——如果没有任何用户应用程序,则重新进入
UDF状态,也就是形成了一个超级循环。
trampoline.x约定了用户应用程序的结构:程序从0x80000000开始执行,用户应用程序
必须从_stext作为起始入口地址,其位置任意。而trampoline.x自动在虚拟入口0x80000200
处加入了一个跳转语句,将系统控制权交给_stext的代码。实际上trampoline.x不是一个
简单的代码定位汇编函数,而是一个一石二鸟的补丁程序:
如果芯片中有UDF,因为trampoline.x编译生成的代码正好与UDF的代码重合,因此不会
被实际写入到芯片中,因而,系统地引导实际是由UDF完成的:UDF把控制权交给0x80000200
处的trampoline.x子程序program start,而trampoline.x的program start则通过相对跳转
语句将控制权转交给了用户应用程序的_stext。
如果芯片中没有UDF,因为trampoline.x在0x80000000处放置了有效的代码,将系统控制
权直接交给program start,因而加入了trampoline.x的用户应用程序可以同时兼容使用UDF
或者不使用UDF的情况。
这种接力棒式的传递,就是boot.x和trampoline.x的秘密契约。 >> AVR32 Studio的Startup和Software Framework的Startup
如果你很细心,你一定会提出以下的问题之一:
A、在Software Framework提供的UDF源代码中,同时存在Boot.x和trampoline.x,那么编译器究竟听谁的呢?
或者说,这两个汇编代码编译以后占用相同的FLASH空间,编译器又是如何取舍的呢?
B、在没有trampoline.x的情况下,系统会有一个_start段,并且该段会被固定的放置在0x80000000处,加入
trampoline.x这个文件以后,为什么_start段仍然放置在0x80000000的位置,那么trampoline.x不就失去
作用了么?还需要什么额外的设置将trampoline.x的核心函数_trampoline放置到0x80000000处呢?此时
_start段又如何被处理了呢?
以上两个疑问的核心就集中在_start段是什么?完成了什么功能?_stext又是什么?完成了什么功能?我们
如何定义他们,我们如何使用他们呢?
<font color=red> >>文件编译过滤器
为了解释第一个问题(问题A),请大家打开UDF工程的属性页:单击工程文件夹 Alt + Enter,打开属性窗口
Properties。选择C/C++ General->Path and Symboles->Source Location,将看到如下的内容:
http://cache.amobbs.com/bbs_upload782111/files_12/ourdev_420989.GIF
我们注意到,这里有一个针对源程序文件夹:/xxxxx/src的filter。单击filter,并按下边上的按钮Edit Filter
将看到如下的内容:
http://cache.amobbs.com/bbs_upload782111/files_12/ourdev_420990.GIF
聪明的你会注意到,里面列举的都是工程中不参与实际编译的文件和文件夹。
是的,所有工程中我们不希望实际参与编译的文件和文件夹,我们都可以添加进来。这就是解决Boot.x和
trampoline.x冲突的法宝。有的时候,我们需要加入一些库文件,比如.a,而同时为了便于理解代码,也会将这些
库文件的源程序文件加入到工程中,为了避免这些源程序文件再次参与编译,通常将其都加入到filter中。 期待楼主下文! 现想将Bootload改为从dataflash中拷贝升级文件,改写flash。应用程序有USB host功能,可检测U盘中升级文件并拷贝至dataflash中。然后程序重启进入Bootload,可有什么建议! 字节写一个从U盘读取文件的Bootloader就可以了阿……
牵涉到FAT Service 、USB Host、FLASHC……
或者你能把问题提得具体一些么? 最新更新,文件过滤器filter的内容,希望大家喜欢。 我用的是AT32UC3A0512,我的应用程序有USB host功能和FAT文件系统,可以检测到U盘里的升级文件,然后将其直接写入DATAFLASH最后512k单元中(这一部分保留没有做文件系统)。然后系统复位进入bootload程序。按资料所说,一般bootload预留的为8kbyte的空间吧。所以我打算在bootload中不用FAT文件系统,也不需要USB功能,直接从dataflash最后512kbyte中读取更新文件写入flash。我现在的问题是例子UDF中
一般是通过一个固定设置的按键进入,我现在要设置为每次系统启动后都要进入bootload,在bootload读取DATAFLASH中的信息,如果有
更新的程序就更新,没有就跳至应用程序即0x80002000处开始执行。那段启动的汇编代码我之前看不懂,经楼主讲解已经明白了好多,
关于:“ .balign 2
//定义系统事件 _evba段,详细解释参照论坛的相关专题 “这个不知道在论坛那个专题可以找到,我找了好久没看到,不好意思。
另外在向flash中写入的时候,是不是从dataflash中读取1byte就按顺序写入1byte至flash中呀(从0x80002000地址处)。另外我看UDF程序从USB下载,有个小端、大端模式的转换,我这个应该不用吧? _evba段的内容在中断控制器章节里面详细介绍的。
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=3207531&bbs_page_no=1&bbs_id=1030
大小端的问题基本不用考虑。不可以以字节为单位来写flash。 如果我不想用UDF,想写一个自己的Bootloader,这个Bootloader可检测U盘里有没有升级程序(用户程序)文件,如果检测到有,就升级用户程序,然后把U盘里面的升级文件删除掉,关机重新上电后就能用上升级后的用户程序了。
请问楼主,此Bootloader能不能开发出来并替换原来的UDF? 可以,只要你构建这个UDF的时候,注意复制上面的结构就可以。 请教傻孩子一个问题:我用AVR32STUDIO创建一个FLASHC的例子,
执行起来出现如下问题,(我用的是百特EVK1100开发板,AT32UC3A0512)
程序没有完全执行:
http://cache.amobbs.com/bbs_upload782111/files_12/ourdev_421944.JPG
(原文件名:E2.JPG)
我用单步仿真发现程序在执行 flashc_memset((void *)nvram_data, 0x00, 8, sizeof(*nvram_data), TRUE);
就会出现意外:
http://cache.amobbs.com/bbs_upload782111/files_12/ourdev_421943.JPG
(原文件名:E01.JPG) 你的板子是Baite的,EVK1100是ATMEL的,这个例子是EVK1100的。
你操作的NVRAM可能在不同的板子上物理连接或者影射都不同,这是直接导致错误的原因。
你注意错误提示:write failed。 NVRAM只是在FLASH中定义的一个特殊的块,来作为例子的存储地址。我用IAR编译就可以。
http://cache.amobbs.com/bbs_upload782111/files_12/ourdev_422296.jpg
(原文件名:e1.jpg)
以下是执行结果:
http://cache.amobbs.com/bbs_upload782111/files_12/ourdev_422297.jpg
(原文件名:e2.jpg) 看资料上说,E版本的芯片,在写flash时,需要将代码放在ran中运行执行才不会产生异常。
点击此处下载 ourdev_422298.pdf(文件大小:69K) (原文件名:doc32109.pdf)
但是我看例子的DFU程序好象没有这样做,不知道为什么会没有问题,还是我理解错误?
不知大家有没有试一试运行一下FLASHC例子程序。 另外傻孩子在教程里多次提到的一个“虚假的入口地址0x8000,0200”,应该是0x8000,2000吧,一般bootload默认的预留空间为8Kbyte。 你说的没有错,的确是0x80002000……脸红,呵呵呵 你说的没有错,的确是0x80002000……脸红,呵呵呵 虽然没看懂...为表示对楼主的奉献精神的感谢,还是要顶一下 支持 最近正在研究。。。 倒,没有置酷.在酷贴里找了半天 同楼上,应该置酷,找了很长时间
学习中...... 《AVR32 UC3工程师快入门指南》
非常期待啊! 我试验了AVR32UC3B1128,下载程序都没问题,可USB驱动却把我的电脑搞的一团糟…… mark~留用
页:
[1]