最近有一个需求就是为Arduino开发板做一个基于蓝牙的无线烧录程序。目前的Arduino程序都是通过USB线连接到电脑的主机上,实际的传输过程是基于USB协议的,这个过程还是比较麻烦的。因为每次的编译完以后都需要通过一个USB线来完成传输烧录的工作,这个还是很麻烦的。
原理解读
在Arduino中,利用USB来完成传输烧录大概是这么一个过程。每个Arduino源程序,即sketch文件,经过一系列的编译处理以后,最终会形成一个Intel HEX格式的文件,这个HEX文件其实就一个被封装好的数据包,包含头部、长度、偏移量、数据类型、数据和校验和等6个字段。再利用USB协议传输这个数据包,再通过板子上已有的bootloader程序把这个HEX文件中的有效字节码写到板子上的Flash存储器中。就是因为这个bootloader程序的存在,才使得多数的单片机具有片内引导程序自编程功能。MCU通过运行这个常驻Flash的bootloader程序,就可以利用任何可用的数据接口读取代码(注:在Arduino中,这里的代码是指HEX文件中的有效数据字段,是最终字节码的形式)后写入到自身的flash存储器中,从而实现了自编程的功能。
理解了上面的原理以后,你比如说我要做一个支持无线传输的类似bootloader的东西。无线传输采用蓝牙协议。蓝牙的接收端将接收到的数据全部存在串口中,所以核心的技术除了蓝牙收发部分以及对flash存储器的读写和存储空间的管理以外,还需要实现对这个HEX文件的解析,更准确、形象地说应该是对这些数据包的解析。怎么把这个数据包拆开,取出有效的字节码数据,然后把这些字节码按顺序分块组装,写到flash存储器,再把PC指针指到开始的地方就可以了。不过这东西确实很底层,就是在直接跟内存打交道,怎么管理内存,怎么读写内存,怎么拆分组装数据,出错了以后怎么擦除已经写的内容,如何优化等等一些列问题都需要解决。
事非经过不知难,经过方知难与易。慢慢做吧!先来第一步,对HEX格式的文件进行解析。解析之前自然要弄懂HEX文件的具体格式。HEX文件的格式
Intel HEX格式的文件是由多条记录组成,而每条记录又是由6个字段组成。这些记录是由一些代表机器语言代码和常量的16进制数据组成的。Intel HEX 文件常用来传输要存储在 ROM 或者 EPROM 中的程序和数据。大部分的 EPROM 编程器能使用 Intel HEX文件记录的基本格式如下:
RecordMark |
RecordLength |
LoadOffset |
RecordType |
Data |
Checksum |
记录标志 |
记录长度 |
装载偏移 |
记录类型 |
数据 |
校验和 |
其中,RecordMark字段其实就是每条记录的首部,其值为0x3A,在ASCII码中就是冒号“:”。该字段在HEX文件中,这个头部只占有一个字节。RecordLength表示每条记录包含的数据的长度,以字节为单位,最大描述255个字节,表现为2个16进制的字符,该字段在HEX文件中占2个字节。LoadOffset表示该记录中的数据在整个存取器空间中的偏移,用4个十六进制字符描述一个16位数据,在HEX文件中该字段占有4个字节。RecordType表示记录类型,表现为2个十六进制字符。取值有以下几种:
00表示数据记录;
01表示文件结束记录;
02描述拓展段地址记录;
03描述开始段地址记录;
04描述扩展线性地址记录;
05描述开始线性地址记录。
Data字段表示数据的具体内容,描述方法仍是两个16进制的字符表示1字节的数据。此字段的长度由该记录的RecordLength决定,数据的解释取决于记录类型(RecordType)。Checksum字段为校验和。这个校验和是这么来的,将RecordMark(“:”)后的所有的数据按字节相加,即成对相加起来,然后模除256得到余数,再对这个余数求补码,最终得出的结果就是校验和。所以检测方法也很简单:在每一条记录内,将RecordMark(“:”)后的所有数据(包括Checksum)按字节相加后得到的8位数据为0,则说明数据无误,否则说明出错了。
至于什么是拓展段地址记录、开始段地址记录、扩展线性地址记录、开始线性地址记录这里不做详细的介绍,在芯艺的《AVR单片机GCC程序设计》的附录部分有详细的说明。而在Arduino的HEX文件中,记录类型只有两种,数据记录和文件结束记录。所以RecordType这个字段的值不是0x00就是0x01。数据记录适用于8位、16位和32位格式,其详细格式如下:
记录名 |
RecordMark |
RecordLength |
LoadOffset |
RecordType |
Data |
Checksum |
记录标志 |
记录长度 |
装载偏移 |
记录类型 |
数据 |
校验和 |
|
内容 |
“:” |
X |
- |
“00” |
- |
- |
字节数 |
1 |
1 |
2 |
1 |
X |
1 |
文件结束记录适用于8位、16位和32位格式,其详细格式如下: