creep 发表于 2017-4-24 22:57:08

【NUCLEO-L496ZG评测】+ USB OTG 之 HID 远程唤醒PC

本帖最后由 creep 于 2017-4-25 08:46 编辑



    STM32L496上面有个USB OTG FS接口可以作为Host也可以作为Device,使用ST提供的USB库可以将STM32L496-Nucleo 枚举成一个HID设备,因为HID设备在windows是免驱,在很多对通信速度要求不高的场合时使用HID设备通信是一个很好的选择。如果对速度要求比较高可以考虑使用全速CDC模式或者高速CDC,但是鉴于我们都懂的原因,国内的很多操作系统都是不完整的系统,在使用CDC模式很大的可能性会遇到驱动的安装问题。


全速USB使用内部的48MHZ的HSI时钟,硬件连接如下:
   
   


在底层初始化中要按照硬件的连接进行相应功能的设置:


<font face="微软雅黑" size="3">void HAL_PCD_MspInit(PCD_HandleTypeDef *hpcd)
{
GPIO_InitTypeDefGPIO_InitStruct;

/* Configure USB FS GPIOs */
__HAL_RCC_GPIOA_CLK_ENABLE();

/* Configure DM DP Pins */
GPIO_InitStruct.Pin = (GPIO_PIN_11 | GPIO_PIN_12);
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* Configure VBUS Pin */
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* Configure ID pin */
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Alternate = GPIO_AF10_OTG_FS;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* Enable USB FS Clock */
__HAL_RCC_USB_OTG_FS_CLK_ENABLE();

/* Set USB FS Interrupt priority */
HAL_NVIC_SetPriority(OTG_FS_IRQn, 0x0F, 0);

/* Enable USB FS Interrupt */
HAL_NVIC_EnableIRQ(OTG_FS_IRQn);

if(hpcd->Init.low_power_enable == 1)
{
    /* Enable EXTI Line 18 for USB wakeup */
    __HAL_USB_OTG_FS_WAKEUP_EXTI_ENABLE_IT();            
}   
}</font>

HID作为PC的一个USB devcie 支持remote wakeup 功能可以睡眠状态下的电脑唤醒,工作原理是如果使能了唤醒功能,USB内核会发送一个wakeup信号给Host(PC):





为了模拟这个效果我们使用STM32L496-Nucleo上的USER 按键来触发唤醒信号,当检测到按键按下中断时就发一个唤醒信号给主机PC,按键的中断回调函数如下:信号的发送要严格按下参考手册描述的进行执行。


<font face="微软雅黑" size="3">void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == SEL_JOY_PIN)
{
    if ((((USBD_HandleTypeDef *)hpcd.pData)->dev_remote_wakeup == 1)&&
      (((USBD_HandleTypeDef *)hpcd.pData)->dev_state == USBD_STATE_SUSPENDED))
    {
      if ((&hpcd)->Init.low_power_enable)
      {
      /* Reset SLEEPDEEP bit of Cortex System Control Register */
      SCB->SCR &= (uint32_t)~((uint32_t)(SCB_SCR_SLEEPDEEP_Msk | SCB_SCR_SLEEPONEXIT_Msk));
      
      SystemClockConfig_STOP();
      }
      
      /* Ungate PHY clock */
      __HAL_PCD_UNGATE_PHYCLOCK((&hpcd));
      
      /* Activate Remote wakeup */
      HAL_PCD_ActivateRemoteWakeup((&hpcd));
      
      /* Remote wakeup delay */
      HAL_Delay(10);
      
      /* Disable Remote wakeup */
      HAL_PCD_DeActivateRemoteWakeup((&hpcd));
      
      /* change state to configured */
      ((USBD_HandleTypeDef *)hpcd.pData)->dev_state = USBD_STATE_CONFIGURED;
      
      /* Change remote_wakeup feature to 0*/
      ((USBD_HandleTypeDef *)hpcd.pData)->dev_remote_wakeup=0;
      remotewakeupon = 1;
    }
}
}</font>

移植USB设备可以使用cubemx也可以参考HAL库移植好的例子进行修改,基本常见的模式都可以找到例子,移植的时候要安装原理图的USB接线进行修改。通过简单的移植后下载到Nucleo 中可以看到电脑上枚举出来的设备,如果有多个设备可以使用VID&PID进行区分:





首先在XP系统中进行测试,可以看到电脑休眠后按下开发板的user按键马上可以点亮电脑屏幕唤醒系统。







WIN10测试也可以唤醒系统唤醒指纹解锁。有的系统要设置设备能唤醒电脑,但是WIN10上没法设置这个选项。









测试代码:







推荐阅读:


【F769IDISCOVERY评测】高速USB VCP和全速USB VCP 速度对比


【STM32F303开发】+虚拟串口驱动安装失败的解决方法

哈佛祖安智 发表于 2017-4-24 23:41:57

前来顶帖

limale 发表于 2017-4-25 00:07:23

赞赞赞   

Paderboy 发表于 2017-4-25 08:10:19

:loveliness::loveliness:赞,顶起

creep 发表于 2017-4-25 08:37:03

哈佛祖安智 发表于 2017-4-24 23:41
前来顶帖

感谢支持   

creep 发表于 2017-4-25 08:37:23

limale 发表于 2017-4-25 00:07
赞赞赞

:handshake               

creep 发表于 2017-4-25 08:37:55

Paderboy 发表于 2017-4-25 08:10
赞,顶起

谢谢 Paderboy :)

pener 发表于 2017-4-26 08:41:14

这个不错不错,先备注

creep 发表于 2017-4-26 08:56:53

pener 发表于 2017-4-26 08:41
这个不错不错,先备注

:handshake            

请叫我小张张 发表于 2017-4-26 09:20:04

赞赞赞
页: [1] 2
查看完整版本: 【NUCLEO-L496ZG评测】+ USB OTG 之 HID 远程唤醒PC