cancel
Showing results for 
Search instead for 
Did you mean: 

How determine when USB TX is complete from device to host

Stig Hornang
Associate II
Posted on November 04, 2014 at 17:22

- STM32CubeF4 V1.3.0

-STM32_USB_Device_Library from STM32CubeF4 V1.3.0

- VCP_V1.3.1_Setup.exe (ST's host side USB CDC driver for Windows 7)

- STM32F4Discovery (STM32F407)

- FreeRTOS 8.1.2

I'm using the CDC class driver bundled with the USB device library.

My goal is to stream binary data from USB device to host through USB CDC. The streaming works fine, but problem arises when there is no client application connected to the virtual COM port when data is beeing transmitted from the USB device.

See USBD_CDC_TransmitPacket function from usbd_cdc.c below. It has been modified according toPoint no. 22 at this page:

http://visualgdb.com/tutorials/arm/stm32/usb/

.

uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)

{

USBD_CDC_HandleTypeDef *hcdc = pdev->pClassData;

if

(pdev->pClassData != NULL)

{

if

(hcdc->TxState == 0)

{

/* Tx Transfer in progress */

hcdc->TxState = 1;

/* Transmit next packet */

USBD_LL_Transmit(pdev,

CDC_IN_EP,

hcdc->TxBuffer,

hcdc->TxLength);

return

USBD_OK;

}

else

{

return

USBD_BUSY;

}

}

else

{

return

USBD_FAIL;

}

}

As you can see this function just returns ''busy'' if the previous transfer is in progress. This happens if nobody is listening on the PC side. This is probably correct and kind of an improvement to a regular COM port without flow control.

What I want is to block (for some time) until I can transmit my next packet. This is possible by polling on TxState flag, not very elegant but it works.

This is the code that resets the TxFlag:

static

uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum)

{

USBD_CDC_HandleTypeDef *hcdc = pdev->pClassData;

if

(pdev->pClassData != NULL)

{

hcdc->TxState = 0;

return

USBD_OK;

}

else

{

return

USBD_FAIL;

}

}

Two questions:

1. What does

USBD_CDC_DataIn

really mean? Is this the callback for when a (bulk) transfer has succesfully been transmitted to the host PC?

2. Is there a way to implement blocking version of a ''USB transmit''-function? I'm using FreeRTOS which indeed have mutexes, but I'm unsure where I should lock and unlock.

3. Before calling

USBD_CDC_TransmitPacket

one have to call

USBD_CDC_SetTxBuffer.

Can this ruin the ongoing transfer? There is not TxState check in this function.

#usb-cdc-vcp #discovery #freertos

3 REPLIES 3
Posted on February 05, 2015 at 15:24

Hi hornang,

Please find below answers to your questions:

 What does USBD_CDC_DataIn really mean?

   >> Yes this the callback for when a (bulk) transfer has succesfully been transmitted to

         the host PC

2. Is there a way to implement blocking version of a ''USB transmit''-function?

   >> Can you test the code below.

        USBD_CDC_SetTxBuffer(&USBD_Device, ''Hi this the second buffer'', 25);

        USBD_CDC_TransmitPacket(&USBD_Device); // The first call of  USBD_CDC_TransmitPacket() returns USBD_OK

  while(USBD_CDC_TransmitPacket(&USBD_Device) == USBD_BUSY); // while the previuos is not yet USBD_CDC_TransmitPacket() sent returns USBD_BUSY

Be aware the data transfer over USB is handled by interrupt so the code above can't work if called inside interrupt handler whose the interrupt priority is higher than USB.

With best regards,

Stig Hornang
Associate II
Posted on June 05, 2015 at 13:14

Ok, thanks I have implemented a similar solution, although instead of busy waiting I'm sleeping the task using RTOS primitive.

I have a follow-up question. When receiving with USB_CDC you have to at some point call 

USBD_CDC_ReceivePacket

to get ready for the next packet to be received, right?

When should it be called?

- In the interrupt handler?

Problems: The main thread may be transmitting using

 USBD_CDC_TransmitPacket

and the ''hpcd'' me be locked and the

 USBD_CDC_ReceivePacket

call will fail since

 __HAL_LOCK(hpcd)

 will just return

HAL_BUSY

- In the main thread? (when signaled by the interrupt)

Problem: There may be an incoming reception and the same problem will happen as above, but now the lock is held by the interrupt handler rather than the main thread.

The problem in both cases is that no further USB packets will be received.

Please advice the correct way to handle this problem.

Using STM32Cube v1.4.0
spflanze
Associate II
Posted on September 02, 2015 at 23:52

The callbacks you are looking for are:

 __weak void HAL_PCD_DataOutStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)

__weak void HAL_PCD_DataInStageCallback(PCD_HandleTypeDef *hpcd, uint8_t epnum)

These are defined in stm32f3xx_hal_pcd.c.