2016-12-14 07:55 AM
Hi,
I'm trying to figure out a way to emulate UART RTS / CTS flow control with the USB CDC. My main goal is to be able to tell the host to stop sending data if the �c is busy.
After a little googling I come up with some conclusions leading to more questions than results.
1/ Nacking is intrinsic in the CDC class but it seems that bintevall should be modified in the endpoint descriptor. is this true? if no how can we enable it and take control of it to use it for data flow control?
2/ Is Nacking possible when using Full speed devices or it is only for high speed devices?
3/In case of stopping the host from sending data, would that generate errors with the host size? is there a timeout that needs to be configured? and how can we tell the host to resume transmitting?
I'm sorry I asked too many questions. Any help would be much appreciated.
Thanks
#flow-control #cdc #nack2016-12-14 11:49 AM
First let me say that I am not a USB expert and have not used HAL or STM32CubeMX to generate any code so I may not be much use for answering questions. That said, I have modified an older ST example CDC application for flow control. Here is what I did:
In the file usbd_cdc_core.c there is a function usbd_cdc_DataOut()
This function contains a call:
APP_FOPS.pIf_DataRx(USB_Rx_Buffer, USB_Rx_Cnt);
This calls a user function that handles the received data. In that function I took the data and sent it to a comport routine that puts it into a circular buffer for output via an interrupt-driven uart (large enough to receive the entire packet). My application basically sent data received by the USB and sent it out a comport like a USB to serial adapter.
The next line down in usbd_cdc_DataOut() was:
DCD_EP_PrepareRx(pdev,CDC_OUT_EP,(uint8_t*)(USB_Rx_Buffer),CDC_DATA_OUT_PACKET_SIZE);
It is my understanding that this line causes the USB to quit NAKing incoming packets and allows it to receive more data. I commented this line out and replaced it with setting a flag that I created:
hold_usb_datarx = 1;
Also in usbd_cdc_core.c I added a function:
extern USB_OTG_CORE_HANDLE USB_OTG_dev;
void Enable_USB_data_rx(void){ if(hold_usb_datarx) { hold_usb_datarx = 0; NVIC_DisableIRQ(OTG_FS_IRQn); // Prepare Out endpoint to receive next packet DCD_EP_PrepareRx(&USB_OTG_dev, //pdev,CDC_OUT_EP,(uint8_t*)(USB_Rx_Buffer),CDC_DATA_OUT_PACKET_SIZE); NVIC_EnableIRQ(OTG_FS_IRQn); }}Now in my main() loop I added:
if(!COM_data_to_xmit()) Enable_USB_data_rx();
COM_data_to_xmit() is simply a function that returns TRUE if the interrupt-driven uart has not yet transmitted all the data from the circular buffer. This call to Enable_USB_data_rx() probably could have been put in my uart transmit interrupt ISR, but I preferred not to modify that module so I put it in the main() loop. It could probably be optimized to re-enable the USB reception after the data in the circular buffer has dropped below a threshold which left enough room to handle another packet.
Good luck!
2016-12-14 07:27 PM
I'm swimming in the same USB whirlpool here too. But Tut is further along than me. I have voiced similar questions that have been met with 0 replies but I can tell you that the UM1734 and the README file in the example code for CDC all mention the NACK as being THE flow control method on the HOST side. I have not tried to overrun the data path from PC to micro yet but the data seems to indicate this is the way. This question or ones like it are numerous on the forums. It will be a few days for me before I pound on it in this manner but I'll post what I find.
As Tut says - Good Luck!