Category: uC

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.



USBasp driver for Windows 10

In the past I used USBtiny and USBasp programmers to flash Atmel microcontrollers. Under Windows 10 the programmers did not work, even though Windows 10 seemed to detect them correctly.
It turns out Windows 10 does not use/fetch the correct drivers.
To make things work again most folk use Zadig a tool which automatically installs some legacy drivers typically used for USB programmer dongles.

USB driver installation with Zadig

After the drivers are installed Windows 10 finally detects my USBasp programmer dongle as it should.


Realizing Arbitrary Functions with ROM-Based Lookup Tables

When tasked with the implementation of a rather complex function, e.g. a polynomial of higher order, the resource utilization quickly shoots through the roof if implemented straight forward (also called the naïve implementation).
To avoid this it is often easier, simpler and faster to use a lookup table (LUT) solution.

Instead of doing a lot of calculations and mathematics, the results for a given function argument is just read from a read-only memory (ROM) which contains precalculated results.
Oftentimes a LUT/ROM based implementation can be used in place of a “proper” implementation during early prototyping. In a later stage of the project the LUT/ROM can be replaced with an optimized implementation.

Arbitrary function realized using a LUT/ROM

Most people will encounter a ROM based lookup table solution when dealing with sine and cosine functions. The technique is then often called direct digital synthesis (DDS), because a waveform is generated by digital logic instead of analog circuitry, as it was done in ancient times.
Since this is a more or less common task I wrote an Octave script that takes a function as input and generates a memory initialization file for a LUT/ROM solution. The parameter range of interest can be specified and the width and depth of the LUT/ROM can be defined.
Periodic functions will likely result in problems if not handled carefully. E.g. a lot of people will specify the parameter range for a sine LUT/ROM go from 0 to 2*Pi. However, since the boundaries of the interval are always part of the LUT/ROM the start/end value of the period will appear twice, once at the highest LUT/ROM address and once at the lowest LUT/ROM address (because sin(0) = sin(2*Pi) = 0). This gotcha does not hold for non-periodic functions. It can also easily be fixed.

The quality of the result this technique yields depends on both the LUT/ROM’s memory depth and the LUT/ROM’s word width. The former defines the number of available sampling points and thus the quantization of the function parameter(s). The latter defines the quantization of the function result, which means how close a single LUT/ROM data value is to the exact result of the function. Both kinds of quantization contribute to the error of the LUT/ROM implementation, i.e. the deviation of the LUT/ROMs result from the precise function result value.

The total size of the LUT/ROM is memory depth * word width bits.
Another performance characteristic is the maximum operating frequency under which an implementation can run. On FPGAs the maximum operating frequency will depend on the number of BRAMs required to realize the LUT ROM. If only one BRAM is used there is not need for additional routing or coupling glue logic and thus the operating frequency will be maximized.
Using more than one BRAM requires “chaining”/”coupling” of BRAMs and thus will reduce the maximum operating frequency due to additional routing and/or logic delays.

LUT/ROM composed of multiple BRAMs

STM32 Programming Entry

For the STM32 family of microcontrollers a number of different support libaries are available: Cortex Microcontroller Software Interface Standard (CMSIS), Standard Peripheral Library (SPL), Hardware Abstraction Layer (HAL).

CMSIS (by ARM) is basically just a bunch of header files with common defines for all registers of the microcontroller and its periperal devices. There are no API functions or drivers included at all. The CMSIS gives the programmer the most control and performance, but requires the most work.

SPL (by ST Microelectronics) consists of libraries allowing to use peripheral devices of the STM32 microcontroller much easier and abstracting away most of the wiggle work of register bits. The SPL is officially obsolete and will no longer be supported or maintained.

HAL (by ST Microelectronics) is the most recent library to support STM32 microcontrollers. It’s similar to SPL but offers some advanced features. Code written for HAL is supposed to be easily portable between different microcontrollers. On the other hand performance may not be at maximum since a lot of different hardware is supported by the same functions/API.

There is also a new thing called the Low Layer Library (LLL). The LLL defines different abstraction layers and allows the programmer to decide how much low level control she wants to take.

For more details check out the articles below.


USBasp in Windows 10

Unfortunately Windows 10 does not accept the standard drivers for the USBasp programmer. The reason is that the drivers have no valid signature from Microsoft (as required by Windows 10).

The only way around this problem seems to be to temporarily disable signature checking and then install the drivers (if you are fine with the security risk). This is described in detail here.