本帖最后由 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; } 三、效果
|