diff --git a/examples/dual_AN00127_video_class/XCORE-AI-EXPLORER-2V0-4TILE.xn b/examples/dual_AN00127_video_class/XCORE-AI-EXPLORER-2V0-4TILE.xn
new file mode 100644
index 00000000..f2f66d2f
--- /dev/null
+++ b/examples/dual_AN00127_video_class/XCORE-AI-EXPLORER-2V0-4TILE.xn
@@ -0,0 +1,87 @@
+
+
+ Board
+ xcore.ai Explorer Kit x2 Wired as 4 tile system
+
+
+ tileref tile[4]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/dual_AN00127_video_class/src/config.xscope b/examples/dual_AN00127_video_class/src/config.xscope
new file mode 100644
index 00000000..4b96626a
--- /dev/null
+++ b/examples/dual_AN00127_video_class/src/config.xscope
@@ -0,0 +1,3 @@
+
+
+
diff --git a/examples/dual_AN00127_video_class/src/main.xc b/examples/dual_AN00127_video_class/src/main.xc
new file mode 100644
index 00000000..e3da33b4
--- /dev/null
+++ b/examples/dual_AN00127_video_class/src/main.xc
@@ -0,0 +1,121 @@
+// Copyright 2015-2022 XMOS LIMITED.
+// This Software is subject to the terms of the XMOS Public Licence: Version 1.
+
+/* Includes */
+#include
+#include
+#include
+#include
+#include
+
+#include "usb_video.h"
+#include "xud.h"
+extern "C"{
+ #include "xud_wrapper.h"
+}
+
+/* xSCOPE Setup Function */
+#if (USE_XSCOPE == 1)
+void xscope_user_init(void) {
+ xscope_register(0, 0, "", 0, "");
+ xscope_config_io(XSCOPE_IO_BASIC); /* Enable fast printing over XTAG */
+}
+#endif
+
+/* USB Endpoint Defines */
+#define EP_COUNT_OUT 1 // 1 OUT EP0
+#define EP_COUNT_IN 3 // (1 IN EP0 + 1 INTERRUPT IN EP + 1 ISO IN EP)
+
+/* Endpoint type tables - informs XUD what the transfer types for each Endpoint in use and also
+ * if the endpoint wishes to be informed of USB bus resets
+ */
+XUD_EpType epTypeTableOut[EP_COUNT_OUT] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE};
+XUD_EpType epTypeTableIn[EP_COUNT_IN] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_INT, XUD_EPTYPE_ISO};
+
+XUD_EpType epTypeTableOut2[EP_COUNT_OUT] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE};
+XUD_EpType epTypeTableIn2[EP_COUNT_IN] = {XUD_EPTYPE_CTL | XUD_STATUS_ENABLE, XUD_EPTYPE_INT, XUD_EPTYPE_ISO};
+
+
+/*
+ #define PORT_USB_CLK on USB_TILE: XS1_PORT_1J
+ #define PORT_USB_TXD on USB_TILE: XS1_PORT_8A
+ #define PORT_USB_RXD on USB_TILE: XS1_PORT_8B
+ #define PORT_USB_TX_READYOUT on USB_TILE: XS1_PORT_1K
+ #define PORT_USB_TX_READYIN on USB_TILE: XS1_PORT_1H
+ #define PORT_USB_RX_READY on USB_TILE: XS1_PORT_1I
+ #define PORT_USB_FLAG0 on USB_TILE: XS1_PORT_1E
+ #define PORT_USB_FLAG1 on USB_TILE: XS1_PORT_1F
+*/
+
+XUD_resources_t resources =
+{
+ on tile[0]: XS1_PORT_1E, // flag0_port
+ on tile[0]: XS1_PORT_1F, // flag1_port
+ null, // flag2_port
+ on tile[0]: XS1_PORT_1J, // p_usb_clk
+ on tile[0]: XS1_PORT_8A, // p_usb_txd
+ on tile[0]: XS1_PORT_8B, // p_usb_rxd
+ on tile[0]: XS1_PORT_1K, // tx_readyout
+ on tile[0]: XS1_PORT_1H, // tx_readyin
+ on tile[0]: XS1_PORT_1I, // rx_rdy
+ on tile[0]: XS1_CLKBLK_4, // tx_usb_clk
+ on tile[0]: XS1_CLKBLK_5, // rx_usb_clk
+};
+
+XUD_resources_t resources2 =
+{
+ on tile[2]: XS1_PORT_1E,
+ on tile[2]: XS1_PORT_1F,
+ null,
+ on tile[2]: XS1_PORT_1J,
+ on tile[2]: XS1_PORT_8A,
+ on tile[2]: XS1_PORT_8B,
+ on tile[2]: XS1_PORT_1K,
+ on tile[2]: XS1_PORT_1H,
+ on tile[2]: XS1_PORT_1I,
+ on tile[2]: XS1_CLKBLK_4,
+ on tile[2]: XS1_CLKBLK_5,
+};
+
+int main() {
+
+ chan c_ep_out[EP_COUNT_OUT], c_ep_in[EP_COUNT_IN];
+ chan c_ep_out2[EP_COUNT_OUT], c_ep_in2[EP_COUNT_IN];
+
+
+ /* 'Par' statement to run the following tasks in parallel */
+ par
+ {
+ on USB_TILE:
+ {
+ init_xud_resources(resources);
+ printstr("XUD\n");
+ XUD_Main(c_ep_out, EP_COUNT_OUT, c_ep_in, EP_COUNT_IN,
+ null, epTypeTableOut, epTypeTableIn,
+ XUD_SPEED_HS, XUD_PWR_BUS);
+ }
+
+ on USB_TILE: Endpoint0(c_ep_out[0], c_ep_in[0], PRODUCT_ID);
+
+ on USB_TILE: VideoEndpointsHandler(c_ep_in[1], c_ep_in[2], 0);
+
+#undef USB_TILE
+#define USB_TILE tile[2]
+
+ on USB_TILE:
+ {
+ init_xud_resources(resources2);
+ printstr("XUD\n");
+ XUD_Main_wrapper(c_ep_out2, EP_COUNT_OUT, c_ep_in2, EP_COUNT_IN,
+ null, epTypeTableOut2, epTypeTableIn2,
+ XUD_SPEED_HS, XUD_PWR_BUS);
+ }
+
+ on USB_TILE: Endpoint0_wrapper(c_ep_out2[0], c_ep_in2[0], PRODUCT_ID + 1);
+
+ on USB_TILE: VideoEndpointsHandler_wrapper(c_ep_in2[1], c_ep_in2[2], 1);
+
+
+ }
+ return 0;
+}
diff --git a/examples/dual_AN00127_video_class/src/usb_video.h b/examples/dual_AN00127_video_class/src/usb_video.h
new file mode 100644
index 00000000..b4fff83d
--- /dev/null
+++ b/examples/dual_AN00127_video_class/src/usb_video.h
@@ -0,0 +1,19 @@
+// Copyright 2015-2021 XMOS LIMITED.
+// This Software is subject to the terms of the XMOS Public Licence: Version 1.
+
+#ifndef USB_VIDEO_H_
+#define USB_VIDEO_H_
+
+#include "xud_device.h"
+#include "uvc_req.h"
+#include "uvc_defs.h"
+
+#define DEBUG 0
+
+/* Function to handle all endpoints of the Video class excluding control endpoint0 */
+void VideoEndpointsHandler(chanend c_epint_in, chanend c_episo_in, unsigned instance);
+
+/* Endpoint 0 handles both std USB requests and Video class-specific requests */
+void Endpoint0(chanend chan_ep0_out, chanend chan_ep0_in, unsigned short PID);
+
+#endif /* USB_VIDEO_H_ */
diff --git a/examples/dual_AN00127_video_class/src/usb_video.xc b/examples/dual_AN00127_video_class/src/usb_video.xc
new file mode 100644
index 00000000..04210907
--- /dev/null
+++ b/examples/dual_AN00127_video_class/src/usb_video.xc
@@ -0,0 +1,379 @@
+// Copyright 2015-2021 XMOS LIMITED.
+// This Software is subject to the terms of the XMOS Public Licence: Version 1.
+
+#include "string.h"
+#include "usb_video.h"
+
+/* Definition of Descriptors */
+/* USB Device Descriptor */
+static unsigned char devDesc[] =
+{
+ 0x12, /* 0 bLength */
+ USB_DESCTYPE_DEVICE, /* 1 bdescriptorType - Device*/
+ 0x00, /* 2 bcdUSB version */
+ 0x02, /* 3 bcdUSB version */
+ 0xEF, /* 4 bDeviceClass - USB Miscellaneous Class */
+ 0x02, /* 5 bDeviceSubClass - Common Class */
+ 0x01, /* 6 bDeviceProtocol - Interface Association Descriptor */
+ 0x40, /* 7 bMaxPacketSize for EP0 - max = 64*/
+ (VENDOR_ID & 0xFF), /* 8 idVendor */
+ (VENDOR_ID >> 8), /* 9 idVendor */
+ (PRODUCT_ID & 0xFF), /* 10 idProduct */
+ (PRODUCT_ID >> 8), /* 11 idProduct */
+ (BCD_DEVICE & 0xFF), /* 12 bcdDevice */
+ (BCD_DEVICE >> 8), /* 13 bcdDevice */
+ 0x01, /* 14 iManufacturer - index of string*/
+ 0x02, /* 15 iProduct - index of string*/
+ 0x00, /* 16 iSerialNumber - index of string*/
+ 0x01 /* 17 bNumConfigurations */
+};
+
+/* USB Configuration Descriptor */
+static unsigned char cfgDesc[] = {
+
+ 0x09, /* 0 bLength */
+ USB_DESCTYPE_CONFIGURATION, /* 1 bDescriptorType - Configuration*/
+ 0xAE,00, /* 2 wTotalLength */
+ 0x02, /* 4 bNumInterfaces */
+ 0x01, /* 5 bConfigurationValue */
+ 0x03, /* 6 iConfiguration - index of string */
+ 0x80, /* 7 bmAttributes - Bus powered */
+ 0xFA, /* 8 bMaxPower (in 2mA units) - 500mA */
+
+ /* Interface Association Descriptor */
+ 0x08, /* 0 bLength */
+ USB_DESCTYPE_INTERFACE_ASSOCIATION, /* 1 bDescriptorType - Interface Association */
+ 0x00, /* 2 bFirstInterface - VideoControl i/f */
+ 0x02, /* 3 bInterfaceCount - 2 Interfaces */
+ USB_CLASS_VIDEO, /* 4 bFunctionClass - Video Class */
+ USB_VIDEO_INTERFACE_COLLECTION, /* 5 bFunctionSubClass - Video Interface Collection */
+ 0x00, /* 6 bFunctionProtocol - No protocol */
+ 0x02, /* 7 iFunction - index of string */
+
+ /* Video Control (VC) Interface Descriptor */
+ 0x09, /* 0 bLength */
+ USB_DESCTYPE_INTERFACE, /* 1 bDescriptorType - Interface */
+ 0x00, /* 2 bInterfaceNumber - Interface 0 */
+ 0x00, /* 3 bAlternateSetting */
+ 0x01, /* 4 bNumEndpoints */
+ USB_CLASS_VIDEO, /* 5 bInterfaceClass - Video Class */
+ USB_VIDEO_CONTROL, /* 6 bInterfaceSubClass - VideoControl Interface */
+ 0x00, /* 7 bInterfaceProtocol - No protocol */
+ 0x02, /* 8 iInterface - Index of string (same as iFunction of IAD) */
+
+ /* Class-specific VC Interface Header Descriptor */
+ 0x0D, /* 0 bLength */
+ USB_DESCTYPE_CS_INTERFACE, /* 1 bDescriptorType - Class-specific Interface */
+ USB_VC_HEADER, /* 2 bDescriptorSubType - HEADER */
+ 0x10, 0x01, /* 3 bcdUVC - Video class revision 1.1 */
+ 0x28, 0x00, /* 5 wTotalLength - till output terminal */
+ WORD_CHARS(100000000), /* 7 dwClockFrequency - 100MHz (Deprecated) */
+ 0x01, /* 11 bInCollection - One Streaming Interface */
+ 0x01, /* 12 baInterfaceNr - Number of the Streaming interface */
+
+ /* Input Terminal (Camera) Descriptor - Represents the CCD sensor (Simulated here in this demo) */
+ 0x12, /* 0 bLength */
+ USB_DESCTYPE_CS_INTERFACE, /* 1 bDescriptorType - Class-specific Interface */
+ USB_VC_INPUT_TERMINAL, /* 2 bDescriptorSubType - INPUT TERMINAL */
+ 0x01, /* 3 bTerminalID */
+ 0x01, 0x02, /* 4 wTerminalType - ITT_CAMERA type (CCD Sensor) */
+ 0x00, /* 6 bAssocTerminal - No association */
+ 0x00, /* 7 iTerminal - Unused */
+ 0x00, 0x00, /* 8 wObjectiveFocalLengthMin - No optical zoom supported */
+ 0x00, 0x00, /* 10 wObjectiveFocalLengthMax - No optical zoom supported*/
+ 0x00, 0x00, /* 12 wOcularFocalLength - No optical zoom supported */
+ 0x03, /* 14 bControlSize - 3 bytes */
+ 0x00, 0x00, 0x00, /* 15 bmControls - No controls are supported */
+
+ /* Output Terminal Descriptor */
+ 0x09, /* 0 bLength */
+ USB_DESCTYPE_CS_INTERFACE, /* 1 bDescriptorType - Class-specific Interface */
+ USB_VC_OUPUT_TERMINAL, /* 2 bDescriptorSubType - OUTPUT TERMINAL */
+ 0x02, /* 3 bTerminalID */
+ 0x01, 0x01, /* 4 wTerminalType - TT_STREAMING type */
+ 0x00, /* 6 bAssocTerminal - No association */
+ 0x01, /* 7 bSourceID - Source is Input terminal 1 */
+ 0x00, /* 8 iTerminal - Unused */
+
+ /* Standard Interrupt Endpoint Descriptor */
+ 0x07, /* 0 bLength */
+ USB_DESCTYPE_ENDPOINT, /* 1 bDescriptorType */
+ (VIDEO_STATUS_EP_NUM | 0x80), /* 2 bEndpointAddress - IN endpoint*/
+ 0x03, /* 3 bmAttributes - Interrupt transfer */
+ 0x40, 0x00, /* 4 wMaxPacketSize - 64 bytes */
+ 0x09, /* 6 bInterval - 2^(9-1) microframes = 32ms */
+
+ /* Class-specific Interrupt Endpoint Descriptor */
+ 0x05, /* 0 bLength */
+ USB_DESCTYPE_CS_ENDPOINT, /* 1 bDescriptorType - Class-specific Endpoint */
+ 0x03, /* 2 bDescriptorSubType - Interrupt Endpoint */
+ 0x40, 0x00, /* 3 wMaxTransferSize - 64 bytes */
+
+ /* Video Streaming Interface Descriptor */
+ /* Zero-bandwidth Alternate Setting 0 */
+ 0x09, /* 0 bLength */
+ USB_DESCTYPE_INTERFACE, /* 1 bDescriptorType - Interface */
+ 0x01, /* 2 bInterfaceNumber - Interface 1 */
+ 0x00, /* 3 bAlternateSetting - 0 */
+ 0x00, /* 4 bNumEndpoints - No bandwidth used */
+ USB_CLASS_VIDEO, /* 5 bInterfaceClass - Video Class */
+ USB_VIDEO_STREAMING, /* 6 bInterfaceSubClass - VideoStreaming Interface */
+ 0x00, /* 7 bInterfaceProtocol - No protocol */
+ 0x00, /* 8 iInterface - Unused */
+
+ /* Class-specific VS Interface Input Header Descriptor */
+ 0x0E, /* 0 bLength */
+ USB_DESCTYPE_CS_INTERFACE, /* 1 bDescriptorType - Class-specific Interface */
+ USB_VS_INPUT_HEADER, /* 2 bDescriptorSubType - INPUT HEADER */
+ 0x01, /* 3 bNumFormats - One format supported */
+ 0x47, 0x00, /* 4 wTotalLength - Size of class-specific VS descriptors */
+ (VIDEO_DATA_EP_NUM | 0x80), /* 6 bEndpointAddress - Iso EP for video streaming */
+ 0x00, /* 7 bmInfo - No dynamic format change */
+ 0x02, /* 8 bTerminalLink - Denotes the Output Terminal */
+ 0x01, /* 9 bStillCaptureMethod - Method 1 supported */
+ 0x00, /* 10 bTriggerSupport - No Hardware Trigger */
+ 0x00, /* 11 bTriggerUsage */
+ 0x01, /* 12 bControlSize - 1 byte */
+ 0x00, /* 13 bmaControls - No Controls supported */
+
+ /* Class-specific VS Format Descriptor */
+ 0x1B, /* 0 bLength */
+ USB_DESCTYPE_CS_INTERFACE, /* 1 bDescriptorType - Class-specific Interface */
+ USB_VS_FORMAT_UNCOMPRESSED, /* 2 bDescriptorSubType - FORMAT UNCOMPRESSED */
+ 0x01, /* 3 bFormatIndex */
+ 0x01, /* 4 bNumFrameDescriptors - 1 Frame descriptor followed */
+ 0x59,0x55,0x59,0x32,
+ 0x00,0x00,0x10,0x00,
+ 0x80,0x00,0x00,0xAA,
+ 0x00,0x38,0x9B,0x71, /* 5 guidFormat - YUY2 Video format */
+ BITS_PER_PIXEL, /* 21 bBitsPerPixel - 16 bits */
+ 0x01, /* 22 bDefaultFrameIndex */
+ 0x00, /* 23 bAspectRatioX */
+ 0x00, /* 24 bAspectRatioY */
+ 0x00, /* 25 bmInterlaceFlags - No interlaced mode */
+ 0x00, /* 26 bCopyProtect - No restrictions on duplication */
+
+ /* Class-specific VS Frame Descriptor */
+ 0x1E, /* 0 bLength */
+ USB_DESCTYPE_CS_INTERFACE, /* 1 bDescriptorType - Class-specific Interface */
+ USB_VS_FRAME_UNCOMPRESSED, /* 2 bDescriptorSubType */
+ 0x01, /* 3 bFrameIndex */
+ 0x01, /* 4 bmCapabilities - Still image capture method 1 */
+ SHORT_CHARS(WIDTH), /* 5 wWidth - 480 pixels */
+ SHORT_CHARS(HEIGHT), /* 7 wHeight - 320 pixels */
+ WORD_CHARS(MIN_BIT_RATE), /* 9 dwMinBitRate */
+ WORD_CHARS(MAX_BIT_RATE), /* 13 dwMaxBitRate */
+ WORD_CHARS(MAX_FRAME_SIZE), /* 17 dwMaxVideoFrameBufSize */
+ WORD_CHARS(FRAME_INTERVAL), /* 21 dwDefaultFrameInterval (in 100ns units) */
+ 0x01, /* 25 bFrameIntervalType */
+ WORD_CHARS(FRAME_INTERVAL), /* 26 dwFrameInterval (in 100ns units) */
+
+ /* Video Streaming Interface Descriptor */
+ /* Alternate Setting 1 */
+ 0x09, /* 0 bLength */
+ USB_DESCTYPE_INTERFACE, /* 1 bDescriptorType - Interface */
+ 0x01, /* 2 bInterfaceNumber - Interface 1 */
+ 0x01, /* 3 bAlternateSetting - 1 */
+ 0x01, /* 4 bNumEndpoints */
+ USB_CLASS_VIDEO, /* 5 bInterfaceClass - Video Class */
+ USB_VIDEO_STREAMING, /* 6 bInterfaceSubClass - VideoStreaming Interface */
+ 0x00, /* 7 bInterfaceProtocol - No protocol */
+ 0x00, /* 8 iInterface - Unused */
+
+ /* Standard VS Isochronous Video Data Endpoint Descriptor */
+ 0x07, /* 0 bLength */
+ USB_DESCTYPE_ENDPOINT, /* 1 bDescriptorType */
+ (VIDEO_DATA_EP_NUM | 0x80), /* 2 bEndpointAddress - IN Endpoint */
+ 0x05, /* 3 bmAttributes - Isochronous EP (Asynchronous) */
+ 0x00, 0x04, /* 4 wMaxPacketSize 1x 1024 bytes*/
+ 0x01, /* 6 bInterval */
+
+};
+
+unsafe{
+ /* String table - unsafe as accessed via shared memory */
+ static char * unsafe stringDescriptors[]=
+ {
+ "\x09\x04", /* Language ID string (US English) */
+ "XMOS", /* iManufacturer */
+ "XMOS USB Video Device",/* iProduct */
+ "Config", /* iConfiguration string */
+ };
+}
+
+/* Endpoint 0 handles both std USB requests and Video class-specific requests */
+void Endpoint0(chanend chan_ep0_out, chanend chan_ep0_in, unsigned short PID)
+{
+ devDesc[10] = PID & 0xff;
+ devDesc[11] = PID >> 8;
+
+ USB_SetupPacket_t sp;
+
+ unsigned bmRequestType;
+ XUD_BusSpeed_t usbBusSpeed;
+
+ XUD_ep ep0_out = XUD_InitEp(chan_ep0_out);
+ XUD_ep ep0_in = XUD_InitEp(chan_ep0_in);
+
+ UVC_InitProbeCommitData();
+
+ while(1)
+ {
+ /* Returns XUD_RES_OKAY on success */
+ XUD_Result_t result = USB_GetSetupPacket(ep0_out, ep0_in, sp);
+
+ if(result == XUD_RES_OKAY)
+ {
+ /* Set result to ERR, we expect it to get set to OKAY if a request is handled */
+ result = XUD_RES_ERR;
+
+ /* Stick bmRequest type back together for an easier parse... */
+ bmRequestType = (sp.bmRequestType.Direction<<7) |
+ (sp.bmRequestType.Type<<5) |
+ (sp.bmRequestType.Recipient);
+
+ if ((bmRequestType == USB_BMREQ_H2D_STANDARD_DEV) &&
+ (sp.bRequest == USB_SET_ADDRESS))
+ {
+ // Host has set device address, value contained in sp.wValue
+ }
+
+ switch(bmRequestType)
+ {
+ /* Direction: Device-to-host and Host-to-device
+ * Type: Class
+ * Recipient: Interface / Endpoint
+ */
+ case USB_BMREQ_H2D_CLASS_INT:
+ case USB_BMREQ_D2H_CLASS_INT:
+ case USB_BMREQ_H2D_CLASS_EP:
+ case USB_BMREQ_D2H_CLASS_EP:
+
+ /* Inspect for VideoControl Class interface number or
+ * VideoStreaming Class interface number or EP number;
+ * If an Entity is addressed, the High byte has to be checked
+ * for Entity ID */
+ if(sp.wIndex == 0 || sp.wIndex == 1 || sp.wIndex == (VIDEO_DATA_EP_NUM | 0x80))
+ {
+ /* Returns XUD_RES_OKAY if handled,
+ * XUD_RES_ERR if not handled,
+ * XUD_RES_RST for bus reset */
+ result = UVC_InterfaceClassRequests(ep0_out, ep0_in, sp);
+ }
+ break;
+ }
+ } /* if ends */
+
+ /* If we haven't handled the request about then do standard enumeration requests */
+ if(result == XUD_RES_ERR )
+ {
+ /* Returns XUD_RES_OKAY if handled okay,
+ * XUD_RES_ERR if request was not handled (STALLed),
+ * XUD_RES_RST for USB Reset */
+ unsafe{
+ result = USB_StandardRequests(ep0_out, ep0_in, devDesc,
+ sizeof(devDesc), cfgDesc, sizeof(cfgDesc),
+ null, 0, null, 0, stringDescriptors, sizeof(stringDescriptors)/sizeof(stringDescriptors[0]),
+ sp, usbBusSpeed);
+ }
+ }
+
+ /* USB bus reset detected, reset EP and get new bus speed */
+ if(result == XUD_RES_RST)
+ {
+ usbBusSpeed = XUD_ResetEndpoint(ep0_out, ep0_in);
+ }
+ }
+}
+
+/* Buffer to hold Video data in YUYV format */
+unsigned int gVideoBuffer[3][PAYLOAD_SIZE / 4];
+
+/* Function to handle all endpoints of the Video class excluding control endpoint0 */
+void VideoEndpointsHandler(chanend c_epint_in, chanend c_episo_in, unsigned instance)
+{
+ XUD_Result_t result;
+ int frame = 0x0C;
+ int pts, tmrValue = 0;
+ timer presentationTimer;
+
+ int sofCounts = 0, frameCounts = 0;
+ unsigned int index = 0;
+ unsigned int i_index = 0;
+ int split = (MAX_FRAME_SIZE / 6);
+ int i_split = (MAX_FRAME_SIZE / 6);
+
+ /* Initialize all endpoints */
+ XUD_ep epint_in = XUD_InitEp(c_epint_in);
+ XUD_ep episo_in = XUD_InitEp(c_episo_in);
+
+ /* Just to keep compiler happy */
+ epint_in = epint_in;
+ /* XUD will NAK if the endpoint is not ready to communicate with XUD */
+
+ /* Fill video buffers with different color data */
+ for(int i = 0; i < (PAYLOAD_SIZE/4); i++) {
+ /* Set RED color */
+ gVideoBuffer[0][i] = 0x7010D010 * instance;
+ /* Set GREEN color */
+ gVideoBuffer[2][i] = 0x00000000;
+ /* Set BLUE color */
+ gVideoBuffer[1][i] = 0xDC206020;
+ }
+
+ while(1)
+ {
+ int expectedPixels = MAX_FRAME_SIZE;
+ presentationTimer :> pts;
+
+ /* Fill the buffers with payload header */
+ for(int i=0; i<3; i++)
+ {
+ /* Make the Payload header */
+ (gVideoBuffer[i], unsigned char[])[0] = PAYLOAD_HEADER_LENGTH;
+ (gVideoBuffer[i], unsigned char[])[1] = frame;
+ /* Set dwPresentationTime */
+ (gVideoBuffer[i], unsigned short[])[1] = pts;
+ (gVideoBuffer[i], unsigned short[])[2] = pts>>16;
+ /* Set scrSourceClock */
+ (gVideoBuffer[i], unsigned short[])[3] = pts;
+ (gVideoBuffer[i], unsigned short[])[4] = pts>>16;
+ (gVideoBuffer[i], unsigned short[])[5] = (sofCounts>>3) & 2047;
+ }
+
+ /* Just to simulate the motion in the video frames */
+ i_split = (i_split - ((WIDTH)*8));
+ if(i_split <= 0) {
+ i_split = MAX_FRAME_SIZE / 6;
+ i_index = (i_index + 1) % 3;
+ }
+ presentationTimer :> tmrValue;
+
+ /* Let the frames scroll */
+ index = i_index;
+ split = i_split;
+
+ /* Transmits single frame */
+ while(expectedPixels > 0)
+ {
+ if(expectedPixels < (PAYLOAD_SIZE - PAYLOAD_HEADER_LENGTH)) {
+ /* Payload transfer */
+ result = XUD_SetBuffer(episo_in, (gVideoBuffer[index], unsigned char[]), expectedPixels+PAYLOAD_HEADER_LENGTH);
+ } else {
+ /* Payload transfer */
+ result = XUD_SetBuffer(episo_in, (gVideoBuffer[index], unsigned char[]), 1024);
+ }
+ /* Note down the SOF counts */
+ sofCounts++;
+
+ expectedPixels -= ((PAYLOAD_SIZE)- PAYLOAD_HEADER_LENGTH);
+
+ if(expectedPixels <= (MAX_FRAME_SIZE - split)) {
+ index = (index + 1) % 3;
+ split += (MAX_FRAME_SIZE / 6);
+ }
+ }
+ frame = frame ^ 1; /* Toggle FID bit */
+ frameCounts++;
+ }
+}
diff --git a/examples/dual_AN00127_video_class/src/uvc_defs.h b/examples/dual_AN00127_video_class/src/uvc_defs.h
new file mode 100644
index 00000000..0c30e6ac
--- /dev/null
+++ b/examples/dual_AN00127_video_class/src/uvc_defs.h
@@ -0,0 +1,78 @@
+// Copyright 2015-2021 XMOS LIMITED.
+// This Software is subject to the terms of the XMOS Public Licence: Version 1.
+
+#ifndef UVC_DEFS_H_
+#define UVC_DEFS_H_
+
+/* USB Video device product defines */
+#define BCD_DEVICE 0x0100
+#define VENDOR_ID 0x20B1
+#define PRODUCT_ID 0x1DE0
+
+/* USB Sub class and Protocol codes */
+#define USB_VIDEO_CONTROL 0x01
+#define USB_VIDEO_STREAMING 0x02
+#define USB_VIDEO_INTERFACE_COLLECTION 0x03
+
+/* Descriptor types */
+#define USB_DESCTYPE_CS_INTERFACE 0x24
+#define USB_DESCTYPE_CS_ENDPOINT 0x25
+
+/* USB Video Control Subtype Descriptors */
+#define USB_VC_HEADER 0x01
+#define USB_VC_INPUT_TERMINAL 0x02
+#define USB_VC_OUPUT_TERMINAL 0x03
+#define USB_VC_SELECTOR_UNIT 0x04
+#define USB_VC_PROCESSING_UNIT 0x05
+
+/* USB Video Streaming Subtype Descriptors */
+#define USB_VS_INPUT_HEADER 0x01
+#define USB_VS_OUPUT_HEADER 0x02
+#define USB_VS_STILL_IMAGE_FRAME 0x03
+#define USB_VS_FORMAT_UNCOMPRESSED 0x04
+#define USB_VS_FRAME_UNCOMPRESSED 0x05
+#define USB_VS_FORMAT_MJPEG 0x06
+#define USB_VS_FRAME_MJPEG 0x07
+
+/* USB Video resolution */
+#define BITS_PER_PIXEL 16
+#define WIDTH 480
+#define HEIGHT 320
+
+/* Frame rate */
+#define FPS 30
+
+#define MAX_FRAME_SIZE (WIDTH * HEIGHT * BITS_PER_PIXEL / 8)
+#define MIN_BIT_RATE (MAX_FRAME_SIZE * FPS * 8)
+#define MAX_BIT_RATE (MIN_BIT_RATE)
+#define PAYLOAD_SIZE (1 * 1024)
+
+/* Interval defined in 100ns units */
+#define FRAME_INTERVAL (10000000/FPS)
+
+/* To split numbers into Little Endian format */
+#define WORD_CHARS(x) (x&0xff), ((x>>8)&0xff), ((x>>16)&0xff), ((x>>24)&0xff)
+#define SHORT_CHARS(x) (x&0xff), ((x>>8)&0xff)
+
+/* Endpoint Addresses for Video device */
+#define VIDEO_STATUS_EP_NUM 1 /* (0x81) */
+#define VIDEO_DATA_EP_NUM 2 /* (0x82) */
+
+/* Video Class-specific Request codes */
+#define SET_CUR 0x01
+#define GET_CUR 0x81
+#define GET_MIN 0x82
+#define GET_MAX 0x83
+#define GET_RES 0x84
+#define GET_LEN 0x85
+#define GET_INFO 0x86
+#define GET_DEF 0x87
+
+/* Video Streaming Interface Control selectors */
+#define VS_PROBE_CONTROL 0x01
+#define VS_COMMIT_CONTROL 0x02
+
+/* Video Stream related */
+#define PAYLOAD_HEADER_LENGTH 12
+
+#endif /* UVC_DEFS_H_ */
diff --git a/examples/dual_AN00127_video_class/src/uvc_req.c b/examples/dual_AN00127_video_class/src/uvc_req.c
new file mode 100644
index 00000000..06a23f9c
--- /dev/null
+++ b/examples/dual_AN00127_video_class/src/uvc_req.c
@@ -0,0 +1,113 @@
+// Copyright 2015-2021 XMOS LIMITED.
+// This Software is subject to the terms of the XMOS Public Licence: Version 1.
+
+#include
+#include "uvc_req.h"
+#include "uvc_defs.h"
+
+UVC_ProbeCommit_Ctrl_t dataProbeCommit;
+
+/* Initializes Probe/Commit control parameters with defaul values */
+void UVC_InitProbeCommitData()
+{
+ dataProbeCommit.bmHint = 0;
+ dataProbeCommit.bFormatIndex = 0x01;
+ dataProbeCommit.bFrameIndex = 0x01;
+ dataProbeCommit.dwFrameInterval = FRAME_INTERVAL;
+ dataProbeCommit.wKeyFrameRate = 0;
+ dataProbeCommit.wPFrameRate = 0;
+ dataProbeCommit.wCompQuality = 0;
+ dataProbeCommit.wCompWindowSize = 0;
+ dataProbeCommit.wDelay = 0;
+ dataProbeCommit.dwMaxVideoFrameSize = MAX_FRAME_SIZE;
+ dataProbeCommit.dwMaxPayloadTransferSize = PAYLOAD_SIZE;
+ dataProbeCommit.dwClockFrequency = 100000000;
+}
+
+
+/* Video Class-specific requests handler function */
+XUD_Result_t UVC_InterfaceClassRequests(XUD_ep ep_out, XUD_ep ep_in, USB_SetupPacket_t *sp)
+{
+ /* Word aligned buffer */
+ unsigned int probe_buffer[16];
+ unsigned int buffer[16];
+ unsigned int length;
+ XUD_Result_t result = XUD_RES_ERR;
+
+#if defined (DEBUG) && (DEBUG == 1)
+ printhexln(sp->bRequest);
+#endif
+
+ switch(sp->bRequest)
+ {
+ case SET_CUR:
+ /* VideoStreaming Interface */
+ if(sp->wIndex == 0x01)
+ {
+ switch((sp->wValue >> 8) & 0xFF)
+ {
+ /* Negotiation of Video parameters */
+ case VS_COMMIT_CONTROL:
+ case VS_PROBE_CONTROL:
+ /* Get the parameters in Probe buffer */
+ if((result = XUD_GetBuffer(ep_out, (unsigned char *) probe_buffer, &length)) != XUD_RES_OKAY)
+ {
+ return result;
+ }
+ /* Set the given parameters */
+ if(length == sizeof(dataProbeCommit)) {
+ //memcpy(((unsigned char *) &dataProbeCommit)+2, ((unsigned char*)probe_buffer)+2, length-2);
+ }
+ break;
+ }
+ }
+ else
+ {
+ if((result = XUD_GetBuffer(ep_out, (unsigned char *) buffer, &length)) != XUD_RES_OKAY)
+ {
+ return result;
+ }
+ }
+
+ result = XUD_DoSetRequestStatus(ep_in);
+ return result;
+ break;
+
+ case GET_DEF:
+ case GET_MIN:
+ case GET_MAX:
+ case GET_CUR:
+ /* VideoControl Interface */
+ if(sp->wIndex == 0x00)
+ {
+ /* Handle VideoControl interface requests here */
+ }
+ /* VideoStreaming Interface */
+ else if(sp->wIndex == 0x01)
+ {
+ switch((sp->wValue >> 8) & 0xFF)
+ {
+ case VS_PROBE_CONTROL:
+ if(sp->wLength <= sizeof(dataProbeCommit)) {
+ length = sp->wLength;
+ result = XUD_DoGetRequest(ep_out, ep_in, (unsigned char *) (&dataProbeCommit), length, sp->wLength);
+ return result;
+ }
+ break;
+
+ default:
+ // Unknown command
+ break;
+ }
+ }
+ break;
+
+ default:
+ // Error case
+ printhexln(sp->bRequest);
+ return result;
+ break;
+ }
+ return XUD_RES_ERR;
+}
+
diff --git a/examples/dual_AN00127_video_class/src/uvc_req.h b/examples/dual_AN00127_video_class/src/uvc_req.h
new file mode 100644
index 00000000..09c24420
--- /dev/null
+++ b/examples/dual_AN00127_video_class/src/uvc_req.h
@@ -0,0 +1,44 @@
+// Copyright 2015-2021 XMOS LIMITED.
+// This Software is subject to the terms of the XMOS Public Licence: Version 1.
+
+#ifndef UVC_REQ_H_
+#define UVC_REQ_H_
+
+#include
+#include "xud_device.h"
+
+/* Video Class-specific requests definitions */
+
+#ifdef __STDC__
+
+/* Video Probe and Commit Controls (Table 4-47 , UVC 1.1) */
+typedef struct
+{
+ unsigned short bmHint;
+ unsigned char bFormatIndex;
+ unsigned char bFrameIndex;
+ unsigned int dwFrameInterval;
+ unsigned short wKeyFrameRate;
+ unsigned short wPFrameRate;
+ unsigned short wCompQuality;
+ unsigned short wCompWindowSize;
+ unsigned short wDelay;
+ unsigned int dwMaxVideoFrameSize;
+ unsigned int dwMaxPayloadTransferSize;
+ unsigned int dwClockFrequency;
+ unsigned char bmFramingInfo;
+ unsigned char bPreferedVersion;
+ unsigned char bMinVersion;
+ unsigned char bMaxVersion;
+} __attribute__((packed)) UVC_ProbeCommit_Ctrl_t;
+
+extern UVC_ProbeCommit_Ctrl_t dataProbeCommit;
+
+#endif
+
+void UVC_InitProbeCommitData();
+
+XUD_Result_t UVC_InterfaceClassRequests(XUD_ep ep_out, XUD_ep ep_in, REFERENCE_PARAM(USB_SetupPacket_t,sp));
+
+
+#endif /* UVC_REQ_H_ */
diff --git a/examples/dual_AN00127_video_class/src/xud_wrapper.c b/examples/dual_AN00127_video_class/src/xud_wrapper.c
new file mode 100644
index 00000000..96f68acc
--- /dev/null
+++ b/examples/dual_AN00127_video_class/src/xud_wrapper.c
@@ -0,0 +1,27 @@
+#include
+#include
+
+#include "xud.h"
+#include "usb_video.h"
+
+
+int XUD_Main_wrapper(chanend c_epOut[], int noEpOut,
+ chanend c_epIn[], int noEpIn,
+ NULLABLE_RESOURCE(chanend, c_sof),
+ XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[],
+ XUD_BusSpeed_t desiredSpeed,
+ XUD_PwrConfig pwrConfig
+){
+
+ return XUD_Main(c_epOut, noEpOut, c_epIn, noEpIn,
+ c_sof, epTypeTableOut, epTypeTableIn,
+ desiredSpeed, pwrConfig);
+}
+
+void Endpoint0_wrapper(chanend chan_ep0_out, chanend chan_ep0_in, unsigned short PID){
+ Endpoint0(chan_ep0_out, chan_ep0_in, PID);
+}
+
+void VideoEndpointsHandler_wrapper(chanend c_epint_in, chanend c_episo_in, unsigned instance){
+ VideoEndpointsHandler(c_epint_in, c_episo_in, instance);
+}
diff --git a/examples/dual_AN00127_video_class/src/xud_wrapper.h b/examples/dual_AN00127_video_class/src/xud_wrapper.h
new file mode 100644
index 00000000..3c34d530
--- /dev/null
+++ b/examples/dual_AN00127_video_class/src/xud_wrapper.h
@@ -0,0 +1,15 @@
+#include
+
+#include "xud.h"
+#include "usb_video.h"
+
+
+int XUD_Main_wrapper(chanend c_epOut[], int noEpOut,
+ chanend c_epIn[], int noEpIn,
+ NULLABLE_RESOURCE(chanend, c_sof),
+ XUD_EpType epTypeTableOut[], XUD_EpType epTypeTableIn[],
+ XUD_BusSpeed_t desiredSpeed,
+ XUD_PwrConfig pwrConfig);
+
+void Endpoint0_wrapper(chanend chan_ep0_out, chanend chan_ep0_in, unsigned short PID);
+void VideoEndpointsHandler_wrapper(chanend c_epint_in, chanend c_episo_in, unsigned instance);
diff --git a/lib_xud/api/xud.h b/lib_xud/api/xud.h
index 72842308..45daaa80 100644
--- a/lib_xud/api/xud.h
+++ b/lib_xud/api/xud.h
@@ -71,6 +71,10 @@
#endif
#endif // PORT_USB_CLK
+#ifndef XUD_EXTERNAL_RESOURCES
+#define XUD_EXTERNAL_RESOURCES 0
+#endif
+
/**
* \var typedef XUD_EpTransferType
* \brief Typedef for endpoint data transfer types. Note: it is important that ISO is 0
@@ -120,6 +124,22 @@ typedef enum XUD_Result
XUD_RES_ERR = 2,
} XUD_Result_t;
+/* All of the resources accessed by XUD */
+typedef struct XUD_resources_t
+{
+ port flag0_port;
+ port flag1_port;
+ NULLABLE_RESOURCE(port, flag2_port);
+ in_buffered_port_32_t p_usb_clk;
+ out_buffered_port_32_t p_usb_txd;
+ in_buffered_port_32_t p_usb_rxd ;
+ port tx_readyout;
+ port tx_readyin;
+ port rx_rdy;
+ xcore_clock_t tx_usb_clk;
+ xcore_clock_t rx_usb_clk;
+} XUD_resources_t;
+
/** This performs the low-level USB I/O operations. Note that this
* needs to run in a thread with at least 80 MIPS worst case execution
* speed.
@@ -516,5 +536,15 @@ typedef struct XUD_ep_info
unsigned int array_ptr_setup; // 12
} XUD_ep_info;
-#endif
+/**
+ * \brief Resource initialisation for cases where we have multiple instances of XUD in a project.
+ * This is only relevant when the XUD_EXTERNAL_RESOURCES define is set to non-zero.
+ * This MUST be called prior to running XUD_Main otherwise XUD will assert 0.
+ * \param resources A struct of type XUD_resources_t declared in XC by the user application
+ * containing the XUD resources (see XUD_resources_t). These must be placed on a specific tile.
+ */
+void init_xud_resources(REFERENCE_PARAM(XUD_resources_t, resources));
+
+#endif // __ASSEMBLER__
+
#endif // _XUD_H_
diff --git a/lib_xud/src/core/XUD_DeviceAttach.xc b/lib_xud/src/core/XUD_DeviceAttach.xc
index d1808327..29822b37 100755
--- a/lib_xud/src/core/XUD_DeviceAttach.xc
+++ b/lib_xud/src/core/XUD_DeviceAttach.xc
@@ -8,10 +8,6 @@
#include "XUD_TimingDefines.h"
#include "XUD_HAL.h"
-extern in port flag0_port;
-extern in port flag1_port;
-extern in port flag2_port;
-extern out buffered port:32 p_usb_txd;
#define TUCHEND_DELAY_us (1500) // 1.5ms
#define TUCHEND_DELAY (TUCHEND_DELAY_us * PLATFORM_REFERENCE_MHZ)
@@ -23,6 +19,7 @@ extern out buffered port:32 p_usb_txd;
#define INVALID_DELAY (INVALID_DELAY_us * PLATFORM_REFERENCE_MHZ)
extern int resetCount;
+extern XUD_resources_t XUD_resources;
/* Assumptions:
* - In full speed mode
@@ -37,8 +34,7 @@ int XUD_DeviceAttachHS(XUD_PwrConfig pwrConfig)
int detecting_k = 1;
int tx;
unsigned int chirpCount = 0;
-
- clearbuf(p_usb_txd);
+ clearbuf(XUD_resources.p_usb_txd);
/* On detecting the SE0 move into chirp mode */
XUD_HAL_EnterMode_PeripheralChirp();
@@ -49,15 +45,13 @@ int XUD_DeviceAttachHS(XUD_PwrConfig pwrConfig)
#else
for (int i = 0; i < 16000; i++) // 16000 words @ 480 MBit = 1.066 ms
#endif
- {
- p_usb_txd <: 0;
- }
-
+ XUD_resources.p_usb_txd <: 0;
+
// J, K, SE0 on flag ports 0, 1, 2 respectively (on XS2)
// XS3 has raw linestate on flag port 0 and 1
// Wait for fs chirp k (i.e. HS chirp j)
#if defined(__XS2A__)
- flag1_port when pinseq(0) :> tmp; // Wait for out k to go
+ XUD_resources.flag1_port when pinseq(0) :> tmp; // Wait for out k to go
#endif
t :> start_time;
@@ -76,8 +70,8 @@ int XUD_DeviceAttachHS(XUD_PwrConfig pwrConfig)
/* TODO Use a timer to save some juice...*/
#if !defined(__XS2A__)
unsigned dp, dm;
- flag0_port :> dm;
- flag1_port :> dp;
+ XUD_resources.flag0_port :> dm;
+ XUD_resources.flag1_port :> dp;
if(dp || dm)
{
@@ -85,7 +79,7 @@ int XUD_DeviceAttachHS(XUD_PwrConfig pwrConfig)
return 0;
}
#else
- flag2_port :> tmp;
+ XUD_resources.flag2_port :> tmp;
if(!tmp)
{
@@ -106,11 +100,11 @@ int XUD_DeviceAttachHS(XUD_PwrConfig pwrConfig)
#if !defined(__XS2A__)
// Note, J and K definitions are reversed in XS3A
-#define j_port flag1_port
-#define k_port flag0_port
+#define j_port XUD_resources.flag1_port
+#define k_port XUD_resources.flag0_port
#else
-#define k_port flag1_port
-#define j_port flag0_port
+#define k_port XUD_resources.flag1_port
+#define j_port XUD_resources.flag0_port
#endif
case detecting_k => k_port when pinseq(1):> void @ tx: // K Chirp
k_port @ tx + T_FILT_ticks :> tmp;
@@ -137,7 +131,7 @@ int XUD_DeviceAttachHS(XUD_PwrConfig pwrConfig)
// TODO ideally dont use a polling loop here
while (XUD_HAL_GetLineState() != XUD_LINESTATE_SE0);
#else
- flag2_port when pinseq(1) :> tmp;
+ XUD_resources.flag2_port when pinseq(1) :> tmp;
#endif
/* Return 1 to indicate successful HS handshake*/
diff --git a/lib_xud/src/core/XUD_HAL.xc b/lib_xud/src/core/XUD_HAL.xc
index 32ad1961..f70b4da4 100644
--- a/lib_xud/src/core/XUD_HAL.xc
+++ b/lib_xud/src/core/XUD_HAL.xc
@@ -10,14 +10,9 @@
#include "xs1_to_glx.h"
#include "xs2_su_registers.h"
#include "XUD_USBTile_Support.h"
-extern in port flag0_port;
-extern in port flag1_port;
-extern in port flag2_port;
-extern buffered in port:32 p_usb_clk;
+
#else
-extern in port flag0_port; /* For XS3: RXA or DP */
-extern in port flag1_port; /* For XS3: RXE or DM */
-extern buffered in port:32 p_usb_clk;
+
void XUD_SetCrcTableAddr(unsigned addr);
unsigned XtlSelFromMhz(unsigned m)
{ // NOCOVER
@@ -48,7 +43,8 @@ unsigned XtlSelFromMhz(unsigned m)
return 0b000;
}
#endif
-extern clock rx_usb_clk;
+
+extern XUD_resources_t XUD_resources;
unsigned int XUD_EnableUsbPortMux();
@@ -88,10 +84,10 @@ void XUD_HAL_EnableUsb(unsigned pwrConfig)
#endif
/* Wait for USB clock (typically 1ms after reset) */
- p_usb_clk when pinseq(1) :> int _;
- p_usb_clk when pinseq(0) :> int _;
- p_usb_clk when pinseq(1) :> int _;
- p_usb_clk when pinseq(0) :> int _;
+ XUD_resources.p_usb_clk when pinseq(1) :> int _;
+ XUD_resources.p_usb_clk when pinseq(0) :> int _;
+ XUD_resources.p_usb_clk when pinseq(1) :> int _;
+ XUD_resources.p_usb_clk when pinseq(0) :> int _;
#ifdef __XS2A__
/* Some extra settings are required for proper operation on XS2A */
@@ -210,6 +206,7 @@ void XUD_HAL_EnterMode_PeripheralHighSpeed_Start()
write_periph_word_two_part_start((chanend)c, USB_TILE_REF, XS1_SU_PER_UIFM_CHANEND_NUM, XS1_SU_PER_UIFM_FUNC_CONTROL_NUM, 0);
}
}
+
void XUD_HAL_EnterMode_PeripheralHighSpeed_Complete()
{
unsafe
@@ -288,11 +285,11 @@ void XUD_HAL_EnterMode_TristateDrivers()
void XUD_HAL_Mode_Signalling()
{
/* Reset port to use XS1_CLKBLK_REF (from rx_usb_clk) */
- set_port_use_on(flag1_port);
+ set_port_use_on(XUD_resources.flag1_port);
#ifdef __XS2A__
/* For XS2 we invert VALID_TOKEN port for data-transfer mode, so undo this for signalling */
- set_port_no_inv(flag2_port);
+ set_port_no_inv(XUD_resources.flag2_port);
write_periph_word(USB_TILE_REF, XS1_GLX_PER_UIFM_CHANEND_NUM, XS1_GLX_PER_UIFM_MASK_NUM,
((1< j;
- flag1_port :> k;
- flag2_port :> se0;
+ XUD_resources.flag0_port :> j;
+ XUD_resources.flag1_port :> k;
+ XUD_resources.flag2_port :> se0;
if(j)
return XUD_LINESTATE_HS_J_FS_K;
@@ -390,11 +387,11 @@ unsigned XUD_HAL_WaitForLineStateChange(XUD_LineState_t ¤tLs, unsigned tim
/* Wait for a change on any flag port */
select
{
- case flag0_port when pinsneq(j) :> void:
+ case XUD_resources.flag0_port when pinsneq(j) :> void:
break;
- case flag1_port when pinsneq(k) :> void:
+ case XUD_resources.flag1_port when pinsneq(k) :> void:
break;
- case flag2_port when pinsneq(se0) :> void:
+ case XUD_resources.flag2_port when pinsneq(se0) :> void:
break;
case timeout != null => t when timerafter(time + timeout) :> int _:
return 1;
diff --git a/lib_xud/src/core/XUD_Main.xc b/lib_xud/src/core/XUD_Main.xc
index ef53f213..aaa9e2ec 100755
--- a/lib_xud/src/core/XUD_Main.xc
+++ b/lib_xud/src/core/XUD_Main.xc
@@ -10,6 +10,7 @@
#include
#include
#include
+#include
#include "xud.h" /* External user include file */
#include "XUD_USB_Defines.h"
@@ -39,25 +40,42 @@ unsigned g_curSpeed;
unsigned g_desSpeed;
unsigned g_txHandshakeTimeout;
-in port flag0_port = PORT_USB_FLAG0; /* For XS3: Mission: RXE, XS2 is configurable and set to RXE in mission mode */
-in port flag1_port = PORT_USB_FLAG1; /* For XS3: Mission: RXA, XS2 is configuratble and set to RXA in mission mode*/
+#if !XUD_EXTERNAL_RESOURCES
/* XS2A has an additonal flag port. In Mission mode this is set to VALID_TOKEN */
#ifdef __XS2A__
-in port flag2_port = PORT_USB_FLAG2;
+#define FLAG2_PORT PORT_USB_FLAG2
#else
-#define flag2_port null
+#define FLAG2_PORT null
#endif
-in buffered port:32 p_usb_clk = PORT_USB_CLK;
-out buffered port:32 p_usb_txd = PORT_USB_TXD;
-in buffered port:32 p_usb_rxd = PORT_USB_RXD;
-out port tx_readyout = PORT_USB_TX_READYOUT;
-in port tx_readyin = PORT_USB_TX_READYIN;
-in port rx_rdy = PORT_USB_RX_READY;
+XUD_resources_t XUD_resources = {
+ PORT_USB_FLAG0, /* For XS3: Mission: RXE, XS2 is configurable and set to RXE in mission mode */
+ PORT_USB_FLAG1, /* For XS3: Mission: RXA, XS2 is configuratble and set to RXA in mission mode*/
+ FLAG2_PORT,
+ PORT_USB_CLK,
+ PORT_USB_TXD,
+ PORT_USB_RXD,
+ PORT_USB_TX_READYOUT,
+ PORT_USB_TX_READYIN,
+ PORT_USB_RX_READY,
+ on USB_TILE: XS1_CLKBLK_4,
+ on USB_TILE: XS1_CLKBLK_5
+};
-on USB_TILE: clock tx_usb_clk = XS1_CLKBLK_4;
-on USB_TILE: clock rx_usb_clk = XS1_CLKBLK_5;
+#else
+
+extern XUD_resources_t XUD_resources;
+
+#endif
+
+/* These are globals to allow assembler functions to access resource IDs
+ using the DP relative addressing mode*/
+int rx_rdy = 0;
+int flag1_port = 0;
+int flag2_port = 0;
+int p_usb_rxd = 0;
+int p_usb_txd = 0;
// We use a single array instrad of two here and append epAddr_Ready_setup on the end to save some instructions in the Setup
// token handling code. i.e. what we really want is the following, but's less efficient.
@@ -155,14 +173,16 @@ static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epAddr_Ready[], chane
int reset = 1; /* Flag for if device is returning from a reset */
/* Make sure ports are on and reset port states */
- set_port_use_on(p_usb_clk);
- set_port_use_on(p_usb_txd);
- set_port_use_on(p_usb_rxd);
- set_port_use_on(flag0_port);
- set_port_use_on(flag1_port);
+ set_port_use_on(XUD_resources.p_usb_clk);
+ set_port_use_on(XUD_resources.p_usb_txd);
+ set_port_use_on(XUD_resources.p_usb_rxd);
+ set_port_use_on(XUD_resources.flag0_port);
+ set_port_use_on(XUD_resources.flag1_port);
+
+
#if defined(__XS2A__)
/* Extra flag port in XS2 */
- set_port_use_on(flag2_port);
+ set_port_use_on(XUD_resources.flag2_port);
#endif
#if !defined(__XS2A__)
@@ -208,38 +228,39 @@ static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epAddr_Ready[], chane
#endif
// Handshaken ports need USB clock
- configure_clock_src(tx_usb_clk, p_usb_clk);
- configure_clock_src(rx_usb_clk, p_usb_clk);
+ configure_clock_src(XUD_resources.tx_usb_clk, XUD_resources.p_usb_clk);
+ configure_clock_src(XUD_resources.rx_usb_clk, XUD_resources.p_usb_clk);
// This, along with the following delays, forces the clock
// to the ports to be effectively controlled by the
// previous usb clock edges
- set_port_inv(p_usb_clk);
- set_port_sample_delay(p_usb_clk);
+ set_port_inv(XUD_resources.p_usb_clk);
+ set_port_sample_delay(XUD_resources.p_usb_clk);
// This delay controls the capture of rdy
- set_clock_rise_delay(tx_usb_clk, TX_RISE_DELAY);
+ set_clock_rise_delay(XUD_resources.tx_usb_clk, TX_RISE_DELAY);
// This delay controls the launch of data.
- set_clock_fall_delay(tx_usb_clk, TX_FALL_DELAY);
+ set_clock_fall_delay(XUD_resources.tx_usb_clk, TX_FALL_DELAY);
// This delay the capture of the rdyIn and data.
- set_clock_rise_delay(rx_usb_clk, RX_RISE_DELAY);
- set_clock_fall_delay(rx_usb_clk, RX_FALL_DELAY);
+ set_clock_rise_delay(XUD_resources.rx_usb_clk, RX_RISE_DELAY);
+ set_clock_fall_delay(XUD_resources.rx_usb_clk, RX_FALL_DELAY);
- set_pad_delay(flag1_port, 2);
+ set_pad_delay(XUD_resources.flag1_port, 2);
- start_clock(tx_usb_clk);
- start_clock(rx_usb_clk);
+ start_clock(XUD_resources.tx_usb_clk);
+ start_clock(XUD_resources.rx_usb_clk);
- configure_out_port_handshake(p_usb_txd, tx_readyin, tx_readyout, tx_usb_clk, 0);
- configure_in_port_strobed_slave(p_usb_rxd, rx_rdy, rx_usb_clk);
+ configure_out_port_handshake(XUD_resources.p_usb_txd, XUD_resources.tx_readyin, XUD_resources.tx_readyout, XUD_resources.tx_usb_clk, 0);
+ configure_in_port_strobed_slave(XUD_resources.p_usb_rxd, XUD_resources.rx_rdy, XUD_resources.rx_usb_clk);
/* Clock RxA port from USB clock - helps fall event */
- configure_in_port(flag1_port, rx_usb_clk);
+ configure_in_port(XUD_resources.flag1_port, XUD_resources.rx_usb_clk);
unsigned noExit = 1;
+
while(noExit)
{
unsigned settings[] = {0};
@@ -400,7 +421,18 @@ static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epAddr_Ready[], chane
/* flag0: Rx Error
flag1: Rx Active
flag2: Null / Valid Token */
- noExit = XUD_LLD_IoLoop(p_usb_rxd, flag1_port, p_usb_txd, flag0_port, flag2_port, epTypeTableOut, epTypeTableIn, epAddr_Ready, noEpOut, c_sof);
+ unsafe{
+ noExit = XUD_LLD_IoLoop(XUD_resources.p_usb_rxd,
+ XUD_resources.flag1_port,
+ XUD_resources.p_usb_txd,
+ XUD_resources.flag0_port,
+ XUD_resources.flag2_port,
+ epTypeTableOut,
+ epTypeTableIn,
+ epAddr_Ready,
+ noEpOut,
+ c_sof);
+ }
set_thread_fast_mode_off();
@@ -411,15 +443,18 @@ static int XUD_Manager_loop(XUD_chan epChans0[], XUD_chan epAddr_Ready[], chane
/* TODO stop clock blocks */
+ unsafe{
+
/* Turn ports off */
- set_port_use_off(p_usb_txd);
- set_port_use_off(p_usb_rxd);
- set_port_use_off(flag0_port);
- set_port_use_off(flag1_port);
+ set_port_use_off(XUD_resources.p_usb_txd);
+ set_port_use_off(XUD_resources.p_usb_rxd);
+ set_port_use_off(XUD_resources.flag0_port);
+ set_port_use_off(XUD_resources.flag1_port);
#ifdef __XS2A__
- set_port_use_off(flag2_port);
+ set_port_use_off(XUD_resources.flag2_port);
#endif
- set_port_use_off(p_usb_clk);
+ set_port_use_off(XUD_resources.p_usb_clk);
+ } // unsafe
return 0;
}
@@ -559,7 +594,6 @@ void SetupEndpoints(chanend c_ep_out[], int noEpOut, chanend c_ep_in[], int noEp
}
}
-
#pragma unsafe arrays
int XUD_Main(chanend c_ep_out[], int noEpOut,
chanend c_ep_in[], int noEpIn,
@@ -569,6 +603,15 @@ int XUD_Main(chanend c_ep_out[], int noEpOut,
{
g_desSpeed = speed;
+ /* Ensure global resids accessed by ASM are initt'd */
+ unsafe{
+ rx_rdy = (int)XUD_resources.rx_rdy;
+ flag1_port = (int)XUD_resources.flag1_port;
+ flag2_port = (int)XUD_resources.flag2_port;
+ p_usb_rxd = (int)XUD_resources.p_usb_rxd;
+ p_usb_txd = (int)XUD_resources.p_usb_txd;
+ }
+
SetupEndpoints(c_ep_out, noEpOut, c_ep_in, noEpIn, epTypeTableOut, epTypeTableIn);
#if 0
diff --git a/lib_xud/src/core/XUD_TestMode.xc b/lib_xud/src/core/XUD_TestMode.xc
index 1b588af1..b658b399 100644
--- a/lib_xud/src/core/XUD_TestMode.xc
+++ b/lib_xud/src/core/XUD_TestMode.xc
@@ -5,7 +5,7 @@
#include "xud.h"
#include "XUD_TestMode.h"
-extern out buffered port:32 p_usb_txd;
+extern XUD_resources_t XUD_resources;
#define T_INTER_TEST_PACKET_us 2
#define T_INTER_TEST_PACKET (T_INTER_TEST_PACKET_us * PLATFORM_REFERENCE_MHZ)
@@ -40,7 +40,7 @@ int XUD_UsbTestModeHandler(unsigned cmd)
while(1)
{
- p_usb_txd <: 0xffffffff;
+ XUD_resources.p_usb_txd <: 0xffffffff;
}
break;
@@ -50,7 +50,7 @@ int XUD_UsbTestModeHandler(unsigned cmd)
while(1)
{
- p_usb_txd <: 0;
+ XUD_resources.p_usb_txd <: 0;
}
break;
@@ -78,9 +78,9 @@ int XUD_UsbTestModeHandler(unsigned cmd)
#pragma loop unroll
for (i=0; i < sizeof(test_packet)/sizeof(test_packet[0]); i++)
{
- p_usb_txd <: test_packet[i];
+ XUD_resources.p_usb_txd <: test_packet[i];
};
- sync(p_usb_txd);
+ sync(XUD_resources.p_usb_txd);
test_packet_timer :> i;
test_packet_timer when timerafter (i + T_INTER_TEST_PACKET) :> int _;
}
diff --git a/lib_xud/src/core/XUD_resources.c b/lib_xud/src/core/XUD_resources.c
new file mode 100644
index 00000000..f9414265
--- /dev/null
+++ b/lib_xud/src/core/XUD_resources.c
@@ -0,0 +1,20 @@
+#include
+#include "xud.h"
+
+/* This is the global declaration of the resources struct used to keep
+ the resource IDs of this instance of XUD. Needs initialising if
+ multiple instances of XUD are used and XUD_EXTERNAL_RESOURCES defined.
+ This needs to be declared in C to avoid checks and is initialised
+ before the call to XUD_Main */
+
+#if XUD_EXTERNAL_RESOURCES
+XUD_resources_t XUD_resources = {0};
+#endif
+
+
+extern XUD_resources_t XUD_resources;
+
+void init_xud_resources(XUD_resources_t * resources)
+{
+ memcpy(&XUD_resources, resources, sizeof(XUD_resources_t));
+}
\ No newline at end of file