cPiArtFrame

the PiArtFrame in C++

Posted by Giulio Magnifico on Friday, September 13, 2024

Shelly Grafana summary

Intro

Here’s a quick update on the PiArtFrame. I already posted an update in the old post, so to keep things organized, I decided to write a new one.

As reference you can read the old post

Basically, GitHub user kevlol has ported the Python code by runezor (the original PiArtFrame) to C++. This is awesome because:

  1. The system is more stable.
  2. You can choose the exact refresh time.
  3. You can adjust the “black level” of the generated image.
  4. The Raspberry Pi is less stressed and uses less power.

Explanation:

  1. C++ is a precompiled language, so it doesn’t need an interpreter.
  2. With Python, rendering a new zoom on the fractal could last 15 minutes or 4 hours, depending on the image’s complexity (and the RPi CPU power). With C++, rendering is much faster (few seconds), enabling the ability to set a refresh intervals like 1, 20, 60, whatever, minutes, with new images appearing exactly on time.
  3. You can easily adjust the “black level” (correct term should be ‘uniformity’) of the displayed image by tweaking two values.
  4. Since C++ uses significantly less CPU time, it reduces power consumption and heat.

Why again?

Few months ago I thougt that my e-paper display was broken, because it was display weird vertical lines. So I put the PiArtFrame project inside a drawer and left it there, until a few days ago, when I decided to buy a new e-paper display and build again the PiArtFrame.

broken e-paper

When the new display arrived, I connected it to the Raspberry PI…but it didn’t work again! So I spent several hours in front of the terminal, trying to figure out what the cause was but I couldn’t find it. Every time I tried to show something on the display, the Raspberry PI was outputting this log and nothing was visible on the display:

EPD_7IN5_V2_test Demo
/***********************************/ 
Current environment: Debian
/***********************************/ 
e-Paper Init and Clear...
Debug: e-Paper busy
Debug: e-Paper busy release
Debug: e-Paper busy
Debug: e-Paper busy release
0 S
Paint_NewImage
show window BMP-----------------
pixel = 800 * 480
Debug: e-Paper busy
Debug: e-Paper busy release

At one point I got tired of trying via software and I started examining the hardware.

…and surprise! The header I soldered -obviously poorly- had a pin that had come unsoldered, and every time I tried to connect the e-paper hat by pushing it to the RPi header, this pin was no longer make contact, slipping inside and exiting from the back of the board. This was the reason for the log above, why it always seemed occupied, in reality, that pin was not occupied, but it was not even touching the e-paper hat.

So (at 2 a.m.) I made again the soldering, tested it again and of course, the new display was working perfectly. So I thought, “Do you want to see that the old one works too and isn’t broken?!” I tried to connect the old display, launched the executable, it refreshed and displayed the image as if it were new!

e-paper working

So I decided to keep the old display, send the new one back to Amazon, and redo the entire installation.

And here we are:

Hardware

  • A Raspberry Pi, of course (I used the Zero 2), with this heat dissipator/case. It’s perfect because it has a flat metal surface on the back, allowing you to attach double-sided tape and stick it to the back of the frame.

  • An e-paper display from Waveshare. I used this one: 7.5", 800x400px, priced at 70€ on Amazon.it. You can also use other dimensions as long as it’s from Waveshare.

  • A frame. I used this one from Amazon in the 10cm x 15cm option. It’s quite inexpensive (two frames for about 15€).

Software

You need to install gcc, make, git, and other dependencies according to your system (Raspbian already has many of them pre-installed).

Go to the folder where you want to store the project and download it:

git clone https://github.com/giuliomagnifico/PiArtFrame-CPP and after cd into the folder.

⚠️
Optional: If you want to change the render time and uniformity level, read below, otherwise, jump to the next step after the quote block.

In order to adjust the update time of rendered image change the 15 value in main.c on the line 14:

static constexpr unsigned long SecondsBetweenImages = 15*60;

15 minutes is my value, if you want 1 minute or 30 minutes, adjust it.

If you want more black pixels in the rendered images, tweak the values in mandelbrot.cpp. Change return (std::get<2>(x) >= 0.95); in both code blocks. These values determine the uniformity range where the algorithm randomly selects an image to zoom in on.

auto lessUniformChoices = choices;
lessUniformChoices.erase(std::remove_if(
    lessUniformChoices.begin(),
    lessUniformChoices.end(),
    [](const tuple<double, double, double>& x) { 
        return (std::get<2>(x) >= 0.95); 
    }), lessUniformChoices.end());

auto topTierChoices = choices;
topTierChoices.erase(std::remove_if(
    topTierChoices.begin(),
    topTierChoices.end(),
    [](const tuple<double, double, double>& x) { 
        return (std::get<2>(x) >= 0.85); 
    }), topTierChoices.end());

Run make (or make -j5on a RPi with 4 cores) to compile it and wait few seconds for the compilation end. Then start the executable using: ./PiArtFrame.

Check the e-paper display, and if everything is working, you can set it to launch the process at boot using a systemd service or cron. I used cron this time: crontab -e and add the line (it will wait 15 seconds after boot, then launch PiArtFrame):

@reboot sleep 15 && cd /root/piArtFrame && ./piArtFrame

Assembly

The construction is always easy, just insert the display into the frame, allowing the flat cable to come out, and then attach the Raspberry PI to the frame with double-sided tape.

build build