Working with HPS proto2

The HPS prototype board revision 2 (“proto2”) is an external board with the HPS circuit, plus additional components which are useful for development. The board is not publicly available. Googlers can refer to go/hps-care for more details about the hardware.

One-time setup

The proto2 board uses an FTDI FT4232H chip to provide UART and power control to the host over USB, and an MCP2221 chip for I2C over USB. It needs some extra packages and configuration on the host (your gLinux workstation) before you can use it.

Run the setup script inside the ChromiumOS chroot:

scripts/setup

Also run the accompanying setup script outside the chroot. This script grants permission for your user account to access the relevant USB devices:

scripts/setup-proto2-on-host

If your user account cannot access the FT4232H USB device, the helper scripts may print an error like:

ValueError: The device has no langid (permission issue, no string descriptors supported or device error)

or:

Error: libusb_open() failed with LIBUSB_ERROR_ACCESS
Error: no device found
Error: unable to open ftdi device with vid 0403, pid 6011, description '*', serial '*' at bus location '*'

If your user account cannot access the MCP2221 USB device, the helper scripts may print an error like:

Error: Failed to open HPS via I2C: USB error: Access denied (insufficient permissions)

Running the MCU application

Start OpenOCD:

scripts/proto2-openocd

Example output:

** Programming Started **
** Programming Finished **
** Verify Started **
** Verified OK **
** Resetting Target **
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections

Leave the script running OpenOCD in one terminal, and continue working in another terminal. Scripts such as mcu-run and fpga-rom-run interact with OpenOCD over port 4444.

To build and run the MCU program, run:

scripts/mcu-run

This helper script builds the MCU application with development features enabled, then programs it onto the MCU flash and runs it. It then shows output from the MCU program and allows further interaction.

NOTE: The first time you program the MCU flash (or if you have erased it), the STM32 bootloader will not correctly reset into the application. As a workaround, power cycle the board using scripts/proto2-power-cycle.py, then run scripts/mcu-run again.

Interacting with the MCU application

When the MCU application is built with development features enabled, it accepts debugging commands using the RTT (Real-Time Transfer) protocol.

Use the monitor program to interact with the MCU over RTT. In the terminal that's running scripts/mcu-run, press enter to activate the console, then type a command. The monitor prints messages it receives over RTT. Example output:

>> reset_mcu
MCU> INFO: Found expected flash chip
MCU> INFO: Default HM01B0 configuration applied
MCU> INFO: MCU application started. CPU is running at 60MHz

>> launch_app
Command LaunchApp running
Command LaunchApp complete
MCU> INFO: FPGA reported boot #1
FPGA> Hello from the Rust FPGA
FPGA> Classifier status: InitOk

You can also program the FPGA bitstream and FPGA application image via the MCU using the write_gateware and write_soc_rom commands. The script assumes you have already built the bitstream and application using the scripts/build-fpga-bitstream and scripts/build-fpga-rom-dev helper scripts.

Check help for a complete list of monitor commands.

Running the MCU stage0 boot loader

On a real HPS peripheral, the stage0 boot loader is permanently programmed at the beginning of flash, and it executes the stage1 application from an offset in flash after verifying its signature. When working with proto2, we typically skip the stage0 boot loader because it’s not necessary for development. The scripts/mcu-run helper script mentioned above writes the application to the beginning of flash; the stage0 boot loader is not involved.

However, if you are testing a change to the stage0 boot loader, you may want to run it on proto2. There is a corresponding helper script for stage0:

scripts/proto2-stage0-run

There is no monitor command for stage0. It does not support RTT. You can interact with stage0 using the hps-util Rust tool or the C++ hps tool from platform2.

On proto2 the WP (Write Protect) line is controlled by a GPIO pin on the FT4232H. If you want to test stage0 signature verification, you can assert WP:

scripts/proto2-power-cycle.py --write-protect

By default the script deasserts WP.

Accessing the UART

Note that although proto2 has UART connections, HPS firmware does not have any code or FPGA logic for interacting with the UART. You will not see any output on the UART. However, the proto2 UART connections are still useful with CFU-Playground, where the code does interact with the UART.

To connect your terminal to the UART, run:

scripts/proto2-term

This script wraps the Litex terminal interface. Press Control-C twice in quick succession to disconnect.

Observing the interrupt line

On proto2 the MLB interrupt line (signal from HPS to the main logic board to request its attention) is connected to an ATmega16u4 USB-capable MCU. Its UART is connected to FT4232H port D and its USB interface is connected to proto2's USB hub.

In order to observe the interrupt line, you need to program the ATmega16u4:

scripts/avr-prog

You can then run the helper script to watch the UART output from the ATmega16u4:

scripts/avr-term

The UART output will show ! when the interrupt line goes high and . when it goes low.

The hps-mon and hps-util tools can also monitor the interrupt line state via the ATmega16U4 UART. Pass --interrupt=avr-ftdi-proxy to enable support.

Unlocking RDP (flash protection in the MCU)

If you use hps-factory to write stage0 to proto2, it will also configure readout protect (RDP) level 1 to protect the MCU flash. OpenOCD (and all the helper scripts) will then be unable to program flash in that case:

[...]
Error: stm32x device protected
Error: failed erasing sectors 0 to 28
embedded:startup.tcl:530: Error: ** Programming Failed **
in procedure 'program'
in procedure 'program_error' called at file "embedded:startup.tcl", line 595
at file "embedded:startup.tcl", line 530

To remove RDP and unlock the flash, first start the OpenOCD helper script:

scripts/proto2-openocd

In another terminal, use GDB to issue the necessary register writes:

arm-none-eabi-gdb \
    --ex 'target extended-remote localhost:3333' \
    --ex 'set {int}0x40022008 = 0x45670123' \
    --ex 'set {int}0x40022008 = 0xCDEF89AB' \
    --ex 'set {int}0x4002200c = 0x08192A3B' \
    --ex 'set {int}0x4002200c = 0x4C5D6E7F' \
    --ex 'set {int}0x4002202c = 0x3f' \
    --ex 'set {int}0x40022020 = 0xfffffeaa' \
    --ex 'set {int}0x40022014 = 0x20000'