29.1 實驗內(nèi)容
通過本實驗主要學習以下內(nèi)容:
? USB IAP升級操作
29.2 實驗原理
USB IAP升級本例程中使用的是Custom HID中的IAP設(shè)備類,其設(shè)備類協(xié)議的實現(xiàn)與HID的類似,主要包括GET_REPORT/GET_IDLE/GET_PROTOCOL/SET_REPORT/SET_IDLE/SET_PROTOCOL/USB_GET_DESCRIPTOR等。IAP的功能為通過USB接口通信的方式對app端代碼進行更新。
29.3 硬件設(shè)計
USB虛擬鍵盤實驗章節(jié)已介紹。
29.4 代碼解析
IAP主函數(shù)如下所示,開始主要為delay延遲配置以及按鍵配置,之后判斷KEY1按鍵是否被按下,如果KEY1按鍵沒被按下,將會進入到跳轉(zhuǎn)代碼段,如果APP_LOADED_ADDR(0x08008000U)地址中有對應(yīng)APP的堆棧指針,則認為APP段有數(shù)據(jù)可直接跳轉(zhuǎn)執(zhí)行。如果堆棧指針校驗異常,則跳出判斷執(zhí)行后續(xù)代碼;如果KEY1按鍵被按下,則跳過跳轉(zhuǎn)語句段,直接運行USB IAP的升級代碼。通過RCU/USB等相關(guān)配置后,在PC端將會識別一個USB IAP設(shè)備。
C
int main(void)
{
uint32_t app_address;
app_func application;
uint32_t sram_sect = REG32(APP_LOADED_ADDR);
driver_init();
/* configure KEY1 key to run firmware */
bsp_key_init(&KEY1);
/* KEY1 key must be pressed on board when power on */
if(SET !=bsp_key_state_get(&KEY1)) {
/* test if user code is programmed starting from address 0x8008000 */
if((sram_sect >= SRAM_BASE_ADDR) && (sram_sect < SRAM_END_ADDR)){
app_address = *(__IO uint32_t*) (APP_LOADED_ADDR + 4U);
application = (app_func) app_address;
/* initialize user application's stack pointer */
__set_MSP(*(__IO uint32_t*) APP_LOADED_ADDR);
/* jump to user application */
application();
}
}
/* system clocks configuration */
rcu_config();
/* GPIO configuration */
gpio_config();
/* USB device configuration */
usbd_init(&usbd_iap, &iap_desc, &iap_class);
/* NVIC configuration */
nvic_config();
/* enabled USB pull-up */
usbd_connect(&usbd_iap);
while (1){
}
}
HID報文描述符如下所示,該報文描述符描述了收發(fā)數(shù)據(jù)類型以及長度,其中,主機發(fā)送的IAP命令和數(shù)據(jù)長度為63個字節(jié),MCU從機回復(fù)的狀態(tài)數(shù)據(jù)長度為16個字節(jié)。
C
const uint8_t iap_report_desc[USB_DESC_LEN_IAP_REPORT] =
{
0x05, 0x01, ????/* USAGE_PAGE (Generic Desktop) */
0x09, 0x00, ????/* USAGE (Custom Device) ???????*/
0xa1, 0x01, ????/* COLLECTION (Application) ????*/
/* IAP command and data */
0x85, 0x01, ????/* REPORT_ID (0x01) ?????????*/
0x09, 0x01, ????/* USAGE (IAP command) ??????*/
0x15, 0x00, ????/* LOGICAL_MINIMUM (0) ??????*/
0x25, 0xff, ????/* LOGICAL_MAXIMUM (255) ????*/
0x75, 0x08, ????/* REPORT_SIZE (8) ??????????*/
0x95, 0x3f, ????/* REPORT_COUNT (63) ????????*/
0x91, 0x82, ????/* OUTPUT (Data,Var,Abs,Vol) */
/* device status and option byte */
0x85, 0x02, ????/* REPORT_ID (0x02) ??????????????*/
0x09, 0x02, ????/* USAGE (Status and option byte) */
0x15, 0x00, ????/* LOGICAL_MINIMUM (0) ???????????*/
0x25, 0xff, ????/* LOGICAL_MAXIMUM (255) ?????????*/
0x75, 0x08, ????/* REPORT_SIZE (8) ???????????????*/
0x95, 0x10, ????/* REPORT_COUNT (16) ?????????????*/
0x81, 0x82, ????/* INPUT (Data,Var,Abs,Vol) ??????*/
0xc0 ???????????/* END_COLLECTION ???????????*/
};
MCU接收到主機發(fā)送的數(shù)據(jù)后,將會進入iap_data_out回調(diào)函數(shù),其中實現(xiàn)了IAP download(數(shù)據(jù)下載)、IAP Erase(擦除操作)、IAP OPTION BYTE(獲取選項字節(jié))、IAP LEAVE(退出IAP模式)、IAP GETBIN ADDRESS(獲取APP起始地址)幾個功能。
C
static void iap_data_out (usb_dev *udev ,uint8_t ep_num)
{
usbd_iap_handler *iap = (usbd_iap_handler *)udev->class_data[USBD_IAP_INTERFACE];
if (0x01U == iap->report_buf[0]) {
switch(iap->report_buf[1]) {
case IAP_DNLOAD:
iap_req_dnload(udev);
break;
case IAP_ERASE:
iap_req_erase(udev);
break;
case IAP_OPTION_BYTE:
iap_req_optionbyte(udev);
break;
case IAP_LEAVE:
iap_req_leave(udev);
break;
case IAP_GETBIN_ADDRESS:
iap_address_send(udev);
break;
default:
break;
}
}
usbd_ep_recev(udev, IAP_OUT_EP, iap->report_buf, IAP_OUT_PACKET);
}
29.5 實驗結(jié)果
將本實驗歷程燒錄到紅楓派開發(fā)板中,打開GD32 ALL IN One上位機,如下圖所示,接口選擇USB,Bootloader協(xié)議選擇IAP,之后點擊connect進行連接。
連接成功后,顯示如下圖所示,connect按鈕變成disconnect,且在左下角顯示芯片信息。
右側(cè)欄目即為USB IAP可實現(xiàn)的功能,主要包括載升級代碼,其他功能為灰色不能操作。點擊Browse選擇下載bin或者hex文件,之后點擊download即可進行下載,下載完成后,進度條顯示100%,即完成升級下載。