Basic usage#
Basic use is termed to mean each endpoint runs in its own dedicated thread. Multiple endpoints in a single thread are possible, please see Advanced usage.
Operation is synchronous in nature: The endpoint tasks make calls to blocking functions and waits for the transfer to complete before proceeding.
XUD IO task#
XUD_Main()
is the main task that interfaces with the USB transceiver.
It performs connection and handshaking on the USB bus as well as other bus-states such
as suspend and resume. It also handles passing packets to/from the various endpoints.
This function should be called directly from the top-level par
statement in main()
to
ensure that the XUD library is ready within the 100ms allowed by the USB specification (assuming a
bus-powered device).
-
int XUD_Main(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)#
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.
- Parameters:
c_epOut – An array of channel ends, one channel end per output endpoint (USB OUT transaction); this includes a channel to obtain requests on Endpoint 0.
noEpOut – The number of output endpoints, should be at least 1 (for Endpoint 0).
c_epIn – An array of channel ends, one channel end per input endpoint (USB IN transaction); this includes a channel to respond to requests on Endpoint 0.
noEpIn – The number of input endpoints, should be at least 1 (for Endpoint 0).
c_sof – A channel to receive SOF tokens on. This channel must be connected to a process that can receive a token once every 125 ms. If tokens are not read, the USB layer will lock up. If no SOF tokens are required
null
should be used for this parameter.epTypeTableOut – See
epTypeTableIn
.epTypeTableIn – This and
epTypeTableOut
are two arrays indicating the type of the endpoint. Legal types include:XUD_EPTYPE_CTL
(Endpoint 0),XUD_EPTYPE_BUL
(Bulk endpoint),XUD_EPTYPE_ISO
(Isochronous endpoint),XUD_EPTYPE_INT
(Interrupt endpoint),XUD_EPTYPE_DIS
(Endpoint not used). The first array contains the endpoint types for each of the OUT endpoints, the second array contains the endpoint types for each of the IN endpoints.desiredSpeed – This parameter specifies what speed the device will attempt to run at i.e. full-speed (ie 12Mbps) or high-speed (480Mbps) if supported by the host. Pass
XUD_SPEED_HS
if high-speed is desired orXUD_SPEED_FS
if not. Low speed USB is not supported by XUD.pwrConfig – Specifies whether the device is bus or self-powered. When self-powered the XUD will monitor the VBUS line for host disconnections. This is required for compliance reasons. Valid values are XUD_PWR_SELF and XUD_PWR_BUS.
Endpoint type tables#
The endpoint type tables are arrays of type XUD_EpType
and are used to inform lib_xud
about the endpoints in use. This information is used to indicate the transfer-type of each endpoint
(bulk, control, isochronous or interrupt) as well as whether the endpoint wishes to be informed
about bus-resets (see Status Reporting). Two tables are required, one for IN and one for OUT
endpoints.
Suitable values are provided in the XUD_EpTransferType
enum:
XUD_EPTYPE_ISO
: Isochronous endpoint
XUD_EPTYPE_INT
: Interrupt endpoint
XUD_EPTYPE_BUL
: Bulk endpoint
XUD_EPTYPE_CTL
: Control endpoint
XUD_EPTYPE_DIS
: Disabled endpoint
OUT endpoint N will use index N of the output-endpoint-table, IN endpoint 0x8N will use index N of the inpout-endpoint-table. Endpoint 0 must exist in both tables.
..note:
Endpoints that are not used will ``NAK`` any traffic from the host.
PwrConfig
#
The PwrConfig
parameter to XUD_Main()
indicates if the device is bus or self-powered.
Valid values for this parameter are XUD_PWR_SELF
and XUD_PWR_BUS
.
When XUD_PWR_SELF
is used, XUD_Main()
monitors the VBUS input for a valid voltage and
responds appropriately. The USB Specification states that the devices pull-ups must be disabled
when a valid VBUS is not present. This is important when submitting a device for compliance
testing since this is explicitly tested.
If the device is bus-powered XUD_PWR_BUS
can be used since it is assumed that the device is not
powered up when VBUS is not present and therefore no voltage monitoring is required. In this
configuration the VBUS input to the device/PHY need not be present.
XUD_PWR_BUS
can be used in order to run on a self-powered board without provision for VBUS
wiring to the PHY/device, but this is not advised and is not USB specification compliant.
VBUS monitoring#
For self-powered devices it is important that lib_xud
is aware of the VBUS state.
This allows the device to disconnect its pull-up resistors from D+/D- and ensure the device does not
have any voltage on the D+/D- pins when VBUS is not present. Compliance testing specifically
checks for this in the USB Back Voltage test.
Warning
Failure to conform to this requirement will lead to an uncompliant device and likely lead to interoperability issues.
USB-enabled xcore-200 series devices have a dedicated VBUS pin which should be wired up as per the data-sheet recommendations including over-voltage protection.
For increasing flexibility, xcore.ai series devices do not have a dedicated VBUS pin. A generic IO port/pin should be used for this purpose (with appropriate external circuitry - see data-sheet recommendations).
lib_xud
makes a call to a function XUD_HAL_GetVBusState()
that which should be implemented
to match the target hardware. For example:
on tile[XUD_TILE]: in port p_vbus = XS1_PORT_1P;
unsigned int XUD_HAL_GetVBusState(void)
{
unsigned vBus;
p_vbus :> vBus;
return vBus;
}
The function should return 1 if VBUS is present, otherwise 0. In the case of the example above, the validity of VBUS is directly represented by the value on port 1P, however, this may not be the case for all hardware implementations, it could be inverted or even require a read from an external IO expander, for example.
Note
VBUS need not be connected if the device is wholly powered by USB i.e. a bus powered device.
USB_TILE define#
In order that lib_xua
may instantiate resources on the correct tile (typically ports) it
requires a USB_TILE
define to be set. The default value for the define is tile[0]
so a
developer only needs to set this if XUD_Main()
is executing on a tile other than 0.
There are two ways of setting this define, either in the application CMakeLists.txt for example:
set(APP_COMPILER_FLAGS -DXUD_TILE=tile[0])
Or, following XMOS software library convention, providing a xud_conf.h file in the application
codebase. This header file will be automatically detected by the build system and used by
lib_xud
. Example content for this header file is as follows:
#indef _XUD_CONF_H_
#define _XUD_CONF_H_
#define XUD_TILE tile[0]
#endif
Data transfer#
Communication state between an endpoint client task and the XUD IO task is encapsulated in an opaque type:
-
typedef unsigned int XUD_ep#
Typedef for endpoint identifiers.
All client calls communicating with the XUD library pass in this type. These data structures can be created at the start of execution of a client task with the following call that takes as an argument the endpoint channel connected to the XUD library:
-
XUD_ep XUD_InitEp(chanend c_ep)#
Initialises an XUD_ep.
- Parameters:
c_ep – Endpoint channel to be connected to the XUD library.
- Returns:
Endpoint identifier
Endpoint data is sent/received using three main functions, XUD_SetBuffer()
, XUD_GetBuffer()
and XUD_GetSetupBuffer()
.
These functions implement the low-level shared memory/channel communication with the XUD_Main()
task.
These functions will automatically deal with any low-level complications required such as Packet ID (PID) toggling etc.
XUD_SetBuffer()
#
-
XUD_Result_t XUD_SetBuffer(XUD_ep ep_in, unsigned char buffer[], unsigned datalength)#
This function must be called by a thread that deals with an IN endpoint. When the host asks for data, the low-level driver will transmit the buffer to the host.
- Parameters:
ep_in – The endpoint identifier (created by
XUD_InitEp
).buffer – The buffer of data to transmit to the host.
datalength – The number of bytes in the buffer.
- Returns:
XUD_RES_OKAY on success, for errors see
Status Reporting
_.
XUD_GetBuffer()
#
-
XUD_Result_t XUD_GetBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length))#
This function must be called by a thread that deals with an OUT endpoint. When the host sends data, the low-level driver will fill the buffer. It pauses until data is available.
- Parameters:
ep_out – The OUT endpoint identifier (created by
XUD_InitEP
).buffer – The buffer in which to store data received from the host. The buffer is assumed to be word aligned.
length – The number of bytes written to the buffer
- Returns:
XUD_RES_OKAY on success, for errors see
Status Reporting
_.
XUD_GetSetupBuffer()
#
-
XUD_Result_t XUD_GetSetupBuffer(XUD_ep ep_out, unsigned char buffer[], REFERENCE_PARAM(unsigned, length))#
Request setup data from usb buffer for a specific endpoint, pauses until data is available.
- Parameters:
ep_out – The OUT endpoint identifier (created by
XUD_InitEP
).buffer – A char buffer passed by ref into which data is returned.
length – Length of the buffer received (expect 8 bytes)
- Returns:
XUD_RES_OKAY on success, for errors see
Status Reporting
_.
For user convenience these functions are wrapped up in functions that match commonly required packet sequences:
XUD_SetBuffer_EpMax()
#
This function provides a similar function to XUD_SetBuffer
function but it breaks the data up
in packets of a fixed maximum size. This is especially useful for control transfers where large
descriptors must be sent in typically 64 byte transactions.
-
XUD_Result_t XUD_SetBuffer_EpMax(XUD_ep ep_in, unsigned char buffer[], unsigned datalength, unsigned epMax)#
Similar to XUD_SetBuffer but breaks up data transfers into smaller packets. This function must be called by a thread that deals with an IN endpoint. When the host asks for data, the low-level driver will transmit the buffer to the host.
- Parameters:
ep_in – The IN endpoint identifier (created by
XUD_InitEp
).buffer – The buffer of data to transmit to the host.
datalength – The number of bytes in the buffer.
epMax – The maximum packet size in bytes.
- Returns:
XUD_RES_OKAY on success, for errors see
Status Reporting
_.
XUD_DoGetRequest()
#
-
XUD_Result_t XUD_DoGetRequest(XUD_ep ep_out, XUD_ep ep_in, unsigned char buffer[], unsigned length, unsigned requested)#
Performs a combined
XUD_SetBuffer
andXUD_GetBuffer
. It transmits the buffer of the given length over theep_in
endpoint to answer an IN request, and then waits for a 0 length Status OUT transaction onep_out
. This function is normally called to handle Get control requests to Endpoint 0.- Parameters:
ep_out – The endpoint identifier that handles Endpoint 0 OUT data in the XUD manager.
ep_in – The endpoint identifier that handles Endpoint 0 IN data in the XUD manager.
buffer – The data to send in response to the IN transaction. Note that this data is chopped up in fragments of at most 64 bytes.
length – Length of data to be sent.
requested – The length that the host requested, (Typically pass the value
wLength
).
- Returns:
XUD_RES_OKAY on success, for errors see
Status Reporting
_
XUD_DoSetRequestStatus()
#
-
XUD_Result_t XUD_DoSetRequestStatus(XUD_ep ep_in)#
This function sends an empty packet back on the next IN request with PID1. It is normally used by Endpoint 0 to acknowledge success of a control transfer.
- Parameters:
ep_in – The Endpoint 0 IN identifier to the XUD manager.
- Returns:
XUD_RES_OKAY on success, for errors see
Status Reporting
_.
Data transfer example#
A simple endpoint task is shown below demonstrating basic data transfer to the host.
void ExampleEndpoint(chanend c_ep_in)
{
char buffer[512];
XUD_ep ep_to_host = XUD_InitEp(chan_ep_in);
while(1)
{
XUD_SetBuffer(ep_to_host, buffer, 512);
}
}
Status reporting#
An endpoint can register for “status reporting” such that bus state can be known. This is achieved
by ORing XUD_STATUS_ENABLE
into the relevant endpoint in the endpoint type table.
This means that endpoints are notified of USB bus resets (and therefore bus-speed changes). The
lib_xud
access functions discussed previously (XUD_GetBuffer
, XUD_SetBuffer
, etc) return
XUD_RES_RST
if a USB bus reset is detected.
This reset notification is important if an endpoint task is expecting alternating IN and OUT transactions. For example, consider the case where an endpoint is always expecting the sequence OUT, IN, OUT (such as a control transfer or a request response protocol). If an unplug/reset event was received after the first OUT, the host would return to sending the initial OUT after a re-plug, whilst the endpoint task would hang trying to send a response the IN. The endpoint needs to know of the bus reset in order to reset its state machine.
Note
Endpoint 0 requires this functionality to be enabled since it deals with bi-directional control transfers
This functionality is also important for high-speed devices, since it is not guaranteed that a host will enumerate the device as a high-speed device, say if it’s plugged via full-speed hub.
The device typically needs to know what bus-speed it is currently running at.
After a reset notification has been received, the endpoint must call the XUD_ResetEndpoint()
function. This will return the current bus speed as a XUD_BusSpeed_t
with the value
XUD_SPEED_FS
;or XUD_SPEED_HS
.
XUD_ResetEndpoint()
#
-
XUD_BusSpeed_t XUD_ResetEndpoint(XUD_ep one, NULLABLE_REFERENCE_PARAM(XUD_ep, two))#
This function will complete a reset on an endpoint. Can take one or two
XUD_ep
as parameters (the second parameter can be set tonull
). The return value should be inspected to find the new bus-speed. In Endpoint 0 typically two endpoints are reset (IN and OUT). In other endpointsnull
can be passed as the second parameter.- Parameters:
one – IN or OUT endpoint identifier to perform the reset on.
two – Optional second IN or OUT endpoint structure to perform a reset on.
- Returns:
Either
XUD_SPEED_HS
- the host has accepted that this device can execute at high speed,XUD_SPEED_FS
- the device is running at full speed, orXUD_SPEED_KILL
to indicate that the USB stack has been shut down by another part of the user code (using XUD_Kill). If the last value is returned, the endpoint code should call XUD_CloseEndpoint and then terminate.
Status reporting example#
A simple endpoint task is shown below demonstrating basic data transfer to the host and bus status inspection.
void ExampleEndpoint(chanend c_ep_in)
{
char buffer[512];
XUD_Result_t result;
XUD_ep ep_to_host = XUD_InitEp(chan_ep_to_host);
while(1)
{
if((result = XUD_SetBuffer(ep_to_host, buffer, 512)) == XUD_RES_RST)
{
XUD_ResetEndpoint(ep_from_host, ep_to_host);
}
}
}
SOF channel#
An application can pass an optional channel-end to the c_sof
parameter of XUD_Main()
.
This will cause a word of data to be output every time
the device receives a SOF (Start Of Frame) packet from the host. This can be used for timing
information in audio devices etc.
If this functionality is not required null
should be passed as the parameter.
Note
If an optional channel-end is passed into XUD_Main()
there must be a responsive task ready
to receive SOF notifications otherwise the XUD_Main()
task will be blocked attempting to
send these messages leading to it being unresponsive to the host.
Halting#
The USB specification requires the ability for an endpoint to send a STALL response to the host if
an endpoint is halted, or if control pipe request is not supported. lib_xud
provides
various functions to support this. In some cases it is convenient to use the XUD_ep
whilst in
other cases it is easier to use the endpoint address. Functions to use either are provided.
XUD_SetStall()
#
XUD_SetStallByAddr()
#
-
void XUD_SetStallByAddr(int epNum)#
Mark an endpoint as STALL based on its EP address. Cleared automatically if a SETUP received on the endpoint. Note: the IN bit of the endpoint address is used.
Warning
Must be run on same tile as XUD core
- Parameters:
epNum – Endpoint number.
XUD_ClearStall()
#
XUD_ClearStallByAddr()
#
-
void XUD_ClearStallByAddr(int epNum)#
Mark an endpoint as NOT STALLed based on its EP address. Note: the IN bit of the endpoint address is used.
Warning
Must be run on same tile as XUD core
- Parameters:
epNum – Endpoint number.
USB test modes#
lib_xud
supports the required test modes for USB Compliance testing.
lib_xud
accepts commands from the endpoint 0 channels (in or out) to signal which test mode
to enter via the XUD_SetTestMode()
function. The commands are based on the definitions
of the Test Mode Selector Codes in the USB 2.0 Specification Table 11-24. The supported test
modes are summarised in Table 3.
Value |
Test Mode Description |
---|---|
1 |
Test_J |
2 |
Test_K |
3 |
Test_SE0_NAK |
4 |
Test_Packet |
The passing other codes endpoints other than 0 to XUD_SetTestMode()
could result in undefined
behaviour.
As per the USB 2.0 Specification a power cycle or reboot is required to exit the selected test mode.