cancel
Showing results for 
Search instead for 
Did you mean: 

Discovery USB OUT Report example

nihaoraja
Associate II
Posted on October 29, 2013 at 15:56

Hello everybody,

I'm looking for a working example using OUT Endpoint on STM32F4 Discovery board.

I have no success with it. I modified Demo sample for an OUT Endpoint and Custom usage, and try to send one byte report (2 bytes with ID) to the board from a PC client. Something definitely arrives at the board. The debugger shows the OUT FIFO buffer content changing. The FIFO data however is strange and inconsistent. When sending the same Report repeatedly, the FIFO shows always different values and never the one I actually send. Endpoint interrupt (OTG_FS_GINTMSK.OEPINT) never happens.

Thank you for any advice.
5 REPLIES 5
nihaoraja
Associate II
Posted on January 12, 2014 at 20:25

The reason for the bug was incorrect configuration used for the OUT transfer. The function 'DCD_EP_PrepareRx' has to be used to setup OTG_FS_DOEPTSIZ.XFRSIZ. After setting XFRSIZ to 64 my code started working i.e. 'XFRC interrupt' was generated OK.

nihaoraja
Associate II
Posted on March 30, 2014 at 00:00

There seems to be another problem here - with STM USB OTG library.

I see the problem in both ''STM32_USB-Host-Device_Lib_V2.1.0'' and ''STM32F4-Discovery_FW_V1.1.0''.

Concern #1 - ''usb_core.c:USB_OTG_ReadPacket'' function.

=======================================

void *USB_OTG_ReadPacket(USB_OTG_CORE_HANDLE *pdev, uint8_t *dest,  uint16_t len)

{

  uint32_t i=0;

  uint32_t count32b = (len + 3) / 4;

 

  __IO uint32_t *fifo = pdev->regs.DFIFO[0];

 

  for ( i = 0; i < count32b; i++, dest += 4 )

  {

    *(__packed uint32_t *)dest = USB_OTG_READ_REG32(fifo);

  }

  return ((void *)dest);

}

================================================

This function copies data from FIFO into EP buffer (*dest). The data is read correctly but returns the pointer to EP buffer offset by ''4*count32b'' i.e. in my case the packet length is 64 bytes and ''dest'' becomes ''dest+64'' when function returns. Here is the debugger output to clear the point:

Expected output (the correct one):

(gdb) p/x *dest@64

$5 = {0x2, 0x11, 0x0 <repeats 62 times>}  // 0x2 is report ID and 0x11 is the data

The actual result:

(gdb) p/x *(dest)@64

$5 = {0x22, 0xbf, 0x1, 0x20, 0x10, 0xbf, 0x1, 0x20, 0x18, 0xbf, 0x1, 0x20, 0xb0, 0x1, 0x0, 0x20, 0x0, 0x0, 0x1, 0x0, 0xb0, 0x1, 0x0, 0x20, 0x18, 0x0, 0x8,

  0xc0, 0x20, 0x5, 0x0, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x50, 0xbf, 0x1, 0x0, 0xb0, 0x1, 0x0, 0x20, 0x50, 0xbf, 0x1, 0x20, 0x40, 0xbf,

  0x40, 0x0, 0xc8, 0xbe, 0x1, 0x20, 0xb0, 0x1, 0x0, 0x20}

i.e. is a random data from location *(dest+64) and looks like a bug to me.

The correct function would be like:

====================================================

void *USB_OTG_ReadPacket(USB_OTG_CORE_HANDLE *pdev, uint8_t *dest, uint16_t len)

{

  uint32_t i=0;

  uint32_t count32b = (len + 3) / 4;

 

  uint8_t *tmp = dest; // Bug fix. Otherwise wrong pointer is returned, offset from original by 4*count32b

  __IO uint32_t *fifo = pdev->regs.DFIFO[0];

 

  for ( i = 0; i < count32b; i++, tmp += 4 )

  //for ( i = 0; i < count32b; i++, dest += 4 ) // to fix 'bug'

  {

    *(__packed uint32_t *)tmp = USB_OTG_READ_REG32(fifo);

//    *(__packed uint32_t *)dest = USB_OTG_READ_REG32(fifo); // the fix

  }

  return ((void *)dest);

}

===================================================

Now the original pointer ''dest'' returned unchanged i.e. points to the EP buffer start.

Concern #2 - function ''usb_dcd_int.c:DCD_HandleRxStatusQueueLevel_ISR''

========================================================

...

  case STS_DATA_UPDT:

    if (status.b.bcnt)

    {

      USB_OTG_ReadPacket(pdev,ep->xfer_buff, status.b.bcnt);

      ep->xfer_buff += status.b.bcnt; // this line adds an offset to the original EP buf pointer

      ep->xfer_count += status.b.bcnt;

    }

    break;

...

===================================================

I don't understand the meaning of the offset added to the EP buffer pointer.

The 2 above functions offset the original EP buffer pointer twice by total amount of 128 bytes (in my case). When eventually (on OUT transfer complete) I access the EP buffer as follows:

=====================================================

static uint8_t  USBD_HID_DataOut (void  *pdev, uint8_t epnum)

{

...

  buf_ptr = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_buff;

  USBD_USR_DataOut(buf_ptr, HID_OUT_PACKET);

...

}

================================================

my ''buf_ptr'' points 128 bytes past the correct location i.e. in order to read the OUT packet I have to reference ''buf_ptr-128''.

And here is the debugger output to support this:

=============================================

(gdb) p/x *buf_ptr@64

$22 = {0x22, 0xbf, 0x1, 0x20, 0x10, 0xbf, 0x1, 0x20, 0x18, 0xbf, 0x1, 0x20, 0xb0, 0x1, 0x0, 0x20, 0x0, 0x0, 0x1, 0x0, 0xb0, 0x1, 0x0, 0x20, 0x18, 0x0, 0x8,

  0xc0, 0x20, 0x5, 0x0, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x50, 0xbf, 0x1, 0x1, 0xb0, 0x1, 0x0, 0x20, 0x8, 0xbf, 0x1, 0x20, 0x40, 0x3,

  0x40, 0x0, 0x48, 0xbf, 0x1, 0x20, 0x25, 0xc9, 0x0, 0x8} /// gibberish

(gdb) p/x *(buf_ptr-128)@64

$23 = {0x2, 0x11, 0x0 <repeats 62 times>} /// the correct data

=============================================

This seems wrong to me. A programmer is expected to know to do the offset to get to the correct data.

Do I miss something here?

Posted on March 30, 2014 at 03:12

Can you debug this is a way that doesn't dead stop it in a command line debugger? The multiples of 64 bytes in a FIFO is suggestive that the host is sending data. Do you have a USB analyzer? Does that indicate transfers?

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
nihaoraja
Associate II
Posted on March 30, 2014 at 14:47

As described in my previous mails, I'm testing my application by sending 1 packet of 64 bytes from PC to the device (Discovery) in OUT transfer. USB analyzer shows that transaction IS OK and packet is ACKed (no problem on this part). 64 byte packet actually has only 2 bytes set (report ID and a data byte - number 17 i.e. 0x2, 0x11), the rest are zeros (that's the way Windows does it). I tested the transfer both with and without debugger with the same result: transfer is OK, something apparently transmitted, but the data at final destination (user handler 'USBD_USR_DataOut') is corrupt. I tried breakpoints in different parts of the code, and I'm pretty sure the process is clean i.e. the debugger doesn't cause faults.

The point of my message is ''the transfer is OK'', but the offset added to the 'dest' buffer by the library functions causes wrong results, unless the programmer compensates for that offset when reading the buffer. My application works <fine> if I read 'dest-128' instead of just 'dest'.

nihaoraja
Associate II
Posted on March 30, 2014 at 17:26

Actually after more debugging the only 'dark spot' remaining is the offset added by 'DCD_HandleRxStatusQueueLevel_ISR:ep->xfer_buff += status.b.bcnt;'.

'USB_OTG_ReadPacket' seems to be OK after all. Even though not clear why. Offset is still there, but it 'evaporates' after function returns.

In the end I only need to compensate for 64 byte offset (not 128) as follows:

static uint8_t  USBD_HID_DataOut (void  *pdev, uint8_t epnum)

{

...

  buf_ptr = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_buff - ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_len;

...

}

Here is the debug session output with inline comments:

=========================================================

Breakpoint 2, DCD_HandleRxStatusQueueLevel_ISR (pdev=0x200001b0)

    at C:/a02_projects/STM32F4-Discovery_FW_V1.1.0/Libraries/STM32_USB_OTG_Driver/src/usb_dcd_int.c:607

...

...

(gdb) n

623           USB_OTG_ReadPacket(pdev,ep->xfer_buff, status.b.bcnt);

(gdb) s

USB_OTG_ReadPacket (pdev=0x200001b0, dest=0x2001bec8 ''\001'', len=64)

    at C:/a02_projects/STM32F4-Discovery_FW_V1.1.0/Libraries/STM32_USB_OTG_Driver/src/usb_core.c:195

...

...

(gdb) n

208       return ((void *)dest);

(gdb) p/x *dest@64                        // while inside 'USB_OTG_ReadPacket' the buffer seems screwed

$3 = {0x22, 0xbf, 0x1, 0x20, 0x10, 0xbf, 0x1, 0x20, 0x18, 0xbf, 0x1, 0x20, 0xb0, 0x1, 0x0, 0x20, 0x0, 0x0, 0x1, 0x0, 0xb0, 0x1, 0x0, 0x20, 0x18, 0x0, 0x8,

  0xc0, 0x20, 0x5, 0x0, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x50, 0xbf, 0x1, 0x0, 0xb0, 0x1, 0x0, 0x20, 0x50, 0xbf, 0x1, 0x20, 0x40, 0xbf,

  0x40, 0x0, 0x8, 0xbf, 0x1, 0x20, 0xb0, 0x1, 0x0, 0x20}

(gdb) p/x *(dest-64)@64                   // correct if offset is annulled

$4 = {0x2, 0x11, 0x0 <repeats 62 times>}

...

...

(gdb) n

DCD_HandleRxStatusQueueLevel_ISR (pdev=0x200001b0) at C:/a02_projects/STM32F4-Discovery_FW_V1.1.0/Libraries/STM32_USB_OTG_Driver/src/usb_dcd_int.c:624

624           ep->xfer_buff += status.b.bcnt;

(gdb) p/x *(ep->xfer_buff)@64

$7 = {0x2, 0x11, 0x0 <repeats 62 times>}        // however(!) buffer is OK after returning from 'USB_OTG_ReadPacket' (how come?)

(gdb) n

625           ep->xfer_count += status.b.bcnt;  // now an offset is applied again inside 'DCD_HandleRxStatusQueueLevel_ISR'

(gdb) p/x *(ep->xfer_buff)@64                   // and the buffer is screwed for good

$8 = {0x22, 0xbf, 0x1, 0x20, 0x10, 0xbf, 0x1, 0x20, 0x18, 0xbf, 0x1, 0x20, 0xb0, 0x1, 0x0, 0x20, 0x0, 0x0, 0x1, 0x0, 0xb0, 0x1, 0x0, 0x20, 0x18, 0x0, 0x8,

  0xc0, 0x20, 0x5, 0x0, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x50, 0xbf, 0x1, 0x0, 0xb0, 0x1, 0x0, 0x20, 0x50, 0xbf, 0x1, 0x20, 0x40, 0xbf,

  0x40, 0x0, 0x8, 0xbf, 0x1, 0x20, 0xb0, 0x1, 0x0, 0x20}

...

...

Breakpoint 1, USBD_HID_DataOut (pdev=0x200001b0, epnum=1 '\001') at usbd_desc.c:619

619                     buf_ptr = ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_buff - ((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_len;

(gdb) p/x *(((USB_OTG_CORE_HANDLE*)pdev)->dev.out_ep[epnum].xfer_buff)@64       // without (-64) looking into mess

$9 = {0x22, 0xbf, 0x1, 0x20, 0x10, 0xbf, 0x1, 0x20, 0x18, 0xbf, 0x1, 0x20, 0xb0, 0x1, 0x0, 0x20, 0x0, 0x0, 0x1, 0x0, 0xb0, 0x1, 0x0, 0x20, 0x18, 0x0, 0x8,

  0xc0, 0x20, 0x5, 0x0, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x30, 0xbf, 0x1, 0x20, 0x50, 0xbf, 0x1, 0x1, 0xb0, 0x1, 0x0, 0x20, 0x50, 0xbf, 0x1, 0x20, 0x40, 0x3,

  0x40, 0x0, 0x48, 0xbf, 0x1, 0x20, 0x41, 0xc9, 0x0, 0x8}

(gdb) n

620                     USBD_USR_DataOut(buf_ptr, HID_OUT_PACKET);

(gdb) p/x *(buf_ptr)@64                       // after offset is annulled looking into right location

$10 = {0x2, 0x11, 0x0 <repeats 62 times>}     // Good! So, only 'DCD_HandleRxStatusQueueLevel_ISR:ep->xfer_buff += status.b.bcnt;' remains a dark spot

=========================================================