STM32F1 custom USB

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

Moderator: RoccoMarco

User avatar
ADI-mistrzu
Posts: 12
Joined: Mon Jun 29, 2015 8:37 am

STM32F1 custom USB

Post by ADI-mistrzu »

Hi,

I try run USB as Vendor specific with libUSB driver.

At this moment, device it's correct detected in system, but I can't receive from host any data.

My code it's look that:

Code: Select all

#define   USBD1_DATA_REQUEST_EP1         0x01
#define   USBD1_DATA_REQUEST_EP2         0x02

/*
 * USB Device Descriptor.
 */
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).                   */
            0x5750,      /* idProduct.                       */
            0x0100,      /* bcdDevice.                       */
            1,         /* iManufacturer.                   */
            2,         /* iProduct.                        */
            3,         /* iSerialNumber.                   */
            1)         /* bNumConfigurations.              */
};

/*
 * Device Descriptor wrapper.
 */
static const USBDescriptor device_descriptor = {
      sizeof device_descriptor_data,
      device_descriptor_data
};



/* Configuration Descriptor tree*/
static const uint8_t configuration_descriptor_data[32] = {
  /* Configuration Descriptor.*/
      USB_DESC_CONFIGURATION( // 8
            32,               /* wTotalLength.                    */
            0x01,            /* bNumInterfaces.                  */
            0x01,            /* bConfigurationValue.             */
            0,               /* iConfiguration.                  */
            0xC0,            /* bmAttributes (self powered).     */
            200),            /* bMaxPower (400mA).               */
  /* Interface Descriptor.*/
      USB_DESC_INTERFACE( // 9
            0x00,            /* bInterfaceNumber.                */
            0x00,            /* bAlternateSetting.               */
            0x02,            /* bNumEndpoints.                   */
            0xFF,            /* bInterfaceClass (Vendor Specific).                            */
            0x00,            /* bInterfaceSubClass  */
            0x00,            /* bInterfaceProtocol                */
            0),               /* iInterface.                      */
  /* Endpoint 3 Descriptor.*/
      USB_DESC_ENDPOINT( // 7
            USBD1_DATA_REQUEST_EP1,            /* bEndpointAddress.*/
            0x02,            /* bmAttributes (Bulk).             */
            0x0040,            /* wMaxPacketSize.                  */
            0x00),            /* bInterval.                       */
  /* Endpoint 1 Descriptor.*/
      USB_DESC_ENDPOINT( // 7
            USBD1_DATA_REQUEST_EP2,            /* bEndpointAddress.*/
            0x02,            /* bmAttributes (Bulk).             */
            0x0040,            /* wMaxPacketSize.                  */
            0x00)            /* bInterval.                       */
};


/*
 * Configuration Descriptor wrapper.
 */
static const USBDescriptor configuration_descriptor = {
      sizeof configuration_descriptor_data,
      configuration_descriptor_data
};

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

/*
 * Vendor string.
 */
static const uint8_t usb_string1[] = {
      USB_DESC_BYTE(12),                    /* bLength.                         */
      USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
      'S', 0, 'T', 0, 'O', 0, 'R', 0, 'K', 0,
};

/*
 * Device Description string.
 */
static const uint8_t usb_string2[] = {
      USB_DESC_BYTE(14),                    /* bLength.                         */
      USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
      'D', 0, 'E', 0, 'V', 0, 'I', 0, 'C', 0, 'E', 0,
};




/*
 * Serial Number string.
 */
static const uint8_t usb_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,
};

/*
 * Strings wrappers array.
 */
static const USBDescriptor usb_strings[] = {
      {sizeof usb_string0, usb_string0},
      {sizeof usb_string1, usb_string1},
      {sizeof usb_string2, usb_string2},
      {sizeof usb_string3, usb_string3}
};

/*
 * Handles the GET_DESCRIPTOR callback. All required descriptors must be
 * handled here.
 */
static const USBDescriptor *get_descriptor(USBDriver *usbp,
                                           uint8_t dtype,
                                           uint8_t dindex,
                                           uint16_t lang) {

   (void)usbp;
   (void)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 &usb_strings[dindex];
   }
   return NULL;
}

/**
 * @brief   IN EP1 state.
 */
static USBInEndpointState ep1instate;

/**
 * @brief   OUT EP1 state.
 */
static USBOutEndpointState ep1outstate;

/**
 * @brief   EP1 initialization structure (both IN and OUT).
 */
static const USBEndpointConfig ep1config = {
      USB_EP_MODE_TYPE_BULK,
      NULL,
      sduDataTransmitted,
      usbDataReceived,
      0x0040,
      0x0040,
      &ep1instate,
      &ep1outstate,
      2,
      NULL
};


/**
 * @brief   OUT EP2 state.
 */
static USBOutEndpointState ep2outstate;

/**
 * @brief   EP2 initialization structure (IN only).
 */
static const USBEndpointConfig ep2config = {
      USB_EP_MODE_TYPE_BULK,
      NULL,
      NULL,
      usbDataReceived,
      0x0000,
      0x0040,
      NULL,
      &ep2outstate,
      2,
      NULL
};

/*
 * Handles the USB driver global events.
 */
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, USBD1_DATA_REQUEST_EP1, &ep1config);
      usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP2, &ep2config);

      chSysUnlockFromIsr();
      return;
   case USB_EVENT_SUSPEND:
      return;
   case USB_EVENT_WAKEUP:
      return;
   case USB_EVENT_STALLED:
      return;
   }
   return;
}

/*
 * USB driver configuration.
 */
static const USBConfig usbcfg = {
      usb_event,
      get_descriptor,
      NULL,
      NULL
};


usbDataReceived look's that:

Code: Select all

void usbDataReceived(USBDriver *usbp, usbep_t ep)
{
   LED_red_ON;
}


So, when I try send some information, then LED should be turn on, but this isn't happening.
I must activation EndPoint or something that?

I want transfer simple information like some short strings.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32F1 custom USB

Post by Giovanni »

Hi,

You are only showing the descriptors with no code. I don't see anything wrong in those but this is expected since the device is enumerated apparently.

It is better if you start from one of the USB demos under /testhal then start doing changes.

Giovanni
User avatar
ADI-mistrzu
Posts: 12
Joined: Mon Jun 29, 2015 8:37 am

Re: STM32F1 custom USB

Post by ADI-mistrzu »

I do that, search some example code and try modification.

Now I return to use Serial USB driver and now I know how read some information from USB.
But still I have a problem with transmision.

I must use 2 EndPoints, EP1 as transmiter to host and EP2 as receiver from host.
In all on one EndPoint I add the same transmision function (for test) and in this function put code to turn on LED.
Sow, when some information will be sent from device, there LED should be show me that.

USB code:

Code: Select all

static msg_t USB_thread(void *arg)
{
   (void)arg;
   chRegSetThreadName("USB");

   EventListener el1;
   flagsmask_t flags;
   uint8_t cmd_res[2];
   uint8_t clear_buff[64];

   sduObjectInit(&SDU1);
   sduStart(&SDU1, &serusbcfg);

   usbDisconnectBus(serusbcfg.usbp);
   chThdSleepMilliseconds(1500);
   usbStart(serusbcfg.usbp, &usbcfg);
   usbConnectBus(serusbcfg.usbp);

   chEvtRegisterMask(chnGetEventSource(&SDU1), &el1, ALL_EVENTS);
   while(SDU1.state != USB_READY)
      chThdSleepMilliseconds(10);

   while(GPIOA->IDR&GPIO_IDR_IDR9)
   {
      chEvtWaitAny(ALL_EVENTS);
       chSysLock();
       flags = chEvtGetAndClearFlagsI(&el1);
       chSysUnlock();

       if(flags & CHN_INPUT_AVAILABLE)
       {
          chnReadTimeout((BaseChannel *)&SDU1, cmd_res, 1, MS2ST(25) );
          switch(cmd_res[0])
          {
          case cmd_GSM_nr:

          break;
          case cmd_IMEI:

          break;
          case cmd_Signal:

          break;
          case cmd_FV_state:

          break;
          case cmd_USART_cnt:
//             LED_green_tog;
             cmd_res[0] = 2;
             chnWriteTimeout((BaseChannel *)&SDU1, cmd_res, 2, MS2ST(25) );
          break;
          }
          chnReadTimeout((BaseChannel *)&SDU1, clear_buff, 64, MS2ST(25) );
       }
   }

   usbStop(serusbcfg.usbp);
   usbDisconnectBus(serusbcfg.usbp);
   chThdSleepMilliseconds(500);
}

Descriptors:

Code: Select all

/*
 * usbcfg.h
 *
 *  Created on: 24 maj 2015
 *      Author: Mistrzu
 */

#ifndef INC_USBCFG_H_
#define INC_USBCFG_H_

#include "usb_param.h"

/*===========================================================================*/
/* USB related stuff.                                                        */
/*===========================================================================*/

/*
 * Endpoints to be used for USBD1.
 */

#define   USBD1_DATA_REQUEST_EP1         0x81
#define   USBD1_DATA_REQUEST_EP2         0x02

/*
 * Serial over USB Driver structure.
 */
SerialUSBDriver SDU1;

/*
 * USB Device Descriptor.
 */
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).                   */
            0x5750,      /* idProduct.                       */
            0x0100,      /* bcdDevice.                       */
            1,         /* iManufacturer.                   */
            2,         /* iProduct.                        */
            3,         /* iSerialNumber.                   */
            1)         /* bNumConfigurations.              */
};

/*
 * Device Descriptor wrapper.
 */
static const USBDescriptor device_descriptor = {
      sizeof device_descriptor_data,
      device_descriptor_data
};



/* Configuration Descriptor tree for a CDC.*/
static const uint8_t configuration_descriptor_data[32] = {
  /* Configuration Descriptor.*/
      USB_DESC_CONFIGURATION( // 8
            32,               /* wTotalLength.                    */
            0x01,            /* bNumInterfaces.                  */
            0x01,            /* bConfigurationValue.             */
            0,               /* iConfiguration.                  */
            0xC0,            /* bmAttributes (self powered).     */
            200),            /* bMaxPower (400mA).               */
  /* Interface Descriptor.*/
      USB_DESC_INTERFACE( // 9
            0x00,            /* bInterfaceNumber.                */
            0x00,            /* bAlternateSetting.               */
            0x02,            /* bNumEndpoints.                   */
            0xFF,            /* bInterfaceClass (Vendor Specific).                            */
            0x00,            /* bInterfaceSubClass (Abstract Control Model, CDC section 4.3).   */
            0x00,            /* bInterfaceProtocol (AT commands, CDC section 4.4).                */
            0),               /* iInterface.                      */
  /* Endpoint 3 Descriptor.*/
      USB_DESC_ENDPOINT( // 7
            USBD1_DATA_REQUEST_EP1,            /* bEndpointAddress.*/
            0x02,            /* bmAttributes (Bulk).             */
            0x0040,            /* wMaxPacketSize.                  */
            0x00),            /* bInterval.                       */
  /* Endpoint 1 Descriptor.*/
      USB_DESC_ENDPOINT( // 7
            USBD1_DATA_REQUEST_EP2,            /* bEndpointAddress.*/
            0x02,            /* bmAttributes (Bulk).             */
            0x0040,            /* wMaxPacketSize.                  */
            0x00)            /* bInterval.                       */
};


/*
 * Configuration Descriptor wrapper.
 */
static const USBDescriptor configuration_descriptor = {
      sizeof configuration_descriptor_data,
      configuration_descriptor_data
};

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

/*
 * Vendor string.
 */
static const uint8_t usb_string1[] = {
      USB_DESC_BYTE(42),                    /* bLength.                         */
      USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
      'S', 0, 'T', 0, 'O', 0, 'R', 0, 'K', 0, ' ', 0, 'f', 0,   'o', 0,
      'r', 0, ' ', 0,   'I', 0, 'N', 0, 'V', 0, 'E', 0, 'S', 0,   'T', 0,      // STORK for INVEST-POL
      '-', 0, 'P', 0, 'O', 0, 'L', 0
};

/*
 * Device Description string.
 */
static const uint8_t usb_string2[] = {
      USB_DESC_BYTE(24),                    /* bLength.                         */
      USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
      'R', 0, 'E', 0, 'M', 0, 'O', 0, 'T', 0, 'E', 0, ' ', 0, 'S', 0,      // REMOTE STOP
      'T', 0, 'O', 0, 'P', 0
};


/*
 * Serial Number string.
 */
static const uint8_t usb_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,
};

/*
 * Strings wrappers array.
 */
static const USBDescriptor usb_strings[] = {
      {sizeof usb_string0, usb_string0},
      {sizeof usb_string1, usb_string1},
      {sizeof usb_string2, usb_string2},
      {sizeof usb_string3, usb_string3}
};





/*
 * Handles the GET_DESCRIPTOR callback. All required descriptors must be
 * handled here.
 */
static const USBDescriptor *get_descriptor(USBDriver *usbp,
                                           uint8_t dtype,
                                           uint8_t dindex,
                                           uint16_t lang) {

   (void)usbp;
   (void)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 &usb_strings[dindex];
   }
   return NULL;
}

/**
 * @brief   IN EP1 state.
 */
static USBInEndpointState ep1instate;

/**
 * @brief   OUT EP1 state.
 */
static USBOutEndpointState ep1outstate;

/**
 * @brief   EP1 initialization structure (both IN and OUT).
 */
static const USBEndpointConfig ep1config = {
      USB_EP_MODE_TYPE_BULK,
      NULL,
      sduDataTransmitted,
      NULL,
      0x0040,
      0x0000,
      &ep1instate,
      NULL,
      2,
      NULL
};

/**
 * @brief   IN EP2 state.
 */
static USBInEndpointState ep2instate;

/**
 * @brief   OUT EP2 state.
 */
static USBOutEndpointState ep2outstate;

/**
 * @brief   EP2 initialization structure (IN only).
 */
static const USBEndpointConfig ep2config = {
      USB_EP_MODE_TYPE_BULK,
      NULL,
      sduDataTransmitted,
      sduDataReceived,
      0x0040,
      0x0040,
      &ep2instate,
      &ep2outstate,
      2,
      NULL
};

/*
 * Handles the USB driver global events.
 */
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, USBD1_DATA_REQUEST_EP1, &ep1config);
      usbInitEndpointI(usbp, USBD1_DATA_REQUEST_EP2, &ep2config);

      sduConfigureHookI(&SDU1);

      chSysUnlockFromIsr();
      return;
   case USB_EVENT_SUSPEND:
      return;
   case USB_EVENT_WAKEUP:
      return;
   case USB_EVENT_STALLED:
      return;
   }
   return;
}

/*
 * USB driver configuration.
 */
static const USBConfig usbcfg = {
      usb_event,
      get_descriptor,
      sduRequestsHook,
      NULL
};

/*
 * Serial over USB driver configuration.
 */
static const SerialUSBConfig serusbcfg = {
      &USBD1,
      USBD1_DATA_REQUEST_EP1,
      USBD1_DATA_REQUEST_EP2
};

#endif /* INC_USBCFG_H_ */


I should be do something before send?
All EndPoint is BULK type and I modification CDC example code.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32F1 custom USB

Post by Giovanni »

Hi,

A recent modification in the CDC code in 3.0 allows to use only two endpoints, you could try that.

Anyway, are the debug options in chconf.h enabled? try to enable checks, assertions and the "state checker" and see if something is caught. Errors stop the system, at that point examine the stack trace and see where it stopped.

Giovanni
User avatar
ADI-mistrzu
Posts: 12
Joined: Mon Jun 29, 2015 8:37 am

Re: STM32F1 custom USB

Post by ADI-mistrzu »

Ok, i found what is wrong,

EndPoint 1 it's must 0x01 value, 0x81 it's needed only in configuration_descriptor.
Now I can read and write data :D

But I have another problem... I try send answer for incoming command:

Code: Select all

while(TRUE){
      chThdSleepMilliseconds(1);
      if(SDU1.iqueue.q_counter)
       {

          sdReadTimeout( &SDU1, cmd_res, 1, MS2ST(25) );
          switch(cmd_res[0])
          {
          case cmd_GSM_nr:
             sdWriteTimeout(&SDU1, "000000000", 9, MS2ST(100) );
          break;
          case cmd_IMEI:
             sdWriteTimeout(&SDU1, "0123456789ABCDE", 15, MS2ST(25) );
          break;
          case cmd_Signal:
             sdWriteTimeout(&SDU1, "00", 2, MS2ST(25) );
          break;
          case cmd_FV_state:
             sdWriteTimeout(&SDU1, __DATE__, 12, MS2ST(25) );
          break;
          }
      }
}

It's looking easy, but work really weird, all data is mixed:
Image
In "Firmware version" I have some data from "IMEI", in "IMEI" I don't know what I have...
And it's random, whenever it's difrent.

At old software for device everything with USB work OK, so I'm sure that PC aplication work fine.

I really would like try 3.0, but I don't have a time, I must finish that.
I don't use debug function, but it's can help me in this problem?
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32F1 custom USB

Post by Giovanni »

You are specifying timeouts, this means that "read" function may return less bytes than specified.

Giovanni
User avatar
ADI-mistrzu
Posts: 12
Joined: Mon Jun 29, 2015 8:37 am

Re: STM32F1 custom USB

Post by ADI-mistrzu »

Yea, I trying write and read without timeout, but still do the same.

In system exist only 2 threads, one with only chThdSleepMilliseconds(650) in while loop, and secound with this USB, so system most of the time do nothing.
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32F1 custom USB

Post by Giovanni »

You perform an usbStop() there, that would interrupt any transmission in progress.

Please enable the debug functions I mentioned, those are able to find a lot of errors.

Giovanni
User avatar
ADI-mistrzu
Posts: 12
Joined: Mon Jun 29, 2015 8:37 am

Re: STM32F1 custom USB

Post by ADI-mistrzu »

Ok, I run debuging and compile project with options:

Code: Select all

CH_DBG_SYSTEM_STATE_CHECK
CH_DBG_ENABLE_CHECKS
CH_DBG_ENABLE_ASSERTS
CH_DBG_THREADS_PROFILING


Sorry, but I don't understand what did you mean about use usbSTOP on transmission.

I set breakopint at first sdWrite, and i think I know why it's work that.
When I send some information, then system do that and additionally read that, so when I finish write, then I have this information in read buffor.

The question is, how to change it?
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: STM32F1 custom USB

Post by Giovanni »

I meant, calling usbStop() stops the driver immediatelly. Exiting from sdWriteTimeout() does not mean that data HAS BEEN transmitted, the data has just been queued for transmission. Stopping the driver means that the queued data will never be transmitted.

Just a note, it is not correct to use "sd" functions on the Serial_USB driver, those are meant for the serial driver. Using them happens to work because the two drivers use the same queues and those functions are just macros. The correct way is to use the channel functions (macros): chnWriteTimeout().

Channels functions are meant to work indipendently from the underlying driver because they access the driver through a virtual table.

Giovanni
Post Reply