The USB topic

This forum is dedicated to feedback, discussions about ongoing or future developments, ideas and suggestions regarding the ChibiOS projects are welcome. This forum is NOT for support.
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: The USB topic

Post by Giovanni »

It is an example of badly designed web site, you usually have better luck using Google than trying to navigate it. The old site was ugly like sin too but at least you could find things.

Giovanni
m9202108
Posts: 3
Joined: Mon Jan 16, 2012 12:56 pm

Re: The USB topic

Post by m9202108 »

I am trying serial over USB at version 2.3.4 on STM32L-Discovery.
There are two problems.
One is after call palSetPadMode(), like below
palSetPadMode(GPIOA, 11, PAL_MODE_ALTERNATE(10));
palSetPadMode(GPIOA, 12, PAL_MODE_ALTERNATE(10));
USB can't work if not to reset GPIOA->MODER to input.
GPIOA->MODER = GPIOA->MODER & 0xFC3FFFFF;

The other problem is OUT data endpoint can't handle burst data more than 64 bytes.
I test it use windows HyperTerminal and send a 64 bytes string.
I don't know why but I will keep tracing code.
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: The USB topic

Post by Giovanni »

Hi,

It is possible that the USB peripheral requires input pins, not alternate, something to verify on the RM. Try to set them as input without pullups instead of alternate.

About the 64 bytes, the packet maximum size is programmed to 64 bytes, you should be able to write more than 64 bytes on the simulated serial port however.

Giovanni
m9202108
Posts: 3
Joined: Mon Jan 16, 2012 12:56 pm

Re: The USB topic

Post by m9202108 »

Hi Giovanni:

I trace the code and got the problem.
If send > 64 bytes data from PC to device quickly(like paste a string or send file to HyperTerminal), the USB RX interrupt will call sduDataReceived() two times very quickly.
But the second time, ChSysIQIsEmptyI(&sdup->iqueue) will return FALSE because MCU can't handle iqueue data so quickly and usbStartReceiveI(usbp, ep) will not be called.
This result make the USB RX can't receive data at next time forever.

Thanks.
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: The USB topic

Post by Giovanni »

Thanks for finding this, I will try to fix this issue before next release.

Giovanni
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: The USB topic

Post by Giovanni »

Just a note.

It is right that the packet cannot be read because the queue is not empty yet, it is supposed to work that way, however sbStartReceiveI(usbp, ep) should be called when the input queue is emptied from within the function inotify(), that should restart the endpoint.

Is inotify() triggered in your application? if not, the only scenario I can imagine is that the application does not empty the input queue and the endpoint is not restarted because of this.

Giovanni
m9202108
Posts: 3
Joined: Mon Jan 16, 2012 12:56 pm

Re: The USB topic

Post by m9202108 »

My test program is take data from USB RX and put to RS232

Code: Select all

  while (TRUE) {   
     if (SDU1.vmt->getwouldblock((void *)&SDU1) == FALSE)
     {
        tx_cnt = SDU1.iqueue.q_counter;
        SDU1.vmt->read((void *)&SDU1, tx_buf, tx_cnt);
        uartStartSend(&UARTD1, tx_cnt, tx_buf);
     }
  }

I am not sure this coding is right or not, could it empty iqueue data ?
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: The USB topic

Post by Giovanni »

Hi,

There are several problems with that code:

Code: Select all

SDU1.vmt->getwouldblock((void *)&SDU1)


You can use a macro for this: sdGetWouldBlock().

Code: Select all

tx_cnt = SDU1.iqueue.q_counter;
SDU1.vmt->read((void *)&SDU1, tx_buf, tx_cnt);


This could be replaced with: sdReadTimeout(,,,TIME_IMMEDIATE), this returns all the data contained in the queue without waiting. In general you don't need to access the inner fields of the various drivers, there should always be a function or a macro that is the official interface (internal details are not API and can change).

The critical point is this one:

Code: Select all

uartStartSend(&UARTD1, tx_cnt, tx_buf)


That function is an asynchronous call, if you call it while the previous uartStartSend() is still active the the behavior is unpredictable a crash or a lock are not impossible, see the state diagram of the UART driver. Probably you need a buffered output here, you should use the serial driver instead of the UART driver.

Anyway if you want to stress test the USB driver just do the emptying of the input queue, add the serial part later.

Giovanni
Xamusk
Posts: 81
Joined: Sat Mar 05, 2011 10:47 pm

Re: The USB topic

Post by Xamusk »

So, finally I found what was wrong with my app. Yes, it was the hardware that I screwd up, even after checking (literally) more than five times.

Anyway, I have a suggestion for the demo code for using USB_CDC. For the descriptor strings, I managed to get a way that allows me to type the strings directly on code instead of using that ugly form interlaced with zeros. Not only that, but I suppose my form is easier to handle when non-ASCII characters are present.

So, instead of:

Code: Select all

static const uint8_t vcom_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
};

I used:

Code: Select all

static const struct {uint8_t l;uint8_t t; char16_t s[56/2];} vcom_string2 = {
  USB_DESC_BYTE(56),                    /* bLength.                         */
  USB_DESC_BYTE(USB_DESCRIPTOR_STRING), /* bDescriptorType.                 */
  u"ChibiOS/RT Virtual COM Port"
};


The only possible problem I see is portability. This worked for what I'm using, which is GCC (CodeSourcery 4.5.2), but I have no idea if that works on other compilers.

Besides, instead of using 56 and 56/2, we could also use a more straightforward number and let the compiler do the math, such as 27+1 and (27+1)*2
User avatar
Giovanni
Site Admin
Posts: 14891
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: The USB topic

Post by Giovanni »

I think it is a C++11 extension, probably GCC supports it as a custom extension to the C language. It is OK to use in applications but I can't use it in the standard demo.

Giovanni
Post Reply