detecting usb attachment

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

detecting usb attachment

1,547件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by jjsd on Tue Aug 16 10:22:04 MST 2011
I'm using LPCXpresso v3.6.3_317 with a LPC1754 micro in a CDC virtual comm port application using the LPC1700_usbstack example code for the CDC support. The micro board is self-powered.

Is there a way to detect on the micro side when the host computer has attached and enumerated the usb? Looking basically to generate a flag that indicates the port is open and ready or not.

Thanks.
0 件の賞賛
返信
2 返答(返信)

1,424件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by jjsd on Mon Aug 22 11:47:48 MST 2011
I have something working now. Not perfect, but works. I'm using the USB stack from Bertrik Sikke.

I  added a variable, uint8_t vcom_portOpen, to act as a flag, initialized  to FALSE. I modified the HandleClassRequest and USBHwISR functions.

There  is a sequence of usb activity that occurs when a port is opened. On  Windows XP and 7 it looks like the sequence of activity appears to be  the same, but I'm apprehensive to count on it. The amount of time the  sequence takes before the port is actually open varies with the host  computer speed. Among other things several HandleClassRequest calls are  made to SET_LINE_CODING. You could track the sequence to get as close to  the port being fully open, but I just watch for a SET_LINE_CODING call.  The port is actually opened and working a short time later. That's the not so perfect part, the amount of time before the port is actually opened varies depending on the speed of the host computer.

Two things occur that indicate a port closing. First, in the HandleClassRequest function if you get two consecutive calls with
SET_CONTROL_LINE_STATE  0 that indicates the host computer closed the port gracefully. Second,  if you get a device status interrupt call to USBHwISR and devStatus ==  13 the port hardware was disconnected, ie usb plug pulled abruptly.

I added a function that just returns vcom_portOpen that can be called to see if the port is open.

HandleClassRequest function with mods...
static BOOL HandleClassRequest(TSetupPacket *pSetup, int *piLen, U8 **ppbData)
{
    static uint8_t setStateCnt = 0; // jjsd: keep track of consecutive SET_CONTROL_LINE_STATE 0 calls

    switch (pSetup->bRequest)
    {

    // set line coding
    case SET_LINE_CODING:
        DBG("SET_LINE_CODING\r\n");
        memcpy((U8 *) &LineCoding, *ppbData, 7);
        *piLen = 7;
        DBG("dwDTERate=%u, bCharFormat=%u, bParityType=%u, bDataBits=%u\r\n",
                LineCoding.dwDTERate,
                LineCoding.bCharFormat,
                LineCoding.bParityType,
                LineCoding.bDataBits);

        setStateCnt = 0;         // jjsd: reset our consecutive SET_CONTROL_LINE_STATE 0 count
        vcom_portOpen = TRUE;     // jjsd: indicate the port is open
        break;

        // get line coding
    case GET_LINE_CODING:
        DBG("GET_LINE_CODING\r\n");
        *ppbData = (U8 *) &LineCoding;
        *piLen = 7;

        setStateCnt = 0;         // jjsd: reset our consecutive SET_CONTROL_LINE_STATE 0 count
        break;

        // set control line state
    case SET_CONTROL_LINE_STATE:
        // bit0 = DTR, bit = RTS
        DBG("SET_CONTROL_LINE_STATE %X\r\n", pSetup->wValue);

        if (pSetup->wValue == 0)     // jjsd: keep track of SET_CONTROL_LINE_STATE 0 consecutive count
            setStateCnt++;
        if (setStateCnt == 2)         // jjsd: two consecutive SET_CONTROL_LINE_STATE 0 means the port is closing
            vcom_portOpen = FALSE;    // jjsd: indicate the port is closed
        break;

    default:
        return FALSE;
    }
    return TRUE;
}
USBHwISR function with mods...
void USBHwISR(void)
{
    U32 dwStatus;
    U32 dwIntBit;
    U8 bEPStat, bDevStat, bStat;
    int i;
    U16 wFrame;

    // LED9 monitors total time in interrupt routine
    DEBUG_LED_ON(6);

    // handle device interrupts
    dwStatus = LPC_USB->USBDevIntSt;

    // frame interrupt
    if (dwStatus & FRAME)
    {
        // clear int
        LPC_USB->USBDevIntClr = FRAME;
        // call handler
        if (_pfnFrameHandler != NULL)
        {
            wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR);
            _pfnFrameHandler(wFrame);
        }
    }

    // device status interrupt
    if (dwStatus & DEV_STAT)
    {

        /*    Clear DEV_STAT interrupt before reading DEV_STAT register.
         This prevents corrupted device status reads, see
         LPC2148 User manual revision 2, 25 july 2006.
         */
        LPC_USB->USBDevIntClr = DEV_STAT;
        bDevStat = USBHwCmdRead(CMD_DEV_STATUS);

        if (bDevStat == 13)                         // jjsd: bDevStat == 13 indicates the usb hardware has been disconnected
            vcom_portOpen = FALSE;         // jjsd: indicate port is closed

        if (bDevStat & (CON_CH | SUS_CH | RST))
        {
            // convert device status into something HW independent
            bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) | ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0)
                    | ((bDevStat & RST) ? DEV_STATUS_RESET : 0);
            // call handler
            if (_pfnDevIntHandler != NULL)
            {
                DEBUG_LED_ON(5);
                _pfnDevIntHandler(bStat);
                DEBUG_LED_OFF(5);
            }
        }
    }

    // endpoint interrupt
    if (dwStatus & EP_SLOW)
    {
        // clear EP_SLOW
        LPC_USB->USBDevIntClr = EP_SLOW;
        // check all endpoints
        for (i = 0; i < 32; i++)
        {
            dwIntBit = (1 << i);
            if (LPC_USB->USBEpIntSt & dwIntBit)
            {
                // clear int (and retrieve status)
                LPC_USB->USBEpIntClr = dwIntBit;
                Wait4DevInt(CDFULL);
                bEPStat = LPC_USB->USBCmdData;
                // convert EP pipe stat into something HW independent
                bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) | ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0)
                        | ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) | ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED
                        : 0) | ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0);
                // call handler
                if (_apfnEPIntHandlers[i / 2] != NULL)
                {
                    DEBUG_LED_ON(7);
                    _apfnEPIntHandlers[i / 2](IDX2EP(i), bStat);
                    DEBUG_LED_OFF(7);
                }
            }
        }
    }

    DEBUG_LED_OFF(6);
}
0 件の賞賛
返信

1,424件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by Rob65 on Tue Aug 16 23:13:29 MST 2011
J.

this all depends on the USB stack you are using (or actually not ...)

The Keil example (the one named usbcdc) shows the use of the global USB_Configuration variable (or should I say misused) to detect if the device is connected. USB_Configurations is given a value somewhere during the initialization process but I have no idea when...

I use the USB stack from Bertrik Sikken which can be found in the RDB1768cmsis examples. This stack has a number of advantages over the Keil stack. For one it has no limitations on distribution as either binary or source code (you are not allowed to distribute source code of the Keil stack) but it is also much nicer to configure.

If you look at the usb_serial example in the mentioned example set, you'll see that almost everything is placed in main_serial.c.
In the main() function USB is initialized and the interrupt handlers for the endpoints are registered.

I am not sure how familiar you are with USB, I will try (if not for you then maybe for others who read this :rolleyes:) to explain very shortly how USB is used.
During initialization the host reads the device descriptors of the device.
These descriptors contain the information about the device (ID, serial no., name, device type, ...) including information on the end points.
End points are the main interface between the USB host and your application.

For the CDC There are two end points: BULK_IN_EP and BULK_OUT_EP. The host (PC) reads the BULK_IN and writes to BULK_OUT in certain intervals (as configured in the device descriptors).
This bulk end points contain 0 or more bytes of data, any characters send towards the PC are to be placed in the IN end point (IN for the PC), any characters send from the PC are received in the OUT end point.

If you look at the source you will see that there are two functions BulkIn() and BulkOut(), these are being called by the USB stack to tell the program USB want to read or write data.

A third function that might be of interest is HandleClassRequest(). This function is called when the PC wants to configure the (virtual) serial port (e.g. set the baud rate).

This is (almost) all you need to know about USB, most USB devices work in a similar way. End points may vary in type and number and the HandleClassRequest of course contains different requests depending of the device but as you look at the different USB examples (in the RDB1768cmsis examples) you will see how this is done.

Knowing this, it is a simple task to include your own 'Yes, we are alive!" checks.
You can set a flag as soon as you the BulkIn() function is called. This then signals that the PC is now polling your device for data.
You can also set a flag when HandleClassRequest() is called, but you have to try a bit to see if, and when, this function is called. I am not sure if this function is always called or at what time it is called.

What I do not know is if there are ways to tell if an application has the device open or not. I.e: I have my device attached to the PC, open a (terminal) program that uses the device, close the program, open it again, etc...
I have not checked if this open/close sequence is visible on the lpc1754 side of the USB stack.

This should also be possible with the Keil stack but I have no idea where this is placed inside the code of that stack.

Hope this helps.

Regards,[INDENT]Rob
[/INDENT]
0 件の賞賛
返信