Skip to content

FX3 firmware

How to build the Domesday Duplicator's USB 3.0 firmware and get it onto the device, with a check to confirm each step actually worked.

The FX3 is a Cypress EZ-USB FX3 SuperSpeed Explorer Kit (CYUSB3KIT-003) that plugs into the Domesday Duplicator PCB. Everything on this page happens over the FX3's own USB connector.

There are two ways to program it, and you will usually want both:

Writes to Survives a power cycle Use for
RAM (-u) Volatile memory No Testing a build before committing to it
I2C EEPROM (-p) The kit's onboard EEPROM Yes Normal use

Start with RAM. It cannot leave the device in a bad state — a power cycle undoes it completely — so it is the safe way to find out whether an image works before making it permanent.

There is no SPI flash here

The SuperSpeed Explorer Kit boots from an I2C EEPROM. Older versions of fx3-programmer's help text described -p as programming "SPI flash"; that was wrong, and there has never been an SPI code path. If you are reading documentation that mentions SPI flash for this board, it is out of date.

The application can do this for you

Everything on this page is now also available from ddd-guiTools ▸ Firmware ▸ Bring up a new or legacy board… — which programs both the FX3 and the FPGA with no vendor toolchain installed at all. See Bringing up a new or legacy board.

This page remains the reference for what the wizard is doing, and the route to take when something needs doing by hand.

Before you start

  1. Set up device accessLinux device access. Without it every command below reports that no device was found.
  2. Locate the PMODE jumper, J4, on the FX3 board. You will be moving it.

The two positions, which every step below refers to as fitted and removed:

Jumper J4 fitted — the USB-boot position

Jumper J4 removed — the EEPROM-boot position

1. Build the firmware

From anywhere in a checkout:

nix build .#fx3-firmware
ls result/
firmware.elf  firmware.img  firmware.map

firmware.img is the one you program. Nothing needs installing first — the ARM cross compiler, the image builder and the SDK all come from the flake.

For an editing loop rather than a one-shot build, nix develop .#fx3 gives the same toolchain as a shell; the build options are in fx3/firmware/README.md.

Check: does the build know what it is?

The firmware stamps the commit it was built from into its USB product descriptor, which is how you will confirm later that the device is running your image and not the one that was already on it. The configure step prints it:

-- Firmware version: d0566b3e

A value of unknown means the build could not determine a version — pass one explicitly with -DFIRMWARE_VERSION=<hash>. A -dirty suffix means the working tree had uncommitted changes, so the hash alone does not describe what you built. Both are worth noticing before you program anything.

2. Put the FX3 into bootloader mode

Both programming modes need the FX3's boot ROM in control. Once the device is running firmware, the boot ROM is not, and neither -u nor -p will work.

  1. Fit the PMODE jumper (J4).
  2. Power cycle the board — unplug the FX3's USB cable and plug it back in.

Check: is it in bootloader mode?

$ lsusb -d 04b4:
Bus 007 Device 013: ID 04b4:00f3 Cypress Semiconductor Corp. FX3 micro-controller (DFU mode)

04b4:00f3 and "DFU mode" is what you want. And through the tool:

$ fx3-programmer -l
Found 1 FX3 device(s):

[0] VID:PID=04b4:00f3 Bus=007 Device=013 Mode=Bootloader (FX3)

If it still shows 1209:2347 / Mode=Application, the jumper is not fitted or the board was not actually power cycled. Note that a warm reboot of your PC may not cut USB bus power — unplug the cable.

3a. Load into RAM — the test path

fx3-programmer -d 0 -u result/firmware.img
Uploading result/firmware.img (111348 bytes) to FX3 device 0...
Target device: VID:PID=04b4:00f3
........................................................
Program entry address: 0x400074e8

Successfully uploaded 111300 bytes to FX3 device 0

The bootloader transfers control to the image as soon as the download finishes — there is no separate start step. The device disappears from the bus and comes back as the Domesday Duplicator a second or so later.

This is volatile. Power cycle and it is gone. That is the point: if the image is broken, you have lost nothing.

3b. Write the EEPROM — the production path

Do this once you are satisfied the image works.

fx3-programmer -d 0 -p result/firmware.img -v
Downloading flash programmer /…/share/domesday-duplicator/cyfxflashprog.img to device 0...
Successfully uploaded 106408 bytes to FX3 device 0
Found FX3 flash programmer (device 0)
Programming result/firmware.img (111348 bytes, padded to 111360) to FX3 I2C EEPROM...
..
Successfully programmed 111360 bytes to FX3 I2C EEPROM
Verifying result/firmware.img against FX3 I2C EEPROM (111348 bytes, padded to 111360)...
..
Verification successful: EEPROM matches result/firmware.img
Power cycle the device (remove J4/PMODE to boot from EEPROM)

Three things worth understanding in that output:

  • A Cypress secondary loader is downloaded first. The FX3 boot ROM can only write RAM, so reaching the EEPROM needs a helper program running on the device. fx3-programmer ships it and finds it automatically.
  • The device re-enumerates as 04b4:4720 partway through. That is the loader running. It is expected and goes away at the next power cycle.
  • -v is worth using. It re-reads the EEPROM and compares it against the file. Each chunk is also verified as it is written, but -v checks the whole image afterwards.

Then:

  1. Remove the PMODE jumper (J4).
  2. Power cycle the board.

It should now boot the programmed firmware on its own, with no host involvement.

Confirming what is running

This is the step people skip, and it is the only one that proves anything.

$ lsusb -d 1209:2347
Bus 008 Device 005: ID 1209:2347 Generic Domesday Duplicator (d0566b3e)

Then read the descriptors:

$ lsusb -v -d 1209:2347 | grep -iE "bcdUSB|iManufacturer|iProduct"
  bcdUSB               3.00
  iManufacturer           1 Domesday86
  iProduct                2 Domesday Duplicator (d0566b3e)

Three things to check, in order of importance:

Field Expect If it is wrong
iProduct Domesday Duplicator (<commit>) The hash in brackets is the commit the firmware was built from. If it is not the one your build printed, the device is running something else — most likely the previous EEPROM contents, meaning your programming did not take
bcdUSB 3.00 At 2.10 or lower the device fell back to USB 2.0. Try a different cable or port — this halves your capture bandwidth and causes dropped samples
iManufacturer Domesday86 Anything else is not this firmware

You can also confirm the negotiated link speed:

$ for d in /sys/bus/usb/devices/*/; do
    [ "$(cat $d/idVendor 2>/dev/null)" = "1209" ] && \
    echo "$(cat $d/speed) Mbps — $(cat $d/product)"
  done
5000 Mbps  Domesday Duplicator (d0566b3e)

5000 Mbps is SuperSpeed and is what you need. 480 Mbps means USB 2.0.

Troubleshooting

Symptom Cause and fix
No FX3 devices found, but lsusb shows it Device permissions. See Linux device access
Error: device 0 is not in bootloader mode The FX3 is running firmware. Fit J4 and power cycle
Error: Device must be in bootloader mode to launch flash programmer Same — -p needs the boot ROM
Error: cyfxflashprog.img not found The Cypress secondary loader is missing. It ships with the programmer; if you are running from a build tree rather than an install, set FX3_FLASH_PROG to its path
Device never reappears after -u The image is not bootable. Power cycle with J4 fitted to get back to the bootloader — RAM loading cannot brick anything
iProduct still shows the old commit The EEPROM write did not take, or J4 is still fitted so it booted over USB instead. Re-check step 3b and that J4 is removed
iProduct shows unknown The firmware was built without version information. Rebuild passing -DFIRMWARE_VERSION=
Device enumerates at 480 Mbps USB 2.0 fallback. Use a USB 3.0 port and a cable rated for it
The host takes ~20 seconds to wake from sleep, with a blank screen Not a device fault. A board left in bootloader mode across a suspend — see below

There is no software reset

fx3-programmer has no reset option, and one is not possible: the FX3 boot ROM offers no reset command, and the Domesday Duplicator firmware implements only its own capture control requests. Changing boot mode always means a physical power cycle, with J4 fitted or removed to choose where the device boots from.

Leaving the board in bootloader mode can stall suspend and resume

Finish a programming session by putting the board back to application firmware, or by unplugging it. A board left sitting in bootloader mode is running the Cypress boot ROM, and the boot ROM does not survive a host suspend reliably.

On Linux, waking from S3 with an 04b4:00f3 device still attached can stall the kernel's device-resume phase for around twenty seconds:

usb 7-3.3: reset high-speed USB device number 23 using xhci_hcd
usb 7-3.3: device descriptor read/64, error -110

-110 is -ETIMEDOUT: after resetting the port, the kernel asked the device for its descriptors and got no answer. All of that happens before Restarting tasks, so userspace — including whatever is drawing your screen — is still frozen for the whole stall. The machine looks dead, with a blank display and no response to input, until the kernel gives up on the device and lets userspace run again.

It is not deterministic. The same board in the same state has resumed cleanly from a short suspend and stalled after a long one, so a session that ended fine yesterday is no guarantee. A board running application firmware (1209:2347) is unaffected — it resumes in the same fraction of a second as a machine with nothing on the port at all.

The cure is to not leave it there: remove J4 and power cycle when you have finished, or unplug the cable. Nothing in this project can do it for you, because there is no software reset — the boot ROM has no command that would return the device to application firmware, and the host cannot power cycle it.

If you would rather the host coped, Linux can be told to power the port down at suspend rather than trying to resume the device:

usbcore.quirks=04b4:00f3:m,04b4:4720:m

m is USB_QUIRK_DISCONNECT_SUSPEND, which makes usb_suspend() call usb_port_disable() on the way into suspend. At resume there is nothing on the port to reset, so the timeout never happens and the device re-enumerates normally afterwards. 4720 is the transient flash-programmer identity, which is the same boot-ROM-era code and worth covering too. This is a boot parameter, so it needs a reboot to take effect — and unrecognised flag letters are silently ignored, so check the letter against Documentation/admin-guide/kernel-parameters.txt for your own kernel rather than expecting a typo to report itself.

Recovering a device that will not boot

You cannot brick the FX3 by programming it, because the PMODE jumper bypasses the EEPROM entirely. Fit J4, power cycle, and the boot ROM takes over regardless of what is in the EEPROM. Then reprogram.