Hey,
After some messing with Interface Association Descriptors, I now have a working composite device that supports both HID and audio streaming. Now, I would like the HID to be able to wake the computer via remote wakeup. The HID device is recognized as having this capability by Windows, but what is the right way to actually initiate the remote wakeup sequence? Is there any support for this in the STM32 internal USB state machine or USB standard library?
Resume(RESUME_EXTERNAL) does not seem to work, and I couldn't find any reference to the proper wakeup sequence (D+ high, D- low for at least 12 ms). Is this implemented at all in the standard library or should I write my own routine for this?
Much obliged.
Thanks Tsuneo, but now I'm a bit confused. So far I've only used the USB peripheral for communication with the host, and not using USB-OTG at all. It is my understanding that these are two totally separate parts of the hardware.
So now to wake up the host, connected to the USB peripheral, I need to in addition use the USB-OTG peripheral? When I then set the WKUPINT bit, this will play nice with the (not-OTG)-USB state machine?
Which STM32 are you working on? - STM32F4 / F2 (OTG_FS/OTG_HS) or - STM32F105/7 (OTG_FS) or - STM32F103 / STM32L (USB device)
Tsuneo
For STM32F103 / STM32L, this bit enables RESUME signaling from the device - ie. remote wakeup.
USB control register (USB_CNTR) Bit 4 RESUME: Resume request The microcontroller can set this bit to send a Resume signal to the host. It must be activated, according to USB specifications, for no less than 1mS and no more than 15mS after which the Host PC is ready to drive the resume sequence up to its end.
On the configuration descriptor, set D5 bit (Remote Wakeup) to 1 at bmAttributes field.
/* Configuration 1 */ 0x09, /* bLength */ USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType */ 0x6D, /* wTotalLength 110 bytes*/ 0x00, 0x02, /* bNumInterfaces */ 0x01, /* bConfigurationValue */ 0x00, /* iConfiguration */ 0xC0, /* bmAttributes Self Powred*/ // <--- 0xE0 0x32, /* bMaxPower = 100 mA*/
Dear Tsuneo,
Based on your reference, I could see that I was calling the Resume function with the wrong parameter. Earlier I was using Resume(RESUME_EXTERNAL), which had no effect. With Resume(RESUME_INTERNAL) or Resume(RESUME_START), the host (Windows 7) wakes up, but very strange: the display does not turn on. So it seems the USB is being left in an incorrect state or does not signal the wakeup correctly.
I also tried a Linux host. Wakeup seems to work okay there, but probably I am making an error somewhere.
Again, much obliged for your help.
From usb_pwr.c (I checked that the ESOF interrupt is enabled):
/******************************************************************************* * Function Name : Resume * Description : This is the state machine handling resume operations and * timing sequence. The control is based on the Resume structure * variables and on the ESOF interrupt calling this subroutine * without changing machine state. * Input : a state machine value (RESUME_STATE) * RESUME_ESOF doesn't change ResumeS.eState allowing * decrementing of the ESOF counter in different states. * Output : None. * Return : None. *******************************************************************************/ void Resume(RESUME_STATE eResumeSetVal) { u16 wCNTR; if (eResumeSetVal != RESUME_ESOF) ResumeS.eState = eResumeSetVal; switch (ResumeS.eState) { case RESUME_EXTERNAL: Resume_Init(); ResumeS.eState = RESUME_OFF; break; case RESUME_INTERNAL: Resume_Init(); ResumeS.eState = RESUME_START; break; case RESUME_LATER: ResumeS.bESOFcnt = 2; ResumeS.eState = RESUME_WAIT; break; case RESUME_WAIT: ResumeS.bESOFcnt--; if (ResumeS.bESOFcnt == 0) ResumeS.eState = RESUME_START; break; case RESUME_START: wCNTR = _GetCNTR(); wCNTR |= CNTR_RESUME; _SetCNTR(wCNTR); ResumeS.eState = RESUME_ON; ResumeS.bESOFcnt = 10; break; case RESUME_ON: ResumeS.bESOFcnt--; if (ResumeS.bESOFcnt == 0) { wCNTR = _GetCNTR(); wCNTR &= (~CNTR_RESUME); _SetCNTR(wCNTR); ResumeS.eState = RESUME_OFF; } break; case RESUME_OFF: case RESUME_ESOF: default: ResumeS.eState = RESUME_OFF; break; } }