cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_PCDEx_SetTxFiFo and fifo number/order

Jerome Godbout
Associate II

Hi, I'm having a hard time understanding the HAL_PCDEx_SetTxFiFo() function that I should call inside the USBD_LL_Init() function for my Stm32L476. I have attach my descriptor results from USBTreeView. But here the highlight:

My composite device have multiple interface:

  • 1 HID interface
    • 1 interrupt IN EP 0x83
  • 1 interface for application
    • 1 Bulk IN EP 0x84
    • 1 Bulk OUT EP 0x04
    • 1 interrupt IN EP 0x85
    • 1 ISO IN EP 0x86
  • IAD Link both CDC interfaces
    • 1 CDC Control interface
      • 1 Interrupt IN EP 0x82
    • 1 CDC Data interface
      • 1 Bulk IN EP 0x81
      • 1 Bulk OUT EP 0x01

I did keep the IAD and CDC as the last into the descriptor since it seem to confuse some COM driver. But I still have a hard time with my endpoints and the call to init the TX buffer, I'm not sure I do the right thing.

Does HAL_PCDEx_SetTxFiFo() use for the fifo 2nd argument :

  1. the endpoint id without the direction (& ~0x80)?
  2. the order they appear into descriptor and interface number?

What is it represent exactly? Can I skip some? How much can be used, is 6 too much?

It seem like if I remove my application endpoints my CDC work normally and when I add them my write cannot be perform since the

CDC_Transmit_FS()

if (hcdc->TxState != 0){

  return USBD_BUSY;

 }

The TXState is always busy. This even if no driver and I do nothing with the other endpoints, the CDC stop working. I suspeect I don't do the rith thing with my tx buffer init with HAL_PCDEx_SetTxFiFo 

HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40); /* Default control EP */

   HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x40); /* CDC bulk EP */

   HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 2, 0x10); /* CDC interrupt EP */

   HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 3, 0x10); /* HID interrupt EP */

   HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 4, 0x40); /* App bulk EP */

   HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 5, 0x40); /* App interrupt EP */

   HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 6, 0x40); /* App isochronous EP */

Maybe I got this wrong, I'm just not sure how this get link to the proper endpoint or if I overflow the RX space (I have read the F4 only support 0..5, not sure if this is true for the L4?).

Does the descriptor order and interface order and endpoint numbering have any requirements? like does the lowest interfaces should have the lowest endpoints numbers?

1 ACCEPTED SOLUTION

Accepted Solutions

> yes we are using Stm32L476 as stated in the first message.

Sorry, I overlooked that information.

> since we are using small packet for 2 interrupts (0x10 for 16 multiples each) we could still have some RAM availables for a few endpoints with each (0x40).

Yes, but bear in mind that the sum of Rx FIFO and all Tx FIFOs is max. 1.25kB, i.e. max. 0x140 words).

> Where is this limitation [max. number of endpoints] documetend?

0690X000006DtbCQAS.png

and also at several places in the OTG_FS chapter in RM.

> We though based on this presentation from ST that we were having 8 bi-directional endpoints (16 totals)

That presentation talks about the lower-end 'L4 range, see page 2. They contain an entirely different device-only USB module.

JW

View solution in original post

12 REPLIES 12
Ben K
Senior III

I would rather recommend skipping these HAL calls, and configure the registers directly according to the reference manual. It will save you some time.

The HAL_PCDEx_SetTxFiFo() calls (and the Rx as well) are used in the examples as if they were allocating byte size in the FIFOs. Inside however they take the input as is, and write to the registers which are supposed to hold 32 bit word sizes. The reference manuals also contradict each other between devices with the same OTG IP: https://github.com/IntergatedCircuits/USBDevice4Cube/issues/1#issuecomment-439653127

Jerome Godbout
Associate II

humm, k, any offical documentation about those registers?

and why does the HAL_PCDEx_SetTxFiFo() have any issues or is buggy? I would rather not have to rewrite the whole HAL setup here if possible. I'm just trying to understand that function and known if I do the right thing. So I should use these formula how exactly?

L4:

(5 * number of control endpoints + 😎 + ((largest USB packet used / 4) + 1 for status information) + (2 * number of OUT endpoints) + 1 for Global NAK

This is my stm32l4xx_hal_pcd_ex.c file for this functions. Not sure the equation match anything near that methode behavior.

HAL_StatusTypeDef HAL_PCDEx_SetTxFiFo(PCD_HandleTypeDef *hpcd, uint8_t fifo, uint16_t size)
{
  uint8_t index = 0;
  uint32_t Tx_Offset = 0;
 
  /*  TXn min size = 16 words. (n  : Transmit FIFO index)
      When a TxFIFO is not used, the Configuration should be as follows: 
          case 1 :  n > m    and Txn is not used    (n,m  : Transmit FIFO indexes)
         --> Txm can use the space allocated for Txn.
         case2  :  n < m    and Txn is not used    (n,m  : Transmit FIFO indexes)
         --> Txn should be configured with the minimum space of 16 words
     The FIFO is used optimally when used TxFIFOs are allocated in the top 
         of the FIFO.Ex: use EP1 and EP2 as IN instead of EP1 and EP3 as IN ones.
     When DMA is used 3n * FIFO locations should be reserved for internal DMA registers */
  
  Tx_Offset = hpcd->Instance->GRXFSIZ;
  
  if(fifo == 0)
  {
    hpcd->Instance->DIEPTXF0_HNPTXFSIZ = (size << 16) | Tx_Offset;
  }
  else
  {
    Tx_Offset += (hpcd->Instance->DIEPTXF0_HNPTXFSIZ) >> 16;
    for (index = 0; index < (fifo - 1); index++)
    {
      Tx_Offset += (hpcd->Instance->DIEPTXF[index] >> 16);
    }
    
    /* Multiply Tx_Size by 2 to get higher performance */
    hpcd->Instance->DIEPTXF[fifo - 1] = (size << 16) | Tx_Offset;
  }
  
  return HAL_OK;
}

I don't use Cube so won't comment on usage of given function; you can look it up yourself, it's open source.

You didn't tell us which 'L4 are you talking about, so I assume it's 'L476 with respective RM0351; if it's not, look the respective details up in the RM for your particular model.

Also, the code snippet you gave us does not match the descriptor you attached, but that's not that important for the key points.

First of all, the 'L476 contains besides endpoints for EP0 only 5 IN and 5 Out endpoints, so that's probably your primary problem.

(Just a sidenote, in the mainstream 'F4xx there are two OTG modules and the OTG_HS has more endpoints).

The OTG module contains a certain amount of FIFO RAM (1.25kB for the 'L476), and you ought to tell the module how do you want to partition it, between one common Rx FIFO (common for all IN endpoints), and one FIFO for each Tx (OUT) endpoint. This is done by setting OTG_GRXFSIZ, OTG_DIEPTXF0 and OTG_DIEPTXFx registers, see description of these registers in OTG_FS registers subchapter of the OTG_FS chapter in RM. Note, all FIFO-related values are in words (how does this translate to the requirements of Cube/HAL functions, is up to you to find out). The Tx-FIFO registers generally contain not only the size of FIFO, but also its beginning, so the user can partition the FIFO in non-continuous chunks (even if this does not make much sense).

JW

> (5 * number of control endpoints + 😎 + ((largest USB packet used / 4) + 1 for status information) + (2 * number of OUT endpoints) + 1 for Global NAK

That's the recommendation for the Rx FIFO, i.e. the value to go to OTG_GRXFSIZ . See FIFO RAM allocation subchapter of the OTG_FS chapter in RM. I'm not going to comment on this formula nor the overall quality of documentation here.

JW

Jerome Godbout
Associate II

@Community member​ 

yes we are using Stm32L476 as stated in the first message.

Thanks for the information. If the number of endpoints is limited to 5 IN and 5 OUT + the Control IN/OUT EP 0 if I understand well, that could explain the problems I see. I was not there when they did choose the hardware and I trying to add features into existing code.

I might need to revise my whole design. But I did not knew this limitation I knew it was 1.25 Kb RAM buffer was available, since we are using small packet for 2 interrupts (0x10 for 16 multiples each) we could still have some RAM availables for a few endpoints with each (0x40).

I did check that document:

https://www.st.com/content/ccc/resource/technical/document/application_note/group0/0b/10/63/76/87/7a/47/4b/DM00296349/files/DM00296349.pdf/jcr:content/translations/en.DM00296349.pdf

Where is this limitation documetend? is it HAL limitation or the chip itself? I will add an assert so anybody who will try to do this on the chips will not compile anymore. We though based on this presentation from ST that we were having 8 bi-directional endpoints (16 totals) on page 3:

https://www.st.com/content/ccc/resource/training/technical/product_training/98/89/c8/6c/3e/e9/49/79/STM32L4_Peripheral_USB.pdf/files/STM32L4_Peripheral_USB.pdf/jcr:content/translations/en.STM32L4_Peripheral_USB.pdf

This is a bummer, since the CDC use 2 of them already, 1 for HID, that leave me with only 2 on the application control. I will go 1 bulk and 1 interrupt and remove the isochronous one. This is a rather complicated device that is used by 3 different drivers (1x HID driver, 1x VCOM for debug and production and 1x custom driver to control and operate the device).

Anyway thanks for the information, I will trim the design and see what I can do.

reagrds,

> yes we are using Stm32L476 as stated in the first message.

Sorry, I overlooked that information.

> since we are using small packet for 2 interrupts (0x10 for 16 multiples each) we could still have some RAM availables for a few endpoints with each (0x40).

Yes, but bear in mind that the sum of Rx FIFO and all Tx FIFOs is max. 1.25kB, i.e. max. 0x140 words).

> Where is this limitation [max. number of endpoints] documetend?

0690X000006DtbCQAS.png

and also at several places in the OTG_FS chapter in RM.

> We though based on this presentation from ST that we were having 8 bi-directional endpoints (16 totals)

That presentation talks about the lower-end 'L4 range, see page 2. They contain an entirely different device-only USB module.

JW

Jerome Godbout
Associate II

Thanks for the information, I did remove the isochronous endpoint to reduce to 5 endpoints IN. Now I have the following descriptor. I have goes through the usbcdc110.pdf and reorder the interfaces and endpoints to be into an easier way to follow and make sure the descriptor is in order. Now I have

  • 5 IN + 0 Control IN
  • 2 OUT + 0 Control OUT
  • The interfaces are declared into order and endpoint number increase as they are declared.

I still have issues with my COM port for some reason, I cannot write the bus is stick to busy, maybe something I do is totally wrong or my handling is wrong, but I have a hard time understanding why the VCOM is not working anymore (I have a setup where I only have the HID and VCOM and it work, if I add the app control interfaces with his 3 endpoints it stop working). So I guess I have declare something either impossible or badly that make the VCOM stop working. Any requirements in the interfaces orders and numbering?

Now my usbd_conf.c have the following lines:

/* RX buffer is a big as the biggest one */
 HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 0x80);
      
/* Lower level can only support from 0 to 5 maximum for L4 series for IN endpoints */
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40); /* Default control EP */
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x10); /* HID interrupt EP */
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 2, 0x40); /* App bulk EP */
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 3, 0x10); /* App interrupt EP */
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 4, 0x40); /* CDC bulk EP */
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 5, 0x10); /* CDC interrupt EP */

I can read the VCOM data, the RX is working, but when I try to send the data through the USBWrite() from usbd_cdc_if.c, but the transfer doesn't succeed since the TxState is not IDLE (== 0) but busy but it never goes back to idle. I'm wondering why. I guess the CDC Communication interrupt is no more working properly, but I don't know why.

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)
{
  uint8_t result = USBD_OK;
  /* USER CODE BEGIN 7 */
  USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*)hUsbDeviceFS.pClassData;
  if (hcdc->TxState != 0){
    return USBD_BUSY;  // I end up here with the new config
...
}

The TxState is set to BUSY (1) during USBD_CDC_TransmitPacket() fonction only. And if should be clear with USBD_CDC_DataIn() set back to 0, but I don't get this call anymore.

I'm not sure why I don't get those IN communication anymore, I also have IN issue with the Application Control endpoints. I don't get what is going on. Any tips or info on how to debug this properly, would be welcome.

Jerome Godbout
Associate II

Here is my wireshark capture when I do th enumeration. There some broken pipe error and other problems, but I really don't known why!?! Any tips on how to do this or debug this.

  1. /* RX buffer is a big as the biggest one */
  2. HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_FS, 0x80);
  3. /* Lower level can only support from 0 to 5 maximum for L4 series for IN endpoints */
  4. HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 0, 0x40); /* Default control EP */
  5. HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 1, 0x10); /* HID interrupt EP */
  6. HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 2, 0x40); /* App bulk EP */
  7. HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 3, 0x10); /* App interrupt EP */
  8. HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 4, 0x40); /* CDC bulk EP */
  9. HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_FS, 5, 0x10); /* CDC interrupt EP */

0x80 + 0x40 + 0x10 + 0x40 + 0x10 + 0x40 + 0x10 = 0x170 > 0x140

I don't say this is the only problem in your code.

I might've mentioned that I don't use Cube.

JW