cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 Cube USB VCP

alexpabouct9
Associate II
Posted on August 18, 2014 at 14:31

Hello,

I'm trying to get a virtual com port working on the stm32f4 discovery board. This is something that I've managed to do in the past using the old USB libraries and std peripheral libraries. However, since st is pushing its users to use the STM32Cube i'm trying to setup my new project with it instead.

Unfortunately i'm having a fair amount of issues in getting it to work properly. Furthermore, the generate code is so different than what i'm used to seeing, i'm not sure how to modify in order to work as required; with a simple Tx and Rx circular buffer.

At the moment my code compiles without issues and I have a loop which calls the following code every ~1s :

  char string[12] = ''Flyability\r\n'';

  CDC_Transmit_FS(string,12);

I modified the CDC_Transmit_FS to copy the function input string into the UserTxBuffer (But doesn't append the data, which is what a proper Tx circular buffer requires):

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)

{

  uint8_t result = USBD_OK;

  /* USER CODE BEGIN 8 */ 

  uint16_t i;

  for(i=0;i<Len;i++)

  {

      UserTxBufferFS[i]=Buf[i];

  }

  USBD_CDC_SetTxBuffer(hUsbDevice_0, UserTxBufferFS, Len);   

  result = USBD_CDC_TransmitPacket(hUsbDevice_0);

  /* USER CODE END 8 */ 

  return result;

}

If i run the application, the code works and i receive the test strings in my console, but only for a couple seconds, after which no more data is received on the com port. At this point the returned result value is equal to 1 (USB BUSY).

Any help with these 2 issues (where to modify the code to implement a proper Tx/Rx circular buffer, and why it only works for the first couple seconds) would be greatly appreciated.

Regards.

Alex

#stm32-usb-fs-cdc-vcp #stm32cube #usb-vcp
4 REPLIES 4
klaus
Associate II
Posted on August 19, 2014 at 08:57

Hi Alex,

this is working for me:

uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)

{

  uint8_t result = USBD_OK;

  /* USER CODE BEGIN 8 */

  USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, Len);

  result = USBD_CDC_TransmitPacket(hUsbDevice_0);

  if ((Len%64==0) && (result==USBD_OK))

  {

    USBD_CDC_SetTxBuffer(hUsbDevice_0, Buf, 0);

    result = USBD_CDC_TransmitPacket(hUsbDevice_0);

  }

  /* USER CODE END 8 */

  return result;

}

best regards, Klaus

Clonimus74
Senior II
Posted on February 18, 2016 at 10:28

Just for future readers who find this post useful, I found there's a need to modify the CDC_Transmit_FS for it to work properly as such (I use STM32L4 but it should be identical):


uint8_t CDC_Transmit_FS(uint8_t* Buf, uint16_t Len)

{

USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) usb_vcp_handle.pClassData;

uint8_t result = USBD_OK;


/* USER CODE BEGIN 7 */

USBD_CDC_SetTxBuffer(&usb_vcp_handle, Buf, Len);


do

{

result |= USBD_CDC_TransmitPacket(&usb_vcp_handle);

}

while((result != USBD_OK) && (result != USBD_FAIL));


if ((Len%64==0) && (result==USBD_OK))

{

while(hcdc->TxState);

USBD_CDC_SetTxBuffer(&usb_vcp_handle, Buf, 0);

result |= USBD_CDC_TransmitPacket(&usb_vcp_handle);

}

Without line #17 the code following this line will execute too early and will have no effect. Also before calling CDC_Transmit_FS one should check the device is enumerated and ready:

1.
if (usb_vcp_handle.dev_state == USBD_STATE_CONFIGURED)
2.
CDC_Transmit_FS(&tx_buffer1.byte_data[0], tx_length);

StefanoBettega1
Associate II
Posted on July 11, 2016 at 15:43

As reported in

https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Java/Flat.aspx?RootFolder=https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Java/STM32Cube%20USB%20CDC%20%28possible%29%20Bug%20Found%20-%20Rx%20Tx%20Race%20condition&FolderCTID=0x01200200770978C69A1141439FE559EB459D758000F9A0E3A95BA691...

, it seems that there is a possible race condition in Tx and Rx interrupts. Is there any solution for this at this moment?

We are experiencing such a problem in our application, so that we digged out all of the tasks and interrupts, leaving only a main loop without OS, and only USBD and Systick (for HAL timing) as interrupt sources.

USB VCP behave like an old serial port on top of which we run a ''consolidated'' Q&A protocol: PC acts as master, querying device, and device answers to requets as slave. Eventually PC sends retries if a packet is lost or corrupted (we have a framing and checksum control in protocol).

Things normally works with small data, but as we try to transfer big data buffer (i.e. packets of 1010 bytes, that are 1000 bytes payload and 10 bytes of framing), data exchange stops. PC queries device, device prepares the transmission buffer and starts to send it out, but PC doesn't receive them. Probably data transfer is partially started, because if we dig into USB registers we see that count of transferred data is 640 (10 packets of 64 bytes), and peripheral seems to be stuck with TxState = 1.

Any suggestion on how to overcome this problem?

Thanks,

Stefano

stm322399
Senior
Posted on July 11, 2016 at 18:24

Stefano,

there is definitively a race condition in HAL/VCP. Rx and Tx share a lock, and when Tx is in thread, while an Rx interrupt arrives, the Rx flow can be interrupted when VCP only tries to acknowledge/restart RX from the interrupt callback.

Do not use USBD_CDC_ReceivePacket without care in CDC_Restart_RX callback !!

To overcome this problem, I modified USBD_CDC_ReceivePacket to make it able to return an error code (originating from failure to take the lock), and restart Rx from a polling loop everytime the callback failed to take the lock.