STM32 BootLoader 刷新项目 (四) 通信协议
文章目录
- STM32 BootLoader 刷新项目 (四) 通信协议
- 1. 通信流程
- 2. 支持指令
- 3. 通信流程
- 4. 指令结构
- 5. 操作演示
前面几章节,我们已经介绍了BootLoader的整体程序框架,方案设计,以及STM32CubdeMX的配置操作。下面切入整个BootLoader项目的核心内容,通信协议。
我理解的通信协议,其实就是双方提前约定好的暗号。比如说到了提前约定好的地方,一个人逢人便说:“天王盖地虎”。只有懂他暗号对接的人才知道,这是他要找的人,另外一个人就回:”小鸡炖蘑菇“。至此,这两个便通过暗号,传达到了他们配对的信息。
所以,在我们进入到BootLoader模式的时候,必须得发送Host主机端和从机定义好的协议进行通讯,二者才能执行正确的行为。
1. 通信流程
下图便是整个通信的流程,显示主机通过UART发送命令指令,从机收到主机发送的命令,如果是正确的命令,则回复ACK,错误的话则回复NACK,然后在回复之后从机会回复多少字节数据。然后再回复结果。
2. 支持指令
下面是整个Customer BootLoader支持的指令,其中比较重要的是0x55(BL跳转固定地址),0x56(指定擦除扇区),0x57(在不同内存写数据)。后续将详细介绍整个Customer BootLoader的方案实现和代码实现。
主机发送 | 命令码 | BootLoader回复 | 备注 |
---|---|---|---|
BL_GET_VER | 0x51 | BootLoader版本号(1 byte) | 从MCU中读BootLoader的版本号 |
BL_GET_HELP | 0x52 | 所有支持的命令码(10 bytes) | 列出BootLoader支持的所有命令 |
BL_GET_CID | 0x53 | Chip identification number(2 bytes) | 读芯片的识别号 |
BL_GET_RDP_STATUS | 0x54 | 返回芯片读保护等级(1 byte) | 读行骗Flash的读保护等级 |
BL_GO_TO_ADDR | 0x55 | 返回成功或错误(1 byte) | BL跳转固定地址 |
BL_FLASH_ERASE | 0x56 | 返回成功或错误(1 byte) | 指定擦除扇区 |
BL_MEM_WRITE | 0x57 | 返回成功或错误(1 byte) | 在不同内存写数据 |
BL_EN_R_W_PROTECT | 0x58 | 返回成功或错误(1 byte) | 使能读/写保护 |
BL_MEM_READ | 0x59 | 主机请求的内存内容长度 | TO DO |
BL_READ_SECTOR_STATUS | 0x5A | 所有Sector状态 | 读所有扇区的保护状态 |
BL_OTP_READ | 0x5B | OTP contents | TO DO |
BL_DIS_R_W_PROTECT | 0x5C | 返回成功或错误(1 byte) | 该命令用于禁用用户Flash的不同扇区的读写保护功能。该命令将保护状态恢复为默认状态。 |
下图是上位机的操作界面,是由Python脚本进行编写的,执行脚本后,先输入和开发板对应的串口号,进行连接。然后可以看到支持的指令,通过输入相应的数字,即可向从机发送相应的命令。
3. 通信流程
下面我们来介绍一下,BootLoader通信协议的命令组成,首先第一个字节为接下来要发送数据的长度,第二个字节是命令,第3-6字节为四个字节的CRC校验码。
当从机收到数据后,先收第一字节数据,得到接下来发送数据的长度,然后更具接收数据的长度,在确定接下来应该接收多少字节的数据。将收到的数据解析,第一个字节(除掉一开始收到的长度位)为命令,通过swich case指令,来判断应该执行哪种命令的操作。代码如下图所示:
while (1)
{
memset(bl_rx_buffer, 0, 200);
//here we will read and decode the commands coming from host
//first read only one byte from the host , which is the "length" field of the command packet
HAL_UART_Receive(C_UART,bl_rx_buffer,1,HAL_MAX_DELAY);
rcv_len= bl_rx_buffer[0];
HAL_UART_Receive(C_UART,&bl_rx_buffer[1],rcv_len,HAL_MAX_DELAY);
switch(bl_rx_buffer[1])
{
case BL_GET_VER:
bootloader_handle_getver_cmd(bl_rx_buffer);
break;
case BL_GET_HELP:
bootloader_handle_gethelp_cmd(bl_rx_buffer);
break;
case BL_GET_CID:
bootloader_handle_getcid_cmd(bl_rx_buffer);
break;
case BL_GET_RDP_STATUS:
bootloader_handle_getrdp_cmd(bl_rx_buffer);
break;
case BL_GO_TO_ADDR:
bootloader_handle_go_cmd(bl_rx_buffer);
break;
case BL_FLASH_ERASE:
bootloader_handle_flash_erase_cmd(bl_rx_buffer);
break;
case BL_MEM_WRITE:
bootloader_handle_mem_write_cmd(bl_rx_buffer);
break;
case BL_EN_RW_PROTECT:
bootloader_handle_en_rw_protect(bl_rx_buffer);
break;
case BL_MEM_READ:
bootloader_handle_mem_read(bl_rx_buffer);
break;
case BL_READ_SECTOR_P_STATUS:
bootloader_handle_read_sector_protection_status(bl_rx_buffer);
break;
case BL_OTP_READ:
bootloader_handle_read_otp(bl_rx_buffer);
break;
case BL_DIS_R_W_PROTECT:
bootloader_handle_dis_rw_protect(bl_rx_buffer);
break;
default:
printmsg("BL_DEBUG_MSG:Invalid command code received from host \n");
break;
}
}
下图为整个Customer BootLoader运行的整个过程:
4. 指令结构
下图展示了BootLoader支持的所有指令结构:
BL_GET_VER指令为获取软件版本号:
可以看到上图,发送的数据为0x05, 0x51, 0xe7, 0xe9, 0xab, 0x7c.
启动第一个字节,为接下来要发送数据的长度,即为5个字节,第二个字节为0x51,即为上面获取软件版本号的指令,后四位为前两位的CRC校验位。
下面为了更清晰的指导整个协议发送过程的逻辑,展示了获取软件版本号的代码,如下所示:
/**************Implementation of Boot-loader Command Handle functions *********/
/*Helper function to handle BL_GET_VER command */
void bootloader_handle_getver_cmd(uint8_t *bl_rx_buffer)
{
uint8_t bl_version;
// 1) verify the checksum
printmsg("BL_DEBUG_MSG:bootloader_handle_getver_cmd\n");
//Total length of the command packet
uint32_t command_packet_len = bl_rx_buffer[0]+1 ;
//extract the CRC32 sent by the Host
uint32_t host_crc = *((uint32_t * ) (bl_rx_buffer+command_packet_len - 4) ) ;
if (! bootloader_verify_crc(&bl_rx_buffer[0],command_packet_len-4,host_crc))
{
printmsg("BL_DEBUG_MSG:checksum success !!\n");
// checksum is correct..
bootloader_send_ack(bl_rx_buffer[0], 1);
bl_version = get_bootloader_version();
printmsg("BL_DEBUG_MSG:BL_VER : %d %#x\n",bl_version,bl_version);
bootloader_uart_write_data(&bl_version,1);
}else
{
printmsg("BL_DEBUG_MSG:checksum fail !!\n");
//checksum is wrong send nack
bootloader_send_nack();
}
}
当CRC校验位没有问题,则发送ACK,并且发送软件版本号,否则发送NACK。
BL_GET_HELP:获取帮助
下面的命令后续文章再一一讲解:
5. 操作演示
下面打开上位机,连接上位机和开发板连接的串口,根据显示的指令,进行相应的操作。
下面我们展示一下读取版本号的功能,输入1,获取版本号为0x10.
下面我们在试一个刷新命令。下面是录制的一整个执行的流程。
BootLoader串口刷新
如果大家有什么疑问,请随时私信联系我。