vic*_*tcu 28 avr arduino bootloader
有人可以解释一下Arduino引导加载程序的工作原理吗?我不是在寻找一个高级答案,我已经阅读了代码,我得到了它的要点.
在Arduino IDE和引导加载程序代码之间发生了许多协议交互,最终产生了许多内联汇编指令,这些指令通过串行接口传输程序来自动编程闪存.
我不清楚的是第270行:
void (*app_start)(void) = 0x0000;
Run Code Online (Sandbox Code Playgroud)
...我认为函数指针的声明和初始化为NULL.随后在引导加载程序要委托执行用户加载代码的位置调用app_start.
当然,某种程度上app_start需要在某些时候获得非NULL值,以便将所有这些组合在一起.我在引导加载程序代码中没有看到它......它是否被引导加载程序加载的程序神奇地链接了?我认为引导加载程序的主要部分是芯片复位后进入软件的入口点.
包含70个左右的程序集必须是秘密的解码器环,告诉主程序app_start到底在哪里?或者也许是Arduino IDE利用了一些隐含的知识?我所知道的是,如果某人没有将app_start更改为指向0以外的其他位置,那么引导加载程序代码将永远自行旋转......那么诀窍是什么?
编辑
我有兴趣尝试将引导加载程序移植到没有用于引导加载程序代码的单独内存空间的Tiny AVR.由于我很明显引导加载程序代码依赖于某些保险丝设置和芯片支持,我想我真正感兴趣的是将引导加载程序移植到没有这些保险丝和硬件的芯片需要做些什么.支持(但仍具有自编程能力)?
Nic*_*k T 41
地址0不是空指针make."空指针"是更抽象的东西:适用函数应该识别为无效的特殊值.C表示特殊值为0,虽然语言表示解除引用它是"未定义的行为",但在微控制器的简单世界中,它通常具有非常明确的效果.
通常,在复位时,AVR的程序计数器(PC)初始化为0,因此微控制器开始在地址0处执行代码.
但是,如果设置了引导复位保险丝("BOOTRST"),程序计数器将被初始化为存储器上端的块地址(这取决于保险丝的设置方式,请参见数据表( PDF,7 MB)具体细节).从那里开始的代码可以做任何事情 - 如果你真的想要你可以把你自己的程序放在那里,如果你使用ICSP(引导程序通常不能覆盖自己).
通常,它是一个特殊的程序 - 一个引导加载程序 - 能够从外部源(通常通过UART,I 2 C,CAN等)读取数据来重写程序代码(存储在内部或外部存储器中,具体取决于微).引导加载程序通常会寻找一个"特殊事件",它实际上可以是任何东西,但是对于开发来说,最方便的是数据总线上它将从中提取新代码.(对于生产,它可能是一个特殊的逻辑电平,因为它几乎可以立即检查.)如果引导加载程序看到特殊事件,它可以进入bootloading-mode,它将重新刷新程序存储器,否则它通过控制关闭用户代码.
另外,引导加载程序保险丝和高端内存块的要点是允许使用引导加载程序而不修改原始软件(只要它不会一直延伸到引导加载程序的地址).可以使用原始HEX和所需的保险丝闪烁,而不是闪烁原始的HEX,引导加载程序和修改过的保险丝,并添加了presto,bootloader.
无论如何,在Arduino的情况下,我认为它使用STK500的协议,它试图通过UART进行通信,如果它在规定的时间内没有响应:
uint32_t count = 0;
while(!(UCSRA & _BV(RXC))) { // loops until a byte received
count++;
if (count > MAX_TIME_COUNT) // 4 seconds or whatever
app_start();
}
Run Code Online (Sandbox Code Playgroud)
或者如果通过获得意外响应而导致错误太多:
if (++error_count == MAX_ERROR_COUNT)
app_start();
Run Code Online (Sandbox Code Playgroud)
它将控制权传递回位于0的主程序.在上面看到的Arduino源代码中,这是通过调用来完成的app_start();,定义为void (*app_start)(void) = 0x0000;.
因为它是作为C函数调用的,所以在PC跳到0之前,它会将当前PC值推送到堆栈,堆栈中还包含引导加载程序中使用的其他变量(例如count,error_count从上面).这会从您的程序中窃取RAM吗?好吧,在PC设置为0之后,执行的操作明显"违反"正确的C函数(最终将返回)应该执行的操作.在其他初始化步骤中,它重置堆栈指针(有效地消除调用堆栈和所有局部变量),回收RAM.全局/静态变量初始化为0,其地址可以与引导加载程序使用的任何内容自由重叠,因为引导加载程序和用户程序是独立编译的.
引导加载程序的唯一持久影响是对硬件(外设)寄存器的修改,良好的引导加载程序不会留在有害状态(打开可能在您尝试休眠时浪费电源的外设).通常还可以完全初始化您将使用的外围设备,因此即使引导加载程序做了一些奇怪的事情,您也可以按照自己的意愿设置它.
在ATtinys上,正如您所提到的,引导加载程序保险丝或内存并不奢侈,因此您的代码将始终从地址0开始.您可以将引导加载程序放入更高的内存页并将RESET向量指向它,然后每当你收到一个新的hex文件闪存时,取出地址为0:1的命令,将其替换为引导加载程序地址,然后将替换的地址存储在其他地方以调用正常执行.(如果是RJMP(" 相对跳跃"),显然需要重新计算该值)