搜索
bottom↓
回复: 30

[交流]AVR32 UC3专题学习:细说AVR32 UC3 启动[2009-2-20 Updated]

[复制链接]

出0入296汤圆

发表于 2009-2-16 08:46:53 | 显示全部楼层 |阅读模式

[闲扯两句]

    仔细算来,鄙人在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>[AVR32 UC3启动话题]



    以下内容请顺次阅读,跳跃将导致某些内容“理解不能”

    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

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入296汤圆

 楼主| 发表于 2009-2-16 08:47:29 | 显示全部楼层

>> 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的人来说,灾难才刚刚开始。

出0入296汤圆

 楼主| 发表于 2009-2-16 08:54:16 | 显示全部楼层

>> 都是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、在菜单中选择:
   
(原文件名:1.JPG)
   选择UDF版本
   
(原文件名:2.JPG)

   设置UDF启动IAP时检测的引脚,引脚的编号与引脚名称的对应关系可以从头文件uc3xxxxx.h中找到,例如13在UC3B0256中
   对应的引脚可以在uc3b0256.h中找到。
   其中 ISP_IO_COND_PIN用以选择引脚,ISP_IO_COND_LEVEL用以选择启动启动IAP的有效电平。

   
(原文件名:3.JPG)
   等待完成
   
(原文件名:4.JPG)

出0入296汤圆

 楼主| 发表于 2009-2-16 08:59:18 | 显示全部楼层

>> trampoline.x和UDF的秘密协定


    任意打开一个UDF的Example,我们都能在src文件夹下看到这样两个文件:

    <font color=blue>trampoline.x
boot.x



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的
  .org  PROGRAM_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的秘密契约。

出0入296汤圆

 楼主| 发表于 2009-2-16 09:00:20 | 显示全部楼层

>> 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,将看到如下的内容:

    我们注意到,这里有一个针对源程序文件夹:/xxxxx/src的filter。单击filter,并按下边上的按钮Edit Filter
将看到如下的内容:

    聪明的你会注意到,里面列举的都是工程中不参与实际编译的文件和文件夹。
    是的,所有工程中我们不希望实际参与编译的文件和文件夹,我们都可以添加进来。这就是解决Boot.x和
trampoline.x冲突的法宝。有的时候,我们需要加入一些库文件,比如.a,而同时为了便于理解代码,也会将这些
库文件的源程序文件加入到工程中,为了避免这些源程序文件再次参与编译,通常将其都加入到filter中。

出0入0汤圆

发表于 2009-2-18 20:59:12 | 显示全部楼层
期待楼主下文!

出0入0汤圆

发表于 2009-2-19 23:52:36 | 显示全部楼层
现想将Bootload改为从dataflash中拷贝升级文件,改写flash。应用程序有USB host功能,可检测U盘中升级文件并拷贝至dataflash中。然后程序重启进入Bootload,可有什么建议!

出0入296汤圆

 楼主| 发表于 2009-2-20 00:01:33 | 显示全部楼层
字节写一个从U盘读取文件的Bootloader就可以了阿……
牵涉到FAT Service 、USB Host、FLASHC……
或者你能把问题提得具体一些么?

出0入296汤圆

 楼主| 发表于 2009-2-20 13:32:18 | 显示全部楼层
最新更新,文件过滤器filter的内容,希望大家喜欢。

出0入0汤圆

发表于 2009-2-21 00:13:36 | 显示全部楼层
我用的是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下载,有个小端、大端模式的转换,我这个应该不用吧?

出0入296汤圆

 楼主| 发表于 2009-2-21 21:09:46 | 显示全部楼层
_evba段的内容在中断控制器章节里面详细介绍的。
http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=3207531&bbs_page_no=1&bbs_id=1030

大小端的问题基本不用考虑。不可以以字节为单位来写flash。

出0入0汤圆

发表于 2009-2-24 14:53:21 | 显示全部楼层
如果我不想用UDF,想写一个自己的Bootloader,这个Bootloader可检测U盘里有没有升级程序(用户程序)文件,如果检测到有,就升级用户程序,然后把U盘里面的升级文件删除掉,关机重新上电后就能用上升级后的用户程序了。
请问楼主,此Bootloader能不能开发出来并替换原来的UDF?

出0入296汤圆

 楼主| 发表于 2009-2-24 16:18:21 | 显示全部楼层
可以,只要你构建这个UDF的时候,注意复制上面的结构就可以。

出0入0汤圆

发表于 2009-2-24 21:51:33 | 显示全部楼层
请教傻孩子一个问题:我用AVR32STUDIO创建一个FLASHC的例子,
执行起来出现如下问题,(我用的是百特EVK1100开发板,AT32UC3A0512)
程序没有完全执行:

(原文件名:E2.JPG)

我用单步仿真发现程序在执行 flashc_memset((void *)nvram_data, 0x00, 8, sizeof(*nvram_data), TRUE);
就会出现意外:

(原文件名:E01.JPG)

出0入296汤圆

 楼主| 发表于 2009-2-24 23:19:52 | 显示全部楼层
你的板子是Baite的,EVK1100是ATMEL的,这个例子是EVK1100的。
你操作的NVRAM可能在不同的板子上物理连接或者影射都不同,这是直接导致错误的原因。
你注意错误提示:write failed。

出0入0汤圆

发表于 2009-2-26 21:23:09 | 显示全部楼层
NVRAM只是在FLASH中定义的一个特殊的块,来作为例子的存储地址。我用IAR编译就可以。

(原文件名:e1.jpg)

以下是执行结果:


(原文件名:e2.jpg)

出0入0汤圆

发表于 2009-2-26 21:29:41 | 显示全部楼层
看资料上说,E版本的芯片,在写flash时,需要将代码放在ran中运行执行才不会产生异常。
点击此处下载 ourdev_422298.pdf(文件大小:69K) (原文件名:doc32109.pdf)

但是我看例子的DFU程序好象没有这样做,不知道为什么会没有问题,还是我理解错误?
不知大家有没有试一试运行一下FLASHC例子程序。

出0入0汤圆

发表于 2009-2-26 21:34:18 | 显示全部楼层
另外傻孩子在教程里多次提到的一个“虚假的入口地址0x8000,0200”,应该是0x8000,2000吧,一般bootload默认的预留空间为8Kbyte。

出0入296汤圆

 楼主| 发表于 2009-2-27 03:57:48 | 显示全部楼层
你说的没有错,的确是0x80002000……脸红,呵呵呵

出0入296汤圆

 楼主| 发表于 2009-2-27 03:57:49 | 显示全部楼层
你说的没有错,的确是0x80002000……脸红,呵呵呵

出0入0汤圆

发表于 2009-3-30 10:16:29 | 显示全部楼层
虽然没看懂...为表示对楼主的奉献精神的感谢,还是要顶一下

出0入0汤圆

发表于 2009-4-3 10:47:50 | 显示全部楼层
支持 最近正在研究。。。

出0入0汤圆

发表于 2009-6-7 21:21:24 | 显示全部楼层
倒,没有置酷.在酷贴里找了半天

出0入0汤圆

发表于 2010-3-10 21:15:22 | 显示全部楼层
同楼上,应该置酷,找了很长时间

学习中......

出0入0汤圆

发表于 2010-3-23 15:46:00 | 显示全部楼层
《AVR32 UC3工程师快入门指南》

非常期待啊!

出0入0汤圆

发表于 2010-3-26 16:34:17 | 显示全部楼层
我试验了AVR32UC3B1128,下载程序都没问题,可USB驱动却把我的电脑搞的一团糟……

出0入0汤圆

发表于 2012-9-16 14:45:49 | 显示全部楼层
mark~留用
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-11 16:03

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表