STM32F1自带的ISP协议
背景
STM32F1在厂家固件中固定写入一个ISP的驱动,当配制好相应的启动管脚时,就可以通过UART1及相关的通信协议与MCU进行通信。可以进行一个FLASH的读写操作。
从使用的角度添加了一个交互操作方法,用户可以通过这种方式对MCU进行程序烧序,或者通过SWD,或者自己定义程序更新的应用。
硬件电路
BOOT管脚配置
BOOT0 = 1, BOOT1 = 0这种情况下上电即可。
一键ISP电路
配制成串口ISP的时候,若想从MAIN FLASH中开始运行程序,需要将BOOT0,BOOT1的管脚进行重新配置,操作起来比较麻烦。通过一键ISP电路,通过设置UART的RTS,与DTR管脚设置来达到切换BOOT0,BOOT1管脚电平的效果。
可以在不用改动硬件接线的情况下,通过软件设置来达到启动选项的切换。
UART参数设置
UART硬件参数为,1位起始位,8位数据位,偶校检,1位停止位。波特率STM32在收到0x7F这个配对信号后,自动调整与之相对应的波特率。
ISP协议解析
概览
不同版本的ISP协议,命令会有些偏差。
返回代码ACK=0x79,NACK=0x1F
sync
host | device | note |
---|---|---|
0x7f | - | 发送0x7f,单片机收到后会自动匹配波特率。 |
- | 0x79(ACK)/0x1F(NACK) | device返回ACK或NACK,表示对host的反应。 |
在已经发送过其他非0x7f的命令下,再发送0x7f,有时间并不会返回ACK指令,或者会返回NACK指令。
原因在于刚开始的指令造成STM32本身的波特率选择混乱,故不能正常返回。需要在复位后第一时间发送同步0x7f指令。
get command
host | device | note |
---|---|---|
0x00 + 0xff | - | |
- | 0x79(ACK)/0x1F(NACK) | |
- | N | 1字节,表示下面要接收到的字节数。bootloaderversion字节数 + 所有指令字节数 = N+1 |
- | bootloader version | 1字节,如0x21代表2.1版本 |
- | 所有支持的指令 | 多个字节,每个字节数据都表示一个支持的指令 |
- | 0x79(ACK)/0x1F(NACK) | 指令执行结束后会返回0x79 |
返回的所有指令 |
get version & read protection
host | device | note |
---|---|---|
0x01+0xfe | - | |
- | 0x79(ACK)/0x1F(NACK) | |
- | bootloader version | 0x10 = 1.0 |
- | 2个字节 | 这两个字节和保护状态有关 |
- | 0x79(ACK)/0x1F(NACK) |
get ID command
host | device | note |
---|---|---|
0x02+0xfd | - | |
- | 0x79(ACK)/0x1F(NACK) | |
- | N | 1字节,表示下面 PID字节数 - 1 |
- | PID | 多字节(上一个字节已指明字节数),先传高位后传低位。我这次用的stm32f103c8t6是2字节。 |
- | 0x79(ACK)/0x1F(NACK) |
Erase Memory command
host | device | note |
---|---|---|
0x43+0xbc | - | |
- | 0x79(ACK)/0x1F(NACK) | |
0xff+0x00 | - | 这是全擦指令 |
- | 0x79(ACK)/0x1F(NACK) |
Write Memory command
host | device | note |
---|---|---|
0x31+0xCE | - | |
- | 0x79(ACK)/0x1F(NACK) | |
addr | - | 4字节,下载地址。用户flash起始地址是0x08000000。先发高位,后发低位 |
addr checksum | - | 1字节,地址的checksum,就是上面4字节数据的异或。 |
- | 0x79(ACK)/0x1F(NACK) | |
count | - | 1字节,表示后面将要传输的字节数,范围(0, 255]。字节数 = 这个值+1,也就是说最大传输256字节。 |
data | - | 多字节,字节数 = count + 1,最大256字节。这里下载进去的是bin文件,不是hex |
checksum | - | 1字节,上面的data数据,以及数据个数count的checksum。注意这里的checksum包含数据和个数 |
- | 0x79(ACK)/0x1F(NACK) |
Read Memory command
host | device | note |
---|---|---|
0x11+0xEE | 0x79(ACK)/0x1F(NACK) | |
addr | - | 4字节,下载地址。用户flash起始地址是0x08000000。先发高位,后发低位 |
addr checksum | - | 1字节,地址的checksum,就是上面4字节数据的异或。 |
- | 0x79(ACK)/0x1F(NACK) | |
count | - | 1字节,将要读取的数据个数,0~255。count+1就是将要读取的字节数,最多读取256字节。 |
checksum | - | 1字节,count的按位取反。 |
- | 0x79(ACK)/0x1F(NACK) | |
- | data | count+1个字节,这就是要读取的数据。 |
Readout Protect command
host | device | note |
---|---|---|
0x82+0x7d | - | 发送0x7f,单片机收到后会自动匹配波特率。 |
- | 0x79(ACK)/0x1F(NACK) | device返回ACK或NACK,表示对host的反应。 |
- | 0x79(ACK)/0x1F(NACK) | device返回ACK或NACK,表示对host的反应。 |
Readout Unprotect command
host | device | note |
---|---|---|
0x92+0x6d | - | 发送0x7f,单片机收到后会自动匹配波特率。 |
- | 0x79(ACK)/0x1F(NACK) | device返回ACK或NACK,表示对host的反应。 |
- | 0x79(ACK)/0x1F(NACK) | device返回ACK或NACK,表示对host的反应。 |
Readout Protect 与 Unprotect 命名返回的ACK,是分一个间隔返回的,并不是同时返回的,处理的时候需要一个等待操作
同时无论Protect 还是 Unprotect操作后,ISP的通信都需要重新同步后,才能正常工作。
checksum计算方法
checksum主要计算的是发送的数据的checksum并不包括最早的指令,以addr为例,checksum就是addr的四个字节进行xor计算出checksum的值
uint8_t Isp::check_sum(uint8_t *pData_, int len_)
{
uint8_t checkSum = 0;
while(len_--)
{
checkSum ^= *pData_++;
}
return checkSum;
}
总结
STM32F1的ISP协议给了我们用户多了一种途径对程序固件进行更新的操作方式。
不过STM32F1的ISP容错效果并不是很好,只要一出错就需要将ISP重新开始同步,有时还需要将芯片进行复位操作