Month: December 2019

First Steps with the Tang Nano FPGA Development Board

The Tang Nano is a very very low cost FPGA development board by Sipeed featuring a GW1N-1-LV FPGA produced by GOWIN Semiconductors. GOWIN is another Chinese chip manufacturer entering the FPGA arena, like Efinix and Anlogic.
The GW1N-1-LV is the smallest member of GOWINs “Little Bee” series, which consists of small footprint instant-on FPGA devices for IoT and interfacing solutions.

The Tang Nano FPGA development board

The Tang Nano offers the following features:

  • GW1N-1-LV FPGA (QFN48 package)
    • 1152 LUT’s
    • 864 FF’s
    • 4 BRAM’s à 18 kbit (72 kbit total)
    • 96 kbit flash memory
    • 1 PLL
  • 34 user IO pins
  • LCD interface connector (ZIF FFC)
  • 2 user buttons
  • 24 MHz oscillator
  • 64 MBit QSPI PSRAM
  • USB-JTAG downloader/debugger (via USB-C connector)
  • 4 pin JTAG header (split into 2 x 2 pins left/right of the USB-C connector)
  • costs just about 5 $ (like the Longan Nano)

Like most of Sipeed’s latest development boards the Tang Nano comes with a USB-C connector, thus a USB-C cable is required to use the board without unnecessary tinkering.
Regarding the LCD interface I am unsure how this would be useful, except for generating some fancy test patterns. Almost all user IO pins are utilized by the LCD interface if it is used, so there are not many pins left which could be used to get a video signal into the FPGA anymore.

The Toolchain

All steps from HDL to bitstream are handled by GOWIN FPGA Designer, a graphical IDE which offers a project based design flow. Both VHDL and Verilog are supported (allegedly up to SystemVerilog-2017).
Timing constraints are defined by industry standard SDC files, however it is not clear which subset of SDC commands is supported.
Pin assignments and IO constraints are defined in a proprietary CST file. Alternatively UCF syntax is supported, as known from Xilinx ISE.

The design flow is very simple and offers just the most basic options.
The synthesis tool can be set to either GowinSynthesis (included with GOWIN FPGA Designer) or Synplify Pro (external synthesis tool by Synopsys). I strongly doubt that anyone will use Synplify Pro for GOWIN FPGA’s. In the following GowinSynthesis is assumed to be the selected synthesis engine.
The PAR step is simple yet effective as well, however I did not test (yet) how PAR performs once the device utilization reaches a higher percentage.
Timing analysis and power analysis reports can be generated once implementation is complete.
GOWIN FPGA Designer also comes with a programmer utility which can be used to program the Tang Nano and read out some device IDs and status registers. The FPGA configuration bitstream can be programmed into embedded flash memory, into external flash memory or can be written directly to the (volatile) SRAM cells of the FPGA.

The Example

To test that the Tang Nano board is working properly I implemented the infamous blinky LED example.

The Tang Nano offers 2 different clock sources: an on-board 24 MHz oscillator and an integrated oscillator running at roughly 240 MHz.
The external 24 MHz clock reference should be used in conjunction with the PLL inside the FPGA, in order to generate an adequate clock signal to drive the logic on the FPGA fabric. For the start, the PLL is generated by using the IP Generator tool to get the correct parameters for the PLL. However, the 24 MHz reference clock can also be used to drive logic directly, without using the PLL.

/* On-Chip PLL 108 MHz. *****************************************************/
wire clk_108M;
wire pll_lock;
wire pll_reset = 1'b0;

assign clk_24M = XTAL_IN;

Gowin_rPLL Gowin_rPLL_inst(

To make use of the integrated oscillator another IP core is generated with the IP Generator tool. Alternatively the respective device primtive can be instantiated explicitly.

/* On-Chip Oscillator 2.5 MHz (240 MHz / 96). ********************************/
wire clk_2M5;
Gowin_OSC_div96 Gowin_OSC_div96_inst (.oscout(clk_2M5));

Finally one of the generated clocks can be used to drive a counter, which will get the RGB LED blinking.

/* Blink RGB LED. ***********************************************************/
localparam CNT_LEN = 26;
reg [CNT_LEN-1:0] cnt = 0;

always @ (posedge clk_108M, negedge rstn)
    if (rstn == 1'b0) begin
        cnt <= 'd0;
    end else begin
        cnt <= cnt + 1;

always @ (*)
    LED_R <= ~cnt[CNT_LEN-1];
    LED_G <= ~cnt[CNT_LEN-2];
    LED_B <= ~cnt[CNT_LEN-3];

I use the 3 MSB’s of the counter to blink the red, green and blue color channel of the RGB LED respectively. Thus the RGB LED will cycle through all possible combinations of colors. The blinking speed may vary depending on the clock driving the counter.

The final step to get the blinky LED design running on the Tang Nano is to define the pin assignment and timing constraints.
The timing constraints consist of two create_clock commands for the 24 MHz reference clock input and the internal oscillator, which is set to 2.5 MHz.

# tang_nano.sdc
create_clock -name CLK -period 41.667 [get_ports {XTAL_IN}]
create_clock -name SLOW -period 400 [get_pins {Gowin_OSC_div96_inst/osc_inst.OSCOUT}]

The pin assignments can be created using the Floorplanner tool and the Tang Nano schematic. For simplicity the constraints can be copied over from the Tang Nano examples repository or my own example code (file tang_nano.cst). Note that I tried to stay as close to the net names of the schematic while naming the top level ports.

// tang_nano.cst
//Copyright (C)2014-2019 Gowin Semiconductor Corporation.
//All rights reserved. 
//File Title: Physical Constraints file
//GOWIN Version: V1.9.3Beta
//Part Number: GW1N-LV1QN48C6/I5
//Created Time: Tue 12 24 23:51:04 2019

IO_LOC "LCD_R[0]" 27;
IO_LOC "LCD_R[1]" 28;
IO_LOC "LCD_R[2]" 29;
IO_LOC "LCD_R[3]" 30;
IO_LOC "LCD_R[4]" 31;
IO_LOC "LCD_G[0]" 32;
IO_LOC "LCD_G[1]" 33;
IO_LOC "LCD_G[2]" 34;
IO_LOC "LCD_G[3]" 38;
IO_LOC "LCD_G[4]" 39;
IO_LOC "LCD_G[5]" 40;
IO_LOC "LCD_B[0]" 41;
IO_LOC "LCD_B[1]" 42;
IO_LOC "LCD_B[2]" 43;
IO_LOC "LCD_B[3]" 44;
IO_LOC "LCD_B[4]" 45;
IO_LOC "LED_R" 16;
IO_LOC "LED_G" 17;
IO_LOC "LED_B" 18;
GOWIN FPGA Designer: Floorplanner

So far so good. The only thing left now is to generate a programming file for the Tang Nano and toss it on the board.

GOWIN FPGA Designer: Programmer

All done. Time to get impressed by the pinnacle of modern human civilization: a blinking LED.

The Tang Nano skillfully flashing its RGB LED

As usual, the example from this article is available on my Tang Nano github repository.

That’s it for today. See you next time.



Writing and Understanding RISC-V Assembly Code

For quite a while I have followed the RISC-V ISA with growing intereset. Now that RISC-V is becoming more and more popular and catching a lot of public attention, it is time to get my hands dirty with some low level RISC-V assembly coding.

An instruction set architecture (ISA) is a specification of the commands/instructions a specific processor or processor architecture family does understand and that it can execute. For this tutorial we will be looking at the RISC-V ISA.
Assembly code (often abbreviated asm) is textual low-level program code, which can be directly translated to machine code. We will be working with the RISC-V assembly language.
The connection between an ISA and assembly code is such that assembly language/code is used to write a program for a corresponding ISA. In theory there could be more than one assembly language for the same ISA (like there are multiple high level programming language for the same machine architecture), but this is seldom the case (having different “flavors” of the same assembly language is more common).

I think there is no need to reproduce any details about the RISC-V ISA at this point. There are plenty of good sources online, the official specification of the RISCV user-level ISA of course, especially the chapters “Instruction Set Listings” and “RISC-V Assembly Programmer’s Handbook”, or one of the RISCV reference cards.

Another good tutorial for beginners, which is a little slow paced imho, is the Western Digital RISC-V ASM tutorial on Youtube (the tutorial really gets started with part 6). For beginners it is nice to see how the base addresses for peripherals can be found using the datasheet and how to “talk to” those peripheral blocks using assembly code.

Note that all examples presented in the following are created/run on Ubuntu 18.04 (WSL) and platformio is used for convenience (no need to set up the toolchains manually). On Ubuntu platformio can be obtained with apt:

$> sudo apt install platformio

Now lets start by creating a new folder for our platformio project and initializing it.

$> mkdir riscv-asm-examples
$> cd riscv-asm-examples 
$> platformio init

I use the following platformio.ini file to define the project parameters, since I have a HiFive1 board lying around somewhere. Feel free to use any other supported RISC-V board or framework instead. If you do not own a RISC-V board you can still run the assembler and have a look at the machine code. But I really recommend to get a board, the Longan Nano costs only 5$.
The platformio.ini file I am using is very simple:

$> cat ./platformio.ini
platform = riscv
board = freedom-e300-hifive1
framework = freedom-e-sdk

To check that platformio is installed and the platformio.ini file is correct run a sanity check using an empty main function:

$> echo "int main(void) {return 13;}" > ./src/main.c
$> platformio run

Running platformio for the first time can take a while because all the required packages and toolchains will be downloaded, so do not get impatient if its takes a little while.
If everything went fine a [SUCCESS] message should show up after a while.

Okay, the main function has been compiled. To see the assembler code which was produced we can used objdump -d. The -d option stands for disassemble, which means that the given object file will be “translated” to human readable assembler code.
The object file of interest is hidden away by platformio in .pio/build/freedom-e300-hifive1/src/ (folder may vary if you used a different build framework).
To disassemble the almost empty main function from before do like so:

$> objdump -d .pio/build/freedom-e300-hifive1/src/main.o
.pio/build/freedom-e300-hifive1/src/main.o:     file format elf32-little
 objdump: can't disassemble for architecture UNKNOWN!

Uh oh! Why isn’t it working? The tutorial said that this should work. Liar!
Here is why:

$> ls -lha $(which objdump)
lrwxrwxrwx 1 root root 24 May  8  2019 /usr/bin/objdump -> x86_64-linux-gnu-objdump*

The objdump we called is for the x86 ISA, not for RISC-V. We need to call the correct objdump executable from our RISC-V toolchain. The toolchain is hidden away by platformio inside the user’s home folder under ~/.platformio.

~/.platformio/packages/toolchain-riscv/riscv64-unknown-elf/bin/objdump -d .pio/build/freedom-e300-hifive1/src/main.o
Disassembly of section .text.startup:
    0:   4535                    li      a0,13
    2:   8082                    ret

Nice. The general structure of the assembly code is:

<memory_address>: <opcode>    <instruction> [<parameter(s)>]

So the assembly code above tells us that an immediate value 13 is loaded into register a0, then we return. Register a0 is the register which holds the function return value according to the RISC-V calling convention. The value 13 was given as return value in the main function. So this is really the assembly code corresponding to our main function. Hurrah!

To make things easier I recommend to set a symbolic link to the correct objdump executable, e.g. inside the platformio project folder.

$> ln -s ~/.platformio/packages/toolchain-riscv/riscv64-unknown-elf/bin/objdump objdump
$> ./objdump --version
GNU objdump (SiFive Binutils 2.32.0-2019.08.0) 2.32

OK, time to start with some assembly coding examples. Most examples are very minimalistic and use the main function as entry point from which the assembly code is invoced. The main goal, to show that assembly code can achieve the same things as C code, is proven nontheless.

Oh and to upload an example to your board (e.g. HiFive1) run the following command inside the project root directory (folder where platformio.ini is located):

$> platformio run -t upload

On my Windows 10 machine this only worked with VisualStudioCode (with the platformio plugin intalled). WSL did not work (USB driver stuff). Using a Linux VM should not pose any problem though.
Also the HiFive1 requires a push of the red reset button to reset the board and load the new program after it was uploaded.

Example 1: Superblink

This example just reproduces the WesternDigital RISC-V assembler tutorial from Youtube. Some GPIO pins are initialized and LEDs are toggled between on and off.
Check out the code on github.

Cycling through the RGB LEDs with superblink.

Example 2: Superfade

This example is an extension to superblink and uses PWM signals to control the intensity of LED’s. Three PWM channels are used to control the intensity of the 3 RGB color LEDs. One-by-one the LEDs are ramped up to full intensity and then reverted back to 0 intensity, creating a (incomplete) rainbow pattern.
Check out the code on github.

Fading the RGB LEDs with PWM signals.

Example 3: Simple UART Echo

This example waits to receive data in the UART RX FIFO and subsequently sends the same data out to the UART TX FIFO, thus echoing back any characters that are received.
Check out the code on github.

uartecho in action.

That’s all for the moment. See you next time.



Gigabit Transceiver(s) for a Cheap FPGA Development Board

There are a lot of FPGA development boards out there to buy. Official vendor boards with the latest advanced devices on it can easily cost several thousand Euros.
Hobbyists and makers are more interested in FPGA development boards within an affordable price range (roughly << 100 $/€). The logic resources and feature set of the FPGA devices on these boards is not that important on the other hand. The main application for makers/hobbyists is small projects and self-learning, I assume, and not rolling out their own 5G equipment.

There are already a lot of affordable entry level FPGA boards available and more are being released every year. The one thing missing on these boards is usually gigabit transceivers (GT’s). Of course the cheapest FPGA devices do not come with pricey extras like GT’s, but is the price difference really that big?

So I started to search for low cost FPGA devices which include GT’s. I only looked at the three major vendors: Xilinx, Intel/Altera and Lattice. I tried to focus on the latest FPGA families in the low cost segment. The prices from Mouser are as of December 2019 and are valid for single quantity purchase.

Intel/Altera Cyclone IV GX EP4CGX15 with two 2.5 Gbps GT’s
Xilinx Spartan-6 XC6SLX25T with two 3.2 Gbps GT’s
Xilinx Artix-7 XC7A12T with two 6.6 Gbps GT’s
Lattice ECP5 LFE5UM-25 with two 3.2 Gbps GT’s

The comparison shows that Lattice is the first choice when aiming for a low cost FPGA with GT’s. The prices are only from one distributor and only for single quantities, so the price sample must be taken with a grain of salt.
Interestingly the old Spartan-6 is much more expensive than the newer Artix-7.

However, there are other aspects to consider than just the price and transceiver speed, e.g. if a PCIe endpoint IP is available for free or not (the same goes for all IP cores utilizing the GT’s). Without the support of IP cores and tools the GT’s won’t be any good anyhow.

An interesting board announced on CrowdSupply right now is a new member of the TinyFPGA series, the TinyFPGA EX with a EX85-5G FPGA. This one will have two GT’s with up to 5 Gbps. Looking at the board layout it’s not clear to me if the full capability of the GT’s will be usable in the end, because there are only plain pin headers for board IO, no BNC or F-conncetors.
The end user price has not been announced yet. Let’s wait and see what the GT’s are going to cost in a “commercial” product.



First Steps with the iCEBreaker FPGA Development Board

The iCEBreaker board is the first FPGA development board with a fully open-source toolchain, which allows to go all the way from HDL code to configuration bitstream. All the schematics and hardware information is openly available at no extra cost.

The Board

The iCEBreaker board features a Lattice iCE40UP5K FPGA with the following integrated components:

  • 5280 PLB’s consisting of one 4-input LUT, carry-chain and one FF each
  • 128 Mbit dual-port BRAM’s
  • 1 MBit single-port BRAM’s
  • 8 DSP’s
  • 1 programmable PLL and 2 on-chip oscillators
  • 2 hard-IP’s for SPI and I2C each
  • 3 hard-IP’s for PWM
  • Up to 32 user IO pins. The IO pins are available as 3 PMOD edge connectors
  • One PMOD module with 3 push-buttons and 5 LEDs is included
  • On-board FTDI FT2232H for easy FPGA configuration and debugging via USB
  • 128 Mbit Winbond QSPI flash, programmable over USB or via a separate SPI pin-header
Overview of the iCEBreaker.

The Toolchain

The remainder of this article will guide through the procedure of setting up the open-source toolchain for the iCEBreaker. No Lattice tools and software will be used, maybe that will be covered another time. In a final step the toolchain will be tested by implementing and loading a simple example design. The OS will be asusmed to be Ubuntu 18.04 for the rest of this article.

Let’s begin by installing the dependencies which are required to build the toolchain. The command below will install the superset of all dependencies which are required for the steps that follow.

$> sudo apt install build-essential clang bison flex libreadline-dev gawk tcl-dev libffi-dev git mercurial graphviz xdot pkg-config python python3 libboost-system-dev libboost-python-dev libboost-filesystem-dev libftdi-dev qt5-default python3-dev libboost-all-dev cmake libeigen3-dev

Next clone the github repository for yosys, the synthesis tool of the toolchain. The latest stable release/tag of yosys is recommended, but instead the latest master branch can also be used.

$> git clone
$> cd yosys
$> git checkout yosys-v0.9
$> make -j(nproc)
$> sudo make install

Continue with the bitstream generation tool icestorm.

git clone
cd icestorm
make -j$(nproc)
sudo make install

Finally we have to choose between the place-and-route tool nextpnr and arachne-pnr. Since arachne-pnr is considered obsolete it’s successor nextpnr should be used. Since I like to play around and compare results between different tools I will install both, but note that only one of the two is required.

$> git clone
$> cd nextpnr
$> cmake -DARCH=ice40
$> make -j$(nproc)
$> sudo make install
$> git clone
$> cd arachne-pnr
$> make -j$(nproc)
$> sudo make install

That concludes the setup of the toolchain. Time for an example, to see if everything works.

The Example

Now that we are all set, let’s try to synthesize a simple example design, run the place-and-route tool and generate a bitstream for the iCEBreaker.

$> yosys -p "synth_ice40 -top icebreaker_top -blif icebreaker_top.blif" src/icebreaker_top.v
$> arachne-pnr -d 5k icebreaker_top.blif -o icebreaker_top.asc
$> icepack icebreaker_top.asc icebreaker_top.bin
$> iceprog icebreaker_top.bin

Aaaand the board is bricked (for the moment)! The iCEBreaker no longer is properly recognized neither by Ubuntu nor my Windows 10 machine. It took me a few moments to understand what had gone wrong, but not close to as long as I feared it would take.
Well, the problem was that no physical constraint file (.pcf) was passed to arachne-pnr. The .pcf file defines which top module port is connected to which physical package pin. Without this information arachne-pnr will choose these pins assignments arbitrarily, like most place-and-route tools do in such a situation. After asking arachne-pnr to output the pin assignments it had chosen (-w option) the problem became very clear.

$> arachne-pnr -d 5k icebreaker_top.blif -o icebreaker_top.asc -w icebreaker_top.asc.pcf
... (some irrelevant output)
$> cat icebreaker_top.asc.pcf 
$> arachne-pnr 0.1+328+0 (git sha1 c40fb22, g++ 7.4.0-1ubuntu1~18.04.1 -O2)
set_io led_o 35

Cross-checking this with the iCEBreaker pinout-sheet or schematic and we can see that pin 35 is actually connected to the external 12 MHz oscillator output. Unfortunately this oscillator also drives the FTDI chip (FT2232) which takes care of the USB connection to the outside world. Driving a dumb blinky LED signal on that pin will wreak havoc on the 12 MHz clock signal and mess with the FTDI chip.
To fix this issue the CRESET jumper on the board must be closed. Setting the CRESET jumper will keep the FPGA in reset. This way no output pin of the FPGA is driven and we have time to replace the bitstream in the SPI flash with one that doesn’t do any harm.

So let’s try again, this time with the correct .pcf file.

$> arachne-pnr -d 5k icebreaker_top.blif -o icebreaker_top.asc -p constr/icebreaker_top.pcf -w icebreaker_top.asc.pcf
... (some irrelevant output)
$> icepack icebreaker_top.asc icebreaker_top.bin
$> iceprog icebreaker_top.bin 
Behold, the iCEBreaker blinking like a boss! Imagine the possibilities…

The example from this article – and hopefully some more advanced stuff in the near future too – will be available on my iCEBreaker github repository.

That’s it for today. See you next time.



First Steps with the Longan Nano RISC-V Development Board

The Longan Nano is a new contestor in the area of affordable RISC-V development boards. The Longan Nano’s form factor and price puts it up against the Arduino Nano and all other varieties of STM32-based “nano boards”, which can be found abundantly on Ebay and AliExpress.

The Longan Nano features a GigaDevices GD32VF103CBT6 core running at 108 MHz with 32KB SRAM and 128KB flash.
The Longan Nano comes with a small 160×80 pixel LCD glued on top of the board and a practical plastic case. Really no reason to complain for just 5 $. More details in the datasheet.

The first requirement is to install PlatformIO. The command line tools of platformio are sufficient. I will assume the OS as Ubuntu 18.04 in the following.

$> pip3 install platformio 

To get a feeling for the versatility of PlatformIO let’s list the supported boards:

$> python3 -m platformio boards
... (lots of boards)

Now let’s only look at the boards of interest, to see if the Longan Nano is supported at all:

$> python3 -m platformio boards | grep GD32
gd32vf103v-eval     GD32VF103VBT6  108MHz 128KB 32KB GD32VF103V-EVAL
sipeed-longan-nano  GD32VF103CBT6  108MHz 128KB 32KB Sipeed Longan Nano
wio_lite_risc-v     GD32VF103CBT6  108MHz 128KB 32KB Wio Lite RISC-V

Next create a project directory for the Longan Nano and initialize a platformio project:

$> mkdir longan_nano
$> cd longan_nano
$> python3 -m platformio init
$> ls
include  lib  platformio.ini  src  test

Have a look at some information about our platform:

$> python3 -m platformio platform search gd32v
gd32v ~ GigaDevice GD32V
The GigaDevice GD32V device is a 32-bit general-purpose microcontroller based on the RISC-V core with an impressive balance of processing power, reduced power consumption and peripheral set.
Frameworks: arduino, gd32vf103-sdk
Packages: framework-gd32vf103-sdk, framework-arduino-gd32v, tool-openocd-gd32v, tool-gd32vflash, toolchain-gd32v

Before a build can be run some minimum viable source code is required. It is sufficient to put an empty main function into the src folder like so:

$> echo 'int main(int argc, char* argv[]) { return 0; }' > ./src/main.c

Now the project can be run for the first time to make platformio install requires packages and other dependency stuff:

$> python3 -m platformio run
Processing sipeed-longan-nano (platform: gd32v; framework: gd32v103f-sdk; board: sipeed-longan-nano)
PlatformManager: Installing gd32v
Error: This board doesn't support gd32v103f-sdk framework!

Oops! What’s going on here? The content of platformio.ini is copied from Sipeed’s example page, so why isn’t it working?
Well, as so often human error is the cause of this catastrophe. Fix the framework defined in platformio.ini like so:

 framework = gd32vf103-sdk 

Repeat the failing step from before:

$> python3 -m platformio run
Processing sipeed-longan-nano (platform: gd32v; framework: gd32vf103-sdk; board: sipeed-longan-nano)
Building .pio/build/sipeed-longan-nano/firmware.bin
 ================================ [SUCCESS] Took 2.50 seconds ==========================

Success! An empty project has been built, oh the accomplishment! Well at least the toolchain seems to work.
Just for fun the empty program can be uploaded to the Longan Nano board to see that the LED stops blinking (i.e. overwrite the preloaded example design).

To load a program to the Longan Nano it must be properly recognized as a USB device by Ubuntu. This is achieved by pressing and holding down the BOOT button and then pressing the RESET button (while still holding the BOOT button). After the RESET button has been pressed and released the BOOT button can also be released. This is the official way to do it, but may only yield the expected result after several attempts. I could be wrong, but for me it seemed to work quite nicely to unplug the Longan Nano, then hold down the BOOT button and plug the board back in (while still holding the BOOT button).
An unnamed USB device should appear in Linux:

$> lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 004: ID 28e9:0189  
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

Next a USB-serial adapter (3.3V) is required. Check that platformio does recognize the adapter:

$> sudo python3 -m platformio device list
Hardware ID: USB VID:PID=0403:6001 SER=00000000 LOCATION=1-3
Description: FT232R USB UART

OK, one step back, it turns out the upload_protocol = serial part is not what I thought it was and only works with the Arduino framework.

$> sudo python3 -m platformio run --target upload
 Processing sipeed-longan-nano (platform: gd32v; framework: gd32vf103-sdk; board: sipeed-longan-nano)
CURRENT: upload_protocol = serial
 Looking for upload port…
 Auto-detected: /dev/ttyUSB0
 Uploading .pio/build/sipeed-longan-nano/firmware.bin
 Failed to init device.
 stm32flash Arduino_STM32_0.9
*** [upload] Error 1
 Using Parser : Raw BINARY
 Interface serial_posix: 115200 8E1
================================= [FAILED] Took 1.88 seconds ==========================

So that didn’t work.
The next alternative is to use dfu-util which is easily available via apt:

$> sudo apt install dfu-util

Subsequently change the upload_protocol in platformio.ini:

upload_protocol = dfu

Repeat the upload step from before:

$> sudo python3 -m platformio run --target upload
Processing sipeed-longan-nano (platform: gd32v; framework: gd32vf103-sdk; board: sipeed-longan-nano)
Download    [=========================] 100%         6584 bytes
 Download done.
 File downloaded successfully
 dfu-util: dfuse_download: libusb_control_transfer returned -9
 *** [upload] Error 74
================================= [FAILED] Took 2.71 seconds =========================

There is still an error showing at the end, but this one can be ignored (not sure why, but it does work despite of the error). After uploading a new program the Longan Nano has to be reset manually by pressing the RESET button. The Longan Nano should no longer blink it’s RGB LED, but instead remain dark and silent. Yippie?

Since this result is somewhat unsatisfying let’s load the official blinky example to bring the Longan Nano back to light. Get the sources from github (just clone the whole project) and descend into the example directory of interest, then build and upload the longan-nano-blink example.

$> git clone
$> cd ./platform-gd32v/examples/longan-nano-blink
$> sudo python3 -m platformio run --target upload
 Processing sipeed-longan-nano (platform: gd32v; framework: gd32vf103-sdk; board: sipeed-longan-nano)
Download    [=========================] 100%         6584 bytes
 Download done.
 File downloaded successfully
 dfu-util: dfuse_download: libusb_control_transfer returned -9
 *** [upload] Error 74
 ================================= [FAILED] Took 2.91 seconds ==========================

After pressing the RESET button the Longan Nano does start blinking it’s RGB LED again, using only the red color. Success!

Blinking like a real pro: the Longan Nano.

In case at any point the messagedfu-util: No DFU capable USB device available appears this means your host machine dropped the USB device corresponding to the Longan Nano for some reason. Try to connect it again with the BOOT and RESET button combo described above.

And that concludes the first steps with the Longan Nano. See you next time.