# Throttling data from USB serial connection on STM32 microcontroller (flow control)

I've just integrated the code from ST's STM32 USB Virtual Com Port example (stm32_usb-fs-device_lib.zip from here) with my project in order to get the STM32 to appear as a Virtual Serial Port.

However the code example throttles the data it receives by having the callback function EP3_OUT_Callback block (in an interrupt) until all data is dealt with. The exact comment in the code is "USB data will be immediately processed, this allow next USB traffic being NAKed till the end of the USART Xfer"

In my project, I need to process the data that has been received in the main loop (outside of an interrupt), so I need a way of throttling the data that I get from USB without blocking in EP3_OUT_Callback.

What I would like is a function:

Do_Not_Call_EP3_OUT_Callback_Right_Now(bool yes_or_no);

-
 The more I look at this, the more I think that the answer could be calling SetEPRxStatus(ENDP3, EP_RX_?) and then setting it to EP_RX_VALID in the main loop when all data is processed. However I am unable to get this to work - so any input (or examples where this is done) would be appreciated. – Gordon Williams Oct 12 '12 at 9:13

You should be able to do this by setting an atomic flag in the ISR that data is available, detecting that in the main loop to deal with it and then either sending the ack from there, or setting a flag so that it will be acked at the next opportunity

-
 Do you have any example? The main loop knows data is there. The problem is that the ISR (or at least EP3_OUT_Callback) doesn't appear to explicitly ACK. Just the fact that EP3_OUT_Callback is called is an explicit ACK, and by then it is too late. – Gordon Williams Oct 12 '12 at 9:07 that last 'explicit' should be 'implicit'. I have a feeling that the STM32 has some hardware that handles the USB, so it may be a matter of telling that whether to send ACKs or not - rather than explicitly sending them from code. – Gordon Williams Oct 12 '12 at 9:17

I appear to have got this working:

void EP3_OUT_Callback(void) {
...
//SetEPRxValid(ENDP3); //<-- Commented out
SetEPRxStatus(ENDP3, Do_I_Have_Room_For_More_Data() ? EP_RX_VALID : EP_RX_NAK); //<-- Added this
}

void SOF_Callback(void) {
if(bDeviceState == CONFIGURED) {
SetEPRxStatus(ENDP3, Do_I_Have_Room_For_More_Data() ? EP_RX_VALID : EP_RX_NAK); //<-- Added this
...
// Original TX code here
}
}


What's happening is after getting data, and in the Start of Frame callback (every 1ms), I set whether the endpoint is accepting data.

Note: The docs never seem to say just how much data USB_SIL_Read will read - potentially leading to a buffer overrun. However I believe the maximum is what is in VIRTUAL_COM_PORT_DATA_SIZE - and this seems to work great for me.

This would appear to work - however I have no idea if it is the 'right' way of doing it. Please let me know if it's wrong and I'll update it!

-