9 years, 10 months ago.

USB - how can I tell when the host computer is in sleep mode or powered off?

I have a KL25Z project that's acting as a USB HID. When the PC is powered off, it continues to supply the device with power. This is fine, but I'd like to have the device at least recognize when this happens so that it can turn off its indicator LEDs and so on. The same would be nice when the PC is in sleep mode.

So far I haven't found a way to detect power off/sleep on the USB connection. I would have thought that the suspend or connect state flags would be usable for this, so I tried overriding USBDevice::suspendStateChanged() and connectStateChanged() in a custom subclass, but these don't ever seem to get called. Upon closer inspection, the mbed USB code never actually calls connectStateChanged() - whoever wrote the code must have prototyped it and then forgot to actually write that part of the code, The configured_ flag seems to be a proxy for connect state, but once the device connects, this isn't affected by powering off the PC - only by physically unplugging the USB cable. It does look like there are the proper calls to suspendStateChanged() in the mbed USB code, but in practice they don't seem to be happening.

Any pointers to how I can test for host power/sleep mode?

In the usbisr in http://mbed.org/users/mbed_official/code/USBDevice/file/0c6524151939/USBDevice/USBHAL_KL25Z.cpp are the usb interrupts handled. Maybe one of the unhandled ones (which only clear the flag and do little else) could help. Then again, maybe not :)

posted by Erik - 23 Jul 2014

You're quite right. :) A little more digging into the mbed code and the KL25Z manual sorted it out for me.

Here's what I needed to change - changes are all in USBDevice/USBDevice/USBHAL_KL25Z.cpp.

First, enable the SLEEP and RESUME interrupts. There's handling for them in the ISR routine, but it turns out they're not enabled by default. Around line 150 in the constructor (USBHAL::USBHAL()), add the bits for sleep and resume to the interrupt enable mask:

    // USB Interrupt Enablers
    USB0->INTEN |= USB_INTEN_TOKDNEEN_MASK |
                   USB_INTEN_SOFTOKEN_MASK |
                   USB_INTEN_ERROREN_MASK  |
+                  USB_INTEN_SLEEPEN_MASK |
+                  USB_INTEN_RESUMEEN_MASK |
                   USB_INTEN_USBRSTEN_MASK;

Now we just need to add calls to suspendStateChange() in response to the SLEEP and RESUME interrupts. For good measure, I added one to the BUS RESET interrupt as well, since the HAL code for some of the other microcontroller boards does that - not sure if this is necessary, but it doesn't seem like it can hurt, since the device will definitely not be in suspend mode directly after a reset.

In USBHAL::usbisr() starting around line 443:

        // enable control endpoint
        realiseEndpoint(EP0OUT, MAX_PACKET_SIZE_EP0, 0);
        realiseEndpoint(EP0IN, MAX_PACKET_SIZE_EP0, 0);

        Data1 = 0x55555555;
        USB0->CTL |=  USB_CTL_ODDRST_MASK;

        USB0->ISTAT   =  0xFF;  // clear all interrupt status flags
        USB0->ERRSTAT =  0xFF;  // clear all error flags
        USB0->ERREN   =  0xFF;  // enable error interrupt sources
        USB0->ADDR    =  0x00;  // set default address
        
+       suspendStateChanged(0);

        return;
    }

    // resume interrupt
    if (istat & USB_ISTAT_RESUME_MASK) {
        USB0->ISTAT = USB_ISTAT_RESUME_MASK;
+       suspendStateChanged(0);
    }

then around line 528:

    // sleep interrupt
    if (istat & 1<<4) {
        USB0->ISTAT |= USB_ISTAT_SLEEP_MASK;
+       suspendStateChanged(1);
    }

I think all this code was intended to be in there in the official version, since the framework for it is all there. Maybe the original developer(s) got sidetracked before they finished and a few details got dropped.

posted by Mike R 23 Jul 2014

Mike R: If you consider that those changes should be in the device library, feel free to send a pull request on github! Thanks

posted by Martin Kojtal 24 Jul 2014

Thanks for suggesting that - I just put in a pull request.

posted by Mike R 25 Jul 2014
Be the first to answer this question.