OLED spectrum display on Volumio on Raspberry Pi Zero W

I wrote a program for an OLED spectrum display on Volumio on a Raspberry Pi Zero W. The program runs Cava as a subprocess, which reads a copy of the mpd audio from a fifo and writes the spectrum data to another fifo, which is read by the calling program and displayed on the OLED. When there is no audio data the display switches to a clock.

My code depends on a Cava update that has not yet been released. When it is I will upload my code and instructions to Github.

In the following (poor) video audio stars off with a clock showing. When the audio starts the spectrum is displayed. I then rerun the program with more bars. The bars start off above the disply but Cava automatically scales them down to make a good display. You can see from the output of ‘top’ that the Pi Zero can cope well running the display.



Here is the code and instructions


Great work
Is any chance to send cava to hdmi display connected to rpi?

The vol_oled program could be adapted to work with other devices, but if you can run a terminal screen on the HDMI display then maybe you could run Cava directly in that.

I have added some more details to the display. In the following image the top line shows KBitrate, a volume indicator and a connection indicator. Then a a digital clock under that. Then the song “origin”, and song title, and at the bottom a song progress bar.


Here is a video showing a song from an album, and a radio station, and a clock when nothing is playing


Hi Adrii,

This sounds very interesting and is looking really good.

If i set “dtparam=i2c_arm_baudrate=1200000” my i2s audio card with hardware volume control over i2c stops working.

Do you use USB audio ?

  • Josef

Hi Josef

I am using an i2s card, but it doesn’t have hardware volume control.

I don’t have much experience with these devices, but from when I was reviewing this for the program it appeared that the default value was 100000, and 400000 was a higher value that was often used, but 1200000 worked for me so I just went with that. Maybe you could try 400000 and see if your volume control works, while allowing the vol_oled framerate to be set to something acceptable.

I have actually come across some issues with the program today. It needs to start after MPD, and so a working spectrum does not always display on startup. I have fixed the startup order and have just pushed the changes. I have reported an issue with the Cava program (which generates the spectrum) as it is also affected, and this may be the best place to fix it.

I have also noticed the player restart a couple of times after an hour or so. I wonder if it is overheating. I need to investigate this.

vol_oled is definitely work in progress, but I am using it on my main player now and so I will need to fix all the issues!


Hi Adrian,

Thank you - i will try different speed settings on the i2c bus tomorrow morning.

I have another issue with the make command in the instructions while trying to make vol_oled.

g++ -W -Wall -Wno-unused-variable -Wno-unused-parameter -Ofast -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s -c -o main.o main.cpp In file included from main.cpp:27:0: status.h:26:24: fatal error: mpd/client.h: No such file or directory #include <mpd/client.h> ^ compilation terminated. <builtin>: recipe for target 'main.o' failed make: *** [main.o] Error 1

Do you have an idea how to fix this ?
Do i have to install a missing thing ?

  • Josef

Hi Adrian,

i found installing libmpdclient-dev let me make it

sudo apt-get install libmpdclient-dev

Maybe you want to add that to the instructions on github ?

  • Josef

Hi Josef

This is fixed in the current instructions (but might be scrolled off of the right on the Github page). Thanks for letting me know!


I have dropped my i2c bus speed to 400KHz and the display looks fine, in which case I will put this speed in the instructions.

I am also testing a small local patch to Cava that fixes the issues caused by MPD restarting.

At the moment, I am playing a radio stream and the total %CPU is around 70%, with vol_oled/cava accounting for around 20%. The CPU/GPU temperatures are stable at around 47C. This all seems fine. I’ll leave it running all day and see if I still have an issue with the machine restarting.

It turned out that the machine resets were caused by a poor power supply.

The only remaining issue is that using the current Github Cava code the vol_oled service will need to be restarted if MPD is restarted. However, my local changes to Cava are working fine, so there will hopefully soon be a fix for this.

Hi Adrian,

I got it working :smiley: :smiley: :smiley: (using i2c bus speed 400kHz - also my DAC is alive and volume control is working).
This is looking real professional :smiley:

The only problem is - the WebUI of Volumio is not reachable any longer as soon as i start

 sudo ./vol_oled -a 3c -o 6 -b 10 -g20 -f 20

…and the time zone is wrong. Is it set anywhere in the plugin or do i have to adjust the timezone of my volumio device.

Volume control is still working thanks to a connected rotary encoder - but i cannot change anything else.

Do you have an idea ?

Thank you

  • Josef

Hi Josef

Thanks for the feedback, I am pleased it is working!

I forgot I had to set the timezone. I’ll include that in the instructions. An easy way to do this (I am not sure if debconf is installed by default) is

sudo apt-get install debconf sudo dpkg-reconfigure tzdata
I am not sure why the Web UI is not reachable when you run the command. (The command should actually fail with an error as -g is very big and the spectrum graph is too wide to be displayed, but maybe the -g20 is just a typing error). If you don’t have the latest vol_oled changes then grab them by running ‘git pull’ in the source directory, then rebuild the program and then try again with

sudo ./vol_oled -a 3c -o 6 -b 10 -f 20

The vol_oled program includes some code to detect the network connection type, but I don’t think it should interfere with the connection at all. Perhaps you could open a second ssh window to volumio and run ‘top’ in it before running vol_oled in the first window, to see if CPU jumps to 100%, or mpd stops running, or something else strange is happening.


Hi Adrian,

Thank you - it is nearly perfect now.
The WebUI disappearing issue resolved itself the other day and did not happen again… ???

I didn’t have to install debconf - it was already installed available.
Setting the correct time was successful with:

sudo dpkg-reconfigure tzdata

and it is also kept after restarting. :smiley:

I tested a lot and found the i2c bus is also stable at 600kHz at my system and ended up in the following command that i put into vol_oled.service before installing it:

sudo ./vol_oled -a 3c -o 6 -b 16 -g 1 -f 24

The only thing i cannot get around:
After about 4 hours of seamless working the display freezes (also at 400kHz bus speed) and i got the following error message:
terminate called after throwing an instance of ‘std::length_error’
what(): basic_string::_S_create
If this happens - not always but sometimes i see wierd characters in the line where the radio station name is printed.

Do you have another hint for me ?

Just f.y.i.

I’m very happy with your project since i’m still stucked getting an hd44780 display to work and this is the first solution that gets me to success with i2c displays. I just ordered another few of the SD1106 displays in China.

I’m using this display:

I’m testing with:
cheap modified PiFi-DAC2 (with self soldered test pins)
RaspberryPI 1B+,2B, 3B (most time with the 3B because rebooting is much faster in case of need :wink:
reliable DIY linear power supply (torroid transformer, schottky rectifiers, nichikon/vishay RC filter, LT1083 based regulator - 5,15V at 7A,max)

Thank you so much - i hope this will grow up to a official plugin for Volumio

  • Josef

Hi Josef

Thanks for reporting the error. I think I can see what is causing it, and have hopefully fixed it. I have just uploaded the changes to Github.

I don’t know how long it will take for Cava to be updated. I have passed on my changes to the project, but I don’t feel they are the best solution.

When everything with vol_oled appears to be working correctly I will look at what can be done to ease the installation.


Cava has been updated to handle MPD being restarted. Installing the latest version of Cava from Github also fixes this issue in vol_oled.

I notice that vol_oled displays accented characters as graphics characters. I’ll see if I can fix that.

There are no other outstanding issues with vol_oled that I am aware of.

Hi Adrian,

Thank you for your great work.
I didn’t have time to do long term tests with the fixed versions of vol_oled and cava, but it’s working fine until now.
Over the weekend i’m on vacation so i will do further testing next week.

I found a typo you maybe want to change in the instructions on github.

Clone the source repository

git clone git clone https://github.com/antiprism/vol_oled

there is one “git clone” too much…

Should be:

git clone https://github.com/antiprism/vol_oled

Hardware hint for those who are using cables longer than 20cm for SCL and SDL or if you try to increase the bus speed. (My i2c bus which is also controlling the hardware volume control of my DAC is working at 800kHz now with 15cm cables (directly soldered)):
Put 120 Ohm pullup resistors from SCL and from SDL to V+ at the display may help increasing the bus stability/performance.

Another question i did not find an answer to on google right now:
Is it possible to change the i2c address of an OLED module of that kind?

  • Josef
1 Like

Hi Josef

I have just pushed an update to handle non-ASCII characters better. To keep things simple, I just convert non-ASCII characters to an ASCII substitute (iconv: UTF-8 -> ASCII//TRANSLIT). I also fixed the git clone command, thanks.

No more changes planned for now.

I’m sorry, I don’t know how to change the i2c address for these displays.


I try to install it.
And get error :

sudo ./vol_oled -o 6 -b 10 -g 1 -f 20
terminate called after throwing an instance of ‘std::runtime_error’
what(): Type is not convertible to int