IceCube display
LED display to show IceCube event data
endpoint_0.h File Reference

USB Endpoint 0 state machine interface. More...

Include dependency graph for endpoint_0.h:

Go to the source code of this file.

Data Structures

struct  control_transfer_t
 Control transfer state tracking. More...


enum  control_stage_t {
 Constants used to indicate the default control endpoint's current state. More...
enum  vendor_request_t {


void process_setup (struct control_transfer_t *transfer)
 Process setup request for control transfers. More...
void init_control_transfer (struct control_transfer_t *transfer, const struct usb_setup_packet_t *setup)
 Initialise the control transfer. More...
void cancel_control_transfer (struct control_transfer_t *transfer)
 Change the transfer state to STALL and perform the cancel callback, if any.
void control_mark_data_done (struct control_transfer_t *transfer, uint16_t length)
 Mark length bytes of the control transfer as done and perform the data callback.

Detailed Description

USB Endpoint 0 state machine interface.

Control transfers are usually handled asynchronously via interrupts. When the device has to wait for an answer from the host for example, this means that the firmware won't wait and poll to see if an answer has been received, but resumes normal operation until an interrupt is fired. This implies the use of task specific callbacks, since different setup request require different actions to be performed, possibly at different points in the request's lifetime.

See also
Default control endpoint
See section 9.3 of the USB 2.0 specification for more details.
Sander Vanheule (Universiteit Gent)

Enumeration Type Documentation

◆ control_stage_t

Constants used to indicate the default control endpoint's current state.


Control endpoint idle.


New setup request received.


Control endpoint stalled.


Sending data to host.


Receiving data from host.


Handshaking IN transfer.


Handshaking OUT transfer.


Performing post-handshake action.

◆ vendor_request_t

Vendor specific USB control request for display status and control.

Request name bmRequestType bRequest wValue wIndex wLength
VENDOR_REQUEST_DISPLAY_PROPERTIES 0b1_10_00000 2 0 0 2-65535
VENDOR_REQUEST_EEPROM_WRITE 0b0_10_00000 3 0 offset length
VENDOR_REQUEST_EEPROM_READ 0b1_10_00000 4 0 offset length
VENDOR_REQUEST_FRAME_DRAW_SYNC 0b0_10_00000 6 [ms] 0 0
See also
Default control endpoint

Push a single frame to be shown on the display into the frame buffer queue. When connected via USB all other renderers are stopped, so this frame will be displayed until the next one is pushed. Note that the device only updates the display 25 times per second, so pushing frame more frequently than this will result in buffer overflows on the device and consequently control transfers will be stalled until memory is freed. Since some platforms may not support control transfers of the size needed to send a frame, it is possible to send a single frame using multiple PUSH_FRAME commands.

Use the bulk out endpoint EP1 to transmit frame data.

Request a TLV list of display metadata. A reply to this request will always consist of at least two bytes, which provide the total length of the response. A typical query of this metadata will be done the following way:

  1. Perform an IN transfer of wLength 2. This will return the full length of the TLV data as an unsigned 16 bit, little endian integer.
  2. Perform an IN transfer of wLength N, with N being the response of the first request.

To perform the (initial) configuration of the device, one may also use the USB interface to read to and write from the microcontroller's EEPROM. EEPROM_READ and EEPROM_WRITE allow access to an EEPROM segment of arbitrary length, starting from any offset address that is within the size of the EEPROM.

The wIndex field of the setup request is used to provide the address offset of the EEPROM memory segment that is to be written. A request with wIndex=0x00 will start writing at the first byte, while a request with wIndex=0x30 will start writing at the 49th byte. The wLength field provides the length of the EEPROM segment that is to be written. If either wIndex or wIndex+wLength is larger than the size of the device's EEPROM, the control endpoint will be stalled indicating a bad request.

Use the EEPROM_WRITE command with care, as writing bad data to the EEPROM may render the device unusable.


Read a segment from the device's EEPROM. See VENDOR_REQUEST_EEPROM_WRITE on how to use the wIndex and wLength fields. For example, the IceCube string to buffer offset mapping of IceCube display microcontrollers can be read using wIndex=0x30 and wLength=36.


Get the latest frame draw time. The request response consists of two unsigned 16 bit (little endian) integers a defined by display_frame_usb_phase_t.


Correct the frame counter ms value by the provided amount. The ms correction \(\delta\) is provided as a signed (little endian) 16 bit integer contained in the wValue field of the setup request. Corrections larger than \(\pm(2^{15}-1)\)ms should be performed using multiple requests. In this case the first request should perform the largest possible correction including the full USB frame counter phase slip, i.e. \((\delta \bmod 40) + N \times 40 = \Delta_0\) with \(|\Delta_0| \le 2^{15}-1\). This synchronises the fraw draws down to the millisecond, but leaves the frame counters out of phase. Subsequent requests can then correct the remaining offset as multiples of 40ms.

Function Documentation

◆ init_control_transfer()

void init_control_transfer ( struct control_transfer_t transfer,
const struct usb_setup_packet_t setup 

Initialise the control transfer.

Sets the transfer stage to SETUP and stores the provided setup packet setup as the corresping request for the transfer.

◆ process_setup()

void process_setup ( struct control_transfer_t transfer)

Process setup request for control transfers.

The transfer object is updated with the correct information to continue processing the control transfer. In case this is a valid and recognised setup packet, transfer->stage will be updated to the state the transfer is in once this function returns. If the control transfer stage is still CTRL_SETUP when this function returns, the request should be considered invalid and the control endpoint stalled.