Strange behavior of USB driver on STM32F407.

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
Kosyak
Posts: 14
Joined: Tue Jul 22, 2014 3:22 am

Strange behavior of USB driver on STM32F407.

Post by Kosyak »

I'm trying to communicate with my device using libusb and control requests.

Here is code:

Code: Select all

#include "ch.h"
#include "hal.h"

#define USB_DATA_EP           1

static const USBDescriptor *get_descriptor(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang);
static void usb_event(USBDriver *usbp, usbevent_t event);
static bool_t requestsHook(USBDriver *usbp);
static void dataReceived(USBDriver *usbp, usbep_t ep);

static const uint8_t device_descriptor_data[18] =
{
    USB_DESC_DEVICE(0x0110,               /* bcdUSB (1.1).                    */
    0xFF,          /* bDeviceClass (Custom).           */
    0x00,          /* bDeviceSubClass.                 */
    0x00,          /* bDeviceProtocol.                 */
    0x40,          /* bMaxPacketSize.                  */
    0x0483,        /* idVendor (ST).                   */
    0x5740,        /* idProduct.                       */
    0x0000,        /* bcdDevice.                       */
    1,             /* iManufacturer.                   */
    2,             /* iProduct.                        */
    3,             /* iSerialNumber.                   */
    1)             /* bNumConfigurations.              */
};

static const USBDescriptor device_descriptor =
{
    sizeof device_descriptor_data,
    device_descriptor_data
};

/* Configuration Descriptor tree. */
static const uint8_t configuration_descriptor_data[25] =
{
    /* Configuration Descriptor.*/
    USB_DESC_CONFIGURATION(25,            /* wTotalLength.                    */
    0x01,          /* bNumInterfaces.                  */
    0x01,          /* bConfigurationValue.             */
    0,             /* iConfiguration.                  */
    0xC0,          /* bmAttributes (self powered).     */
    50),           /* bMaxPower (100mA).               */
    /* Interface Descriptor.*/
    USB_DESC_INTERFACE(0x00,              /* bInterfaceNumber.                */
    0x00,          /* bAlternateSetting.               */
    0x01,          /* bNumEndpoints.                   */
    0xFF,          /* bInterfaceClass (Custom).        */
    0x00,          /* bInterfaceSubClass (Custom).     */
    0x00,          /* bInterfaceProtocol (Custom).     */
    0),            /* iInterface.                      */
    /* Endpoint 2 Descriptor.*/
    USB_DESC_ENDPOINT(USB_DATA_EP,
    0x02,          /* bmAttributes (Bulk).             */
    0x0040,        /* wMaxPacketSize.                  */
    0x00)          /* bInterval.                       */
};

static const USBDescriptor configuration_descriptor =
{
    sizeof configuration_descriptor_data,
    configuration_descriptor_data
};

static const uint8_t string0[] =
{
    USB_DESC_BYTE(4),                     /* bLength.                         */
    USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
    USB_DESC_WORD(0x0409)                 /* wLANGID (U.S. English).          */
};

static const uint8_t string1[] =
{
    USB_DESC_BYTE(38),                    /* bLength.                         */
    USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
    'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0,
    'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0,
    'c', 0, 's', 0
};

static const uint8_t string2[] =
{
    USB_DESC_BYTE(56),                    /* bLength.                         */
    USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
    'C', 0, 'h', 0, 'i', 0, 'b', 0, 'i', 0, 'O', 0, 'S', 0, '/', 0,
    'R', 0, 'T', 0, ' ', 0, 'V', 0, 'i', 0, 'r', 0, 't', 0, 'u', 0,
    'a', 0, 'l', 0, ' ', 0, 'C', 0, 'O', 0, 'M', 0, ' ', 0, 'P', 0,
    'o', 0, 'r', 0, 't', 0
};

static const uint8_t string3[] =
{
    USB_DESC_BYTE(8),                     /* bLength.                         */
    USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
    '0' + CH_KERNEL_MAJOR, 0,
    '0' + CH_KERNEL_MINOR, 0,
    '0' + CH_KERNEL_PATCH, 0
};

static const USBDescriptor strings[] =
{
    {sizeof string0, string0},
    {sizeof string1, string1},
    {sizeof string2, string2},
    {sizeof string3, string3}
};


static USBOutEndpointState ep1outstate;

static const USBEndpointConfig ep1config =
{
    USB_EP_MODE_TYPE_BULK,
    NULL,
    NULL,
    dataReceived,
    0x0,
    0x0040,
    NULL,
    &ep1outstate,
    2,
    NULL
};

static const USBConfig usbcfg =
{
    usb_event,
    get_descriptor,
    requestsHook,
    NULL
};

static const USBDescriptor *get_descriptor(USBDriver *usbp, uint8_t dtype, uint8_t dindex, uint16_t lang)
{
    switch (dtype)
    {
    case USB_DESCRIPTOR_DEVICE:
        return &device_descriptor;
    case USB_DESCRIPTOR_CONFIGURATION:
        return &configuration_descriptor;
    case USB_DESCRIPTOR_STRING:
        if (dindex < 4)
            return &strings[dindex];
    }
    return NULL;
}

static void usb_event(USBDriver *usbp, usbevent_t event)
{
    switch (event)
    {
    case USB_EVENT_RESET:
        return;
    case USB_EVENT_ADDRESS:
        return;
    case USB_EVENT_CONFIGURED:
        chSysLockFromIsr();
        usbInitEndpointI(usbp, USB_DATA_EP, &ep1config);
        chSysUnlockFromIsr();
        return;
    case USB_EVENT_SUSPEND:
        return;
    case USB_EVENT_WAKEUP:
        return;
    case USB_EVENT_STALLED:
        return;
    }
    return;
}

static bool_t requestsHook(USBDriver *usbp)
{
   if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_VENDOR)
   {
         switch(usbp->setup[1])
         {
         case REQUEST_SET_LED:
            palWritePad(GPIOH, GPIOH_LED1, usbp->setup[2] & (1));
            palWritePad(GPIOH, GPIOH_LED2, usbp->setup[2] & (1 << 1));
            palWritePad(GPIOI, GPIOI_LED3, usbp->setup[2] & (1 << 2));
            palWritePad(GPIOI, GPIOI_LED4, usbp->setup[2] & (1 << 3));
            usbSetupTransfer(usbp, NULL, 0, NULL);
            return TRUE;
         }
   }
    return FALSE;
}

static void dataReceived(USBDriver *usbp, usbep_t ep)
{
}

void initUSB(USBDriver *usbp)
{
    usbDisconnectBus(usbp);
    chThdSleepMilliseconds(1500);
    usbStart(usbp, &usbcfg);
    chThdSleepMilliseconds(1500);
    usbConnectBus(usbp);
}


First of all, if I remove sleep after usbStart, host can't even enumerate device. (Malformed descriptor response packets according to Wireshark)

Another problem is that USB driver not even handle control transfers. libusb_control_transfer on host blocks forever. Wireshark shows that packet was sended to ep0, but no response received.
On device side, seems usb irq for endpoint0 not generated on transfer.

serial_usb driver works perfectly with similiar code (descriptors and callbacks are changed according to demo project). Host application can send CDC control request and recieved response using libusb_control_transfer.

Am I missing something in driver usage?

P.S. ChibiOS 2.6.5
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Strange behavior of USB driver on STM32F407.

Post by Giovanni »

The driver itself only handles few mandatory messages on the EP0, it is the application that must implement code to handle more messages in the "requests_hook_cb" callback, you can see an example in serial_usb.c, function sduRequestsHook().

Giovanni
Kosyak
Posts: 14
Joined: Tue Jul 22, 2014 3:22 am

Re: Strange behavior of USB driver on STM32F407.

Post by Kosyak »

Giovanni wrote:The driver itself only handles few mandatory messages on the EP0, it is the application that must implement code to handle more messages in the "requests_hook_cb" callback, you can see an example in serial_usb.c, function sduRequestsHook().

Giovanni

Code: Select all

static const USBConfig usbcfg =
{
    usb_event,
    get_descriptor,
    requestsHook,
    NULL
};

....

static bool_t requestsHook(USBDriver *usbp)
{
   if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_VENDOR)
   {
         switch(usbp->setup[1])
         {
         case REQUEST_SET_LED:
            palWritePad(GPIOH, GPIOH_LED1, usbp->setup[2] & (1));
            palWritePad(GPIOH, GPIOH_LED2, usbp->setup[2] & (1 << 1));
            palWritePad(GPIOI, GPIOI_LED3, usbp->setup[2] & (1 << 2));
            palWritePad(GPIOI, GPIOI_LED4, usbp->setup[2] & (1 << 3));
            usbSetupTransfer(usbp, NULL, 0, NULL);
            return TRUE;
         }
   }
    return FALSE;
}

In my application, callback is called only during description requests. Other USB control transfers just ignored. However, serial_usb works fine. The main difference between my code and serial_usb in descriptions and that I didn't start receiving on endpoint 1 after configuring (although it doesn't help either).

Found. I've accidentally dead-locked scheduler in other place, so pump thread in usb lld driver could not be resumed.
Post Reply