ADS-B Exchange!

Despite some turbulence within the ADS-B Exchange community after their API policy change, owner James Stanford kindly sent me a key for the new REST API 🙂

In exchange for feeding ADSBx, non-commercial users may use the API for free. Your key needs to be included in the header of each (https) API request.

The following code is at the top of my new What’s Up? sketch for monitoring all aircraft within a distance of 25 nautical miles from my location (latitude- and longitude filters have not (yet) been implemented in the new API, so they need to be applied on the query results programmatically).

Then, inside loop(), I create an instance of WiFiClientSecure and send the API request over https, including my API key in the header:

The json response can now be processed as usual by reading from the stream ‘client’. Although the key names of the new API differ from the old ones, I didn’t have to make any changes to the json streaming parser that I wrote for earlier ADS-B projects because it takes these names from a global array that now looks like:

Some keys from the old API do not (yet) have an equivalent in the new json response. As a temporary solution, I now host a local API on my webserver, returning aircraft model and flight operator for an icao or opicao code. It’s powered by a MySQL database, imported from json files found at

A further change in the new json reponse forced me to rewrite my function for character decoding. The new API uses Unicode code points instead of multi-byte utf-8 for encoding special characters. When using GFX-based graphic libraries, these need to be converted to Extended Ascii Code page 850 (“Latin-1”), or to ‘romanized’ cyrillic characters.

It all works OK, although responses from the new ADBSx API show more drop outs then before. Also, jumps between consecutive position updates seem larger, making the so arduously conquered flicker free icon movements less striking.

I expect to post a video of my new (and hopefully final) ESP32 version of What’s Up? in one of the next posts. In order to use the code, you’ll either have to be (or become) an ADSBx feeder, or buy a key. I went for the first option (with two feeders) and made a donation as well, despite my strong aversion to PayPal.




Self-replicating Cellular Automata

Studying John von Neumann’s self-reproducing universal constructor* reminded me of some unfinished business in my earlier Cellular Automata (CA) projects. Always looking for coding challenges, I wondered if I could write a sketch for simulating self-reproducing CA loops that would fit inside an ESP32.

The general idea is to have a 2-dimensional grid of cells, each of which can be in one out of n states. These cells periodically change their states simultaneously, according to a set of rules. Each cell complies with the same set of rules, which lets it calculate its new state based on its current state and that of its direct neighbours. The way this ‘organism’ will evolve also depends on its initial pattern. A self-reproducing CA is a combination of states, rules and initial pattern that will continuously produce copies of the initial pattern, that will produce more copies of the initial pattern… etc. etc.

I guess that Von Neumann’s universal automaton, with its 29 cell states and large set of rules, could be well out of ESP32’s league. Fortunately there are some famous (be it less universal) simplifications, so I started with the simplest one I could find: Chou-Reggia-2.

ESP32 WROVER simulating Chou-Reggia-2 on a 320×240 display (1-pixel per cell)

The video shows the indefatigable CA at work, producing ever more copies of the initial pattern (just 5 cells). It mimics a much sought after form of life: old cells don’t die…

They’re just like kids, they grow up so fast 😉


In order to squeeze my Chou-Reggia-2 algorithm into the ESP32, I had to come up with some new programming- and storage techniques for cellular automata. I ended up writing a framework for CA sketches, that can import patterns and rules from Golly. It runs on ESP32 WROVER modules, using its PSRAM for storing a double display/states buffer. The two cores of the ESP32 cooperatively calculate a new grid state based on the current one.

As a proof of concept for the new framework, I initialised it with the specific data for Langton’s Loop, an automaton similar to Chou-Reggia-2, but with more rules. Everything worked fine, as did two slightly more complicated automata that have variables in their Golly rules, as well as substantially more states: Evoloop-finite and Perrier Loop.

Now that I have it up and running, my CA framework for ESP32 WROVER modules reduces simulation of most 2D cellular automata to feeding it with their specific data: states, transition rules (with or without variables), neighborhood (Moore or von Neumann) and rule symmetry, all imported from Golly. State colors are not taken from Golly, but chosen to meet the condition (stateColor) % nStates == state, a crucial break-through idea for making the framework fit inside an ESP32 while preserving speed and high refresh rates.

[ After further optimization, my CA sketches run 5x faster than what is shown in the videos! ]

Close up of Langton’s Loop on an ESP32-driven 320×240 TFT display (slow version)

Because every ‘cell’ is represented by a single pixel on a small 2.4″ display, I had to zoom in on the pattern in order to show the difference between ‘living’ and ‘dead’ cells (Langton’s ‘organism’ grows like coral: inner cells die, but their cell-walls are preserved).


* Von Neumann’s abstract and purely logical reasoning about self-replication eventually helped biologists to understand how (real) cells manage to make exact copies of themselves.



Turbocharged TFT display

Here are some first results of the (speed) progress that I’ve made since my previous post about using PSRAM as display buffer.

The first video shows a 200×150 pixels animation generated by looping over 61 frames (ripped from an animated gif). The partial refresh of the relevant display area is so fast that I had to include delays between the frames.



The next video shows my dual core/ dual buffer Julia Fractal Zoomer sketch in action. The two ESP32 cores cooperate in writing Julia Fractals with ever increasing zoom levels to a (double) buffer in PSRAM. When a fractal is finished, the loop function takes care of writing its pixel values from the last completed buffer to the display.

Zooming in on Julia fractal (c = -0.79 -0.15i) ; max iterations: 128


This spinning globe was my first sketch that used PSRAM as a display buffer, written to test the concept and measure its speed. It is generated by looping over 21 frames.



The above videos show a LOLIN TFT-2.4 Shield, driven by a LOLIN D32 Pro with 8MB PSRAM. Sketches will follow after I’ve implemented a new idea that may further increase the zoom speed.



PSRAM Display Buffer

One possible application of ESP32 WROVER’s PSRAM memory is using it as a (double) display buffer. I thought this could be useful for fractal-based animations on a TFT display, as these sketches often require a considerable amount of calculations for each pixel, followed by an update of that single pixel on the display, This way, a full refresh of the display can take a lot of time, but by writing calculated color values to a PSRAM buffer instead, the actual refresh can be done much faster by pushing the entire buffer to the display after all pixel colors have been calculated in a background process (even simultaneously on a different core, using a double buffering technique).

As a proof of concept, I converted one of my Julia Fractal sketches to a version that continuously draws a specific Julia Set Jc with an incrementing zoom level. The first result is satisfying enough, even though my pixel-by-pixel approach is probably not the most efficient way to interact with PSRAM. I may post a video in due course, but for now you can find the prototype sketch for a 320×240 display at the end of this post. It uses both fast cores and a double buffering technique: while one buffer is being filled by a core 1 task, the other one can be read by a core 0 task for filling the display.

Perhaps this display buffer concept can finally make aircraft position updates in my ‘What’s Up’ Flight Radar sketch completely flicker free. Instead of always having to save clean map tiles from the diplay (with readPixel) before drawing updated aircraft sprites on them, it will allow me to restore the appropriate tiles directly from the full map image stored  in PSRAM. That will circumvent my long time problem with the only fast library for the HX8357D display (Bodmer’s TFT_eSPI library): it’s readPixel() function doesn’t work on that display, so until now I couldn’t use it for my Flight Radar sketches. No longer having to use readPixel allows me drive this nice 480×320 display in that library’s parallel mode, which is very fast! With the maximum of 12 aircraft on display, updating all positions will take < 80 milliseconds. So my next post may be ‘What’s Up – final version‘.

Here’s a quick and dirty dual core ‘Julia Fractal Zoomer’ sketch. For some reason, omitting the vTaskDelay command in loop() makes it run slower! Leaving out these commands from the task functions will crash the ESP32. Make sure to enable PSRAM before compiling the sketch on a WROVER based ESP32 (option will appear under ‘Tools’ in the Arduino IDE or can be set with make menuconfig if you use Espressif’s ESP-IDF).

[UPDATE] the prototype sketch below ran much faster after dividing calculations for the new display buffer over both cores and, as expected, by replacing the individual drawPixel commands by pushing the entire display buffer in one single SPI transaction.

Pseudostatic Ram (PSRAM)


Just got me a second LOLIN D32 Pro v.2, this time with the newer ESP32-WROVER-B module on board. For just € 1,- extra, it has 4x more RAM and 2x more PSRAM. But what is this PSRAM, and could I use it for memory-hungry sketches, like the ones where AI or pathfinding algorithms are involved?

Searching the Internet gave me a first idea of what it is, but more important: I found out how to use it, which luckily turned out to be remarkably simple.

Below is a simple demo sketch that shows how to address PSRAM. It allocates a 1 MB buffer in PSRAM and then starts writing random integers at random positions, then reading them back for comparison. Make sure that PSRAM is enabled when you compile it, otherwise the ESP32 will panic! (it’s an option in the Tools menu of the Arduino IDE after a WROVER based ESP32 board has been selected).

[edit: a more useful application can be found in this later post]

Note that GPIO pins 16 and 17 are used for communication between ESP32 and PSRAM, so WROVER-based boards will not have these pins broken out.

Also note that content in PSRAM will be lost after the ESP32 loses power (still have to figure out what happens during deep sleep).

My search for information on PSRAM triggered a more general interest in the chip’s architecture. Espressif’s documentation has been very helpful.

PS: in order to use the upper 4 MB of the module’s 8MB PSRAM, you’ll need to build your application with Espressif’s ESP-IDF and enable ‘bank switching’. Instructions can be found here:

Swinging Needles (analog VU meters)


It took me some time (and strong coffee), but I finally managed to have the ESP32 version of my Internet Radio drive two vintage style analog VU meters!


And here they are…

Web browser controlled prototype with basic display and no matrix keypad attached

Soon after I had purchased a rather obscure VU meter kit, it turned out that the driver board was completely useless because it was mono (Chinese for stereo?).

So I decided to have the ESP32 read the analog (DC-biased) line out signals from the VS1053 mp3 decoder, map the peak-to-peak readings to [0,255] scaled values and send these to the ESP’s DACs for driving the meters. However, I couldn’t figure out how to do that without having to connect the VS1053’s floating audio ground to the system ground, which, so I guessed, would either not work, cause noise or even damage something.

Then I remembered the VU meter plugin for the VS1053, enabling you to read dB levels from a memory register. But these plugin readings are leaking peak dB levels, so I started wondering if it was possible to use them for reconstructing instantaneous dB levels. Not suitable for audio purists, but I wouldn’t mind if the result was convincing. After all, these cheap Chinese meters will never behave like professional VU meters anyway.

So I wrote a simple algorithm with some tuning parameters and functions for scaling and smoothing, calculated resistor values for limiting current to my meters to 0.4 mA max, added (probably unnecessary) flyback diodes to protect the ESP32 from negative voltage spikes, and just gave it a try. Here’s the wiring that I used for the meters.

The first result looked surprisingly good: the needles eagerly followed every move and twist of the music. Since everything is controlled by an algorithm, any desired meter ballistics can be easily simulated without electronics.

For now, further fine tuning seems unnecessary. Besides, a more audiophile approach already crossed my mind: have a FreeRTOS task listen in to the mp3 stream while it’s being sent to the VS1053, and programmatically decode it. That will allow me to extract true dB levels and could even become a replacement for the VS1053 board. Like I recently read in an article about Software Defined Radio (SDR), “software is the new hardware“.

Anyway, music finally looks almost as good again as it did in my youth. Let’s just hope for an analog VU meter revival soon. And how about a global rediscovery of reel-to-reel tapedecks (with analog VU meters, of course)? That would make much more sense to me than the somewhat puzzling comeback of vinyl.

Mini MP3 Player

This little €4 module filled my entire weekend, mainly spent on finding the right documentation and a library that will work on Arduino, ESP8266 and ESP32. It’s a DFPlayer Mini MP3 Player from DFRobot (or, more likely, one of its many clones).

It can play MP3 and WAV files, stored on an SD card in the onboard card reader or from an attached USB drive. So far, I only tested MP3 files from SD.

You can connect one (4 Ω) speaker to the (quite impressive) onboard mono amplifier. Stereo line output is said to be provided on the DAC_R and DAC_L pins.

The main control method of this player is via commands over the module’s 9600 baud serial port. A subset of most commonly used commands can also be executed by means of two GPIO pins and/or two resistor-sensitive ‘ADKEY’ pins.

I made a false start by testing it on an ESP32 over hardware serial. That didn’t seem to work, so I tried an ESP8266 over software serial. That didn’t work either, and I had reached the point of giving up, assuming it was just another Chinese fake, when I gave it one more try on my good old Arduino Uno. With a quick & dirty 1K resistor for level shifting the module’s RX pin, the example sketch of one of many libraries finally made the little guy play me a song! In the end, it was the power supply that made the difference.

Some important things that I learned so far:

  • The module works best when powered by a stable 5 Volt. My Arduino Uno and Wemos D1 R2 could deliver it from their 5V pin, smaller ESP8266 and ESP32 boards couldn’t. In that case: use a separate 5 Volt power supply.
  • Wiring as suggested here caused a shutdown of my laptop’s usb port! I’m still searching for a way to connect the module to ESP32.
  • The module operates on 3.3 V logic level, so make sure to level shift the connection to the module’s RX pin when using a 5 V microcontoller.
  • Startup noise disappeared after I connected both GND pins from the player to ground.
  • Although it’s for a Flyron FN-M16P module, this excellent manual/datasheet has more and better written information than DFRobot’s own poorly translated summary. Apparently both modules use the same commands and probably have the same chip.
  • Getting stereo ouput from the DAC pins is still a problem. According to the manual, DAC is enabled on startup, but is it? Explicitely enabling it by sending 0x0000 to memory address 0x1A made no difference while sending 0x0001 instead (supposed to turn it off) started a terrible noise…
  • I tested quite some libraries from github, most of which have issues [update: starting sketches with delay(1000); solved most of them] and seem unnecessarily complicated to me. An exception is this simple and transparent library that is basically just a wrapper for sending serial commands. It can easily be extended with additional methods, even by unexperienced C++ programmers. You just have to lookup the command- and parameter bytes for the desired function in the datasheet and create a new function to send them (see example at the bottom of this page). [update: the author of the library has meanwhile added more commands]
  • The module has an SPK_1 and an SPK_2 pin, with a GND pin in between, which could suggest that it has a stereo amplifier. Although the documentation clearly says it’s mono, someone actually published a wiring diagram with two speakers connected. This person may own a different version of the module, but mine definitely has a mono amplifier. So the two wires of a single speaker should go to the SPK pins.

[ Wiring for Arduino Uno, with SoftSerial on pins 10 and 11; don’t forget the 1K resistor! ]


The location of files and their names is also very important because of the way commands address them. All information can be found in the datasheet, but here’s a summary:

  • The SD card’s maximum size is 32 GB. It must be FAT or FAT32 formatted.
  • There can be up to 3000 .mp3 (or .wav) files in the root directory of the SD card, named 0001.mp3 to 3000.mp3.
  • The root can have up to 99 subdirectories, named 01, 02, … 99. Each of these subdirectories can hold up to 255 files. Their names must start with 001, 002, … 255,  but you can append decriptive titles to these files, e.g. 007_James_Bond_Tune.mp3.
  • You can have a special subdirectory in the root named MP3. This can hold up to 3000 files, named 0001.mp3 to 3000.mp3.
  • You can also have a subdirecory ADVERT in the root. Special commands are available for making tracks in this folder interrupt currently playing tracks from the MP3 folder (for advertisement puposes). The rules for the MP3 subdirectory apply here as well.
  • Don’t create subdirectories inside subdirectories.
  • The module does not actually use file- or directory names, but the order of files and directories in the SD card’s FAT. The previously mentioned naming conventions just try to give you control over that order. If you properly organize your audio files in a folder on your PC first, and then copy that entire structure to a freshly formatted SD card, then (in theory) the FAT order should match the file- and directory numbering. See also this tool

Apart from adding some extra functions to the above mentioned library, I still have to find out how to reliably receive and read the module’s response to commands and queries. Once that I’m in full control over this (for its price) remarkably versatile module, it will be useful for a couple of ‘talking’ projects that I have in mind. Probably just mono and not ESP32 driven, but anyway: lots of fun for just €4.


Here’s an example of a function that I added to the DFPlayerMini_Fast library. Calling play_in_dir(2, 5) will play file 005.mp3 in subdirectory 02.

Using an existing function as a template, I first added my new function to the DFPlayerMini_Fast.cpp file:

Then I added these two accompanying lines to the DFPlayerMini_Fast.h header file:

and (inside the code for the class):


Explanation: according to the datasheet, the 10 (hexadecimal) bytes that have to be sent (by the sendData() function) to play track 005.mp3  in directory 02 are:

7E FF 06 0F 00 02 05 xx xx EF

7E FF 06 are the first three bytes for every command. The following 0F is de code for ‘play a file in a direcory’, the following 00 means ‘no confirmation feedback needed’ and is followed by the two parameters for the desired directory- and file number: 02 and 05. Then comes xx xx which are two checksum bytes that will be calculated and replaced by the findChecksum() function of the library before the command is sent by sendData(). Finally, every command has to be closed by EF.

As you can see, my newly added function play_in_dir() takes two parameters only, corresponding with two bytes in the command sequence. All other bytes of the sequence are either fixed or calculated by the findChecksum() function.



Dual Core Business

Almost a year after finishing my ESP8266-based Internet Radio project, I still have had no idea why running that sketch on the much more powerful ESP32 produces a heavily stuttering sound, resembling Michael Palin in “A Fish Called Wanda”.  So I wondered if I could solve this problem by dividing the audio streaming process between the ESP32’s two cores: filling the audio buffer on one core, and feeding the VS1053 decoder from that buffer on the other core.

Thanks to its builtin FreeRTOS, pinning a task to a specific core of the ESP32 is easy:

1. Put the code for the task in a function, wrapped in an endless for (;;) { } loop.

2. Create a task handle for the task in the main section of the sketch:

3. Create the task, specifying which function it should execute on which core:


(Since there was nothing in my loop() function (yet), I put a delay(1000); command in it. The loop() function runs on core 1, and I didn’t want it to claim too much of that core’s processor time.)

So my Radio sketch will have two independent tasks running on different cores: one that listens to the radio station’s audio stream for filling the circular buffer, and one for feeding the VS1053 decoder with bytes from that buffer. Both processes maintain their own pointer for accessing the circular buffer and the code guarantees that they will never catch up with the other process’ pointer. So there is no need to use a semaphore.

However, my first step into the dual core business produced an error. A ‘watchdog timer’ had become nervous and halted the ESP32. It turned out that including the following line in both functions solved at least that problem (bug?):


Now the ESP32 no longer crashed, and it actually produced sound. But alas, it was Michael Palin again…!

I can’t think of any reason for this behaviour. The serial monitor shows that the ESP32 has no problem filling the 30 Kbyte circular buffer, so feeding the VS1053 seems to be the bottleneck. I swapped cores for both tasks, but that didn’t help.

UPDATE: Meanwhile, I had become so desperate about finding a solution that I renamed the project “dESPeRadio“. But then, during a sleepless night, I wondered if the ESP32 might perhaps need a different policy for filling the circular buffer. The chunks it reads from the WiFi client per loop cycle have an upper size limit of 1024 bytes, in order to prevent the VS1053 from running dry during the process. But I didn’t specify a lower size limit.

For the ESP8266 this was OK, but the EP32 is so fast that, after it has rapidly filled the circular buffer, there will never be more than just a couple of free positions in the next loop cycle. All following cycles will therefore be very inefficient, causing so much overhead that the VS1053 actually runs dry in a very regular time pattern – the stuttering.

So I added just one single line for skipping the fill cycle if there’s less than 512 bytes of free buffer space available and uploaded the sketch without much hope, because so many ‘good’ ideas had failed before. What followed was complete silence…, which then turned out to be the pause between two movements of  Brahms’ fourth symphony! Then the music started in clean and, above all, uninterrupted sound!

The radio has been running non-stop now for a couple of hours. It looks like I finally have a solid and stable foundation for further development of my dESPeRadio on ESP32. Although using two cores isn’t necessary, it will be nice way to explore FreeRTOS.

In order to keep the code clean and readable, all future features and controls will be implemented as (optional) includible header files. I’ll make the full code available in my first github repository soon, so if you’re interested, stay tuned.

Plans for additional control options, apart from the already implemented keypad, are:

  • ☑ an embedded web server
  • ☐ the touch screen overlay of my display
  • ☐ IR remote
  • ☐ rotary encoders for volume, bass and treble

Other plans:

  • ☑ add VU meters (I love the analogue ones!)
  • ☐ use a FreeRTOS queue instead of a circular buffer






LOLIN TFT-2.4 Shield

Here’s a well designed new display from Wemos Electronics. They call it a (D1 Mini) Shield, but instead of going on top of a Wemos D1 Mini (Pro), it lets you plug in the Mini at the back of the 2.4″ TFT touch screen display, leaving all GPIO pins accessible, thanks to double header rows. Very useful!

This table shows the internal pin mapping when used as a shield. For TFT_LED, TFT_RST and TS_CS, this mapping can be changed by closing solder bridges at the back of the display (default NC for TFT_LED means “backlight always on”).

The default pin mapping leaves I2C pins D1 and D2, as well as D4, A0, TX and RX available for other purposes. With my Wemos Mini Pro v2 plugged in, this shield has become my first choice for battery powered esp8266 projects that require a display.



But there’s more. All pins are also broken out to a breadboard-friendly header and to a TFT connector. Connecting the display to a D32 Pro (that has the same TFT connector) now requires only one (special) cable! The picture shows the connector’s pinout.


The 320×240 display uses the well-proven ili9341 chip, for which I already wrote a lot of sketches, both for esp8266 and esp32 boards. The XPT2046 library can be used to drive the touch screen.

I tested several sketches on a plugged-in Mini Pro, as well as a TFT cable-connected D32 Pro, and everything worked fine. Example sketches on the Wemos site use Adafruit’s ili9341 library, but I prefer the much faster TFT_eSPI library with built-in touch screen support.

Here’s a video showing the display in action:


Conclusion: this is a well-thought product that makes wiring very convenient and stable. Recommended!



Quest for Fire

By no means a gamer myself, I’ve always been interested in the math behind the graphics in video games. A previous post showed how simple clouds can be produced by the Diamond-Square algorithm, running on an esp8266. That algorithm can generate maps and landscapes as well.

Another visual effect on my todo list was algorithmically simulated fire.


The video shows my first attempt on a small TFT display. I had to write a relatively simple algorithm, because it needs to run on a microcontroller. Some further experimenting with the color palette, weighting factors and randomization, as well as adding Perlin noise, will hopefully result in a more realistic fire. I also plan to add a rotary encoder for regulating the ‘fire’.