24 USB config & command protocol
sys64738 edited this page 2021-08-26 18:57:05 +00:00

Wire protocol

The device has a "configuration and command" USB vendor interface, it has subclass number 68 ('D'), and protocol number 80 ('P'). The VID/PID pair is currently cafe:1312.

The host sends a message and the device sends a reply. The device never initiates a transfer.

the first byte of a command is the combination of the mode it is meant for (in the high nybble), and the command number itself in the low nybble. Optional extra command bytes may follow, depending on the command itself. A high nybble of 0 signifies a general configuration command, not meant for a particular mode.

A response consists of a response status byte (enum cfg_resp), followed by a 7-, 14- or 22-bit VLQ int (little-endian) for the payload length, followed by the payload itself.

Response/status enum:

  • Ok: 0x00
  • Illegal/unknown/unimplemented command: 0x01
  • Bad mode for this command: 0x02
  • No such mode exists: 0x03
  • Bad command argument: 0x04
  • Wrong (mode-specific) state for this command: 0x05

General commands

These commands work at any moment and are used to query the general device state and info.

  • Get vesion (0x00): returns a payload of 2 bytes with version data. Should currently be 0x10 0x00 (00.10h).
  • Get modes (0x01): returns 2 bytes with a bitmap containing all supported modes. Bit 0 is for general config (aka this command group) and must always be 1.
  • Get cur mode (0x02): returns a single byte containing the current mode number.
  • Set cur mode (0x03): sets the current mode. One extra request byte (the mode number), no response payload.
  • Get info string (0x04): get a null-terminated string containing human-readable info about the device. For display purposes only.

Persistent storage commands

  • Get storage info (0x0c): returns the 256-byte header data of the persistent storage. No arguments. See Persistent storage.
  • Get mode storage data (0x0d): returns the (variable-length) data of a mode. One argument byte, the mode.
  • Flush data to storage medium (0x0e): writes the storage data when changed. Automatically called on OS USB detach/unmount (as long as there is still power supplied to the device).

Common mode commands

These commands work for any mode, and have the same effect across all of them.

  • Get name (0xM0): returns a name or other descriptive string in the payload. Null-terminated, for display purposes only.
  • Get version (0xM1): returns a 2-byte version number in the payload.
  • Get features (0xM2): gets a bitmap of supported features. Length and meaning of the bits depends on the mode.

Mode-specific commands

A list of all the currently-implemented modes:

  1. Default ('misc')
  2. (N/A)
  3. (N/A: JTAG pinout scanner)
  4. SUMP logic analyzer

Mode 1

Features

  • 0x01: UART<->USB-CDC interface available
  • 0x02: CMSIS-DAP available
  • 0x04: SPI interface available
  • 0x08: I2C interface available
  • 0x10: Temperature sensor available

Commands

  • SPI (serprog) command prefix (0x13): Perform a SPI command, see below.
  • I2C command prefix (0x14): Perform an I2C command, see below.
  • Temperature sensor command prefix (0x15): Perform a temperature sensor command, see below.
  • UART↔USB hardware flow control enable/disable (0x16): has a single argument byte, 0x00 to disable hardware flow control, 0xc3 to read the current value (one byte returned), any other value to enable. Baud rate and other line control settings are done using the standard USB-CDC line control things.

SPI commands

The SPI command format used here is based heavily on Serprog. Keep in mind that serprog responses — including its ACK and NAK status bytes — are wrapped as a response payload as defined in the beginning of this document!

Supported standard serprog commands:

  • NOP (0x00)
  • Q_IFACE (0x01)
  • Q_CMDMAP (0x02)
  • Q_PGMNAME (0x03)
  • Q_SERBUF (0x04)
  • Q_BUSTYPE (0x05)
  • Q_WRNMAXLEN (0x08)
  • SYNCNOP (0x10)
  • Q_RDNMAXLEN (0x11)
  • S_BUSTYPE (0x12)
  • SPIOP (0x13)
  • S_SPI_FREQ (0x14)
    • SPI clock frequency defaults to 512 kHz
  • S_PINSTATE (0x15)

Additionally, a number of nonstandard commands are supported as well, for more specific SPI transfers not necessarily needed for flash programming:

  • S_CMD_Q_SPI_CAPS (0x40): query capabilities of the SPI controller. No arguments. Return struct of 13 bytes (preceded by an ACK):
    • Minimum frequency: 32-bit little-endian value in Hz
    • Maximum frequency: 32-bit little-endian value in Hz
    • Capability flags: 16-bit little-endian value
      • Bit 0 (lsb): CPHA can be 1
      • Bit 1: CPHA can be 0
      • Bit 2: CPOL can be 1
      • Bit 3: CPOL can be 0
      • Bit 4: Standard SPI ("Motorola") frame format is supported
      • Bit 5: TI SSP frame format is supported
      • Bit 6: NatSemi MicroWire frame format is supported
      • Bit 7: MSBit-first transfers are supported
      • Bit 8: LSBit-first transfers are supported
      • Bit 9: CS can be selected to be active-high instead (CS line control command will take note of this, and send CS high/low commands accordingly (in accordance with the Linux kernel), cf. S_CMD_S_SPI_SETCS.)
      • Bit 10 (msb): 3-wire interface supported
    • Number of chip-select lines: 8-bit bitmap
    • Minimum bits-per-transfer-word value (8 bit)
    • Maximum bits-per-transfer-word value (8 bit)
  • S_CMD_S_SPI_CHIPN (0x41): set which chip select lines are to be controlled. Has a single argument byte, a bitmap of chip select line values. No response (aside from an ACK).
  • S_CMD_S_SPI_SETCS (0x42): set the voltage level of the CS line(s) selected by S_CMD_S_SPI_CHIPN. No response (aside from an ACK).
  • S_CMD_S_SPI_FLAGS (0x43): set transfer settings flags, one response byte (actual flags applied), single argument byte:
    • Bit 0 (lsb): CPHA
    • Bit 1: CPOL
    • Bit 2,3: frame format: 0=standard, 1=SSP, 2=MicroWire. 3 is undefined.
    • Bit 4: LSBit-first transfer (clear this bit for MSBit-first transfers)
    • Bit 5: CS is used as active-high signal (clear this bit for active-low CS signals)
    • Bit 6 (msb): Use 3-wire mode (clear this bit for regular 4-wire SPI)
  • S_CMD_S_SPI_BPW (0x44): set bits per word used in a SPI transfer. Single argument byte denoting the number of bits. One response byte: bits per word applied.
  • S_CMD_SPI_READ (0x45): similar to SPIOP (0x13), except without data to write (and no "write data length" argument).
  • S_CMD_SPI_WRITE (0x46): similar to SPIOP (0x13), except without data to read (and no "read data length" argument).
  • S_CMD_SPI_RDWR (0x47): full-duplex SPI transfer (as opposed to SPIOP (0x13), which is only half-duplex), same arguments and result format as SPIOP (0x13).

I2C commands

The I2C command format used here is based heavily on the one of I2C-Tiny-USB (protocol).

  • Echo (0x00): one single argument byte is echoed back as payload.
  • Get functions (0x01): get supported I2C and SMBus operations. Response payload is 4 bytes little endian, Linux kernel I2C_FUNC_xxx flags.
  • Set delay (0x02): sets the clock phase of the SCL signal, in microseconds, two little-endian bytes. No response payload.
  • Get status (0x03): returns the current status as a single payload byte.
    • 0x00: idle status: nothing happened
    • 0x01: The last transfer was successful, an ACK was received from the target I2C device.
    • 0x02: The last transfer failed, a NAK was received from the target I2C device, or no devices responded to the address.
  • Do transfer (0x04..0x07): perform an I2C transfer.
    • Arguments: 2 little-endian 'flags' bytes (Linux kernel I2C_M_xxx flags), 2 little-endian I2C device address bytes, 2 little-endian transfer length bytes.
    • If the lowest bit (bit 0) of the command byte is set, a "start condition" is performed at the start of the I2C transfer. Otherwise, a "repstart" is done.
    • If bit 1 of the command byte is set, a "stop condition" is performed at the end of the transfer, causing the target device to stop listening to further commands, and go back to listening for its address on the bus.
    • If flags & I2C_M_RD, this is a read operation. The amount of bytes read (max. the number of bytes specified in the arguments) is returned as data payload.
    • If the transfer length is 0, this is an address probe. Response contains no payload, but a status byte (together with a 0-length byte) is still sent out.
    • Otherwise, this is a write transfer. The number of bytes specified in the arguments is read from the USB host, and sent over the I2C bus. Response contains no payload, but a status byte (together with a 0-length byte) is still sent out.

Temperature sensor commands

  • Get I2C address (0x00): gets the address of the virtual temperature sensor device on the I2C bus (the one used in cmd. 0x14). 0xff if disabled. Single byte response payload.
  • Set I2C address (0x01): sets the address of the virtual temperature sensor I2C device, 0xff to disable. Single argument byte, two response bytes (old and new addresses).
  • Get temperature (0x02): returns the 2-byte 8.4 fixed point temperature, little endian.
  • Get lower temperature limit (0x03): returns the 2-byte minimum temperature before things start going bad.
  • Get upper temperature limit (0x04): returns the 2-byte maximum temperature before things start going bad.
  • Get critical temperature limit (0x05): returns the 2-byte critical temperature when things are going really bad.

1wire commands

TODO

commands

  • 0x00 <1 byte mode> set mode (see interface modes)

1wire interface modes

  • 0x00 controller
  • 0x10 controller (overdrive)
  • 0x01 peripheral
  • 0x11 peripheral (overdrive)

controller operations

  • 0x01 <2 byte write size> <2 byte read size> <write data> reset, then write / read, returns 1 byte status then up to the number of requested bytes
  • 0x02 <read size> read rom (eg, DS2401). basically a write/read where the write is 0x33, returns 1 byte status then up to the number of requested bytes
  • 0x03 TODO match rom (executes the 1wire match rom algorithm)
  • 0x04 <2 byte maximum number of devices to return> search rom (executes the 1wire search rom algorithm to detect all connected peripherals)
  • TODO

peripheral ops

  • 0x81 <2 byte mode> set peripheral mode (below)
  • 0x82 <2 byte size> <data> set peripheral data (eg, eeprom contents)

peripheral modes

  • 0x2401 DS2401 emulation (with configurable ID)
  • TODO

additional peripheral ops

  • 0x83 report timing (returns a measurement of the time taken between one controller query and the next)

Mode 3 (JTAG/SWD/... pinout scanner)

  • Scan types:
    • JTAG: 0
    • SWD: 1
    • (SBW: 2)

Commands:

  • 0x33: Get status: no argument bytes, one result byte
    • 0x0x: scan busy (type: x, eg. 0x00 = JTAG busy, 0x01 = SWD busy, x < 0x7f)
    • 0x7f: idle
    • 0b1xxxxxxx: scan finished, 0bxxxxxxx matches found
  • 0x34: Get scan result (only if status is finished): no argument bytes, 8*x (JTAG) or 6*x (SWD) result bytes
    • result: for each match:
      • JTAG: all bytes: pin numbers of TCK, TMS, TDI, TDO, nTRST, IR length, # of pins toggled, "possibly a short-circuit" warning flag
      • SWD: swclk, swdio pin numbers (bytes), ID code (4 bytes, little-endian)
  • 0x35: Start scan (only valid if status is not 0x01): three argument bytes (scan type, start and end pin numbers (inclusive)), no result bytes
  • 0x36: Get pin range: no argument bytes, two result bytes (min and max pin numbers, like start/end pins as in 0x35)
  • 0x37: Force-stop scan. No argument or result bytes, sets mode to idle.

Mode 4 (SUMP logic analyzer)

  • 0x43: Get overclocking state: no argument bytes, one result byte (overclocking off/on (resp. 0x00 or nonzero) (or amount, device-dependent, depending on what future devices may bring?))
  • 0x44: Set overclocking state: one argument byte, no result bytes (same format as 0x40)