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.
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; } }