Home

Awesome

TinyDFU Bootloader

Origins

Luke Valenti's USB module, as adapted by Lawrie Griffiths and others. Luke's code was created with the purpose of providing a "bit banged" USB port to SPI bridge for his (awesome) TinyFPGA boards.

The original is here - https://github.com/tinyfpga/TinyFPGA-Bootloader

Lawrie Griffiths and David Williams improved on this USB module to dramatically improve its timing performance, and to convert it into a generic USB - SERIAL bridge. Their work is here - https://github.com/davidthings/tinyfpga_bx_usbserial

This Project

This project uses this improved USB module as a starting point, and creates a USB DFU bootloader that can be used to program FPGA boards with the host tools like dfu-util on Linux or DfuSe on Windows.

This is currently being developed on a Lattice ice40up5k-b-evn, which is doing a poor job of meeting timing due to the slower design of the ice40 UltraPlus family. Eventually we hope to test this on a TinyFPGA BX, and ultimately the Logicbone.

Interface

The interface to the code looks like the following:

usb_dfu u_u (
  .clk_48mhz  (clk_48mhz),
  .reset      (reset),

  // USB pins
  .pin_usb_p( pin_usb_p ),
  .pin_usb_n( pin_usb_n ),

  // SPI pins
  .spi_csel( spi_csel ),
  .spi_clk ( spi_clk ),
  .spi_mosi( spi_mosi ),
  .spi_miso( spi_miso )
);

Clock

You will need a 48Mhz clock. This can be generated by pll from the TinyFPGA BX's 16Mhz oscillator.

SB_PLL40_CORE #(
		.FEEDBACK_PATH("SIMPLE"),
		.DIVR(4'b0000),		// DIVR =  0
		.DIVF(7'b0101111),	// DIVF = 47
		.DIVQ(3'b100),		// DIVQ =  4
		.FILTER_RANGE(3'b001)	// FILTER_RANGE = 1
	) uut (
		.LOCK(locked),
		.RESETB(1'b1),
		.BYPASS(1'b0),
		.REFERENCECLK(clock_in),
		.PLLOUTCORE(clock_out)
		);

In this project, the pll is contained in its own module (pll.v) that is created by the IceStorm project tool icepll.

Amazingly, the 48MHz signal can also be generated by dividing down a faster clock. Using an icepll configured pll at 192MHz, a 48MHz signal can be derived the simple way, by divider, and (possibly unnecessarily) put through the global buffer network for distribution. This worked for a few experiments, but probably requires more development and testing to confirm. Perhaps it can be done better.

wire clk_192mhz;
wire clk_locked;

// Use an icepll generated pll to give us 192MHz
pll pll192( .clock_in(pin_clk), .clock_out(clk_192mhz), .locked(clk_locked) );

reg [4:0] reset_counter = 0;

// Generate the slower clock
reg       clk_48mhz_logic;
reg [1:0] clk_divider;
always @(posedge clk_192mhz ) begin
    if ( ~clk_locked ) begin
        clk_divider <= 0;
    end else begin
        case (clk_divider)
            0: begin
                clk_48mhz_logic <= 1;
                clk_divider <= 1;
            end
            1: begin
                clk_divider <= 2;
            end
            2: begin
                clk_48mhz_logic <= 0;
                clk_divider <= 3;
            end
            3: begin
                clk_divider <= 0;
            end
      endcase
  end
end

// This clock has to go places.  Put it through a global buffer
wire clk_48mhz;
SB_GB gbc(
    .USER_SIGNAL_TO_GLOBAL_BUFFER (clk_48mhz_logic),
    .GLOBAL_BUFFER_OUTPUT ( clk_48mhz ) );

Device Pins

The pins in the interface to the module (pin_usb_p and pin_usb_n) are the raw device pins, the direction control logic is internal to usb_dfu_i40. The original usb_dfu module is retained below to facilitate reuse in other architectures.

Somewhere the USB pull up pin has to be asserted. This is done in the top level code, since usb_dfu doesn't manipulate it.

assign pin_pu = 1'b1;

Use

Development has been done on Ubuntu.

Clone the repo

git clone https://github.com/oskirby/tinydfu-bootloader.git

and enter the build directory for your board

cd tinydfu-bootloader/boards/tinyfpga_bx

And make it!

make

The make process has got to do a few things so it may take a minute.

If it completes successfully, press the "program" button on the TinyFPGA BX and program it

make prog

If all went well, the device should enumerate by usb as a DFU capable device in DFU mode. You should be able to list its partitions with dfu-util

user@example:~$ dfu-util -l
dfu-util 0.9

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2016 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to http://sourceforge.net/p/dfu-util/tickets/

Found DFU: [1d50:6130] ver=0000, devnum=13, cfg=1, intf=0, path="1-4", alt=2, name="Bootloader", serial="123456"
Found DFU: [1d50:6130] ver=0000, devnum=13, cfg=1, intf=0, path="1-4", alt=1, name="User Data", serial="123456"
Found DFU: [1d50:6130] ver=0000, devnum=13, cfg=1, intf=0, path="1-4", alt=0, name="User Image", serial="123456"

Dependencies

Nothing is required beyond the usual tools needed for TinyFPGA development. This is a command-line makefile project.

Icestorm

http://www.clifford.at/icestorm/

Make sure you get NextPNR.

TinyFPGA BX

https://tinyfpga.com/bx/guide.html

License

Copyright 2020 Owen Kirby oskirby@gmail.com

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.