XUD - Support for Multiple Transactions per Microframe

Sub forums for various specialist XMOS applications. e.g. USB audio, motor control and robotics.
User avatar
Ross
XCore Expert
Posts: 966
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

A agree that those Windows and Linux traces don't look very good (What Windows driver are you using?)

I'm quite surprised that OS X only works in one direction...


User avatar
kenmac
Member++
Posts: 21
Joined: Tue May 13, 2014 9:37 am

Post by kenmac »

I have made some progress with this issue although the recent discoveries are not looking good in terms of support multiple transactions per uframe with XUD in its current state:

Ross, I have been using the Thesycon UAC2 ASIO driver to test with. I have taken the problem to Thesycon as our discussion was pointing towards a host problem. Thesycon have been very helpful in helping me debug the issue:

The main problem with the USB transactions on Windows that we saw in my previous post was to do with the USB descriptors. The first transactions on the Isoc IN endpoint (in this case DATA1) must use the total bytes specified in the endpoint's maxPacketSize descriptor before another transaction can be issued. Fixing this small but important value got me perfect USB bus traces on Windows as seen here (OSX seems to have a way around this even with the broken descriptor):

Image

Despite fixing the descriptor I am still facing problems which could be down to XUDs limitations.

Ross, when you initially suggested your quick fix method for multiple transactions per uframe, you only explicitly mentioned IN endpoints. I was under the impression that multiple transactions on the OUT endpoints were supported by XUD, as it has no problem ACKing these, as seen in the above trace. I can verify that XUD has problems dealing with the OUT endpoint data on time, though.

In an attempt to prove this, I timed the XUD_GetData_Select select case handler execution by toggling a GPIO and probing on a scope. XUD_GetData_Select is only being called once every 125us (once per uframe) and is only filling the buffer with one of the transactions every time (768 not 1534 bytes). I have experimented with the thread that XUD_GetData_Select is running in and have confirmed there is nothing blocking this function from executing faster than this.

Can anyone confirm if XUD_GetData_Select in combination with XUD_SetReady_OutPtr can be used multiple times on the same endpoint per uframe? It seems to me like they can't, making multiple Isoc OUT transactions per uframe impossible at present.

Regards,

Kenny
User avatar
Ross
XCore Expert
Posts: 966
Joined: Thu Dec 10, 2009 9:20 pm
Location: Bristol, UK

Post by Ross »

Yes OUT is a bit harder in theory, though the lib doesn't do any PID checking for ISO, the checking is in the user code (which is by passed for Iso endpoints):

Code: Select all

XUD_GetData_CheckDataLength:
    sub         r0, r0, 2                       // Length correction for CRC correction
    ashr        r11, r0, 32                     // Check for < 0. No CRC check on ISO so less than 2 bytes could be received.
    bt          r11, XUD_GetData_Select_BadPkt
    stw         r0, r2[0]                       // Return length (note: passed by ref)

    ldw         r11, r1[5]                      // Load EP type
    bf          r11, XUD_GetData_Select_Return  // Jump over PID toggle and check for ISO
I would like to replicate your test environment here, though I am pretty swamped at the moment so any help/code that you can provide to speed up the process would be greatly appreciated.

I suspect it is the buffering code that is not coping rather than the USB lib.

(BTW there are no ACKs with Iso traffic)
User avatar
kenmac
Member++
Posts: 21
Joined: Tue May 13, 2014 9:37 am

Post by kenmac »

You are right, the library doesn't do PID checking on Isoc OUT transfers. It has no idea that DATA1 and DATA0 should be considered two parts of the same packet. This would be fine as we could handle that part in user code.

The problem is that the select statement with XUD_GetData_Select only executes once every 125us with a length parameter the same size as only one of the transactions e.g. DATA1. We have underflow in the buffering thread, and in that sense it is a buffering problem, but it seems to be down to XUD_GetData_Select not processing more than one transaction on the same endpoint per microframe. Here is the select case code relating to the OUT endpoint that was used in the experiment I described in the previous post:

Code: Select all

/* Received Audio packet HOST -> DEVICE. Datalength written to length */
case XUD_GetData_Select(c_aud_out, ep_aud_out, length, result):
{
	//toggle gpio to get period inbetween executions
	tog = (tog + 1)%2;
	debug <: tog;

	if(aud_from_host_second_packet_flag)
	{
		GET_SHARED_GLOBAL(aud_from_host_buffer, g_aud_from_host_buffer);

		write_via_xc_ptr(aud_from_host_buffer, length+aud_from_host_second_packet_flag);

		/* Toggle to first packet*/
		aud_from_host_second_packet_flag =  0;

		/* Sync with decouple thread */
		SET_SHARED_GLOBAL0(g_aud_from_host_flag, 1);

	}
	else
	{
		aud_from_host_first_packet_len = length;
		aud_from_host_second_packet_flag = 1;


		unsigned aud_from_host_wrptr;
		GET_SHARED_GLOBAL(aud_from_host_wrptr, g_aud_from_host_wrptr);

		XUD_SetReady_OutPtr(ep_aud_out, aud_from_host_wrptr+4+length);

	}
}
break;
As I mentioned before, a scope on the toggled debug gpio reveals that the case statement is only executing once per uframe. We know from the bus trace that the data is being sent on time, but the case statement is not being executed twice per uframe as expected.

I can probably send you the whole code base, but would have to do it privately.

Regards,

Kenny

p.s.

You are right about ACKs/NAKs on ISOC transfers. What I should have said was "the transaction appears correctly on the bus". Thanks for keeping me right :)