Alomst the best I have ever seen (three)


Follow the guide to install (my mirror), only for V1.0.4 system image, and then:

import time
from pinpong.board import Board,Pin


led = Pin(Pin.D0, Pin.OUT)

while True:

The pinpong library covers quite a lot of functionality, and useful examples:

root@milkv-duo2]~# ls /usr/lib/python3.9/site-packages/pinpong/examples/milkv-Duo/                oled2864.pyc
__init__.pyc                                  i2c.pyc                   ozone.pyc
adc.pyc                               i2c_scan.pyc              paj7620.pyc
as7341.pyc                        iic_to_serial.pyc         ph1.pyc
blink.pyc                              ir_recv.pyc               ph2.pyc
bme280.pyc                             ir_send.pyc               pwm.pyc
bme680.pyc                             irq.pyc                   rgb_panel.pyc
bmi160_acc.pyc                    lcd1602.pyc               sen0483.pyc
bmi160_step.pyc                         lis2dh.pyc                servo.pyc
bmp280.pyc                            max30103.pyc              sht31.pyc
bmp388.pyc                       mics_enable_power.pyc     speech_synthesis.pyc
button.pyc                       mics_get_adc_data.pyc     spi.pyc
buzzer.pyc         mics_get_gas_exist.pyc    sr04_urm10.pyc
ccs811_read_baseline.pyc       mics_get_gas_ppm.pyc
ccs811_read_data.pyc               st7789.pyc                    mlx90614.pyc    
dht.pyc                             tcs34725.pyc                  mp3.pyc         
dht20.pyc                      tds.pyc                 neopixel.pyc    
ds0469.pyc                          tone.pyc                 nfc.pyc         
ds1307.pyc                uart.pyc                nfc_card_info.pyc
ds18b20.pyc                    urm09.pyc                 nfc_uart.pyc    
ens160.pyc                vl53l0.pyc           nfc_uart_card.pyc

I will explore those examples.

Start Script at Boot

As of V1.0.4 system image, the /etc/init.d/S99user executes /mnt/data/ if it exists:

% mkdir /mnt/data
% vi /mnt/data/

and list each of the processes:

/path/to/my/ &
python /path/to/another/ &


According this post, tinycc has been ported as well – C compiler and C interpreter in one – download the .zip (my mirror) and run its, and then fix missing executable bit:

% chmod +x /usr/local/bin/tcc

and start playing with test.c:

#!/usr/local/bin/tcc -run

#include <stdio.h>

int main(int argc, char **argv) {
    printf("%s---\n", "hello milk-v!");
    return 0;
% tcc -o test test.c
% ./test
hello milk-v!---
% chmod +x test.c
% ./test.c
hello milk-v!---

Thanks to Yang who ported and provided the download.


I followed the example, and compiled the sources on the board itself with tcc:

tcc -r ssd1306.c -I .
tcc -r linux_i2c.c -I .
tcc -o ssd1306 main.c linux_i2c.o ssd1306.o -I .
./ssd1306 -I 128x64
./ssd1306 -c
./ssd1306 -m "Hello world!\nMilk-V Duo"

OLED SSD1306 connected to Milk-V Duo via I2C, controlled via RISC-V binary ssd1306 from ssd1306_linux

Software State

available memory (RAM) 48MB 55MB 55MB
ssh server ok (dropbear v2020.81) ok (dropbear v2020.81) ok (dropbear v2022.83)
ssh client ok (dropbear v2020.81) ok (dropbear v2020.81) ok (dropbear v2022.83)
python ok (python 3.9.5) ok (python 3.9.5) ok (python 3.11)
py web-server (with socket) ok ok ok
py gpio (with pinpong or gpio) ok ok
py spi (with built-in spidev) available, not yet tested available, not yet tested
py i2c (with pinpong ) available, not yet tested with pinpong
ok with .c (see above section) available, not yet tested with pinpong
ok with .c (see above section)
py pwm (with pinpong) not found, /sys/class/pwm/* is empty not found, /sys/class/pwm/* is empty
pip failed (hangs), enable swap space to use it barely works, enable swap space works (swap space enabled)
cc/gcc/clang not found not included not included
tinycc/tcc ok, see this post how to install ok, see this post how to install ok
rsync not found included included
wget ok, but no https (only http, ftp) ok, but no https (only http, ftp) not included, installable
lua/luac lua (5.4.6): segmentation fault, luac (5.4.6): seems to work (both compiled with tinycc) lua & luac (5.3.6) works lua & luac (5.4.6) works
extras quickjs/qjs, micropython, nano, screen, git, make (no gcc/cc, use tinycc), thttpd, nginx, lighttpd, php-cgi, file, which, sudo pacman (package mgr), lighttpd, file, which, sudo, make

Internet Access for Milk-V Duo

RNDIS (Virtual Ethernet over USB)

The host has to run Ethernet over USB and also operate as transparent router and let the connected board(s) reach the internet, see this guide (use google translate to english), here the brief description:

On The Host

The outgoing_if is the outgoing interface, either eth0 or wpl0s0 or something, check with ifconfig of the proper name, and then as root perform:

% sysctl net.ipv4.ip_forward=1
% iptables -P FORWARD ACCEPT
% iptables -t nat -A POSTROUTING -o outgoing_if -j MASQUERADE

Also, find out which IP your host got (ip_of_host) from the connected board, e.g., also check with ifconfig.

On The Board

% ip r add default via ip_of_host
% echo "nameserver" >> /etc/resolv.conf

Custom BuildRoot Milk-V Duo Disk Image

Here my brief guide – see also this guide (use google translate) – how to customize packages included in the base distribution of the image for the SD card:

% cd duo-buildroot-sdk/buildroot-2021.05
% make menuconfig

then go into the “Target packages”, and then walk through:

  • Audio and video applications
  • Compressors and decompressors
  • Debugging, profiling and benchmark
  • Development tools
  • Filesystem and flash utilities
  • Fonts, cursors, icons, sounds and themes
  • Games
  • Graphic libraries and applications (graphic/text)
  • Hardware handling
  • Interpreter languages and scripting
  • Libraries
  • Mail
  • Miscellaneous
  • Networking applications
  • Package managers
  • Real-Time
  • Security
  • Shell and utilities
  • System tools
  • Text editors and viewers

once you selected the packages you like to have included, choose “Save” and confirm as ‘.config’ and then “Exit”.

% cp .config configs/milkv_duo_musl_riscv64_defconfig
% cd ..
% ./

and after while, depending on how many packages you selected, you find in out/ folder your new disk image you can copy on the SD card.

Note: buildroot is quite a quirky package, e.g. when you select a package and make a build, later deselect a package, it will still be included – worse, if you commit a clean slate in output/, some packages might not fully build anymore – you have to go back to an earlier state of fewer packages, remake the build, and restart re-selecting new packages.

Postfixing missing .so file

As of 2023/10 v1.0.4 buildroot-2021.05 environment, there seems a problem regarding a missing shared library for some of the compiled apps (like qjs), you can fix this:

% cd /lib
% ln -s

My BuildRoot Custom Disk Images

milkv-duo-v1.0.4-20231017-spiritdude-64mb_ram-nocam.img lua, quickjs/qjs, micropython, nano, screen, git, make (no gcc/cc, use tinycc), thttpd), nginx, lighttpd, php-cgi, 55MB RAM available, “fixed” image has .so lib-fix included
milkv-duo-v1.0.4-20231017-spiritdude-64mb_ram-nocam-fixed.img lua, quickjs/qjs, micropython, nano, screen, git, make (no gcc/cc, use tinycc), thttpd), nginx, lighttpd, php-cgi, 55MB RAM available, “fixed” image has .so lib-fix included
milkv-duo-v1.0.4-20231016-spiritdude-64mb_ram-nocam.img lua, quickjs/qjs, micropython, nano, screen, git, make (no gcc/cc, use tinycc), lighttpd (doesn’t work yet out of the box),55MB RAM available
  1. apprx. 55MB actual available RAM, no camera support, INO_SIZE=0
  2. thttpd, nginx and lighttpd are all http-server, only use one, see /etc/init.d/ where those are started.

Ethernet Add-On

The easier way is to get proper networking is to add a real ethernet port and properly wire it to the ethernet router. There are several options & sources (2023/09):

RJ45 Add-on (EUR 2.50)

RJ45 Add-on (EUR 2.50)

IO Expansion: 4x USB 1x Ethernet (USD 5.00 – 9.50)

Printable Case

I did a small case for the bare board without Ethernet or Extension board to be 3D printed:

Milk-V Duo (bare):
bottom case & lid

Milk-V Duo (bare): bottom case

Milk-V Duo case closed

Printed in white & black PLA

white vs black case blue & red LEDs see-through

white PLA cases allow LEDs see through

white PLA (FFF/FDM), white & clear resin (MSLA)


As the Milk-V Duo has the same width and depth (X/Y) as the Raspberry Pico but it’s a bit thicker so the some of the existing cases work only partially:

As soon my Ethernet connectors and Extension boards arrived I will provide case variants (2023/10/05).


1 Like