您尚未登录。

楼主 #1 2019-10-19 13:41:56

明月心惜
会员
注册时间: 2018-08-19
已发帖子: 24
积分: 29

STM32使用cubemx生成HID设备便于USB DFU升级

简介:
      用STM32做东西免不了要考虑升级什么的,特别是对外暴露USB口的时候,大多时候设计个全速USB(12Mbps)就够用了,现在想用这个USB做程序升级。代码中虚拟出可以被DfuSeDemo识别的设备,这样就可以只连USB线,发送指令到MCU进入DFU,升级完跳转到程序。不需要去拨开关什么的额外操作,一根USB线搞定升级。

stm32-0.gif

主要步骤:
STM32F4等系列在system boot里面已经集成了DFU,也就是(BOOT0=1,BOOT1=0),重启进入System memory。
对于开发板,只要把boot0跳到0跑用户程序,跳到1进system boot,可以用串口、DFU等升级用户程序。早期的片子没有集成DFU,自己写一个,然后想办法跳转过去就行了。

stm32-1.jpg

手头有个STM32F401开发板 STM32F401CCU6,tb便宜+Type-c,拿这个跑Demo。

stm32-2.jpg

    把右上角的拨码开关干上去(boot0=1),然后RST一下,打开DfuSeDemo(V3.0.6),接上USB连接电脑。下载程序我就不bb了,注意图中的两个按钮,下载完后按钮2可以跳转到更新的程序,然后就没有然后了(两个按钮都变灰,你无法操作了)。

stm32-3.jpg

现在想把按钮1搞出来,从程序跳转到DFU,释放双手。百毒到处找资料,发现官方的Demo把这个功能阉割了,不管你怎么努力都不行,中文社区还放出了 DfuSeDemo_A.exe下载也是空文件夹,找不到这玩意儿。
DfuSeDemo这个官方给出了源码,在软件的安装目录,C++的,有能耐的大佬可以去改改。后面找到github上有大佬干了这个,我就把别人编译好的文件拿来用了,附件分享可执行文件。现在上位部分识别没问题了,开始cubemx流水化作业了。
新建项目、配置SWD、时钟、USB Device。要给USB 48NHz时钟,时钟树如下:

stm32-4.jpg

简单配置下HID参数,报告描述符设置为23,后面有数据需要填充。

stm32-5.jpg

把堆栈设置大一点,堆8K,栈16K。然后就可以快活玩耍了。

stm32-6.jpg

生成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);
  }

文件下载:

DfuSeDemo Plus.7z

MiniF4WeAct_HID1.7z

写在最后:

如果当前已经使用了USB干别的事情,那么也是可以利用组合设备的方式,将这个hid接口集成进去的。
我目前使用的方法是,系统运行日志存储在spi flash中,然后虚拟出USB mass,电脑上显示U盘,可以直接操作文件。
然后与这个hid集成形成一个组合设备,mass和hid共存,有相关疑问的道友可以回帖,要是需要后期我搞个组合设备的demo。

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn