As a result, it can act as a no-compromise High-Speed USB protocol analyzer, a USB-hacking multi-tool, or a USB development platform. Out-of-the-box, Cynthion acts as a USB protocol analyzer capable of capturing and analyzing traffic between a host and any Low-, Full-, or High-Speed (“USB 2.0”) USB device. It works seamlessly with our...
CHAPTER GETTING STARTED WITH CYNTHION 2.1 Prerequisites To use Cynthion you will need to ensure the following software is installed: • Python v3.9, or later. 2.2 Cynthion Host Software Installation The Cynthion host software distribution can be obtained from the...
Homebrew, MacPorts or some other route. If you are not using a Python distribution from Homebrew you may be able to direct Cynthion to the correct location by explicitly setting DYLD_FALLBACK_LIBRARY_PATH to the location of the libusb native library.
--upgrade cynthion 2.5 Updating Cynthion Microcontroller Firmware and FPGA configu- ration flash To upgrade the Cynthion Microcontroller firmware and FPGA configuration flash to the latest versions run: cynthion update You can update the Microcontroller firmware separately with: cynthion update --mcu-firmware...
Page 14
Cynthion Chapter 2. Getting Started with Cynthion...
THREE USING CYNTHION WITH PACKETRY Together with Packetry, Cynthion can be used as a USB 2.0 protocol analyzer capable of capturing and analyzing traffic between a host and any Low, Full, and High Speed USB device. Before proceeding, please ensure you have completed all steps in the section.
Cynthion 3.3 Connect Hardware Next, see the Packetry documentation for more detail, or the tutorial for a worked Protocol analysis of a USB keyboard example. Chapter 3. Using Cynthion with Packetry...
CHAPTER FOUR USING CYNTHION WITH FACEDANCER Together with Facedancer, Cynthion can be used to quickly and easily emulate USB devices controlled from Python running on the host computer. Before proceeding, please ensure you have completed all steps in the section.
# Type a string with the device await device.type_string("echo hello, facedancer\n") main(device, type_letters()) Open a terminal and run: python ./rubber-ducky.py If all goes well, you should see the string hello, facedancer typed into the target host. Chapter 4. Using Cynthion with Facedancer...
FIVE USING CYNTHION WITH USB PROXY Together with Proxy, Cynthion can proxy packets between a target host and a target device attached to the control computer. Before proceeding, please ensure you have completed all steps in the Getting Started with Cynthion Using Cynthion sections.
If all goes well you should see the output from device enumeration in your terminal and the proxied USB device should be detected by the target computer. 5.3 More Information For further information, see the Facedancer USB Proxy documentation. Chapter 5. Using Cynthion with USB Proxy...
Display Cynthion Microcontroller information: cynthion info --force-offline Note: Once you have switched to the Cynthion Microcontroller by pressing the PROGRAM button or the --force-offline option you will need to press the RESET button to return control to the FPGA.
Page 24
Remove all files installed during set up: cynthion setup --uninstall 6.1.3 Update Cynthion Update both the Cynthion Debug Microcontroller firmware and USB Analyzer bitstream to the latest installed factory versions: cynthion update Update Cynthion Debug Microcontroller firmware to the latest installed factory version:...
Page 25
Cynthion cynthion flash --mcu-firmware <filename> Overwrite the SoC firmware with the one specified by <filename>: cynthion flash --soc-firmware <filename> 6.1. Command Documentation...
Page 26
Cynthion Chapter 6. The cynthion command line interface...
Getting Started with Cynthion • Install Packetry by following Getting Started with Packetry • Run the analyzer gateware on Cynthion by following Using Cynthion with Packetry 7.2 Determine device speed USB 2.0 supports three different speeds: Low (1.5 Mbit/s), Full (12 Mbit/s), and High (480 Mbit/s). The analyzer needs to know what speed to expect, so we need to detemine what speed the target device is using.
Cynthion 7.3 Connect Next, we’ll connect everything up for capture. Within the Cynthion hardware the TARGET C and TARGET A ports are connected together, and the analyzer gateware will capture any packets that are seen going between those ports. These packets are then sent out through the CONTROL port.
Page 29
Cynthion Upon plugging in the target device, a collection of entries should show up in the Traffic Pane, these show the requests that a host makes to find out information about a new device (known as USB enumeration). 7.4. Capture...
Page 30
Cynthion The target device should also show up in the Devices pane to the right. All of the entries in the Traffic and Device panes can be expanded for more detail, by clicking on the black triangles. Clicking on an entry in the Traffic pane to highlight it will show extra detail in the pane below.
7.5.1 Capture button is grayed out and no capture device shows up in Packetry • Double check that the Cynthion CONTROL port is connected to the host running Packetry. • Check that the cable is good, ideally trying it with another USB device that transfers data (not just charging).
Page 32
Cynthion 7.5.4 Traffic shows “unidentified transfer” and Devices shows an “Unknown” de- vice This means that valid packets have been captured, but Packetry did not see the target device enumeration so it doesn’t have enough information to fully decode the USB transactions/transfers. If you would like to see the full decoding, make sure to start the capture in Packetry before plugging in the target device.
EIGHT EMULATION OF A USB DEVICE This tutorial walks through the whole process of emulating a USB device with Cynthion and Facedancer. We’ll emulate HackRF One, a software-defined radio platform. The goal of our emulation is to fool the hackrf_info command into reporting that a HackRF One is connected.
Cynthion 8.3 Connect We need to connect our Cynthion before we can use it to emulate a HackRF One. If you followed the prerequisites above, you should already have connected the Cynthion’s CONTROL port to your computer. Now also connect the TARGET C port to your computer. Facedancer software uses CONTROL to control the Cyn- thion and TARGET C to connect to the target host, the computer which we’ll try to fool into thinking that there is a...
Cynthion We’ve just convinced hackrf_info that it has found a HackRF device! However, hackrf_info failed to read the HackRF’s board ID which distinguishes between the various hardware platforms supported by HackRF software. The pipe error indicates that the device did not provide the expected response to the host’s request for the board ID.
Page 36
(Jawbreaker) hackrf_version_string_read() failed: Pipe error (-1000) We’ve now convinced hackrf_info that our Cynthion is a HackRF Jawbreaker which was the beta platform that preceded HackRF One. Let’s try a higher board ID number. Replace request.reply([1]) with: request.reply([2]) Execute the program: python hackrf_emulation.py --suggest...
Cynthion 8.6 Handle the Version String Request Unfortunately, hackrf_info still indicates an error, this time with reading a version string. The --suggest option on your Facedancer program should give you an idea of how to handle that request: @vendor_request_handler(number=15, direction=USBDirection.IN)
Cynthion (continued from previous page) main(HackRF) Execute the program: python hackrf_emulation.py --suggest While the program is running, execute hackrf_info in another terminal: hackrf_info version: 2023.01.1 libhackrf version: 2023.01.1 (0.8) Found HackRF Index: Serial number: 1234 Board ID Number: (HackRF One) Firmware Version: tutorial version (API:0.00)
Cynthion (continued from previous page) Part ID Number: 0x41414141 0x41414141 hackrf_close() failed: Pipe error (-1000) It looks like the part ID was interpreted as a valid number, and now hackrf_info is trying to close the device! We’re almost done! 8.8 Handle the Close Request Based on the --suggest output, add the following to hackrf_emulation.py:...
Page 40
Cynthion (continued from previous page) class DefaultConfiguration(USBConfiguration): class DefaultInterface(USBInterface): pass @vendor_request_handler(number=14, direction=USBDirection.IN) @to_device handle_board_id_request(self, request): # return 1-byte board ID request.reply([2]) @vendor_request_handler(number=15, direction=USBDirection.IN) @to_device handle_version_string_request(self, request): # return up to 255 bytes request.reply(b"tutorial version") @vendor_request_handler(number=18, direction=USBDirection.IN) @to_device handle_part_id_request(self, request): # return 24 byte part ID request.reply(b"A"...
Before you begin, please make sure you have installed the Cynthion tools by following Getting Started with Cynthion. 9.1.1 Install Toolchain To generate bitstreams for Cynthion you will need a synthesis toolchain that can convert the Verilog produced by Amaranth into a bitstream for Cynthion’s ECP5 FPGA. For these tutorials we recommend YoWASP which provides unofficial WebAssembly-based packages for Yosys and NextPNR.
First we’ll declare a variable half_freq which is exactly half of Cynthion FPGA’s default clock frequency in Hz, next we’ll declare timer to be an Amaranth Signal which is wide enough to contain a value equal to half_freq - 1.
In the second block the timer is still active so we simply increment timer by one. 9.6 Put It All Together The contents of gateware-blinky.py should now look like this: #!/usr/bin/env python3 # This file is part of Cynthion. # Copyright (c) 2024 Great Scott Gadgets <info@greatscottgadgets.com> # SPDX-License-Identifier: BSD-3-Clause from...
The blinky gateware will now be synthesized, placed, routed and automatically uploaded to the Cynthion’s FPGA. Once this process has completed successfully all six of Cynthion’s FPGA LEDs should be flashing on and off. 9.8 Exercises 1. Modify the tutorial to turn the FPGA LEDs into a binary counter that increments by one every 250ms.
CHAPTER USB GATEWARE: PART 1 - ENUMERATION This series of tutorial walks through the process of implementing a complete USB device with Cynthion and LUNA: • USB Gateware: Part 1 - Enumeration (This tutorial) • USB Gateware: Part 2 - WCID Descriptors •...
Page 46
GatewareUSBDevice(Elaboratable): create_descriptors(self): descriptors DeviceDescriptorCollection() with descriptors.DeviceDescriptor() d.idVendor VENDOR_ID d.idProduct PRODUCT_ID d.iManufacturer "Cynthion Project" d.iProduct "Gateware USB Device" d.bNumConfigurations return descriptors elaborate(self, platform): Module() return We have now created a minimal device descriptor with a vendor id, product id, a manufacturer, a product description and one Configuration Descriptor.
Page 47
Cynthion (continued from previous page) d.idProduct PRODUCT_ID d.iManufacturer "Cynthion Project" d.iProduct "Gateware USB Device" d.bNumConfigurations with descriptors.ConfigurationDescriptor() with c.InterfaceDescriptor() i.bInterfaceNumber return descriptors elaborate(self, platform): Module() return We have now created the descriptors for a device with a single configuration descriptor and one interface descriptor with no endpoints.
Build the device gateware and upload it to your Cynthion by typing the following into your terminal shell: python ./gateware-usb-device.py If everything went well and Cynthion’s TARGET C port is connected we should now be able to check if the target host managed to succesfully enumerate our device.
Page 49
If the device enumerated successfully you should see an entry similiar to the highlighted line: % lsusb Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub Device 003: ID 2109:2822 VIA Labs, Inc. USB2.0 Hub Device 045: ID 1d50:615c OpenMoko, Inc. Cynthion Apollo Debugger (continues on next page) 10.3. Testing the Device...
Page 50
<class IOUSBHostDevice, id 0x1000ee65d, registered,␣ matched, active, b$ | +-o USB2.0 Hub@00140000 <class IOUSBHostDevice, id 0x1000ee6b0, registered,␣ matched, active,$ | | +-o Cynthion Apollo Debugger@00144000 <class IOUSBHostDevice, id 0x100180243,␣ registered, $ | +-o Gateware USB Device@00130000 <class IOUSBHostDevice, id 0x100181cb3,␣...
Cynthion We can see our device, but it has a warning icon indicating that it does not have an installed device driver. Unlike macOS or Linux, Windows does not support a generic USB driver for non-class devices with custom vendor interfaces.
• Beyond Logic’s USB in a NutShell. • LUNA Documentation 10.7 Source Code Listing 5: gateware-usb-device-01.py #!/usr/bin/env python3 # This file is part of Cynthion. # Copyright (c) 2024 Great Scott Gadgets <info@greatscottgadgets.com> # SPDX-License-Identifier: BSD-3-Clause from amaranth import from luna.usb2...
Page 53
Module() # configure cynthion's clocks and reset signals m.submodules.car platform.clock_domain_generator() # request the physical interface for cynthion's TARGET C port ulpi platform.request("target_phy") # create the USB device m.submodules.usb USBDevice(bus=ulpi) # create our standard descriptors and add them to the device's control endpoint descriptors self.create_standard_descriptors()
Page 54
Cynthion (continued from previous page) # - main ---------------------------------------------------------------------- __name__ "__main__": with usb1.USBContext() context: list_available_usb_devices(context) Chapter 10. USB Gateware: Part 1 - Enumeration...
CHAPTER ELEVEN USB GATEWARE: PART 2 - WCID DESCRIPTORS This series of tutorial walks through the process of implementing a complete USB device with Cynthion and LUNA: • USB Gateware: Part 1 - Enumeration • USB Gateware: Part 2 - WCID Descriptors (This tutorial) •...
Page 56
GatewareUSBDevice(Elaboratable): elaborate(self, platform): Module() # configure cynthion's clocks and reset signals m.submodules.car platform.clock_domain_generator() # request the physical interface for cynthion's TARGET C port ulpi platform.request("target_phy") # create the USB device m.submodules.usb USBDevice(bus=ulpi) # create our standard descriptors and add them to the device's control endpoint descriptors self.create_standard_descriptors()
Page 57
Cynthion (continued from previous page) 0x53, 0x00, 0x46, 0x00, 0x54, 0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0xee, 0x00, # Vendor Code: 0xee The first 14 bytes correspond to the little-endian encoded Unicode string MSFT100, with the remaining two bytes corresponding to the Vendor Code Windows should use when requesting the other descriptors.
Page 58
Cynthion (continued from previous page) m.d.comb usb.connect.eq(1) return Our remaining descriptors are not returned via Standard Requests, instead they are implemented as Vendor Requests with Microsoft-defined Vendor Indices and the Vendor Code supplied in the Microsoft OS String Descriptor. We will implement the actual vendor request handler in the final step of the tutorial but for now we are just defining the Microsoft OS 1.0 Descriptor Collection that will contain these descriptors.
Page 59
Cynthion (continued from previous page) # add a microsoft descriptor collection for our other two microsoft descriptors msft_descriptors MicrosoftOS10DescriptorCollection() # add the microsoft compatible id feature descriptor with msft_descriptors.ExtendedCompatIDDescriptor() with c.Function() f.bFirstInterfaceNumber f.compatibleID WINUSB # add microsoft extended properties feature descriptor with msft_descriptors.ExtendedPropertiesDescriptor()
11.3.1 Connect • For this tutorial you will need to connect the Cynthion TARGET C port to a Windows computer for testing. • Plug the CONTROL port into the computer you’ve been using to control Cynthion. If this is the same machine as the Windows computer you’re using to test, plug it in there.
Page 61
Cynthion 11.3.2 Build Build the device gateware and upload it to your Cynthion by typing the following into your terminal shell: python ./gateware-usb-device.py If everything went well we should now be able to check if Windows can recognize the device.
Fresco Logic, Inc. - USB2.0 Hub Device 002: ID 1d5c:5000: Fresco Logic, Inc. - USB3.0 Hub Device 003: ID 1d50:615c: Great Scott Gadgets - Cynthion Apollo Debugger Device 007: ID 1209:0001: Cynthion Project - Gateware USB Device 11.4 Conclusion Our device can now be enumerated by Microsoft Windows but it can’t actually do anything yet. In the next part we’ll...
Cynthion 11.7 Source Code Listing 6: gateware-usb-device-02.py #!/usr/bin/env python3 # This file is part of Cynthion. # Copyright (c) 2024 Great Scott Gadgets <info@greatscottgadgets.com> # SPDX-License-Identifier: BSD-3-Clause from amaranth import from luna.usb2 import USBDevice from usb_protocol.emitters import DeviceDescriptorCollection from luna.gateware.usb.request.windows...
Page 64
Module() # configure cynthion's clocks and reset signals m.submodules.car platform.clock_domain_generator() # request the physical interface for cynthion's TARGET C port ulpi platform.request("target_phy") # create the USB device m.submodules.usb USBDevice(bus=ulpi) # create our standard descriptors and add them to the device's control endpoint descriptors self.create_standard_descriptors()
Page 65
Cynthion (continued from previous page) __name__ "__main__": from luna import top_level_cli top_level_cli(GatewareUSBDevice) Listing 7: test-gateware-usb-device-02.py import usb1 # - list available usb devices ------------------------------------------------ list_available_usb_devices(context): device context.getDeviceList(): try: manufacturer device.getManufacturer() product device.getProduct() print(f"{device}: {manufacturer} {product}") except Exception as print(f"{device}: {e}")
Page 66
Cynthion Chapter 11. USB Gateware: Part 2 - WCID Descriptors...
CHAPTER TWELVE USB GATEWARE: PART 3 - CONTROL TRANSFERS This series of tutorial walks through the process of implementing a complete USB device with Cynthion and LUNA: • USB Gateware: Part 1 - Enumeration • USB Gateware: Part 2 - WCID Descriptors •...
Page 68
We’ll start by extending our control endpoints to support two vendor requests: One to set the state of the Cynthion FPGA LEDs and another to get the state of the Cynthion USER BUTTON.
Page 69
GatewareUSBDevice(Elaboratable): elaborate(self, platform): Module() # configure cynthion's clocks and reset signals m.submodules.car platform.clock_domain_generator() # request the physical interface for cynthion's TARGET C port ulpi platform.request("target_phy") # create the USB device m.submodules.usb USBDevice(bus=ulpi) # create our standard descriptors and add them to the device's control endpoint descriptors self.create_standard_descriptors()
Page 70
Cynthion So far our VendorRequestHandler contains references to Cynthion’s FPGA LEDs and USER BUTTON, as well as a StreamSerializer we’ll be using to send data back to the host when it asks for the USER BUTTON status. 12.2.2 Implement Vendor Request Handlers Let’s implement that functionality below:...
IN control request with the data containing the state of the user button. 12.3 Test Control Endpoints First, remember to build and upload the device gateware to your Cynthion with: python ./gateware-usb-device.py Then, open your test-gateware-usb-device.py script from the previous tutorials and add the following code to...
Page 72
Cynthion Listing 3: test-gateware-usb-device.py import usb1 import time VENDOR_ID 0x1209 # https://pid.codes/1209/ PRODUCT_ID 0x0001 VENDOR_SET_FPGA_LEDS 0x01 VENDOR_GET_USER_BUTTON 0x02 # - list available usb devices ------------------------------------------------ list_available_usb_devices(context): device context.getDeviceList(): try: manufacturer device.getManufacturer() product device.getProduct() print(f"{device}: {manufacturer} {product}") except Exception as print(f"{device}: {e}")
Page 73
./test-gateware-usb-device.py And, if all goes well you should see the FPGA LEDs on Cynthion counting in binary. If you press and release the USER button you should see the count reset back to zero and the following text in the terminal.
• Beyond Logic’s USB in a NutShell. • LUNA Documentation 12.6 Source Code Listing 4: gateware-usb-device-03.py #!/usr/bin/env python3 # This file is part of Cynthion. # Copyright (c) 2024 Great Scott Gadgets <info@greatscottgadgets.com> # SPDX-License-Identifier: BSD-3-Clause from amaranth import from luna.usb2...
Page 75
Cynthion (continued from previous page) # shortcuts interface: RequestHandlerInterface self.interface setup: SetupPacket self.interface.setup # get a reference to the FPGA LEDs and USER button fpga_leds Cat(platform.request("led", i).o range(6)) user_button platform.request("button_user").i # create a streamserializer for transmitting IN data back to the host...
Page 76
Module() # configure cynthion's clocks and reset signals m.submodules.car platform.clock_domain_generator() # request the physical interface for cynthion's TARGET C port ulpi platform.request("target_phy") # create the USB device m.submodules.usb USBDevice(bus=ulpi) (continues on next page) Chapter 12. USB Gateware: Part 3 - Control Transfers...
Page 77
Cynthion (continued from previous page) # create our standard descriptors and add them to the device's control endpoint descriptors self.create_standard_descriptors() control_endpoint usb.add_standard_control_endpoint( descriptors, # the blockram descriptor handler lacks support for # non-contiguous string descriptor indices, which is # required for the Microsoft OS string descriptor at 0xEE avoid_blockram=True, # add microsoft os 1.0 descriptors and request handler...
Page 78
Cynthion (continued from previous page) device context.getDeviceList(): try: manufacturer device.getManufacturer() product device.getProduct() print(f"{device}: {manufacturer} {product}") except Exception as print(f"{device}: {e}") # - wrappers for control requests --------------------------------------------- set_fpga_leds(device_handle, led_state): response device_handle.controlWrite( request_type usb1.TYPE_VENDOR usb1.RECIPIENT_DEVICE, request VENDOR_SET_FPGA_LEDS, index value data [led_state],...
Page 79
Cynthion (continued from previous page) last_button_state button_state # slow the loop down so we can see the counter change time.sleep(0.1) # - main ---------------------------------------------------------------------- __name__ "__main__": with usb1.USBContext() context: # list available devices list_available_usb_devices(context) # get a device handle to our simple usb device device_handle context.openByVendorIDAndProductID(VENDOR_ID, PRODUCT_ID)
Page 80
Cynthion Chapter 12. USB Gateware: Part 3 - Control Transfers...
CHAPTER THIRTEEN USB GATEWARE: PART 4 - BULK TRANSFERS This series of tutorial walks through the process of implementing a complete USB device with Cynthion and LUNA: • USB Gateware: Part 1 - Enumeration • USB Gateware: Part 2 - WCID Descriptors •...
Page 82
# https://pid.codes/1209/ PRODUCT_ID 0x0001 MAX_PACKET_SIZE class VendorRequestHandler(ControlRequestHandler): class GatewareUSBDevice(Elaboratable): create_standard_descriptors(self): descriptors DeviceDescriptorCollection() with descriptors.DeviceDescriptor() d.idVendor VENDOR_ID d.idProduct PRODUCT_ID d.iManufacturer "Cynthion Project" d.iProduct "Gateware USB Device" d.bNumConfigurations with descriptors.ConfigurationDescriptor() (continues on next page) Chapter 13. USB Gateware: Part 4 - Bulk Transfers...
Page 83
Cynthion (continued from previous page) with c.InterfaceDescriptor() i.bInterfaceNumber # EP 0x01 OUT - receives bulk data from the host with i.EndpointDescriptor() e.bEndpointAddress USBDirection.OUT.to_endpoint_address(0x01) e.bmAttributes USBTransferType.BULK e.wMaxPacketSize MAX_PACKET_SIZE # EP 0x82 IN - transmits bulk data to the host with i.EndpointDescriptor() e.bEndpointAddress...
Page 84
512 bytes of a bulk transfer. Using the OUT endpoint we could then transmit a stream of data from the host to Cynthion and write it into the FIFO. Then, when we transmit a request from the host to the IN endpoint we can stream the previously queued data back to the host.
Page 85
• fast - a fast clock domain used for the HyperRAM, running at 240 MHz. Because our designs so far have all been interfacing with Cynthion’s USB components we’ve only needed to use the usb clock domain. However, reusable Amaranth components such as SyncFIFO are usually implemented using the default sync domain.
Cynthion This is what DomainRenamer does. And that’s it, we’ve defined our endpoint functions! Let’s try it out. 13.3 Test Bulk Endpoints Open up test-gateware-usb-device.py and add the following code to it: Listing 4: test-gateware-usb-device.py import usb1 import time import...
Cynthion (continued from previous page) value length timeout 1000, return response[0] # - test control endpoints ---------------------------------------------------- test_control_endpoints(device_handle): led_counter False last_button_state while True: # led counter set_fpga_leds(device_handle, led_counter) led_counter (led_counter # reset led counter when the USER button is pressed...
Page 88
Cynthion (continued from previous page) test_bulk_endpoints(device_handle): # bulk_out - write a list of random numbers to memory data list([random.randint(0, 255) range(MAX_PACKET_SIZE)]) response bulk_out_transfer(device_handle, data) print(f"OUT endpoint transmitted {response} bytes: {data[0:4]} {data[-4:]}") # bulk_in - retrieve the contents of our memory...
• Beyond Logic’s USB in a NutShell. • LUNA Documentation 13.6 Source Code Listing 5: gateware-usb-device-04.py #!/usr/bin/env python3 # This file is part of Cynthion. # Copyright (c) 2024 Great Scott Gadgets <info@greatscottgadgets.com> # SPDX-License-Identifier: BSD-3-Clause from amaranth import from amaranth.lib.fifo...
Page 90
Cynthion (continued from previous page) MAX_PACKET_SIZE class VendorRequestHandler(ControlRequestHandler): VENDOR_SET_FPGA_LEDS 0x01 VENDOR_GET_USER_BUTTON 0x02 elaborate(self, platform): Module() # shortcuts interface: RequestHandlerInterface self.interface setup: SetupPacket self.interface.setup # get a reference to the FPGA LEDs and USER button fpga_leds Cat(platform.request("led", i).o range(6)) user_button platform.request("button_user").i...
Page 91
# all USB devices have a single device descriptor with descriptors.DeviceDescriptor() d.idVendor VENDOR_ID d.idProduct PRODUCT_ID d.iManufacturer "Cynthion Project" d.iProduct "Gateware USB Device" d.bNumConfigurations # and at least one configuration descriptor with descriptors.ConfigurationDescriptor() # with at least one interface descriptor with c.InterfaceDescriptor()
Page 92
Module() # configure cynthion's clocks and reset signals m.submodules.car platform.clock_domain_generator() # request the physical interface for cynthion's TARGET C port ulpi platform.request("target_phy") # create the USB device m.submodules.usb USBDevice(bus=ulpi) # create our standard descriptors and add them to the device's control endpoint descriptors self.create_standard_descriptors()
Page 93
Cynthion (continued from previous page) usb.add_endpoint(ep_out) ep_in USBStreamInEndpoint( endpoint_number=0x02, # (EP 0x82) max_packet_size=MAX_PACKET_SIZE usb.add_endpoint(ep_in) # create a FIFO queue we'll connect to the stream interfaces of our # IN & OUT endpoints m.submodules.fifo fifo DomainRenamer("usb")( SyncFIFO(width=8, depth=MAX_PACKET_SIZE) # connect our Bulk OUT endpoint's stream interface to the FIFO's write port stream_out ep_out.stream...
Page 94
Cynthion (continued from previous page) list_available_usb_devices(context): device context.getDeviceList(): try: manufacturer device.getManufacturer() product device.getProduct() print(f"{device}: {manufacturer} {product}") except Exception as print(f"{device}: {e}") # - wrappers for control requests --------------------------------------------- set_fpga_leds(device_handle, led_state): response device_handle.controlWrite( request_type usb1.TYPE_VENDOR usb1.RECIPIENT_DEVICE, request VENDOR_SET_FPGA_LEDS, index value data...
Page 95
Cynthion (continued from previous page) else print(f"USER button is: button_state }") last_button_state button_state # slow the loop down so we can see the counter change time.sleep(0.1) # - wrappers for bulk requests ------------------------------------------------ bulk_out_transfer(device_handle, data): response device_handle.bulkWrite( endpoint 0x01, data...
Page 96
Cynthion (continued from previous page) None: device_handle raise Exception("Device not found.") # claim the device's interface device_handle.claimInterface(0) # pass the device handle to our bulk endpoint test test_bulk_endpoints(device_handle) # pass the device handle to our control endpoint test test_control_endpoints(device_handle) Chapter 13. USB Gateware: Part 4 - Bulk Transfers...
• TARGET C - USB Type-C connector for Packetry traffic capture and Facedancer device emulation. • TARGET A - USB Type-A connector shared with the TARGET C connector. • RESET - Press this button to reset Cynthion’s debug microcontroller and reconfigure the FPGA from flash.
Cynthion 15.4 Front View • A & B - Two Digilent Pmod™ Compatible I/O connectors for a total of 16 high-speed FPGA user IOs. – B can also be configured to act as a serial port and JTAG connector for debugging SoC designs: ∗...
Page 101
SELF-MADE HARDWARE BRINGUP This guide is intended to help you bring up a Cynthion board you’ve built yourself. If you’ve received your board from Great Scott Gadgets, it should already be set up, and you shouldn’t need to follow these steps.
Page 102
Cynthion saturn-v $ make If you’re building a board that predates r0.3 hardware, you’ll need to specify the board you’re building for: saturn-v $ make BOARD=luna_d21 The build should yield two useful build products: bootloader.elf and bootloader.bin; your SWD programmer will likely consume one of these two files.
Page 103
"Flash" If your device shows up as a Cynthion board, congratulations! You’re ready to move on to the next step. 16.3.1 Optional: Bootloader Locking Optionally, you can reversibly lock the bootloader region of the Debug Controller, preventing you from accidentally overwriting the bootloader.
Before you can run the applet, you’ll need to have a working cynthion development environment. See Introduction to get your environment set up. Next, we can check to make sure your Cynthion board is recognized by the Cynthion toolchain. Running the apollo info command will list any detected devices: $ apollo info Detected a Cynthion device! Hardware: Cynthion r1.4...
Page 105
CHAPTER SEVENTEEN THE APOLLO COMMAND LINE UTILITY The cynthion distribution provides the apollo command-line utility, that can be used to perform various simple functions useful in development; including simple JTAG operations, SVF playback, manipulating the board’s flash, and debug communications.
Page 106
Cynthion Chapter 17. The apollo command line utility...
CHAPTER EIGHTEEN GETTING HELP Before asking for help with Cynthion, check to see if your question is answered in this documentation, or addressed in Cynthion GitHub repository issues. For assistance with Cynthion general use or development, please look at the issues on the GitHub project.
Page 109
CHAPTER NINETEEN CYNTHION PROJECTS AND MENTIONS Have you done something cool with Cynthion or mentioned Cynthion in one of your papers or presentations? Email us at info@greatscottgadgets.com with a link to what you’ve done and we might post it here!
Page 110
Cynthion Chapter 19. Cynthion Projects and Mentions...
• A pass-through power supply connected to Cynthion must supply at least 5 V DC and no more than 20 V DC. The pass-through power supply must be rated for the current drawn by the pass-through device connected to Cynthion.
CHAPTER TWENTYONE INTRODUCTION 21.1 Setting up a Development Environment This guide highlights the installation and setup process for setting up a local copy of the Cynthion source code for development. 21.2 Prerequisites • Python v3.9, or later. • A working FPGA toolchain. We only officially support a toolchain composed of the...
Page 114
Cynthion Use git to clone the repository: git clone https://github.com/greatscottgadgets/cynthion.git Note: To install the cynthion Python package and allow for in-place editing of the sources you can use the pip --editable command: # change to the 'cynthion' Python package directory...
Page 115
• analyzer – USB analyzer for using Cynthion with Packetry. • facedancer – System-on-Chip for using Cynthion with Facedancer. Bitstreams can be generated from the cynthion Python package sub-directory as follows: 22.1.1 Analyzer Gateware # change to the 'cynthion' Python package directory...
Page 116
Cynthion 22.1.3 Additional Options Additional options for bitstream generation can be listed by appending --help to the command: $ python3 -m cynthion.gateware.analyzer.top --help usage: top.py [-h] [--output filename] [--erase] [--upload] [--flash] [--dry-run] [--keep-files] [--fpga part_number] [--console port] Gateware generation/upload script for USBAnalyzerApplet gateware.
Page 117
23.3 Building and Running Firmware for the Cynthion SoC can be found in the firmware/moondancer/ sub-directory. You can rebuild the firmware using cargo as follows: # change to the Cynthion firmware directory cd firmware/moondancer/...
Once the firmware is running on the SoC you can execute some unit tests to exercise the firmware. In order to do this you will need to connect both the CONTROL and AUX ports of the Cynthion to the host and then...
Need help?
Do you have a question about the Cynthion and is the answer not in the manual?
Questions and answers