The TxState variable must be set to a nonzero value before the mutex is released. So it must happen in USBD_CDC_SetTxBuffer() or USBD_CDC_TransmitPacket().
Yes that is what happens:
/**
* @brief USBD_CDC_DataOut
* Data received on non-control Out endpoint
* @param pdev: device instance
* @param epnum: endpoint number
* @retval status
*/
uint8_t USBD_CDC_TransmitPacket(USBD_HandleTypeDef *pdev)
{
USBD_CDC_HandleTypeDef *hcdc = (USBD_CDC_HandleTypeDef*) pdev->pClassDataCDC;
if(pdev->pClassDataCDC != 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;
}
}
With more than one task calling the transmit function, the 'no flow control' option does not work at all:
Yes. That's fine. The "no flow control" option is purely for debugs, and I don't care if there is data loss.
The basic problem is that with USB you cannot concurrently achieve
- flow control on transmit data (data Box -> Host)
- the Box not getting hung up if Host is missing / failed / no CDC profile supported / whatever
About all one can do is have some sort of a timeout that if output data is
not disappearing (the Host CDC device profile is not retrieving it) for say 1 second, a flag gets set which discards the output.
That is AIUI and I may well be wrong! My tests below suggest I
am wrong, at least in some cases, but why?
That is why, before CDC outputting, I implement the tests for e.g. VBUS=1 to eliminate the most obvious cases. But as has been pointed out to me before, there is no perfect solution. There was some disagreement on the detail e.g. one person said that if you want to detect
whether the Host is running a CDC device profile on that "endpoint" (I think that is the rioght name) you can't do that unless you have a custom driver, which is not viable because this needs to work on any Windows etc PC.
However I tested this by forcing flow control ON and seeing if the whole box hangs when Teraterm is not running on the PC... It does
not hang. The data still disappears somewhere. Is there a defined action for Windows (to collect all CDC data and if there is no app running, just dump it) or is this just "luck".
It also does not hang when the USB cable is unplugged! But I think that is a different thing: the ST USB code detects the link state and calls usb_deinit. Then the ST code just dumps the data.
I think the scenario where I saw the target hanging must have been a subtle failure at the Host end.
This whole thing is really complicated.
The funny thing is that in the context of driving say Teraterm with debugs you don't need flow control. You just need about a 200 us delay between lines of text

Or limit the packet rate to < 5000/sec. I determined these experimentally, and these numbers are obviously Host dependent. But I found that if you do push out a few k of data flat out, the Host (Teraterm) gets locked up. The data still gets "consumed" but Teraterm needs a restart.
A real need for flow control comes into use only if you are using CDC for transferring data to some more normal application.