Sunday, January 16, 2022

Compiling and deploying TinyML examples to SparkFun Edge

Trying out the SparkFun Edge board. Seems there are changes to the source repositories and many online instructions are outdated.

For example, to build and deploy the micro_speech example:

#set env
export BAUD_RATE=921600
export DEVICENAME=/dev/ttyUSB0

# compile the code
make micro_speech

# convert the binary. "~work/apollo3/downloads/AmbiqSuiteSDK-master" is where I have the SDK installed
arm-none-eabi-objcopy gen/bin/micro_speech gen/bin/micro_speech.bin -O binary

python ~/work/apollo3/downloads/AmbiqSuiteSDK-master/tools/apollo3_scripts/ --bin gen/bin/micro_speech.bin --load-address 0xC000 --magic-num 0xCB -o gen/bin/micro_speech_nonsecure_ota --version 0x0

python ~/work/apollo3/downloads/AmbiqSuiteSDK-master/tools/apollo3_scripts/ --load-address 0x20000 --bin gen/bin/micro_speech_nonsecure_ota.bin -i 6 -o gen/bin/micro_speech_nonsecure_wire --options 0x1

# deploy
python ~/work/apollo3/downloads/AmbiqSuiteSDK-master/tools/apollo3_scripts/ -b ${BAUD_RATE} ${DEVICENAME} -r 1 -f gen/bin/micro_speech_nonsecure_wire.bin -i 6

Monday, August 9, 2021

Enable IOMMU

Notes to self: remember to re-enable IOMMU after flashing new BIOS. Otherwise ROCm OpenCL wont work for iGPU.

Friday, July 16, 2021

Cost of implicit casting in Java

Java has implicit casting (e.g. from float to double). Curious to know what is the performance impact. For example:

// direct cast to double


// explicitly cast to float and implicitly to double

For the above example, when looking at the generated byte code, the direct casting used the "i2d" (integer to double) instruction. The indirect and implicit casting used "i2f" and "f2d" instructions.

  private void lambda$run$2(java.lang.String[], int);
       0: aload_0
       1: aload_1
       2: iconst_0
       3: aaload
       4: invokestatic  #20                 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
       7: i2f
       8: f2d
       9: invokevirtual #21                 // Method dummy:(D)V
      12: return

  private void lambda$run$1(java.lang.String[], int);
       0: aload_0
       1: aload_1
       2: iconst_0
       3: aaload
       4: invokestatic  #20                 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
       7: i2d
       8: invokevirtual #21                 // Method dummy:(D)V
      11: return


On machine with OpenJDK 11, the extra cost for each call is about 2ns.

Full source code available.

Saturday, June 19, 2021

Squeezelite with docker

Besides those dedicated Raspberry Pis running piCorePlayer, sometimes I wanted to simulate a Squeezebox device on my work PC to play music. The easiest way is to run Squeezelite with docker.

A minor patch to the docker run script so that I can pass in upsampling parameters to it as my USB DAC can handle up to 768kHz.

Then just start the container with something like this, where D50s is my DAC:

docker run --rm --env SQUEEZELITE_AUDIO_DEVICE=hw:CARD=D50s --env SQUEEZELITE_SPECIFY_SERVER=yes --env SQUEEZELITE_SERVER_PORT= --env SQUEEZELITE_NAME=openSUSE_PC --env SQUEEZELITE_OPTS='-r 705600,768000 -R vE::4:28:99:100:50' --device /dev/snd --name squeezelite --net host -d giof71/squeezelite

Monday, June 7, 2021

Ripping audio tracks from a DVD

Quick notes on ripping audio tracks from a DVD (Unplugged by The Corrs) using command line:

# rip dvd by track (total 17)
for i in {1..17}; do
  mplayer dvd:// -chapter $i-$i -dumpstream -dumpfile $i.vob;

# find out which audio stream has the 2-channel pcm and copy it into a flac file
for i in {1..17}; do
  tmp=`ffprobe -v error -show_format -show_streams $i.vob | grep -B 1 pcm_dvd | head -n 1 | cut -d '=' -f 2-`
  ffmpeg -i $i.vob -map 0:a:$ai -vn -f flac $i.flac;

# rename flac files by track... TBD

# set metadata
for i in *.flac; do
  ARTIST='The Corrs'
  tracknumber=`echo $i | cut -d ' ' -f 1 | sed 's/^0*//'`
  title=`echo $i | cut -d ' ' -f 2- | cut -f 1 -d '.'`
  metaflac --set-tag="ALBUM=$ALBUM" --set-tag="ARTIST=$ARTIST" --set-tag="tracknumber=$tracknumber" --set-tag="title=$title" --remove-tag=encoder "$i"

Sunday, May 30, 2021

My current audio setup


This is my current audio setup with free software.

  • The Logitech Media Server (LMS) is the music hub. It serves local music files and streams music from Tidal
  • A couple of Raspberry Pis running piCorePlayer as music players. The piCorePlayer is lightweight enough that it can run on the very first generation of Raspberry Pi with just 256MB of RAM
  • More piCorePlayer devices can be added for multi-room setup
  • The desktop setup has a Topping D50s DAC. Recently replaced the KRK Rokit 5 Gen3 active speakers with passive Triangle BR03 and a class-T amplifier. Thinking to replace the amplifier with a proper integrated amplifier (or maybe even a pre-amp + power amp) so I can add a turntable
  • The bedside headphone setup has an old Mini USB DAC and a DIY headamp

Tuesday, April 27, 2021

Experiment with Dart and Flutter


Decided to try out Dart and Flutter for Android development. Some thoughts after re-implementing AndSafe:

  • For simple / standard UI, defining and implementing each page with code is a lot easier than using UI designer
  • If you know JS / node.js, writing Dart code feel like home
  • Although Dart utilizes ahead-of-time compiled code, doing CPU and memory heavy tasks (e.g. scrypt key derivation) is still noticeably slow. Ended up using Dart FFI to call C implementation of scrypt.

I first implemented Android Safe 10 years ago in 2010. This re-write is certainly more enjoyable and easy, thanks to matured development environment.

Wednesday, March 17, 2021

Limit cloudflared upstream connections

Just archived my cloudflared patch repo. My patch was a hack to get around a run-away issue: when there are sudden in-rush of requests or network delay, cloudflared will create lots of connection to upstream DNS-over-HTTPS servers. This will trigger the upstream throttling cloudflared and causing it to create even more connections to upstream. The machine will ended up with high CPU usage and no DNS request being resolved.

That is because cloudflared used golang "http.Transport" for the connection without setting a max limit. My hack hard-coded the max number of connection to 2 to avoid the issue. But it is probably inappropriate if cloudflared is used in an enterprise environment.

Luckily someone worked on a fix by adding a command line parameter to specify the max connection. Just add "--max-upstream-conns num_con" as parameter when starting cloudflared.

Sunday, February 28, 2021

Penney's Game

 Just finished the book Humble Pi. Interesting read, especially if you are interested in math trivia and read about how little math mistakes can cause serious disasters.

In the chapter about probability, it mentioned the Penney's Game and how people's misconception about independent event makes the game interesting.

I ended up writing a program that simulate coin flipping to verify the claims. The result checked out but I did make a mistake when first implementing the logic.

When looping the coin flipping result, I used counter to keep track of the number of matches for each player. When a mismatch happens, I incorrectly reset the counter to zero. Instead, I should have checked if the last one / two coin flipping results match player's pattern.

Tuesday, January 26, 2021

Stable matching

While cleaning my working directory, found a Python function that I wrote a few months ago for solving the stable marriage problem. But couldn't remember why I wrote it...

Anyway, refactored and pushed to github.