自学内容网 自学内容网

STM32 BootLoader 刷新项目 (四) 通信协议

STM32 BootLoader 刷新项目 (四) 通信协议


前面几章节,我们已经介绍了BootLoader的整体程序框架,方案设计,以及STM32CubdeMX的配置操作。下面切入整个BootLoader项目的核心内容,通信协议。

我理解的通信协议,其实就是双方提前约定好的暗号。比如说到了提前约定好的地方,一个人逢人便说:“天王盖地虎”。只有懂他暗号对接的人才知道,这是他要找的人,另外一个人就回:”小鸡炖蘑菇“。至此,这两个便通过暗号,传达到了他们配对的信息。

所以,在我们进入到BootLoader模式的时候,必须得发送Host主机端和从机定义好的协议进行通讯,二者才能执行正确的行为。

1. 通信流程

下图便是整个通信的流程,显示主机通过UART发送命令指令,从机收到主机发送的命令,如果是正确的命令,则回复ACK,错误的话则回复NACK,然后在回复之后从机会回复多少字节数据。然后再回复结果。

image-20240714102347637

2. 支持指令

下面是整个Customer BootLoader支持的指令,其中比较重要的是0x55(BL跳转固定地址),0x56(指定擦除扇区),0x57(在不同内存写数据)。后续将详细介绍整个Customer BootLoader的方案实现和代码实现。

主机发送命令码BootLoader回复备注
BL_GET_VER0x51BootLoader版本号(1 byte)从MCU中读BootLoader的版本号
BL_GET_HELP0x52所有支持的命令码(10 bytes)列出BootLoader支持的所有命令
BL_GET_CID0x53Chip identification number(2 bytes)读芯片的识别号
BL_GET_RDP_STATUS0x54返回芯片读保护等级(1 byte)读行骗Flash的读保护等级
BL_GO_TO_ADDR0x55返回成功或错误(1 byte)BL跳转固定地址
BL_FLASH_ERASE0x56返回成功或错误(1 byte)指定擦除扇区
BL_MEM_WRITE0x57返回成功或错误(1 byte)在不同内存写数据
BL_EN_R_W_PROTECT0x58返回成功或错误(1 byte)使能读/写保护
BL_MEM_READ0x59主机请求的内存内容长度TO DO
BL_READ_SECTOR_STATUS0x5A所有Sector状态读所有扇区的保护状态
BL_OTP_READ0x5BOTP contentsTO DO
BL_DIS_R_W_PROTECT0x5C返回成功或错误(1 byte)该命令用于禁用用户Flash的不同扇区的读写保护功能。该命令将保护状态恢复为默认状态。

下图是上位机的操作界面,是由Python脚本进行编写的,执行脚本后,先输入和开发板对应的串口号,进行连接。然后可以看到支持的指令,通过输入相应的数字,即可向从机发送相应的命令。

image-20240713104433991

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运行的整个过程:

BootLoader_Flow

4. 指令结构

下图展示了BootLoader支持的所有指令结构:

BL_GET_VER指令为获取软件版本号:

image-20240714102542277

image-20240714162041966

可以看到上图,发送的数据为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:获取帮助

image-20240714102528030

image-20240714162801126

下面的命令后续文章再一一讲解:
image-20240714102613163

image-20240714102625964

image-20240714102640901

image-20240714102653304

image-20240714102705943

image-20240714102716603

image-20240714102728108

image-20240714102738998

image-20240714102751460

5. 操作演示

下面打开上位机,连接上位机和开发板连接的串口,根据显示的指令,进行相应的操作。

image-20240713104433991

下面我们展示一下读取版本号的功能,输入1,获取版本号为0x10.

image-20240713104633571

下面我们在试一个刷新命令。下面是录制的一整个执行的流程。

BootLoader串口刷新

如果大家有什么疑问,请随时私信联系我。


原文地址:https://blog.csdn.net/qq_35057766/article/details/140418455

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!