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 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;
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"
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
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.