On revC hardware, loading a new bitstream (e.g. switching applets) unconditionally killed both VIO A and VIO B voltage rails. This made it impossible to configure a device on one port with one applet and then load a second applet to use it — the voltage was gone before the second applet even started.
firmware/fpga.c fpga_reset() explicitly called iobuf_set_voltage(IO_BUF_ALL, 0) and
then waited 250 ms for the rails to discharge before asserting CRESET_N. The original
rationale was that an unconfigured iCE40 has internal weak pull-ups on all I/O pins, and on
revC a high logic level on the level shifter OE pin (driven by the FPGA) enables the level
shifter as an output — which could drive external circuitry unexpectedly during
reconfiguration.
However, the LDO enable pins (ENVA = IOD[0], ENVB = IOD[6]) live on the FX2
microcontroller, not the FPGA. The FPGA reset does not affect FX2 port D state. The voltage
discharge was an intentional but conservative safety measure, not a hard electrical
requirement, and is unnecessary if the connected device can tolerate the ~1.2 ms window
during which the FPGA is unconfigured and outputs go HIGH through 33o resistors.
Removed the iobuf_set_voltage(IO_BUF_ALL, 0) call and the 250 ms discharge delay from the
revC case in fpga_reset() in firmware/fpga.c.
- case GLASGOW_REV_C0:
- case GLASGOW_REV_C1:
- case GLASGOW_REV_C2:
- case GLASGOW_REV_C3: {
- // Disable voltage output.
- // This is necessary because iCE40 FPGAs have pull-ups enabled by default (when unconfigured
- // and on unused pins), and on revC, a high logic level on the OE pin configures the respective
- // level shifter as an output.
- __xdata uint16_t millivolts = 0;
- iobuf_set_voltage(IO_BUF_ALL, &millivolts);
-
- // We don't have feedback from the Vio output to know when it has actually discharged.
- // The device itself has 6 µF of capacitance and a load of 1 kΩ(min), for a t_RC = 6 ms.
- // A reasonable starting point is 3×t_RC = 18 ms. However, external circuitry powered by
- // the device can and likely will add some bulk capacitance. 250 ms of delay would be safe
- // in the worst case of 5 V, 40 uF, no added load. It is also not long enough to become
- // an annoyance.
- delay_ms(250);
-
- // Reset the FPGA now that it's safe to do so.
+ case GLASGOW_REV_C0:
+ case GLASGOW_REV_C1:
+ case GLASGOW_REV_C2:
+ case GLASGOW_REV_C3: {
+ // Reset the FPGA.The Docker-based build in firmware/docker.sh requires network access to pull the Debian
image. As an alternative, build natively on macOS using Homebrew:
brew install sdcc makeYou also need the libfx2 submodule (used for the fx2tool loader):
git submodule update --init vendor/libfx2Use gmake (Homebrew GNU make 4.x) rather than the system make (3.81), which is too old
for the firmware Makefile:
# Build libfx2 first (only needed once, or after submodule update)
gmake -C vendor/libfx2/firmware/library all MODELS=medium
# Build the Glasgow firmware
gmake -C firmware all
# Output: firmware/build/glasgow.ihexThe Glasgow venv Python (3.13) has libusb1; use it directly with fx2tool:
PYTHONPATH=vendor/libfx2/software \
software/.venv/bin/python3.13 -m fx2.fx2tool \
-d 20b7:9db1 load firmware/build/glasgow.ihexThe firmware is loaded into RAM only — it is lost on power cycle. No EEPROM is written.
First deploy the built firmware into the software tree, then flash it:
# Normalize and copy to the location glasgow flash expects
PYTHONPATH=vendor/libfx2/software python3 firmware/normalize.py \
firmware/glasgow.ihex software/glasgow/hardware/firmware.ihex
# Flash to device EEPROM
glasgow flash --firmware# Set port voltages (persists in DAC registers on FX2, not reset by bitstream load)
glasgow voltage A 3.3
glasgow voltage B 1.8
# Run a first applet with explicit voltages
glasgow run experimental-calibrate-clock -V B=1.8,A=3.3 --ref-pin B0 --ref-freq 8388608 --count 5
# Run a second applet WITHOUT -V — voltages are now preserved across the bitstream reload
glasgow run experimental-calibrate-clock --ref-pin B0 --ref-freq 8388608 --count 5 --ext-pin A2 --ext-freq 10e6Previously the second invocation would log cannot configure pulls for port X: Vio is off
and start with dead rails. With this fix the rails stay live.
.ihex available @ https://gist.github.com/i-infra/44f7266bc714a92900299f067123ce48