Sorry for what may be a simple question...I'd have thought this was handled in the CDC examples, but if it's there, I couldn't find it.
I've got something that's essentially like a USB serial port, the host PC is transferring data that gets sent out a serial port at a relatively slow baud rate. So given that the host can transfer data into my device faster than I can get rid of it, how do I tell the host not to send more data for a while, while my buffers empty? I tried just delaying the call to USB_Class_MIDI_Recv_Data, thinking that would hold off some ACK, but no, I just lose data packets.
This is under MQX 4.0, using the USB device framework. It's not actually a CDC, but I've made my own class that seems to work until I throw large amounts of data at it all at once.
John
Hi John,
Oh, It seems that you want to implement a flow control in your CDC class, so what you need to in order to stop the flow it is to implement an stall to the endpoint. This way the host would have enough time to receive (ACK) the data and then you can remove the stall from the endpoint.
I hope this helps,
Have a great day,
Sol
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Thank you for responding, Sol!
Reflecting back what I'm hearing...when my Kinetis USB device receives data that it can't process, I should
* call _usb_device_stall_endpoint(devicePtr->controller_handle, ep_num, USB_RECV);
* wait until the queue has emptied enough to receive more data
* add the data to the queue
* call _usb_device_unstall_endpoint(devicePtr->controller_handle, ep_num, USB_RECV); to unstall the queue
* call _usb_device_recv_data with a new buffer
Or must I do this BEFORE I'm out of space?
When my Kinetis USB device receives any data it should:
* add data to queue
* call _usb_device_recv_data with a new buffer
* test queue, if it is within one packet of being full, call _usb_device_stall
* (wait for queue below threshold)
* call _usb_device_unstall
Which is recommended? The first is much easier, I suspect the latter will require setting a semaphore for stalled and letting the serial tx isr clear it and send the unstall.
John
I seem to have stumbled upon something that works, but I'm not at all convinced that it's the 'right' way to go about it. I'm seeking comments.
USB_Notif_Callback is called with event_type == USB_APP_DATA_RECEIVED.
Previously:
I would swap receive buffers,
call USB_Class_Send_Data
and process the data received.
Now:
I process the data received, putting it in a transmit queue for the (slower) UART.
If there's no more room to buffer the data, I sit and spin (calling _time_delay to allow other threads to run) until there is room
then I call USB_Class_Send_Data.
I can imagine that this slows down transfers somewhat, since in the previous model, the USB host and the peripheral thread of my app could be negotiating another transfer while my app processes the data, but I think the serial transfer occurs so much more slowly than the USB, that it probably doesn't make much difference. Comments? Better way?
John
Using a USB endpoint stall would seem to be implementing this at much to low a level.
It sounds like what you want is just ordinary flow control. There are two standard ways of doing this: in-band signalling using XON/XOFF characters, or out-of-band signalling using RTS/CTS control signals.
XON/OFF signalling would just require you to handle these characters at the application level; send XOFF when your buffer is getting full and send XON when it has emptied. Configure the other end to stop sending when it sees XOFF and resume when it sees XON. And vice versa. If the other end is a standard terminal (or emulator) it will have this capability built in.
RTS/CTS signalling would require you to manipulate/handle the (virtual) RTS/CTS signals in the CDC driver. The Freescale CDC demo does not do this, and the documentation for the CDC class driver is fairly sparse, but it looks like the hooks are there.
Matthew,
{With apologies for the interval, I'm just getting back to this after some other distractions}
Can you elaborate on "much too low a level" and why this is a bad thing?
The protocol I'm using is not RS232 serial data, just very similar. There's no soft (or hard) flow control built into the protocol as far as I know, so I'm hoping I can use something built into the USB communications channel to force the host to stop sending while my buffers empty.
John