12 USB protocol
sys64738 edited this page 2021-06-26 18:45:37 +00:00

The USB interface is an FTDI FT240X (datasheet). While not explicitely supported by libftdi, you can still use it (libftdi will think it is an FT230X).

lsusb output

Bus 001 Device 061: ID 0403:7fd0 Future Technology Devices International, Ltd ScanaQuad SQ50
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass            0 
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x0403 Future Technology Devices International, Ltd
  idProduct          0x7fd0 
  bcdDevice           10.00
  iManufacturer           1 IKALOGIC
  iProduct                2 ScanaQuad SQ50
  iSerial                 3 1003050005482
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength       0x0020
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              400mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass       255 Vendor Specific Class
      bInterfaceSubClass    255 Vendor Specific Subclass
      bInterfaceProtocol    255 Vendor Specific Protocol
      iInterface              2 ScanaQuad SQ50
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x02  EP 2 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
can't get device qualifier: Resource temporarily unavailable
can't get debug descriptor: Resource temporarily unavailable
Device Status:     0x0000
  (Bus Powered)

Note: the serial number matches the one on the sticker on the bottom of the plastic shell.

Protocol

The device operates in two (or three, depending on how you count) operting modes: bootloader mode (and authenticated bootloader mode), and application mode. On startup, the device starts in 'unauthenticated' bootloader mode.

In bootloader mode, you first have to send a magic number for the device (stored in the FT240X' EEPROM) to enable some functionality: when authenticated, in bootloader mode, you can access the Spartan-3AN's internal SPI flash, as well as maybe a few extra bits.

You can switch to application mode (and back to bootloader mode) at any time, however, allegedly (this is the behavior of the ScanaPLUS device, which has a similar setup) capturing samples (in application mode) will not work when not authenticated in bootloader mode.

A log of libftd2xx function calls from ScanaStudio, in various scenarios, is available here.

Commands are typically a one-byte command ID, followed by a variable amount of data bytes. These are sent through the FTDI USB interface (e.g. ftdi_read_data/ftdi_write_data using libftdi), they are not raw USB packets.

Mode-independent

  • 0xfd: Get status/mode
    • Arguments: fixed 0x00 0x01 0x02 0xfe
    • Response:
      • Unauthenticated bootloader mode: 0x09 0x09 0x09 0x09
      • Authenticated bootloader mode: 0x01 0x01 0x01 0x01
      • Application mode: 0x22 0x22 0x22 0x22
  • 0x93: Reset to application mode
    • No arguments
    • No response
  • 0x94: Reset to bootloader mode
    • No arguments
    • No response
    • TODO: does this reset to authenticated or unauthenticated bootloader mode after already having authenticated once? (Doesn't matter that much in the end..)

Bootloader mode

  • 0xf1: Send unlock/authentication code
    • Arguments: 3 bytes from FT240X EEPROM word locations 0x12:0x13 (little-endian, so low byte of 0x12 first, then hi byte of 0x12, then lo byte of 0x13), followed by a fixed 23 zero bytes
    • No response
  • 0x90: Spartan-3AN internal SPI flash chip select
    • Arguments: fixed 0x00
    • No response
  • 0x91: Spartan-3AN internal SPI flash chip deselect
    • Arguments: fixed 0x00
    • No response
  • 0x92: Spartan-3AN internal SPI flash chip data transfer
    • Arguments: single byte to send (0xff for SPI read operations)
    • Response: single byte result of the SPI operation (garbage if the byte transferred was meant as a write)
    • Yes, SPI transfers are done byte-by-byte this way. For details on how to communicate with the Spartan-3AN internal flash, see Xilinx docs (UG333). See the "Example transfers" section below.

Application mode

  • 0xf0: Start transaction
    • Arguments: one (sometimes two) transaction type byte(s)
      • 0x00: Cancel ongoing capture/wait-for-trigger
      • 0x01: Start capture/wait for trigger
        • Response:
          • 3-byte "trigger instant" (little-endian): this is the point at which the trigger happened, units are MS1*16. (That is, if the trigger happened at the very last sample, this value will be MS1*16. If it happens right in the middle, it'll be 50% of MS1*16.) (For MS1: see settings blob.)
          • 1 status byte: 0xdd indicates success, no other values seen.
      • 0x02: Start generating an uploaded signal indefinitely
      • 0x03: Start capture/generate/wait for trigger in mixed mode
        • Response: same as 0xf0 0x01
      • 0x05 0xf3: Start uploading signal generator pattern to the logic analyzer
        • This command is immediately followed by the generator pattern data. For the size of this blob, see the description of the Settings blob.
        • The extra 0xf3 byte seems to always be sent, so it's probably mandatory.
      • 0x06: Start downloading captured signal data
        • Response: capture signal data. For the size of this blob, see the description of the Settings blob.
      • 0x07: Start generating an uploaded signal once
    • No response unless mentioned otherwise in the subtypes
  • 0xf1: Send settings blob
    • Arguments: settings blob (see below)
    • No response
  • 0xf4: Send trigger step blobs
    • Arguments: as many trigger step blobs (32 bits each) as specified in the settings blob (see below for both).
    • No response

Settings blob

This blob is 24 bytes in size.

  • 0x00: Normally 0x01, 0x09 means "scale trigger pulse widths to microseconds". No other values observed.
  • 0x01..0x02: Clock frequency (little-endian). Equal to 100000 divided by the frequency in kHz.
  • 0x03..0x04: Trigger pulse width scale (16-bit little-endian). Maximum 0x8008. This value, multiplied by the minimum/maximum pulse width, should be equal to 4 times the product of the configured pulse width (in seconds) and the sample frequency (in Hz). That is: settings.trigger_pulse_width * trigstep.pw_min = 4 * pw_in_s * samplefreq_in_hz.
  • 0x05..0x07: Memory setting 1 (MS1): For a description, see below.
  • 0x08..0x0a: Memory setting 2 (MS2): For a description, see below.
  • 0x0b..0x0d: Memory setting 3 (MS3): For a description, see below.
  • 0x0e: Unknown, always zero.
  • 0x0f: Number of trigger steps.
  • 0x10: Unknown, always 0xf0.
  • 0x11: Unknown, always 0x0f.
  • 0x12: Channel output settings bitmap, see below.
  • 0x13..0x14: Voltage settings. See below.
  • 0x15: Unknown, always 0x32.
  • 0x16: Capture mode flag. 0x01 in capture and mixed mode, 0x00 in generate mode.
  • 0x17: Generate mode flag. 0x01 in generate and mixed mode, 0x00 in capture mode.

"Passive settings" (used in the "Example transfers" section) means settings that retain frequency, voltage, ..., settings, but disable triggers and reset capture/generate bytes.

The sample rate settings' minimum value is 0x0001, which corresponds to 200 MHz. When given this sample setting, my SQ50 complies and starts sampling at 200 MHz, which it nominally cannot.

Memory settings: These three fields are each 3-byte little-endian values:

  1. MS1 denotes the memory size used for storing captured signal data.
  2. MS2 denotes the total memory size used.
  3. MS3 configures the pre-trigger sample settings: MS3 = MS1 * (1 - pre_trigger_samples), with pre_trigger_samples a float between 0 and 1 (0% pretrigger and 100% pretrigger).

The most significant nybble of MS3 is the complement of the high nybble of teh channel output settings bitmap (0x12), and should be masked out before doing memory size calculations.

In capture mode, MS1 and MS2 are equal. In generator mode, MS1 and MS3 are zero while MS2 denotes the size of the memory used for storing generator patterns. In mixed mode, MS2 is the sum of MS1 (the memory size used for captured data) and the memory size used for generator data.

The number of bytes received as capture data or sent as generator patterns, is equal to the numbers here, multiplied by two. That is, the MSx values are (most likely) in 16-bit units.

In 4-channel capture mode, the maximum memory size for the SQ50 seems to be 0x03d090. This is equal to 1/4th of the sample frequency (in Hz) multiplied by the capture period (in seconds).

Channel output settings bitmap:

The low nybble of this byte is always 0xf. For each channel, if the channel is configured as an output, the bit in the high nybble corresponding to the channel is 1, otherwise it is 0.

In other words, the byte value is (chan-x-is-output ? 1 : 0) << (x+4)) ORed together for each channel x (0..3), ORed together with the constant 0x0f.

Voltage settings:

Voltage (V) Before capturing During capture
1.8 0x46 0x4b 0x46 0x1e
2.8 0x6e 0x4b 0x6e 0x2c
3.3 0x81 0x4b 0x81 0x46
3.6 0x8d 0x4b 0x8d 0x4f
5.0 0xc4 0x4b 0xc4 0x72

The first byte of the voltage settings is equal to floor(max_voltage * 39.2). The second byte is the threshold voltage. In idle mode, the second byte is always 0x4b (1.9V), but during a capture it varies. For some reason, it isn't always half the maximum voltage, sometimes it's above it, sometimes below.

The default settings blob used seems to be 01 04 00 00 00 90 d0 03 90 d0 03 e8 6e f3 00 00 f0 0f 0f 81 4b 32 01 00.

Trigger step blob

Every trigger step is 32 bits (4 bytes) in size. Unlike the above settings blob, this one does not distinguish different functionalities in different bytes as much. Therefore, we will represent it here as a single 32-bit bitmap. This bitmap is still sent as little-endian over the FTDI serial->FIFO USB protocol!

byte:  .---------- 3 -----------.---------- 2 ------------.------------ 1 ------------.-------------------- 0 ----------------------.
bit  : .31 .30.29 28 27 26 25 24'23 22 21. 20 .19.18 17 16'15 14 13 12 11 10.  9 .  8 .  7 .  6 .  5  .  4  .  3  .  2  .  1  .  0  .
       +---+--+-----------------'--------+----+--+--------'-----------------+----+----+----+----+-----+-----+-----+-----+-----+-----+
field: |LVL|0 |          pw_max '        |OVRL|0 |        ' pw_min          |IGN4|IGN3|IGN2|IGN1|NOMAX|NOMIN|HIRI4|HIRI3|HIRI2|HIRI1|
       +---+--+-----------------'--------+----+--+--------'-----------------+----+----+----+----+-----+-----+-----+-----+-----+-----+
  • 31: LVL: edge/level flag: edge-triggered (0) or level-triggered (1). Denotes whether this step is using edge-triggering. If so, only one channel may be marked as enabled/non-ignored.
  • 30: Unknown, always 0.
  • 29..21: pw_max: 9-bit (29..21 → 8..0) maximum pulse width setting. Unit configured in settings blob.
  • 20: OVRL: level trigger override: when this bit is 1, the trigger should still be considered a level trigger, even if bit 31 says otherwise. Used in ScanaStudio for "logic triggers" only.
  • 19: Unknown, always 0.
  • 18..10: pw_min: 9-bit (18..10 → 8..0) minimum pulse width setting. Unit configured in settings blob.
  • 9: IGN4: set to 1 to ignore channel 4 in this trigger step.
  • 8: IGN3: set to 1 to ignore channel 3 in this trigger step.
  • 7: IGN2: set to 1 to ignore channel 2 in this trigger step.
  • 6: IGN1: set to 1 to ignore channel 1 in this trigger step.
  • 5: NOMAX: set to 1 to disable/ignore the maximum pulse width setting.
  • 4: NOMIN: set to 1 to disable/ignore the minimum pulse width setting.
  • 3: HIRI4: set to 1 trigger on channel 4 high or rising, 0 for low or falling. (Edge or level depends on bits 31 and 20)
  • 2: HIRI3: set to 1 trigger on channel 3 high or rising, 0 for low or falling. (Edge or level depends on bits 31 and 20)
  • 1: HIRI2: set to 1 trigger on channel 2 high or rising, 0 for low or falling. (Edge or level depends on bits 31 and 20)
  • 0: HIRI1: set to 1 trigger on channel 1 high or rising, 0 for low or falling. (Edge or level depends on bits 31 and 20)

Example transfers

Below is what the ScanaStudio software does.

Abbreviations/terms used:

  • APP: application mode variant of a command
  • BL bootloader mode variant of a command
  • passive: see "Settings blob".
  • SC/WFT: signal capture/wait-for-trigger
  • While a status response is technically the same byte repeated 4 byte, the byte is only listed once below.

Device init/reset

  1. Send settings (0xf1 APP) (passive) (probably spurious)
  2. Cancel ongoing SC/WFT (0xf0 0x00)
  3. Get status (0xfd 0x00 0x01 0x02 0xfe)
  • Should return either 0x09 (device just started up) or 0x22 (already inited).
  1. Switch to bootloader mode (0x94)
  2. Read 3 magic auth bytes from FT240X EEPROM at (little-endian) word addresses 0x12 and 0x13.
  3. Send the above magic auth bytes (0xf1 BL)
  4. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x01.
  5. Switch to application mode (0x93)
  6. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  7. Send settings (0xf1 APP) (passive)

Capture a signal

  1. Cancel ongoing SC/WFT (0xf0 0x00)
  2. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  3. Send settings (0xf1) (passive) (spurious?)
  4. Send settings (0xf1)
  5. Send trigger steps (0xf4) (optional)
  6. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  7. Cancel ongoing SC/WFT (0xf0 0x00)
  8. Start SC/WFT (0xf0 0x01)
  9. Read 4-byte response (trigger position, result)
  10. Cancel ongoing SC/WFT (0xf0 0x00)
  11. Start capture data download (0xf0 0x06)
  12. Read capture data bytes (MS1*2 bytes)
  13. Cancel ongoing SC/WFT (0xf0 0x00)
  14. Send settings (0xf1) (passive)
  15. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.

Generate a signal

  1. Cancel ongoing SC/WFT (0xf0 0x00)
  2. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  3. Send settings (0xf1) (passive, but generator mode enabled)
  4. Start generator upload pattern (0xf0 0x05 0xf3)
  5. Send generator pattern bytes (MS2*2 bytes)
  6. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  7. Cancel ongoing SC/WFT (0xf0 0x00)
  8. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  9. Start pattern generation, indefinitely (0xf0 0x02) or once (0xf0 0x07)
  10. Send settings (0xf1)
  11. (wait...)
  12. Stop pattern generation: Cancel ongoing SC/WFT (0xf0 0x00)
  13. Send settings (0xf1) (passive, but generator mode enabled)
  14. Send settings (0xf1) (passive)
  15. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.

Perform a mixed-mode transaction

  1. Cancel ongoing SC/WFT (0xf0 0x00)
  2. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  3. Send settings (0xf1) (passive, but capture and generator modes enabled)
  4. Start generator upload pattern (0xf0 0x05 0xf3)
  5. Send generator pattern bytes ((MS2-MS1)*2 bytes)
  6. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  7. Cancel ongoing SC/WFT (0xf0 0x00)
  8. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  9. Send settings (0xf1)
  10. Send trigger steps (0xf4) (optional) (?)
  11. Cancel ongoing SC/WFT (0xf0 0x00)
  12. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  13. Send settings (0xf1)
  14. Send settings (0xf1) (spurious?)
  15. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.
  16. Cancel ongoing SC/WFT (0xf0 0x00)
  17. Start mixed-mode action (0xf0 0x03)
  18. Read 4-byte response (trigger position, result)
  19. Cancel ongoing SC/WFT (0xf0 0x00)
  20. Start capture data download (0xf0 0x06)
  21. Read capture data bytes (MS1*2 bytes)
  22. Cancel ongoing SC/WFT (0xf0 0x00)
  23. Send settings (0xf1) (passive)
  24. Get status (0xfd 0x00 0x01 0x02 0xfe), should return 0x22.

Spartan-3AN internal SPI flash: read ID and status

Flash ID:
  Send 0x90,0x00, no read data
  Send 0x92,0x9f, read 1 byte and discard it
  Send 0x92,0xff, read 1 data byte
  Send 0x92,0xff, read 1 data byte
  Send 0x91,0x00, no read data
Status:
  Send 0x90,0x00, no read data
  Send 0x92,0xd7, read 1 byte and discard it
  Send 0x92,0xff, read 1 data byte
  Send 0x91,0x00, no read data

Spartan-3AN internal SPI flash: dump entire flash (including bootloader and application mode bitstreams)

Send 0x90,0x00, no read data
Send 0x92,0x0b, read 1 byte and discard it
Send 0x92,0x00, read 1 byte and discard it
Send 0x92,0x00, read 1 byte and discard it
Send 0x92,0x00, read 1 byte and discard it
Send 0x92,0xff, read 1 byte and discard it
Repeat 135168 times:
  Send 0x92,0xff, read 1 data byte
Send 0x91,0x00, no read data