cancel
Showing results for 
Search instead for 
Did you mean: 

NUCLEO-U5A5ZJ-Q USB CDC ACM issue with ux_device_class_cdc_acm_write() function

Kannan1
Associate III

Hi,

I have been working on NUCLEO-U5A5ZJ-Q EVK to setup as a USB VCP device with the support of STM32CubeIDE. I got an example from the ST repository. Its using the Azure RTOS USBX stack instead of STM32 USB Device stack. I am not very much familiar with this RTOS framework.

System details:

NUCLEO-U5A5ZJ-Q

Example: Ux_Device_CDC_ACM

I am trying to have a throughput test from data sending from device to Host PC via VCP. So I have edited the thread function usbx_cdc_acm_write_thread_entry() function to remove the UART-USB bridge setup of the example project and just send a bulk data to the HOST. Here is the code, 

 

 

#define MAX_PKT_SIZE  128 /* 200 */ /* 512 */ /* 1024 */

VOID usbx_cdc_acm_write_thread_entry(ULONG thread_input)
{
	ULONG actual_length;
	uint32_t i = 0;
	uint32_t total_bytes_to_send = APP_TX_DATA_SIZE*100;
	uint32_t bytes_to_send = 0;
	uint32_t buf_indx = 0;

	UX_PARAMETER_NOT_USED(thread_input);

	for (i = 0; i < APP_TX_DATA_SIZE; i++)
	{
		UserTxBufferFS[i] = i;
	}

	tx_thread_sleep(MS_TO_TICK(10000));

	while (1)
	{
		while(total_bytes_to_send)
		{
			if (total_bytes_to_send > MAX_PKT_SIZE)
			{
				bytes_to_send = MAX_PKT_SIZE;
			}
			else
			{
				bytes_to_send = total_bytes_to_send;
			}

			/* Send data over the class cdc_acm_write */
			if (ux_device_class_cdc_acm_write(cdc_acm, (UCHAR *)(&UserTxBufferFS[buf_indx]),
					bytes_to_send, &actual_length) == UX_SUCCESS)
			{
				total_bytes_to_send -= actual_length;
				buf_indx += actual_length;
				if (buf_indx >= APP_TX_DATA_SIZE)
				{
					buf_indx = 0;
				}
			}
		}

	    /* Sleep thread for 10ms */
	    tx_thread_sleep(MS_TO_TICK(10));
	}
}

 

 

 Total of 204800 bytes is ready for transmit. MAX_PKT_SIZE is the packet size which I have been used to send in each loop. When I have configured it as just below or equal to 128 bytes, the transactions was successful. But above that the API waits for some interrupts internally for infinite time and it just hangs there, even though this API fragments the data buffer with respect to the UX_SLAVE_REQUEST_DATA_MAX_LENGTH configured as 512 bytes internally. Other configurations of this example is not touched. Do anybody has a hint to look somewhere.

When I pause the execution in CubeIDE its usually in USB_ReadInterrupts() or HAL_PCD_IRQHandler().

Also tried with enabling the UX_DEVICE_CLASS_CDC_ACM_WRITE_AUTO_ZLP, but same effect.

My ultimate aim is to test the speed of sending data from device to PC via USB CDC VCP. 

Thanks

1 ACCEPTED SOLUTION

Accepted Solutions
Imen.D
ST Employee

Hello @Kannan1,

Thank you for having reported this.

Our team is very aware of this issue and an Internal ticket number 171673 is submitted to fix the max packet size:

 

HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_HS, 0x200);
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 0, USBD_MAX_EP0_SIZE/4); 
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 1, USBD_CDCACM_EPIN_HS_MPS/4);
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 2, USBD_CDCACM_EPINCMD_HS_MPS/4);

 

ImenD_0-1706175318177.png

(PS: Internal ticket number: 171673 in only for reference, not available outside of ST)

Thank you for your understanding while we work on this.

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen

View solution in original post

6 REPLIES 6
Imen.D
ST Employee

Hello @Kannan1,

Thank you for having reported this.

Our team is very aware of this issue and an Internal ticket number 171673 is submitted to fix the max packet size:

 

HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_HS, 0x200);
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 0, USBD_MAX_EP0_SIZE/4); 
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 1, USBD_CDCACM_EPIN_HS_MPS/4);
HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 2, USBD_CDCACM_EPINCMD_HS_MPS/4);

 

ImenD_0-1706175318177.png

(PS: Internal ticket number: 171673 in only for reference, not available outside of ST)

Thank you for your understanding while we work on this.

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
Kannan1
Associate III

@Imen.D Thank you very much for the quick reply. Everything works fine by increasing the size of tx fifo 1, which is the BULK Endpoint IN for CDC-ACM. Now I can work with a larger Pkt size of 2048 in my code.

#define MAX_PKT_SIZE  2048

Between, Why you have divided the max pkt size of EPIN_HS (which is 512 bytes maximum for HS) by 4 

HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 1, USBD_CDCACM_EPIN_HS_MPS/4);

Could you explain it please? Also what should be the optimum size of this FIFO for maximum throughput? 

Thank You

Hi @Kannan1 ,

The whole size is 4096 bytes, divide it by 2. The half is for the Rx FIFO and the other half for all Tx FIFO .

The size set for the FIFO is the size of the EP divided by 4 when working on single buffering.

Also, you have to check that all the sizes of Tx FIFO added together should not exceed 2048, because from the beginning we only made 2048 bytes available for all the Tx FIFO.

When your question is answered, please close this topic by clicking "Accept as Solution".
Thanks
Imen
tjaekel
Lead

I have my STM32U5A5 working on NUCLEO board as well as my own one:

GitHub - tjaekel/STM32U5A5-VCP_UART: VCP UART on U5A5 NUCLEO and my board

What to bear in mind - maybe:
VCP UART sends in packets, usually a max. packet size as 64 bytes. If you now send "too fast" (or too much) - it can result in lost packets (or confusing the USB stack).

Try to send with max., 64bytes per VCP transfer packet. And see if you have an option for a flow control.

It depends also, I think, if VCP UART is running as USB FS or USB HS (different packet sizes). But there is for sure a limitation for both modes how large a packet can be.

It looks to me that you hit the issue that a VCP UART packet is max. 64 bytes (therefore 128 goes still through: one in progression, a new one still accepted).

It looks to me to verify, if VCP UART runs really as HS or just FS. Even USB on MCU might look as enabled as HS - not sure if the host (PC side) will establish as HS link (or VCP UART is always just FS, with the 64byte limitation).

Thanks.

As @Imen.D  suggested, I have kept the total Tx fifo size to 2048 bytes. 

  HAL_PCDEx_SetRxFiFo(&hpcd_USB_OTG_HS, 0x200);
  HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 0, USBD_MAX_EP0_SIZE/4);
  HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 1, /*USBD_CDCACM_EPIN_HS_MPS/4*/2030);
  HAL_PCDEx_SetTxFiFo(&hpcd_USB_OTG_HS, 2, USBD_CDCACM_EPINCMD_HS_MPS/4);

 I think the maximum packet size sending for FS configuration is the 64 bytes and for HS is 512 bytes. I was able to execute the function ux_device_class_cdc_acm_write with max size of 2048 bytes as requested_length. So internally this API will fragment the 2048 bytes to 4*512 bytes and send it.

I was able to get a maximum throughput of ~3.8 to 4 MBPS. But I need at least 5MBPS for my application. Is there any other configurations which I can tweak and check. The code is here,

while(total_bytes_to_send)
{
	if (total_bytes_to_send > 2048)
	{
		bytes_to_send = 2048;
	}
	else
	{
		bytes_to_send = total_bytes_to_send;
	}

	/* Send data over the class cdc_acm_write */
	if (ux_device_class_cdc_acm_write(cdc_acm, (UCHAR *)(&UserTxBufferFS[buf_indx]),
			bytes_to_send, &actual_length) == UX_SUCCESS)
	{
		total_bytes_to_send -= actual_length;
		buf_indx += actual_length;
		if (buf_indx >= APP_TX_DATA_SIZE)
		{
			buf_indx = 0;
		}
	}
}

I think there is nothing much to optimize here for increasing speed. Can you suggest any methods/configurations to achieve 5 MBPS. I think for HS, I should get at least 15 MBPS (1/4 of theoretical speed of HS, which is 480mbps).

Kannan1
Associate III

@Imen.D Hi, Do I get better throughput with ux_device_class_cdc_acm_write_with_callback. Is there any example project available?