How do I throttle USB device transfers to the device?

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

How do I throttle USB device transfers to the device?

1,590 Views
jpa
Contributor IV

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

Labels (1)
Tags (4)
0 Kudos
5 Replies

710 Views
soledad
NXP Employee
NXP Employee

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!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

710 Views
jpa
Contributor IV

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

0 Kudos

710 Views
jpa
Contributor IV

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

0 Kudos

710 Views
matthewkendall
Contributor V

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.

0 Kudos

710 Views
jpa
Contributor IV

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

0 Kudos