简介:
用STM32做东西免不了要考虑升级什么的,特别是对外暴露USB口的时候,大多时候设计个全速USB(12Mbps)就够用了,现在想用这个USB做程序升级。代码中虚拟出可以被DfuSeDemo识别的设备,这样就可以只连USB线,发送指令到MCU进入DFU,升级完跳转到程序。不需要去拨开关什么的额外操作,一根USB线搞定升级。
主要步骤:
STM32F4等系列在system boot里面已经集成了DFU,也就是(BOOT0=1,BOOT1=0),重启进入System memory。
对于开发板,只要把boot0跳到0跑用户程序,跳到1进system boot,可以用串口、DFU等升级用户程序。早期的片子没有集成DFU,自己写一个,然后想办法跳转过去就行了。
手头有个STM32F401开发板 STM32F401CCU6,tb便宜+Type-c,拿这个跑Demo。
把右上角的拨码开关干上去(boot0=1),然后RST一下,打开DfuSeDemo(V3.0.6),接上USB连接电脑。下载程序我就不bb了,注意图中的两个按钮,下载完后按钮2可以跳转到更新的程序,然后就没有然后了(两个按钮都变灰,你无法操作了)。
现在想把按钮1搞出来,从程序跳转到DFU,释放双手。百毒到处找资料,发现官方的Demo把这个功能阉割了,不管你怎么努力都不行,中文社区还放出了 DfuSeDemo_A.exe下载也是空文件夹,找不到这玩意儿。
DfuSeDemo这个官方给出了源码,在软件的安装目录,C++的,有能耐的大佬可以去改改。后面找到github上有大佬干了这个,我就把别人编译好的文件拿来用了,附件分享可执行文件。现在上位部分识别没问题了,开始cubemx流水化作业了。
新建项目、配置SWD、时钟、USB Device。要给USB 48NHz时钟,时钟树如下:
简单配置下HID参数,报告描述符设置为23,后面有数据需要填充。
把堆栈设置大一点,堆8K,栈16K。然后就可以快活玩耍了。
生成MDK工程,配置勾选生成hex,然后配置用户指令生成dfu(hex2dfu.exe -t "$h@h.hex")
修改代码:
usbd_custom_hid_if.c
/** Usb HID report descriptor. */
__ALIGN_BEGIN static uint8_t CUSTOM_HID_ReportDesc_FS[USBD_CUSTOM_HID_REPORT_DESC_SIZE] __ALIGN_END =
{
/* USER CODE BEGIN 0 */
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Defined Page 1) 表示一个报文标签之类的用途类页
0x09, 0x01, // USAGE (Vendor Usage 1) 表示一个报告ID标志
0xa1, 0x00, // COLLECTION (Physical) 要以下面最后的0xc0结束它
0x85, 0x80, /* REPORT_ID (128) */
0x09, 0x55, /*USAGE (LED 1) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x26, 0xFF, 0x00, /* LOGICAL_MAXIMUM (255) */
0x75, 0x08, /* REPORT_SIZE (8 bits) */
0x95, 0x01, /* REPORT_COUNT (1) */
0xB1, 0x82, /* FEATURE (Data,Var,Abs,Vol */
/* USER CODE END 0 */
0xC0 /* END_COLLECTION */
};
static int8_t CUSTOM_HID_OutEvent_FS(uint8_t event_idx, uint8_t state)
{
/* USER CODE BEGIN 6 */
extern RTC_HandleTypeDef hrtc;
if(event_idx ==0x80 && state ==0x55)
{
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x5A5A);
HAL_PWR_DisableBkUpAccess();
HAL_NVIC_SystemReset();
while (1);
}
return (USBD_OK);
/* USER CODE END 6 */
}
用RTC寄存器保存标志位,然后重启。重启后判断标志是否需要跳转进system memory
/* USER CODE BEGIN 2 */
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
isJumpDFU=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0);
if(isJumpDFU == 0x5A5A)
{
//ReebUSB();
HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0);
HAL_PWR_DisableBkUpAccess();
JumpToBootloader();
}else
{
HAL_PWR_DisableBkUpAccess();
}
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
HAL_Delay(300);
HAL_GPIO_TogglePin(LED_D1_GPIO_Port,LED_D1_Pin);
}
文件下载:
写在最后:
如果当前已经使用了USB干别的事情,那么也是可以利用组合设备的方式,将这个hid接口集成进去的。
我目前使用的方法是,系统运行日志存储在spi flash中,然后虚拟出USB mass,电脑上显示U盘,可以直接操作文件。
然后与这个hid集成形成一个组合设备,mass和hid共存,有相关疑问的道友可以回帖,要是需要后期我搞个组合设备的demo。
离线
厉害 学习了 我只用过STM32的虚拟串口 其他都还没用过
离线
道友好帖!
离线
这个要赞。
离线
你好,有联系方式吗,请教下
离线
感谢分享
离线
感谢分享,用USB模拟U盘,拖拽更新更简单
离线
强势围观,学习
离线
感谢分享,以前用401做过HID+DFU,每次都只能断电,从HID跳到DFU,当时看官方demo也没跳转功能
离线