[方案相关] F460 USB CDC bootloader案例说明与演示

[复制链接]
 楼主| kensilong 发表于 2025-8-4 11:35 | 显示全部楼层 |阅读模式
本帖最后由 kensilong 于 2025-8-4 11:47 编辑

F460 USB CDC bootloader案例说明与演示
一、案例说明:
a)     硬件平台:F460开发板EV_F460_LQ100_Rev2.0
b)     接口:USBFS
c)     上位机:基于MFC对话框串口升级程序
一般IAP例程都是基于串口来实现,USB的Bootloader可以用DFU,CDC,HID等class来实现,本案例用CDC来实现,比较简单容易实现。
二、代码实现:
a)     状态机对像
typedefstruct
{
    /* data */
    uint32_t cmd;
    uint32_t addr;
    uint32_t len;
    uint8_t *p_data;
    uint16_t rec_len;//数据长度
    uint32_t checksum;
    uint32_t write_addr;
    uint32_t write_pos;
    /* function */
    int32_t (*pf_boot_init)(void);
    int32_t (*pf_boot_set_cfg)(uint32_tstart_addr, uint32_t end_addr);
    int32_t (*pf_boot_erase)(uint32_tstart_addr, uint32_t end_addr);
    int32_t (*pf_boot_write)(uint32_t addr,uint8_t *p_data, uint32_t len);
    int32_t (*pf_boot_get_checksum)(uint32_tstart_addr, uint32_t end_addr);
    int32_t (*pf_boot_reset)(void);
    int32_t (*pf_boot_jump_to_app)(void);
    int32_t (*pf_boot_thread)(void);
    int32_t (*pf_boot_set_recv_len)(uint16_tlen);
    int32_t (*pf_boot_set_rxbuf)(uint8_t*pdata);
} bsp_boot_cfg_t;
bsp_boot_cfg_tg_boot_instance = {
    /* data */
    0,
    0,
    0,
    NULL,
    0,
    0,
    0,
    0,
    /* function */
    .pf_boot_init = bsp_boot_init,
    .pf_boot_set_cfg = bsp_boot_set_cfg,
    .pf_boot_erase = bsp_boot_erase,
    .pf_boot_write = bsp_boot_write,
    .pf_boot_get_checksum =bsp_boot_get_checksum,
    .pf_boot_reset = bsp_boot_reset,
    .pf_boot_jump_to_app =bsp_boot_jump_to_app,
    .pf_boot_thread = bsp_thread,
    .pf_boot_set_recv_len = bsp_set_recv_len,
    .pf_boot_set_rxbuf = bsp_set_rx_buff,
};
b)     状态机
int32_tbsp_thread(void)
{
    volatile uint8_t cmd;
    volatile uint32_t startaddr;
    volatile uint32_t endaddr;
    static uint32_t writeaddr;
    uint32_t ret;
    uint8_t ack[2] = {0,0};
    uint32_t checksum;
    uint32_t *pdata = NULL;
    if(g_boot_instance.p_data == NULL)
    {
        return LL_ERR_INVD_PARAM;
    }
    if(g_boot_instance.rec_len == 0)
    {
        return LL_ERR_BUF_EMPTY;
    }
    pdata = (uint32_t*)&g_boot_instance.p_data[1];
    cmd = g_boot_instance.p_data[0];

    switch(cmd)
    {
        case CMD_SET_CFG:
            startaddr = *pdata;
            pdata++;
            endaddr = *pdata;
            writeaddr = g_boot_instance.addr =g_boot_instance.write_addr = startaddr;
           write_appbaseaddr(g_boot_instance.addr);
            ret =g_boot_instance.pf_boot_set_cfg(startaddr, endaddr);
            break;
        case CMD_ERASE:
            startaddr = *pdata;
            pdata++;
            endaddr = *pdata;
            ret =g_boot_instance.pf_boot_erase(startaddr, endaddr);
            break;
        case CMD_WRITE:
            ret =g_boot_instance.pf_boot_write(writeaddr, (uint8_t *)pdata,g_boot_instance.rec_len-1);
            writeaddr +=(g_boot_instance.rec_len -1);//第一个字节是控制字
            break;
        case CMD_GET_CHECKSUM:
            startaddr = *pdata;
            pdata++;
            endaddr = *pdata;
            checksum =g_boot_instance.pf_boot_get_checksum(startaddr, endaddr);
            break;
        case CMD_RESET:
            g_boot_instance.pf_boot_reset();
            break;
        case CMD_JUMTOAPP:
           g_boot_instance.pf_boot_jump_to_app();
            break;
        case CMD_DATA:

            break;
        default:
            break;
    }
    ack[0] = CMD_ACK;
    ack[1] = 0;
    usb_send_buffer(&usb_dev, ack,ACK_LEN);   
    return LL_OK;
}
c)     USB数据的接收与发送
datain回调函数
voidusb_dev_cdc_datain(void *pdev, uint8_t epnum)
{
USB_Tx_State = 0;
}
dataout回调函数
voidusb_dev_cdc_dataout(void *pdev, uint8_t epnum)
{
    uint16_t usb_rx_cnt;
    usb_rx_cnt = (uint16_t)((usb_core_instance*)pdev)->dev.out_ep[epnum].xfer_count;
   g_boot_instance.pf_boot_set_recv_len(usb_rx_cnt);
    usb_readytorx(pdev, CDC_OUT_EP, (uint8_t*)(usb_rx_buffer), MAX_CDC_OUT_PACKET_SIZE);//不调这个代码就会回复NAK阻塞。
    flag_usb_rx = true;
}
USB发送函数
int32_tusb_send_buffer(void *pdev, uint8_t *pbuf, uint16_t length)
{
    if(USB_Tx_State != 0)
    {
        return LL_ERR_BUSY;
    }
    if(length >MAX_TX_CNT)
    {
        return LL_ERR_INVD_PARAM;
    }
    USB_Tx_State = 1;
    usb_deveptx(pdev, CDC_IN_EP, pbuf, length);
    return LL_OK;
}
d)     跳转APP函数
voidsystem_deInit(void)
{
    stc_gpio_init_t stcGpioCfg;
    usb_ctrldevconnect(&usb_dev.regs,1);//disconnect usb
    FCG_Fcg1PeriphClockCmd(FCG1_PERIPH_USBFS,DISABLE);
    (void)GPIO_StructInit(&stcGpioCfg);
    (void)GPIO_Init(GPIO_PORT_A, GPIO_PIN_12,&stcGpioCfg);
    (void)GPIO_Init(GPIO_PORT_A, GPIO_PIN_11,&stcGpioCfg);
    NVIC_DisableIRQ(INT030_IRQn);
    NVIC_ClearPendingIRQ(INT030_IRQn);
    INTC_IrqSignOut(INT030_IRQn);
}
func_ptr_tJumpToApplication;
staticint32_t IAP_JumpToApp(uint32_t u32Addr)
{
    uint32_t JumpAddress;
    if(*(__IO uint32_t *)(u32Addr) ==0xFFFFFFFF)
    {
        return LL_ERR;
    }
/* Checkif user code is programmed starting from address "u32Addr" */
/* Checkstack top pointer. */
    system_deInit();
    /* Jump to user application */
    JumpAddress = *(__IO uint32_t *)(u32Addr +4);
    JumpToApplication =(func_ptr_t)JumpAddress;
    /* Initialize user application's StackPointer */
    __set_MSP(*(__IO uint32_t *)u32Addr);
    /* Rebase the vector table base address */
    SCB->VTOR = ((uint32_t) u32Addr &SCB_VTOR_TBLOFF_Msk);
    /* Jump to application Reset Handler in theapplication */
    JumpToApplication();

    return LL_ERR;
}
int32_tbsp_boot_jump_to_app(void)
{
    IAP_JumpToApp(g_boot_instance.addr);
    return LL_OK;
}
三、效果
8180268902a366201a.png

usb_dev_cdc_boot.zip

336.41 KB, 下载次数: 2

Debug.zip.001.zip

10 MB, 下载次数: 2

Debug.zip.002.zip

4.8 MB, 下载次数: 2

您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

37

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部