Almost the best I have ever seen (two)

Note: usb0: HOST MAC and MAC are set randomly and change after each (re)boot.

Note: you won’t need to solder the male connectors, I usually just insert them loosely and the cable bending gives sufficient connectivity for a brief login to fix things and then remove UART-USB cable again.

/proc/cpuinfo

[root@milkv-duo]~# more /proc/cpuinfo 
processor       : 0
hart            : 0
isa             : rv64imafdvcsu
mmu             : sv39

df

[root@milkv-duo]~# df
Filesystem           1K-blocks      Used Available Use% Mounted on
/dev/root               763327    157774    562136  22% /
devtmpfs                 14680         0     14680   0% /dev
tmpfs                    14752         0     14752   0% /dev/shm
tmpfs                    14752        52     14700   0% /tmp
tmpfs                    14752        28     14724   0% /run

[root@milkv-duo]~# df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root               745.4M    154.1M    549.0M  22% /
devtmpfs                 14.3M         0     14.3M   0% /dev
tmpfs                    14.4M         0     14.4M   0% /dev/shm
tmpfs                    14.4M     52.0K     14.4M   0% /tmp
tmpfs                    14.4M     28.0K     14.4M   0% /run

ps

PID   USER     COMMAND
    1 root     init
    2 root     [kthreadd]
    3 root     [rcu_gp]
    4 root     [rcu_par_gp]
    5 root     [kworker/0:0-eve]
    7 root     [kworker/u2:0-ev]
    8 root     [mm_percpu_wq]
    9 root     [ksoftirqd/0]
   10 root     [rcu_preempt]
   11 root     [kdevtmpfs]
   12 root     [rcu_tasks_kthre]
   13 root     [oom_reaper]
   14 root     [writeback]
   15 root     [kcompactd0]
   24 root     [kblockd]
   25 root     [watchdogd]
   27 root     [kworker/0:1H-mm]
   28 root     [rpciod]
   29 root     [kworker/u3:0]
   30 root     [xprtiod]
   31 root     [cfg80211]
   32 root     [kswapd0]
   33 root     [nfsiod]
   34 root     [spi0]
   35 root     [spi1]
   36 root     [stmmac_wq]
   37 root     [kworker/u2:1]
   70 root     [irq/45-cviusb-o]
   71 root     [irq/46-cd-gpio-]
   72 root     [sdhci]
   73 root     [irq/23-mmc0]
   75 root     [ion_system_heap]
   76 root     [mmc_complete]
   81 root     [jbd2/mmcblk0p2-]
   82 root     [ext4-rsv-conver]
   97 root     /sbin/syslogd -n
  101 root     /sbin/klogd -n
  131 dhcpcd   dhcpcd: [master] [ip4]
  132 root     dhcpcd: [privileged actioneer]
  133 dhcpcd   dhcpcd: [network proxy]
  134 dhcpcd   dhcpcd: [control proxy]
  147 root     [kworker/0:3-eve]
  156 root     /usr/sbin/ntpd -g -p /var/run/ntpd.pid
  165 root     /usr/sbin/dropbear -R
  170 nobody   /usr/sbin/dnsmasq
  180 root     [cvitask_isp_pre]
  181 root     [cvitask_isp_bla]
  182 root     [cvitask_isp_err]
  184 root     [cvitask_vpss_0]
  185 root     [cvitask_vpss_1]
  187 root     [gdc_work]
  192 root     [cvitask_tpu_wor]
  198 root     {S99user} /bin/sh /etc/init.d/S99user start
  199 root     [kworker/0:2H]
  211 root     -sh
 1297 root     /usr/sbin/dropbear -R
 1302 root     -sh
 1331 root     sleep 0.5
 1332 root     ps

/bin

[root@milkv-duo]~# ls /bin
arch           dmesg          linux64        nuke           sleep
ash            dnsdomainname  ln             pidof          stty
base32         dumpkmap       login          ping           su
base64         echo           ls             pipe_progress  sync
busybox        egrep          lsattr         printenv       tar
cat            false          mk_cmds        ps             touch
chattr         fdflush        mkdir          pwd            true
chgrp          fgrep          mknod          resume         umount
chmod          getopt         mktemp         rm             uname
chown          grep           more           rmdir          usleep
compile_et     gunzip         mount          run-parts      vi
cp             gzip           mountpoint     sed            watch
cpio           hostname       mt             setarch        zcat
date           kill           mv             setpriv
dd             link           netstat        setserial
df             linux32        nice           sh

/usr/bin

[root@milkv-duo]~# ls /usr/bin/
[                  fold               od                 tee
[[                 free               openvt             telnet
ar                 fuser              passwd             test
ascii              gcore              paste              tftp
awk                gdb                patch              time
basename           gdb-add-index      pip                top
bc                 head               pip3               tr
bunzip2            hexdump            pip3.9             traceroute
bzcat              hexedit            printf             truncate
chrt               hostid             pyserial-miniterm  ts
chvt               htop               pyserial-ports     tty
cksum              id                 python             uniq
clear              install            python3            unix2dos
cmp                ipcrm              python3.9          unlink
crc32              ipcs               readlink           unlzma
crontab            killall            realpath           unlzop
cut                last               renice             unxz
cvi_pinmux         less               reset              unzip
dbclient           logger             resize             uptime
dc                 logname            scp                uudecode
deallocvt          lsof               seq                uuencode
diff               lspci              setfattr           vlock
dirname            lsscsi             setkeycodes        w
dos2unix           lsusb              setsid             wc
dropbearconvert    lzcat              sha1sum            wget
dropbearkey        lzma               sha256sum          which
du                 lzopcat            sha3sum            who
easy_install       md5sum             sha512sum          whoami
easy_install-3.9   mesg               shred              xargs
eject              microcom           smtpd.py.9         xmlcatalog
env                mkfifo             sort               xmllint
event_rpcgen.py    mkpasswd           ssh                xmlwf
evtest             nl                 strace             xsltproc
expr               nohup              strace-log-merge   xxd
factor             nproc              strings            xz
fallocate          nslookup           svc                xzcat
find               ntpdate            svok               yes
flock              ntptime            tail

[root@milkv-duo]~# ls -1 /usr/bin/ | wc -l
151

Multiple Milk-V Duos / Alternative IPs

In order to support multiple Milk-V Duos on the same host via USB-C, you assign for each board its own network:

  • board 1: 192.168.51.0
  • board 2: 192.168.52.0
  • board 3: 192.168.53.0

Edit on each board two files:

/mnt/system/usb-rndis.sh (buildroot-based) or /etc/usb-rndis.sh (other systems):

ifconfig usb0 192.168.51.1

/etc/dnsmasq.conf:

dhcp-range=192.168.51.2,192.168.51.242,1h

In order to add a new board, you login into 192.168.42.1 as usual, and change it to the 192.168.52.1 and so on.

Resizing Disk

By default the entire available space of the SD card is only 1GB (or 2GB in case you use another distro), but you can make the rest of the SD card available to /data for example – part of the guide was taken from a post in the forum but updated it:

% mkdir /data
% fdisk /dev/mmcblk0
n (new partition)
p (primary partition)
4
<RETURN> (confirm start selection)
<RETURN> (confirm end selection)
w
q

% reboot

and login again, continue with:

% mkfs.ext4 /dev/mmcblk0p4
% echo "/dev/mmcblk0p4 /data ext4 defaults 0 0" >> /etc/fstab
% reboot

once you login again, you see the new available space:

% df -h
Filesystem                Size      Used Available Use% Mounted on
/dev/root               745.4M    154.1M    549.0M  22% /
devtmpfs                 14.3M         0     14.3M   0% /dev
tmpfs                    14.4M         0     14.4M   0% /dev/shm
tmpfs                    14.4M     52.0K     14.4M   0% /tmp
tmpfs                    14.4M     28.0K     14.4M   0% /run
/dev/mmcblk0p4           13.4G     24.0K     12.7G   0% /data

Making Swap Space

pip won’t work by default, as there is too little memory to work – so you can make swap space in two ways:

mmcblk0p3: unused 256M partition

As of system image v1.0.4 there is an unsed partition you can activate:

% mkswap /dev/mmcblk0p3
% swapon /dev/mmcblk0p3
% echo "/dev/mmcblk0p3 swap swap defaults 0 0" >> /etc/fstab

Swapfile

Or you can create a 256M swapfile to increase available memory, given we claimed the rest of the SD card as /data as previously shown:

% cd /data
% fallocate -l 256M swapfile
% chmod 600 swapfile
% mkswap swapfile
% swapon swapfile

and to make it permanent:

% echo "/data/swapfile swap swap defaults 0 0" >> /etc/fstab

ArchLinux Disk Image

I followed this guide to get ArchLinux working – thanks to Judehahh doing the main work – and added RNDIS support (Virtual Ethernet over USB) and made a disk image to use, the date e.g. “2023-10-09” references the riscv64 rootfs date which was unpacked as a base. Unzip downloaded image first before writing on the SD card.

ssh root@192.168.42.1
passwd: milkv

Note: these are very experimental disk images

DISK IMAGE FEATURES INCLUDED MISSING
milkv-duo-archlinux-riscv64-2023-10-09-2.5gb-v0.0.1-spiritdude.img md5:2ff352bcb7a9d855dfe50b4d3176f69c 2023/10/21 55MB RAM (no camera support),256MB swap enabled, rndis (connect via usb virtual ether), minimum 4GB SD card recommended, 960 apps in /usr/bin/, 1GB free in rootfs pacman (pkg mgr), ssh (dropbear v2022.83), python 3.11, make, tinycc/tcc, lua/luac, lighttpd no quickjs/qjs (not available install mujs instead), no micropython (not available)
milkv-duo-archlinux-riscv64-2023-10-09-1.5gb-v0.0.1-spiritdude.img md5:ecc2ab2076ad9fbec795c5dba73a291e 2023/10/21 55MB RAM (no camera support), 256MB swap enabled, rndis (connect via usb virtual ether), minimum 2GB SD card recommended, 960 apps in /usr/bin/, only 40MB free in rootfs (!!) pacman (pkg mgr), ssh (dropbear v2022.83), python 3.11, make, tinycc/tcc, lua/luac, lighttpd no quickjs/qjs (not available install mujs instead), no micropython (not available), no gcc/llvm (install if you need it, resize rootfs)

Notes:

  • pacman -Fy 'term' or -Q 'term' fails for me (too much memory needed), instead run gzip -d -c /var/lib/pacman/sync/*.files | grep -ai 'term' (-F equivalent) or *.db for (-Q equivalent)

Tips & Examples

Most of the examples relate to the Duo BuildRoot SDK setup, but should be easily adaptable to ArchLinux or other distros.

blink.py with sysfs GPIO

There is a way to control GPIO via sysfs with Python:

Note: you require more memory to run pip, use guide Make Swap Space (previous section) then proceed:

% cd gpio-1.0.0
% pip install .
% chmod +r /sys/class/gpio/export

then use this script blink.py:

import time

import gpio as GPIO

pin = 440
GPIO.setup(pin, GPIO.OUT)

while True:
    GPIO.output(pin, GPIO.HIGH)
    time.sleep(1.0)
    GPIO.output(pin, GPIO.LOW)
    time.sleep(1.0)

and run it:

% python blink.py

See this table for GPIO names, pins and numbers, a copy (2023/10/10):

GPIO NAME GPIO PIN GPIO NUMBER NOTES
GPIOA14 19 494
GPIOA15 20 495
GPIOA16 16 496
GPIOA17 17 497
GPIOA22 24 502
GPIOA23 21 503
GPIOA24 22 504
GPIOA25 25 505
GPIOA26 27 506
GPIOA27 26 507
GPIOA28 1 508
GPIOA29 2 509
GPIOC9 14 425 1.8V
GPIOC10 15 426 1.8V
PWR_GPIO4 29 356 1.8V
PWR_GPIO18 12 370
PWR_GPIO19 6 371
PWR_GPIO20 7 372
PWR_GPIO21 11 373
PWR_GPIO22 10 374
PWR_GPIO23 9 375
PWR_GPIO25 5 377
PWR_GPIO26 4 378
1 Like