Tang Nano 20k FPGA dev board

GOWIN FPGA Designer

I recently bought a Tang Nano 20k development board from Sipeed. The hardware worked out of the box but I had some software problems with the IDE initially. Programming using the built-in Gowin programmer has been working fine so far (which seems to be common problem). I’m using Xubuntu 24.04.4 LTS (which is basically a slimmed down Ubuntu 24.04.4 LTS running with Xorg and XFCE) on a PC.

After downloading ‘Gowin_V1.9.11.03_Education_Linux.tar.gz’ from gowinsemi.com (requires registering), I unpacked the files into ‘/opt/gowin’ (any directory you create is fine), and tried to run it, but got library version errors and core dumps. In order to fix the problem I created a script called ‘gowin_ide.sh’ to launch ‘gw_ide’:

#!/bin/bash
cd /opt/gowin/IDE/bin
export LD_LIBRARY_PATH=/opt/gowin/IDE/lib
./gw_ide

This will make sure the IDE uses its own libraries first (before system) and sub processes launched from the GUI also finds them. There was still a library error where it complains about undefined symbols in “libfontconfig”, this needed a separate fix:

rm /opt/gowin/IDE/lib/libfreetype.so.6

Now finally ‘gw_ide’ launches, and also the tools from within the GUI.

I then decided to try an example tutorial found here:
https://wiki.sipeed.com/hardware/en/tang/tang-nano-20k/example/led.html

This worked for the most part, just had to change the “IO Type” voltages to “LVCMOS33” in the FloorPlanner part, more info about in that comments of that article.

I modified the example LED blink design a bit, added another counter LED blink and a Verilog testbench (even though a testbench might be overkill in this case), mostly to figure out how to run a simulation with this toolchain because I didn’t feel like using DSim from Altair (requires registration) which is linked in the GUI.

Here is the modified ‘led.v’ example:

`timescale 1ns / 1ps
module led(
input wire Clock,
output wire LED1,
output wire LED5
);
/********** Counters **********/
//parameter Clock_frequency = 27_000_000; // Crystal oscillator frequency is 27Mhz
`ifdef SIM_COUNT_OVERRIDE
parameter LED1_value = `SIM_COUNT_OVERRIDE;
parameter LED5_value = `SIM_COUNT_OVERRIDE;
`else
parameter LED1_value = 13_499_999; // The number of times needed to time 0.5s
parameter LED5_value = 1_349_999; // This currently acts like a slow clock for GAO at 0.05s
`endif
reg [23:0] LED1_value_reg = 24'b0; // counter value
reg LED1_value_flag = 1'b0; // IO change flag
always @(posedge Clock) begin
if ( LED1_value_reg <= LED1_value ) begin // not count to 0.5s
LED1_value_reg <= LED1_value_reg + 1'b1; // Continue counting
LED1_value_flag <= 1'b0; // No flip flag
end
else begin //Count to 0.5S
LED1_value_reg <= 24'b0; // Clear counter,prepare for next time counting.
LED1_value_flag <= 1'b1 ; // Flip flag
end
end
reg [23:0] LED5_value_reg = 24'b0; // counter value for LED5
reg LED5_value_flag = 1'b0; // IO change flag
always @(posedge Clock) begin
if ( LED5_value_reg <= LED5_value ) begin //not count to 0.05s
LED5_value_reg <= LED5_value_reg + 1'b1; // Continue counting
LED5_value_flag <= 1'b0; // No flip flag
end
else begin
LED5_value_reg <= 24'b0; // Clear counter,prepare for next time counting.
LED5_value_flag <= 1'b1; // Flip flag
end
end
/********** IO voltage flip **********/
reg LED1_reg = 1'b0; // Initial state
always @(posedge Clock) begin
if ( LED1_value_flag ) begin // Flip flag
LED1_reg <= ~LED1_reg; // IO voltage flip
`ifdef SIMULATION
$strobe("Time: %0t LED1: %0d", $time, LED1_reg);
`endif
end
else // No flip flag
LED1_reg <= LED1_reg; // IO voltage constant
end
assign LED1 = LED1_reg;
/********** IO voltage flip **********/
reg LED5_reg = 1'b0; // Initial state
always @(posedge Clock) begin
if ( LED5_value_flag ) begin // Flip flag
LED5_reg <= ~LED5_reg; // IO voltage flip
`ifdef SIMULATION
$strobe("Time: %0t LED5: %0d", $time, LED5_reg);
`endif
end
else // No flip flag
LED5_reg <= LED5_reg; // IO voltage constant
end
assign LED5 = LED5_reg;
endmodule

…and the testbench ‘tb_led.v’:

`timescale 1ns / 1ps
module tb_led;
// Declare signals to connect to the LED module
reg Clock = 0;
wire LED1;
wire LED5;
// Instantiate your original LED module
led uut (
.Clock(Clock),
.LED1(LED1),
.LED5(LED5)
);
// Generate a 27MHz clock
always #18.5185 Clock <= ~Clock;
always @(LED1) begin
$strobe("time: %0t | Testbench observed LED1 at: %b", $time, LED1);
end
always @(LED5) begin
$strobe("time: %0t | Testbench observed LED5 at: %b", $time, LED5);
end
// Control the simulation timeline
initial begin
// Tell Verilator the name of the waveform file to create
$dumpfile("waveform.fst");
// Dump all signals inside the testbench and child modules (0 means everything)
$dumpvars(0, tb_led);
// Set a clean format for %0t reporting
$timeformat(0, 4, "s", 20);
// Let it run for 1.2 seconds
#1200000000;
$display("Simulation successfully completed!");
$finish;
end
endmodule

What I ended up using for simulation is Verilator which is open source can be installed like this in Ubuntu Linux:

sudo apt-get install verilator

I also installed GTKWave Analyzer to visually see trace dumps from Verilator:

sudo apt-get install gtkwave

To build the simulation for my custom testbench I use a terminal shell (command line) in the directory where the Verilog sources are:

verilator --binary --timing --trace-fst --top-module tb_led -DSIMULATION -Wall +1364-2001ext+v led.v tb_led.v

…and then to run the simulation:

obj_dir/Vtb_led

The trace can be found in current directory after simulation run, I load it like this to view:

gtkwave waveform.fst

After playing around with the Gowin Analyzer Oscilloscope (GAO) for a while which is a tool included in the GUI, it seems very powerful (reminds me of Xilinx ChipScope), more info in the user guide.

I hope this info helps to get started, let me know if you have any questions or want to share your own tips.


Discover more from modrobert weblog

Subscribe to get the latest posts sent to your email.

Discover more from modrobert weblog

Subscribe now to keep reading and get access to the full archive.

Continue reading