Download Software from fomu.im/camp19

Fomu: An FPGA in your USB Port

A whirlwind introduction to Fomu; a workshop in three levels

Sean Cross - https://xobs.io/ - @xobs

Levels of Fomu

Fomu aims to be accessable on three levels:

  1. Python / Interpreter
  2. RISC-V / C
  3. FPGA / HDL

Workshop Outline

  1. What do I need to get started?
  2. What is an FPGA, and what is Fomu?
  3. Working with Fomu using Python, RISC-V, and HDL

What do I need to get started?

  1. DFU utilities
  2. Serial console
  3. RISC-V toolchain
  4. FPGA Toolchain
  5. Python 3

What is an FPGA?

SB_LUT4

What is an FPGA?

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
IO0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
IO1 0 0 0 0 1 1 1 1 0 0 0 0 1 1 1 1
IO2 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1
IO3 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1
O ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

What is an FPGA?


						module example (output reg [0:5] Q, input C);
							reg [0:8] counter;
							always @(posedge C)
							begin
								counter <= counter + 1'b1;
								Q = counter[7] ^ counter[5] | counter<<2;
							end
						endmodule
					
Verilog Synthesis

About the ICE40UP5K

  1. 5280 4-input LUTs (LC)
  2. 16 kilobytes BRAM
  3. 128 kilobytes "SPRAM"
  4. Current-limited 3-channel LED driver
  5. 2x I2C and 2x SPI
  6. 8 16-bit DSP units
  7. Warmboot capability
  8. Open toolchain

What is Fomu?

  • ICE40UP5K
  • 2MB QSPI flash memory
  • Four edge-plated pads
  • ESD protection
  • USB implemented in HDL
  • Fits in your USB port

Fomu Block Design Diagram

Fomu block diagram

What is this PCB?

Fomu EVT1

Fomu EVT1

Misleading Datasheets

Footprint from Crystal

What modifications does it have?

  • Shorting out two zero-ohm resistors (R7, PU)
  • Programming SPI flash
  • Bending SPI flash pins inward (U4)
  • Mounting crystal on its side (U7)
  • Attaching power to crystal

Fomu SPI Flash Layout

Fomu memory layout

Working with Fomu

FAT Bootloader

  • Presents itself as a USB disk
  • Drag and drop files to program
  • Multiple interpreter support

"fail safe" bootloader

Device Firmware Update - DFU

Updating Fomu

$ dfu-util -l
Found DFU: [1209:5bf0] name="Fomu DFU Bootloader v1.7.2"
$ dfu-util -D evt-installable.dfu
Download        [=========                ]  36%   38912 bytes
Download done.
$ dfu-util -l
Found DFU: [1209:5bf0] name="Fomu DFU Bootloader v1.8.1"
$

Python / Interpreted

  1. Goal: Multiple interpreters, auto-reload, USB disk interface
  2. Now: MicroPython binary

Loading Programs onto Fomu


$ dfu-util -l
Found DFU: [1209:5bf0] name="Fomu DFU Bootloader v1.8.1"
$ dfu-util -e                  # Boot current program
$ dfu-util -D new-image.dfu    # Load new program

u5b f0mu

Loading MicroPython

$ dfu-util -D micropython-fomu.dfu

Connecting via serial

screen /dev/cu.usbserial*
screen /dev/ttyACM*
Tera Term
MicroPython v1.10-296-g0a5a77a on 2019-06-18; fomu with vexriscv
>>>

Interacting with Fomu


							>>> import fomu
							>>> rgb = fomu.rgb()
							>>> rgb.mode("error")
							>>> 
					

Read SPI ID


                                >>> spi = fomu.spi()
                                >>> hex(spi.id())
                                '0xc2152815'
                                >>>
                        

Memory-Mapped Registers

#define CSR_VERSION_MAJOR_ADDR 0xe0007000
#define CSR_VERSION_MINOR_ADDR 0xe0007004
#define CSR_VERSION_REVISION_ADDR 0xe0007008
>>> import machine
>>> machine.mem32[0xe0007000]
1
>>>

RGB LED Driver reference

ICE40 LEDD registers
>>> rgb.write_raw(0b0001, 255)
>>> rgb.write_raw(0b1010, 14)
>>> rgb.write_raw(0b1011, 1)
>>> 

Future Work

  • CircuitPython
  • eLua
  • Espurino?

RISC-V

LiteX Model

LiteX Design

Wishbone Bridge

Wishbone bridge

CPU is Optional

  • Multiple CPUs available
    • VexRiscv
    • picorv32
    • lm32
    • ...
  • Also works just fine with no CPU

CSR Access

#define CSR_VERSION_MAJOR_ADDR 0xe0007000
#define CSR_VERSION_MAJOR_SIZE 1
#define CSR_VERSION_MINOR_ADDR 0xe0007004
#define CSR_VERSION_MINOR_SIZE 1
#define CSR_VERSION_REVISION_ADDR 0xe0007008
#define CSR_VERSION_REVISION_SIZE 1
#define CSR_VERSION_GITREV_ADDR 0xe000700c
#define CSR_VERSION_GITREV_SIZE 4
#define CSR_VERSION_GITEXTRA_ADDR 0xe000701c
#define CSR_VERSION_GITEXTRA_SIZE 2
Excerpt from csr.h

Reading CPU Version

$ wishbone-tool --pid 0x5bf0 0xe0007000
Value at e0007000: 00000001
$ wishbone-tool --pid 0x5bf0 0xe0007004
Value at e0007004: 00000008
$ wishbone-tool --pid 0x5bf0 0xe0007008
Value at e0007008: 00000001

Interacting with LEDD directly

ICE40 LEDD registers
#define CSR_RGB_DAT_ADDR 0xe0006800L
#define CSR_RGB_ADDR_ADDR 0xe0006804L
$ wishbone-tool --pid 0x5bf0 0xe0006804 1
$ wishbone-tool --pid 0x5bf0 0xe0006800 0xff

Writing RISC-V Code

$ make
  CC       ./src/main.c        main.o
  CC       ./src/rgb.c rgb.o
  CC       ./src/time.c        time.o
  AS       ./src/crt0-vexriscv.S       crt0-vexriscv.o
  LD       riscv-blink.elf
  OBJCOPY  riscv-blink.bin
  IHEX     riscv-blink.ihex
$ 

From riscv-blink directory in teardown2019-workshop

Modifying RISC-V Code

--- a/riscv-blink/src/main.c
+++ b/riscv-blink/src/main.c
@@ -38,6 +38,7 @@ void isr(void) {
 void main(void) {
     rgb_init();
     irq_setie(0);
+    rgb_write((100000/64000)-1, LEDDBR);
     int i = 0;
     while (1) {
         i++;

Other RISC-V Programs

riscv-usb-cdcacm: echo characters back after adding 1

Hardware Description Language

Yosys and NextPNR

  • Timing Driven!
Max frequency for clock 'clk12':   24.63 MHz (PASS at 12.00 MHz)
Max frequency for clock 'clk48_1': 60.66 MHz (PASS at 48.00 MHz)
Max frequency for clock 'clkraw': 228.05 MHz (PASS at 48.00 MHz)

Blinking an LED

$ make FOMU_REV=evt
...
20 warnings, 0 errors
 PACK     blink.bin
Built 'blink' for Fomu evt1
$ dfu-util -D blink.bin

LiteX and MiGen

  1. Define hardware in Python
  2. Evaluate Python to produce netlist
  3. Synthesize netlist to FPGA

lxbuildenv.py

  1. Python environment using native interpreter
  2. Very stable, good for hardware projects
  3. Should work with system Python
  4. Runs on Linux, Windows, Raspberry Pi

Why do we need a CPU?

LiteX Design

What if we remove the CPU?

  • Workshop project has no CPU
  • DummyUsb module automatically enumerates
  • Wishbone Debug Bridge still accessible

Build Workshop Module

$ python3 workshop.py --placer heap
...
5 warnings, 0 errors
$ 

Load onto Fomu

$ dfu-util -D build/gateware/top.bin
Download      [=========================] 100%    104090 bytes
Download done.
$ 

Write a value to RAM

$ wishbone-tool --pid 0x5bf0 0x10000000
Value at 10000000: 0baf801e
$ wishbone-tool --pid 0x5bf0 0x10000000 0x12345678
$ wishbone-tool --pid 0x5bf0 0x10000000
Value at 10000000: 12345678
$ 

Adding Hardware

Schematic of RGB block

Technology Library Reference

// Verilog Instantiation
SB_RGBA_DRV RGBA_DRIVER (
.CURREN(ENABLE_CURR),
.RGBLEDEN(ENABLE_RGBDRV),
.RGB0PWM(RGB0),
.RGB1PWM(RGB1),
.RGB2PWM(RGB2),
.RGB0(LED0),
.RGB1(LED1),
.RGB2(LED2)
);
defparam RGBA_DRIVER.CURRENT_MODE = "0b0";
defparam RGBA_DRIVER.RGB0_CURRENT = "0b111111";
defparam RGBA_DRIVER.RGB1_CURRENT = "0b111111" ;
defparam RGBA_DRIVER.RGB2_CURRENT = "0b111111";

SBTICETechnologyLibrary201504.pdf page 147

RGB Block

class FomuRGB(Module, AutoCSR):
    def __init__(self, pads):
        self.output = CSRStorage(3)
        self.specials += Instance("SB_RGBA_DRV",
            i_CURREN = 0b1,
            i_RGBLEDEN = 0b1,
            i_RGB0PWM = self.output.storage[0],
            i_RGB1PWM = self.output.storage[1],
            i_RGB2PWM = self.output.storage[2],
            o_RGB0 = pads.r,
            o_RGB1 = pads.g,
            o_RGB2 = pads.b,
            p_CURRENT_MODE = "0b1",
            p_RGB0_CURRENT = "0b000011",
            p_RGB1_CURRENT = "0b000011",
            p_RGB2_CURRENT = "0b000011",
        )

Instantiating FomuRGB

@@ -55,6 +75,10 @@ class BaseSoC(SoCCore):
                 with_ctrl=False,
                 **kwargs)

+        # Add the LED driver block
+        led_pads = platform.request("rgb_led")
+        self.submodules.rgb = FomuRGB(led_pads)
+
         # UP5K has single port RAM....
         # Use this as CPU RAM.
         spram_size = 128*1024

Interacting with the CSR

csr_register,rgb_output,0xe0006800,1,rw

From test/csr.csv

VexRiscv

Thank you

Lunch Time!