找了網上大量的資料,最後發現這個東西人家還出售源碼。又不是什麼算法級的東西,實在了解不了。
至于為什麼要用HID,不用官方的DFU,因為驅動呀,DFU識别USB的時候還是要裝驅動,客戶你永遠了解不了他的水準,是以研發需要cover住所有case.
我是在STM32F4的平台上做的,Cubemax配置工程。以前反感這個UI配置,現在這個東西BUG少了,以前定義一個局部的結構體變量都不初始化。下面是配置圖,注意RCC配置USB的時鐘。

CubeMax配置完生成代碼打開,ST已經給你弄好代碼架構,你隻需要修改裝置描述符,傳輸的位元組,輪詢的時間,中斷回調函數接收。
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
/* USER CODE BEGIN 0 */
0x05, 0x8c, /* USAGE_PAGE (ST Page) */
0x09, 0x01, /* USAGE (Demo Kit) */
0xa1, 0x01, /* COLLECTION (Application) */
// The Input report
0x09,0x03, // USAGE ID - Vendor defined
0x15,0x00, // LOGICAL_MINIMUM (0)
0x26,0x00, 0xFF, // LOGICAL_MAXIMUM (255)
0x75,0x08, // REPORT_SIZE (8bit)
0x95,0x40, // REPORT_COUNT (64Byte)
0x81,0x02, // INPUT (Data,Var,Abs)
// The Output report
0x09,0x04, // USAGE ID - Vendor defined
0x15,0x00, // LOGICAL_MINIMUM (0)
0x26,0x00,0xFF, // LOGICAL_MAXIMUM (255)
0x75,0x08, // REPORT_SIZE (8bit)
0x95,0x40, // REPORT_COUNT (64Byte)
0x91,0x02, // OUTPUT (Data,Var,Abs)
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
};
相關的宏修改 #define USBD_CUSTOM_HID_REPORT_DESC_SIZE 33U//2
#define CUSTOM_HID_EPIN_ADDR 0x81U
#define CUSTOM_HID_EPIN_SIZE 0x40U //64位元組
#define CUSTOM_HID_EPOUT_ADDR 0x01U
#define CUSTOM_HID_EPOUT_SIZE 0x40U
#define CUSTOM_HID_FS_BINTERVAL 0x01U//1ms輪詢
這個是USB的中斷接收函數,根據USB裝置的ID來接收位元組,庫生成的時候隻能接收2個位元組的,
當我們改成0x40,就能接收64個位元組,USB HID一包隻能64個位元組
static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
{
return (USBD_OK);
}
梳理USB HID庫裡面的接收思路,我們可以單獨定義一個接收64位元組的函數 CUSTOM_HID_OutDulBuf_FS
USBD_CUSTOM_HID_ItfTypeDef USBD_CustomHID_fops_FS =
{
CUSTOM_HID_ReportDesc_FS,
CUSTOM_HID_Init_FS,
CUSTOM_HID_DeInit_FS,
CUSTOM_HID_OutEvent_FS,
CUSTOM_HID_OutDulBuf_FS
};
static int8_t CUSTOM_HID_OutDulBuf_FS (uint8_t* DulBuf)
{
return (0);
}
重點關注這個函數,這個函數是完成中斷接收緩存的,Report_buf[],我們插入
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->OutDulBuf(hhid->Report_buf);完成64位元組包的接收
static uint8_t USBD_CUSTOM_HID_DataOut (USBD_HandleTypeDef *pdev,
uint8_t epnum)
{
USBD_CUSTOM_HID_HandleTypeDef *hhid = (USBD_CUSTOM_HID_HandleTypeDef*)pdev->pClassData;
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->OutEvent(hhid->Report_buf[0],
hhid->Report_buf[1]);
((USBD_CUSTOM_HID_ItfTypeDef *)pdev->pUserData)->OutDulBuf(hhid->Report_buf);
USBD_LL_PrepareReceive(pdev, CUSTOM_HID_EPOUT_ADDR , hhid->Report_buf,
USBD_CUSTOMHID_OUTREPORT_BUF_SIZE);
return USBD_OK;
}
自此,USB HID64位元組包的接收我們就完成,關于HID的發送,官方聲明了一個static函數,注釋掉了,調用發送就好了
有些宏定義的查找,不需要去翻檔案了,編譯然後goto definition
上面的工作已經完成了USB HID的雙向通信。重點來,IAP更新,我之前用官方的序列槽IAP更新做過,用的Ymodem協定傳輸,波特率921600,Ymodem我們可以使用secureCRT去進行更新傳輸,官方庫的下位機Ymodem已經做的很好了,也有防錯機制。現在我們用USB傳輸,64位元組一包,尴尬的是沒有上位機去更新,網上或許有下載下傳,但是人家有握手協定,以及包協定,是以基本不能用。由于沒有上位機開發經驗,甚至一度下載下傳了QT Crator準備開發,後面思考了下還是偷懶了,我用BUS Hound去抓包人家上位機傳輸的USB格式,關鍵是這個USB上位機隻負責發,沒有握手協定。還是被我下載下傳到了。
當你的闆子下載下傳程式USB HID識别成功之後,輸入VID 0483 PID 5750 連接配接打開裝置。
下面是stm32 APP端的bin檔案輸出了,在app裡面重新映射中斷向量表,以及代碼flash段,我的是Loader 0x4000 16K
是以APP的開始位址是0x08004000 然後在工程選項下的C++欄 生成bin檔案選項 記得勾選After build。
生成app端的bin檔案之後,需要想的是,這個USB上位機雖然不握手,隻負責發送,但是人家到底有沒有發送格式呢,這就需要我們對比它發送的檔案,以及我們bin檔案的内容。是以用到了visual studio2015 和 Bus hound兩個工具,嵌入式工程師必備吧,工具的使用是人類的進化的标志。
咳咳,暴露了我雙顯示器的配置。 對比發現這個USB上位機就是發送的bin檔案,發送完成最後發了一個空包,全是0,這就好辦了,空包作為傳輸結束标志。
下面的函數就是緩沖接收64位元組包的代碼,這隻是demo,在中斷回調裡面緩沖,并且寫了flash,道理上是不合理的哈。
但是loder又不需要多任務處理,幹就完事了。調試的時候思路卡了一會在flash燒寫的地方,一個是需要先擦除app位置的flash,另一個flash的API需要32位對齊,是以需要64/4,其它就沒啥了
__IO uint32_t flashdestination=APPLICATION_ADDRESS;
__IO uint32_t transfer_error=0;
static int8_t CUSTOM_HID_OutDulBuf_FS (uint8_t* DulBuf)
{
unsigned char j=0;
//memcpy(IAP_buff,DulBuf,64);//緩存64位元組資料
for(unsigned char i=0;i<64;i++)
{
IAP_buff[i]=DulBuf[i];
if(IAP_buff[i]==0x00)
j++;
}
if(j==64)
USB_Received_Flag=1;
if(j<64&&FLASH_If_Write(flashdestination, (uint32_t*)IAP_buff, (uint32_t)64/4)== FLASHIF_OK)
{
flashdestination+=(uint32_t)64;
}
else
transfer_error++;
return (0);
}
再上傳一個loader跳轉到APP,APP跳轉到Loader的代碼
loader跳轉到APP __set_FAULTMASK(1);//關閉所用中斷 至于考慮APP是否使用了RTOS,加上__set_CONTROL(0); 吧
void LoderToApp(void)
{
if (((*(__IO uint32_t*)APPLICATION_ADDRESS) & 0x2FFE0000 ) == 0x20000000)//棧頂位址檢查
{
HAL_RCC_DeInit(); //時鐘失能
HAL_DeInit(); //外設失能
__set_FAULTMASK(1);//關閉所用中斷
JumpAddress = *(__IO uint32_t*) (APPLICATION_ADDRESS + 4);//跳轉到APP位址
JumpToApplication = (pFunction) JumpAddress;
__set_CONTROL(0); //RTOS指針使能
SCB->VTOR = FLASH_BASE |0x4000;//中斷向量表重映射
__set_MSP(*(__IO uint32_t*) APPLICATION_ADDRESS);//MSP指針跳轉
JumpToApplication();
}
}
void AppToLoder(void)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);
__set_FAULTMASK(1);
HAL_NVIC_SystemReset();
}
APP跳轉到Loader就簡單點吧HAL_NVIC_SystemReset();幹脆高效
緻敬開源
--騷年追夢
上位機:https://download.csdn.net/download/u014803614/11603107
下位機:https://download.csdn.net/download/u014803614/11603069