Thursday

Playing around with the Arduino Uno R4 Minima, Uno R4 Wifi and Uno Q

Playing around with the Arduino Uno R4 Minima, Uno R4 Wifi and Uno Q

Stepping up to a new level of micro-controller 

 

 Thanks to the fine people at Arduino, specifically Per Tillisch, an Arduino Support Engineer, I just received some free hardware! An Uno R4 Minima, Uno R4 WiFi and Uno Q!

 

Uno R4 Wifi and Uno R4 Minima
 
Now its just a matter of figuring out what to do with this stuff. I've already begun testing with the RF24 Communication Stack, and most of it works out-of-the-box. The only change required was adjusting the CPU speed detection in RF24Ethernet to accommodate the Uno R4 Wifi and Uno R4 Minima. I've put the changes in, but haven't done a release yet. Users can download the ZIP or clone the repo to install for now.
 
The R4 Minima appears pretty straight forward, with a micro-controller attached to a familiar board type, and a lot more processing power and memory than previous AVR-based designs. Not that the AVR boards are no longer useful, but its nice playing around with the newer designs and architecture. Newer boards actually tend to have a simpler interface when getting into direct register access and control, so its easier to develop libraries and applications that work with the newer boards. The R4 WiFi is more complex, with a main MCU, the Renesas RA4M1, and an ESP32 handling WiFi with a bridge between the MCUs.
 
Now I've played around with the Arduino Q quite a bit already, so will be mostly focusing on understanding and working with these new R4 boards that I have no experience with. I've gotten them working with the RF24 Comm stack as mentioned above, so it will probably be onto the AutoAnalogAudio library, to see what can be accomplished. The Arduino Q runs Linux along with the MCU, with a Serial bridge between them, but these boards are quite different. They seem to be more comparable to regular MCUs, just with enhanced functionality.
 
The boards themselves came with no strings attached, Arduino folks just sent them for free, so I can pretty much do whatever I want, with whatever time frame I want. 
 
Of course the big difference is that the R4 WiFi has an embedded ESP32 chip for WiFi in addition to the main micro-controller, so I will need some time to understand the bridge interface and whether it is worth it to explore programming the ESP32 chip directly. At first I will focus on the Renesas RA4M1 chip and explore its main capabilities, leaving the rest for later.
 
A big thanks to Arduino for these boards!

Monday

RF24Ethernet w/lwIP - Reaching a Point of Long Term Stability

 RF24Ethernet w/lwIP - Reaching a Point of Long Term Stability

Stable & Secure Communications with the RF24 Communication Stack 

Since I started on this journey integrating the lwIP TCP/IP stack into the RF24 Comm Stack, I was unsure if I would ever get to this point. Its been about 6 months since I started, and at this point I can say I am glad I did. Using lwIP really brings the stack up to standard, as previously it used only the uIP TCP/IP stack, which works well, but is no longer maintained. Now, newer micro-controllers will use the newer, up-to-date lwIP stack, while smaller, older MCUs will use the uIP stack.

 Over the past week or so, I've put in quite a lot of work on the RF24 Comm. Stack, including RF24Ethernet. In that time, it has become more secure, more stable, and is working better than it has in a long, long time.


Constant attacks & jamming targeting my networks has been taking place for years, and with the rise of AI, I decided to do some security & code reviews involving the RF24 Comm Stack. This was hugely beneficial, since I was able to work out a number of bugs and security flaws affecting the system. I would assume that most open source projects are beginning to do this as well, since there is a huge benefit from having a computer scan and verify your code.

 In the end, I was able to fix what I see as the "Final Major Issues" affecting the communication stack, from buffer overflows, to memory leaks, to a problem with millis() timer usage, involving rollover un-safe millis() calls. The system is now more resilient and stable than ever before, still susceptible when jamming overwhelms parts of the system, but able to bring itself back online, recovering all functionality as soon as the jamming stops. The constant attacks against my network have slowed significantly, with very little to no impact on the system when they do occur, since there are now less if any avenues to exploit remotely.

 I am now just running some final tests regarding the interaction of RF24Ethernet w/RF24Network when using lwIP, since there seemed to be some timing related issues with delay() vs network.update() calls, which should be addressed in the RF24Network master branch, but require testing before a release is made. These issues cause WDT resets on my ESP8266 while using WiFi in testing, but only occur once every 3-4 days or more, so tracking them down was difficult.

 All in all, I am very happy with the progress made over the last week, satisfied that my security concerns have been addressed, functionality is back to where it should be, and everything just keeps working.

Thursday

Using RF24Ethernet & RF24Gateway with the Arduino Cloud

 Using RF24Ethernet & RF24Gateway with the Arduino Cloud

 Pushing automation even further

 Recently, I was offered an Arduino Uno Q, Arduino Uno R4 Wifi and 1-year of Arduino Cloud access for free! This came as quite the surprise, because I was contacted out of nowhere by Per Tillisch, an Arduino Support Engineer, who offered me the devices and cloud access with no strings attached! I was quick to take him up on his offer. He stated it was due to my work contributing to the Arduino ecosystem.

In looking at the cloud access, it looks like it will be very simple to create dashboards etc, and integrate everything I want from my existing systems into the cloud! No code changes, no updates, no nothing. Just some simple changes in the NodeRed system I use.

With the current wireless IoT systems I am using, based on RF24Ethernet and RF24Gateway + wireless radios + MQTT, I also use NodeRed for managing all the data and interactions locally. This means that all I had to do was install the node-red-contrib-arduino-iot-cloud nodes, setup an API key, and use the newly installed nodes to communicate with the cloud!

 My system is setup so the RF24Ethernet nodes use MQTT to communicate with the RPi running RF24Gateway & NodeRed. NodeRed then handles the communication with the cloud.

See  https://docs.arduino.cc/arduino-cloud/guides/node-red/ for more information.

Right off the bat, I was able to create a simple dashboard that displays incoming Temperature, Humidity & Barometric pressure data on some charts!


 From here, it is very simple to add/remove & create new parts of the dashboard.

All of the existing Arduino devices in my network now have potential cloud access via NodeRed! I didn't have to modify any code, upload new firmware or really do much of anything! This all works with my existing systems!

The beauty of this is users can keep all their data and integrations local, logging to a database if desired etc, and still make use of the Arduino Cloud at the same time. Some data can go to the cloud, some to a local repository, and everything just seems to work in sync!

I currently have all my integrations set up via NodeRed + NodeRed Dashboard, so it is very similar already to the Arduino Cloud Dashboard, though only available locally. Using the cloud, I can now make some parts of it accessible from anywhere.

This is all very cool, I can't wait to get the new hardware! 

 

Monday

AutoAnalogAudio Library - Updated with I2S support for nRF54L15 devices

 AutoAnalogAudio Library - Updated with I2S support for nRF54L15 devices

 Bringing audio to the nRF54L15

 I was able to dabble little over the weekend, and ended up connecting an I2S amp and microphone to a nRF54L15 device. Getting it working was a little confusing at first, but the datasheet provided enough info to figure out the compatibility differences between nRF52840 and nRF54L15 devices. It was just a matter of making a few small changes.

One of the most glaring differences is with the main data pointer (NRF_I2S->RXTXD.MAXCNT). With the nRF52840 it counts by the number of 32-bit words, where the nRF54L15 counts individual bytes, so the main data handling functions needed to be modified.  

The other glaring difference is the pin layouts, but I've used the same physical layout as the 52840. That is, the physical spots on the board are the same, but the underlying pin and port numbers have changed.

 


    Per the AutoAnalogAudio library, these are how the pins are laid out by GPIO Pin / Port numbers:

    I2S_PIN_MCK = 8;
    I2S_PORT_MCK = 2;
    I2S_PIN_SCK = 5;
    I2S_PORT_SCK = 1;
    I2S_PIN_LRCK = 7;
    I2S_PORT_LRCK = 1;
    I2S_PIN_SDOUT = 11;
    I2S_PORT_SDOUT = 1;
    I2S_PIN_SDIN = 10;
    I2S_PORT_SDIN = 1;

 The changes have been pushed to the master branch as of this writing, and I will clean up the code, possibly add support for the PWM and SAADC features, and do a release soon. For now users can clone from the master branch or install from ZIP.

Saturday

The RF24 Wireless Communication Stack: Communication, Consistency & Exploits

 The RF24 Wireless Communication Stack: Communication, Consistency & Exploits

 Using RF24Ethernet & RF24Gateway for an IoT Network

 RF24Ethernet & RF24Gateway are two complimentary software libraries for Arduino that allow users to quickly design, develop & implement IoT networks that utilize TCP/IP for general communication. They use the Arduino Ethernet client/server APIs, so anyone with minimal programming experience can construct and deploy an IoT network in short order.

 


Recently, we discovered a buffer overflow in RF24Network that affected nearly the entire communication stack on Arduino devices. This buffer overflow was "externally triggered", meaning that an external user or system would need to send a certain packet type to a device to trigger the buffer overflow. It doesn't occur under "normal" operation of the system.
 
 The interesting thing about this, is that my devices have been susceptible to this overflow for a long time, and there has been near-daily attempts to disrupt my network. It seems that somebody nearby has a LOT of time on their hands, and a penchant for causing problems. 
 
The good part of this is RF24Mesh, the part of the RF24 Comm Stack that keeps things working, almost no matter what. RF24Mesh is a wireless-mesh system for the comm stack that provides addressing, DHCP type protocols, and self-healing/management of the network. With RF24Mesh involved, the network typically remains stable, despite the constant attacks.
 
  The exploit in RF24Network has now been patched, so users are encouraged to update as soon as possible.
 
 As far as the rest of the stack goes, everything is coming together with support for nRF52 and nRF54 radios, which now work with the comm stack. I have a little bit of work remaining in this regard, but basic support for these radios has been incorporated throughout the stack in the latest releases.
 


A chart of ping response times for one node on the network using NodeRed
 
 There are a lot of different uses for this system, from monitoring, to managing and collecting data from sensors, to remotely controlling devices, etc. and it is very flexible and standardized. I've been using the NodeRed system with MQTT mainly for my devices. MQTT is a standard protocol for messaging and IoT systems, so it is well suited to this type of thing.
 
 For anyone interested in wireless IoT systems, I would highly recommend checking out RF24Ethernet/RF24Gateway. You can be up and running in minutes, with a closed system using just two Arduino devices & RF24Ethernet, or a fully fledged IoT setup, using a Raspberry Pi/Linux for a gateway and a number of Arduino nodes running RF24Ethernet.

nrf_to_nrf Arduino Library: Now supports nRF54l15 devices!

 nrf_to_nrf Arduino Library: Now supports nRF54l15 devices!

New possibilities with nrf54l15 support 

 With the recent addition of an Arduino Core supporting nRF54l15 devices, I decided it was time to attempt to get the nrf_to_nrf library working with these devices. It was confusing initially, but once I worked out the specific differences in registers, things came together pretty quickly.

The main difference between these radios and nRF24 radios is the payload sizes and speeds. The nRF24 is capable of only 32-byte payloads, while the nRF52840 and nRF54l15 devices support much larger payloads. The nRF54l15 is also capable of 4Mbps transfer speeds.

The nrf_to_nrf library is designed to work out of the box between all 3 device types, but users can call 

  radio.begin();
  radio.enableDynamicPayloads(254);

prior to calling network.begin(); or mesh.begin(); functions to configure large payload sizes if setting up communication between nRF52840 and/or nRF54l15 devices. nRF24 is not compatible with sizes > 32-bytes.

I'm still working on getting encryption working on the nRF54l15 devices, and it seems to be a little more complicated than it was on the nRF52840. This might take a while to address.

The rest of the libraries, RF24, RF24Network, RF24Mesh & RF24Ethernet are being updated to accommodate the newer radios. 

 

 

Thursday

nRF24l01 radios: Long Term Stability Issues & Error Handling Enhancements

 nRF24l01 radios: Long Term Stability Issues & Error Handling Enhancements

 Creating robust, reliable networks

 We recently identified and addressed some long-term reliability issues affecting the RF24 radio library for nRF24l01 radios. The issues affect any users that make use of the write() or txStandBy() functions of the library. About a year ago, we found some issues with the radios returning "impossible" values, with one register indicating a payload is available, another saying there is not, and another saying the payload length is 0. This and similar issues appear to have affected the radio in transmitting mode as well, a fact we missed upon initial review of the previous issue. Now, a year later, we've addressed issues affecting transmission as well.

 

As of this writing, we are just completing testing and the changes have been pushed to the master branch of RF24. A new release should be available in a few days (version higher than 1.5.0) for the Arduino and PlatformIO platforms. For now, users can install from ZIP or clone the RF24 repo directly from the master branch.

This should be the final fix for stability in the RF24 platform, as we seem to have identified and implemented handling for all failure modes now.
 

Monday

RF24Ethernet v2.0 Released - lwIP IP Stack Support + Direct TCP/IP connectivity without a RPi

RF24Ethernet v2.0 Released - lwIP IP Stack Support + Direct TCP/IP connectivity without a RPi 

 Better, faster & more reliable connectivity w/lwIP

 Starting over the holidays, I began work with RF24Ethernet and the lwIP IP stack, integrating the IP stack into my existing library. Previously, and on smaller devices, the library utilized the uIP stack, which is no longer maintained, and used only on smaller devices that cannot run the lwIP stack.

This was quite a challenge, the lwIP stack functions in a lot of ways quite differently than the uIP stack, which in itself provided some challenges with integration. The RF24Ethernet library uses the lwIP stack in Mainloop (NO_SYS) mode, and lwIP uses callbacks for most of its functionality, so learning how that worked and the correct processes to use with this IP stack took some doing.  

 I was also able to adjust the code so that a Raspberry Pi or central PC is no longer required, nodes can simply run RF24Ethernet and connect between themselves via TCP/IP & UDP. I've included two examples, in the Headless examples directory, so users can try this new feature out.

 What is it? / How does it work?

 RF24Ethernet is a wireless TCP/IP communication system using nRF24 or nRF52x radios for comms. Users can create wireless mesh networks (NOT WiFi) that use much less power than WiFi networks and have many similar features, but with lower bandwidth.  

 The system mirrors the standard Arduino Ethernet API, and can function in many ways very similarly to standard Ethernet or WiFi connected devices, although over the nRF24 or nRF52 radios. See https://docs.arduino.cc/libraries/ethernet/

Essentially, you set it up, then just use TCP/IP protocols to communicate. Very little to no knowledge of the underlying APIs or code is required. 

 When a Raspberry Pi or other routing capable device is used as the master node, the system can utilize standard protocols to connect out to the internet or other parts of your network, via MQTT, HTTP etc.

 In a standard IoT setup, for example, a Raspberry Pi can run an MQTT server, with Arduino sensors connecting in and logging sensor information to a database etc.

In another IoT system, and ESP32 can connect out to Arduino devices set up as servers. The ESP32 would send and/or retrieve sensor or other information.  

How do I use it? 

 Just install the RF24Ethernet library and its dependencies via the Arduino Library Manager. One may also need to install the Arduino lwIP stack and optionally the MQTT library by Joel Gahwiler.

 Then just run the two examples in the Headless directory on some Arduinos!

 Please log any issues or problems with us at https://github.com/nRF24/RF24Ethernet/issues

 

Saturday

More with MP3 Decoding & Playback on nRF52x devices with the AutoAnalogAudio Library


 More with MP3 Decoding & Playback on nRF52x devices with the AutoAnalogAudio Library

Direct Playback of MP3s from SD card

Since designing and having some new circuit boards made for audio prototyping, I've begun testing more and more with advanced audio options, like decoding and playing MP3 files from SD Card. This is all thanks to a sponsorship from http://PCBWay.com

I've revised some previous experimental code and worked out some bugs, thanks to the simplicity of having a circuit board instead of a big ball of wires and breadboard.

The code shown below requires installation of my AutoAnalogAudio library and the microDecoder library which can both be installed from the Arduino Library Manager.

With my existing circuit board and the Feather 52840 Express or Sense boards, this code will work out of the box. It will also work with any 52840 based board. It is still in experimental stages but is working very well so far!


/*
* Requires https://github.com/TMRh20/microDecoder library
*/

#include <SD.h>
#include <AutoAnalogAudio.h>
#include "mp3.h"  // decoder
#include "pcm.h"

mp3 MP3;
pcm audio;
AutoAnalog aaAudio;


/************ USER CONFIGURATION ***************/
const char* audioFilename = "noceil.mp3";
uint8_t SD_CS_PIN = 2;  // Set this to your CS pin for the SD card/module

float volumeControl = 0.2;
#define AUDIO_BUFFER_SIZE 1152  // Should be a multiple of 64
/**********************************************/

void setup() {

  Serial.begin(115200);
  while (!Serial) delay(10);

  Serial.print("Init SD card...");
  if (!SD.begin(SD_CS_PIN)) {
    Serial.println("init failed!");
    return;
  }
  Serial.println("SD init ok");

  aaAudio.I2S_PIN_LRCK = 28;  // Use different LRCK pin for Feather Express 52840
  aaAudio.maxBufferSize = AUDIO_BUFFER_SIZE;
  aaAudio.begin(0, 2);

  playAudio(audioFilename);
}

void loop() {

  loadBuffer();

  // Control via Serial for testing
  if (Serial.available()) {
    char c = Serial.read();
    if (c == '=') {
      volumeControl += 0.1;
    } else if (c == '-') {
      volumeControl -= 0.1;
      volumeControl = max(0.0, volumeControl);
    } else if (c == 'p') {
      playAudio("atliens.mp3");
    } else if (c == 'c') {
      playAudio("dopeBoys.mp3");
    }
    Serial.println(volumeControl);
  }
}


File myFile;

void playAudio(const char* audioFile) {

  MP3.end();
  if (myFile) {
    myFile.close();
  }
  aaAudio.disableDAC();

  //Open the designated file
  myFile = SD.open(audioFile);

  if (myFile) {

    MP3.begin(myFile);
    MP3.getMetadata();
    aaAudio.setSampleRate(MP3.Fs, 1);
    Serial.println(MP3.Fs);
    aaAudio.dacBitsPerSample = MP3.bitsPerSample;
    Serial.println(MP3.bitsPerSample);
  } else {
    Serial.println("Failed to open file");
  }
}

void loadBuffer() {

  uint32_t sampleCounter = 0;
  if (myFile.available() >= AUDIO_BUFFER_SIZE) {
    for (uint32_t i = 0; i < AUDIO_BUFFER_SIZE / 64; i++) {
      audio = MP3.decode();
      memcpy(&aaAudio.dacBuffer16[sampleCounter], audio.interleaved, 128);  // 128 bytes
      sampleCounter += 64;                                                  // 64 samples per go
    }
    for (uint32_t i = 0; i < AUDIO_BUFFER_SIZE; i++) {
      int16_t sample = aaAudio.dacBuffer16[i];
      sample *= volumeControl;
      aaAudio.dacBuffer16[i] = sample;
    }
    aaAudio.feedDAC(0, sampleCounter);
  } else {
    aaAudio.disableDAC();
  }
}
 

 



Wednesday

Designing & 3D Printing Some Cases for My New Circuit Boards for Audio Prototyping

Designing & 3D Printing Some Cases for My New Circuit Boards 

 The beginnings of a final design

In order to put the finishing touches on my custom designed circuit boards, I figured its about time to build some cases for them. The final addition was a set of 1.5", 4-Ohm speakers I just purchased to complete the project. As shown below, iteration v1 of a case was pretty rough, just figuring out and confirming the basic measurements and form of a design. This ended up being very bulky, which would be OK for use as a tabletop speaker or intercom etc.   

 Case V1.0
Case V1.0
 
In the case shown below, V2, I opted to make it longer instead of wider. I tend to like this layout a little more. There are still a few tweaks to make, like lowering the speaker down into the case, so the USB cable will plug into the MCU without being blocked. I may add round holes for the buttons, but I kind of like the square layout, I still need to wire up the speaker, but this is how it will look. 
 
Case V1.1
Case V1.1
Once I make the necessary changes to this form, I will put the files in the associated GitHub repository here

I'm still trying to decide on a cover, whether or not I really need one, and if so, how to make it snap in and out, so it is easy to remove. I wish I would have made the PCB a little smaller, which I could probably do pretty easily by rearranging the components. All in all though, I think its pretty good for a first attempt at building a real circuit board with functional components. Thanks again to PCBWay.com for sponsoring the PCBs!

 

Friday

Initial Testing, Notes & Progress on new PCB for Wireless Audio Prototyping

 Initial Testing, Notes & Progress on new PCB for Wireless Audio Prototyping

 Testing out the new circuit boards and getting the built-in microphone working

 If you weren't following along I just received some new custom built circuit boards from PCBWay.com and have been testing things out extensively. Everything works! I even got the custom-added I2S microphone working with the nRF52840.

The boards support functionality like voice transmission over the built-in radio, and can function as a radio, intercom or simple music player etc. 



                                            A full test of the new circuit boards

Getting the Microphone working with the AutoAnalogAudio library: 

The nRF52840 Feather Express/Sense does have an I2S interface, but it only supports up to a 24-bit window, whereas the SPH0645LM4H expects 32 SCK pulses per audio frame (18 bits of data + 14 bits of padding) and a 64 x BCK signal, where the nRF52840 typically does a 48 x BCK signal.

After a bit of searching, I found that the appropriate signal could be created by the PWM peripheral of the 52840, and the I2S interface would just need to be configured with special settings to grab the 18-bits of data properly.

The main drawback with using this mode is the I2S interface can only operate in either Input or Output mode, they can't be run at the same time unless both I2S Input & Output devices use the same settings. I had to make some modifications to the AutoAnalogAudio library, released in v1.54.0, in order to allow switching between I2S modes.

Currently, this mode is only supported for input devices. 

                                                                The Feather Express 52840 

Configuration for the Microphone: 

To use the new special settings, users need to set the aaAudio.manualI2S variable to True before calling the aaAudio.begin(2,0); function.

With the Feather Express, the LRCK or WS pin needs to be configured from the default of 29, to something like 28, which is A3 on the Feather Express 52840

Results: 

 I've put together a full Radio Transceiver example for this PCB, found at https://github.com/TMRh20/FeatherAudio/tree/main/Examples/I2S_TransmitterAndReceiver

In order to use the example, upload to two Feather 52840 Express or Sense boards, and plug them into the custom PCB, or manually attach external I2S microphone & amplifier.  

The example features 3 buttons, the PTT button is used to transmit, then there are two for Volume Up/Down. If users press and hold Volume Down, then Press Volume Up, the device will go into a continuous transmission mode, not requiring the PTT button to be pressed.

The device also toggles the onboard red LED when data is received.

 Audio is relatively high quality at 16-bits and 32kHz, so it is pretty clear and useful for many different applications.

 

Tuesday

New Circuit Board for Audio Prototyping, Sponsored by PCBWay.com


 New Circuit Board for Audio Prototyping, Sponsored by PCBWay.com

 Design and manufacturing of a custom circuit board

 With recent developments to my AutoAnalogAudio library for Arduino adding support for nRF52840 based devices like the Feather 52840 or XIAO 52840 lines, I was getting a little sick and tired of having a big tangle of wires in order to run an SD card, I2S microphone, I2S amplifier, speaker etc, in order to test things out and develop this library.

Thanks to a sponsorship from PCBWay.com, I was able to develop a custom circuit board for prototyping and development, that can later be used as a walkie-talkie or intercom, with range similar to bluetooth.

The first part of this was to actually create the custom circuit board, and I chose the KiCad application. This was a big learning curve, as I had only ever designed an extremely simple circuit board before, and that was quite a challenge for me. This would take things to the next level.

So first, in KiCad, one needs to create a schematic for the circuit. This part was not too difficult, although it still presented some challenges, and took up a fair bit of time.   

 


 Above is the original circuit design and all the KiCad files etc, are available on https://github.com/TMRh20/FeatherAudio

The people at PCBWay were very helpful in figuring this all out, and since this is what I consider to be my first real attempt at a proper circuit board, I made a number of mistakes. One of the hardest parts seemed to be matching the KiCad component footprints up with the proper part numbers. I assume there must be an easier way to do this, but I ended up searching and searching, and still made some somewhat unrecoverable errors.

Beyond the correctable errors that the folks at PCBWay helped me fix, one of the main mistakes was ordering the wrong part for the J5 connector. This was in addition to a bunch of other parts that I had incorrect, but were caught prior to production. In the end, I had the boards shipped without the J5 connector, but the PCBWay people shipped some connectors that I was able to modify to work, and soldered them on myself.

I was also missing a position file initially, because I didn't know at first, but you need to send three main files, the gerber files in a ZIP format, the Bill of Materials or BOM, and a Position file, all of which can be generated from within KiCad. Putting this all together was one of the hard parts, again I struggled quite a bit with finding the correct part numbers etc.

 

Above are pictures of the PCB itself, and the assembled PCB, missing the J5 connector which I messed up the part number on. Everything else was correct, thanks to a lot of help from PCBWay.com. As stated, I was able to solder on some slightly modified J5 connectors they sent along with the boards.

Upon hooking it up, inserting an SD card and attempting to play some music, the damn thing worked! I was pretty surprised everything actually seemed to be connected correctly, and functioned flawlessly! Upon trying the microphone however, I discovered that I might have selected an I2S microphone that the attached micro-controller (Feather Express 52840 or Feather Sense 52840) cannot quite handle. According to some searches, I may be able to modify my AutoAnalogAudio library to handle it, but as it stands, the built in mic does not function.

 I am still able to do some testing and work with the Feather Sense 52840, because it has a built in PDM microphone, but I was hoping to use the custom-added I2S microphone. Everything seems to be connected properly circuit wise, its just the 52840 MCU that needs what seems to be a special configuration to work with this microphone.

 


 Above is my test setup with all the components attached. The small battery runs the micro-controller, SD Card and microphone, while the large batteries handle the I2S amplifier. I'm still kind of amazed all the circuitry seems to be correct, there is just a compatibility issue with the microphone!


 

 That's all for now, I've posted all the related files and examples to my GitHub repo at https://github.com/TMRh20/FeatherAudio, and will do some follow up posts detailing how to use the AutoAnalogAudio library along with this circuit board. To be continued... 

 

Sunday

Direct TCP/IP connectivity between Arduinos using a nRF24 or nRF52 radio link w/RF24Ethernet

 Setting up direct TCP/IP connectivity between Arduinos using a nRF24 or nRF52 radio link w/RF24Ethernet

 Utilizing the new functionality of the RF24Ethernet library

 With some recent experimentation and prototyping involving the lwIP IP Stack, I was able to modify the RF24Ethenet library to function standalone, without the need for a Linux/Raspberry Pi device running RF24Gateway. This allows users to directly connect multiple Arduino devices using the RF24Ethernet library, utilizing TCP or UDP protocols to communicate between devices.

The RF24Ethernet library API is based on the official Arduino Ethernet API, so users utilize the same coding style to communicate over nRF24 or nRF52 radio links.  


Setting things up:

1. The first thing to do is verify you have working radios. With nRF52 devices, they are built-in so, there is not much to worry about, but with nRF24 radios, users need to keep in mind power supply and wiring issues, so testing using the official gettingStarted sketch included with the RF24 library is recommended before attempting this.

 2. Install RF24Mesh and its dependencies from Arduino Library Manager

3. Install the RF24Ethernet library from ZIP from https://github.com/nRF24/RF24Ethernet/tree/lwIP  Note: Once deployed, the updated library will be available from the Arduino Library Manager. Users may need to uninstall/reinstall to get the latest updates at that time.

 4. Install the Arduino lwIP library using the Arduino Library Manager as required for non-ESP32 & non-ESP8266 devices which already include lwIP.

5. Run the included examples from the Headless directory in the RF24Ethernet examples on two devices. I've tested so far on Arduino Due, ESP8266, ESP32 and nRF52 based devices. The RPi Pico still utilizes the uIP stack due to technical issues using lwIP with the Arduino MBED based core.

 

What to expect:

The main server example sets up a RF24Mesh 'Master Node' which handles addressing and address look-ups for all other nodes. Nodes not in range of the Master Node will attempt to connect automatically via routing traffic through other connected nodes. 

The client examples simply connect to the Master Node and request an HTML based web-page. 

 In a real life deployment this activity may be reversed. With the Master Node running a modified Client example, and sensor or other nodes running modified Server examples, the Master Node could then connect to each device in turn and retrieve data as required.

To designate a master node, simply call the following before calling mesh.begin()

mesh.setNodeID(0);

then from the main loop()

 mesh.DHCP();

 

 Things to Note: 

 RF24Ethernet makes use of two separate IP Stacks, the older, unmaintained uIP Stack works on smaller devices like Uno, Nano, Mega, etc, while the newer, lwIP stack is used automatically for devices >50MHz CPU speed, including the Arduino Due, ESP32, ESP8266, and nRF52 based devices using the nrf_to_nrf radio library.

To ensure you are using the lwIP stack, users can #define USE_LWIP 1 & #define RF24ETHERNET_USE_UDP 1 in the RF24Ethernet.h file or prior to compilation. 

 

Saturday

Using the lwIP stack with RF24Ethernet and RF24 radios - Another experiment in progress

 Using the lwIP stack with RF24Ethernet and RF24 radios

Another experiment in networking 

 So I finally got some time to play around with the lwIP stack over the holidays, and decided to try my hand at getting it working with the RF24Ethernet/RF24Gateway layers, so users can more conveniently handle TCP/IP traffic over the nRF24 radios.


 

 Overview:

 The RF24Gateway and RF24Ethernet libraries work together to handle TCP/IP and UDP traffic over nRF24 or nRF52 radio links. Users can communicate using standard protocols and techniques, without additional programming or advanced knowledge of the radio software or hardware.

The RF24Gateway library runs on more powerful systems with their own IP stack like a Raspberry Pi or other Linux devices with GPIO and SPI capabilities. The RF24Ethernet library is designed for Micro-controllers like those found using the Arduino platform. Now it supports the faster devices with a more advanced IP stack, lwIP.

 In studying and playing around with lwIP and the Arduino platform, most if not all of the client examples for Arduino utilize a single connection at a time, whereas lwIP supports multiple connections. In server mode, the default behaviour is to listen on a given port, with a backlog. This means that in the current configuration, lwIP will handle the first connection normally, then accept a second connection, but won't complete the second connection until the first connection has finished.

I've also introduced default timeouts, 30 seconds server side, so that if no data is sent or received for a given timeout period the server will disconnect the client. For the server side, call server.setTimeout(30000); . For the client, users need to implement their own timeout conditions. The server timeout can be set to 0 to disable it.

Usage: 

 Usage remains exactly the same as before, with users utilizing the Arduino Ethernet API and client/server functions to connect, disconnect and transfer data between systems. This means that RF24Ethernet users don't have to learn a new API to use the library, as long as they are familiar with the standard Arduino Ethernet API.

As of this writing UDP support is not included but will be added at a later date, TCP/IP support is functional and tested via MQTT and HTTP. The Arduino lwIP library can be installed using the Arduino Library Manager.

 Conclusion:

 I've been wanting to configure lwIP to go along with the RF24Ethernet library for a long time, but just didn't have the time or expertise to sit down and make it happen. With the recent holidays, I was able to put things together, and it came out working very nicely. It is still in prototyping stages, likely with some bugs to work out, but it is functional and available for testing at https://github.com/TMRh20/Sketches/tree/master/RF24Ethernet-lwIP

Update: Jan 18 2026:

As of today, with the latest commits, the server and client tests I am running have been stable for 24 hours. The main bugs have been worked out, and the system is operating normally.  A pull request for the new version of RF24Ethernet will probably be made in the next week or two, pushing the code to a side branch at https://github.com/nRF24/RF24Ethernet and concluding the initial prototyping. Any users making use of the code in the Sketches repository will be encouraged to move to the new branch in the main repo.

 NEW: 

The RF24Ethernet library no longer requires RF24Gateway running! Nodes can simply run RF24Ethernet and establish TCP/IP connections between themselves! See the new Headless examples found in the examples/Headless directory. 

Instructions:

1. Install RF24Mesh & its dependencies from Arduino Library Manager

2. Download the RF24Ethernet library from the link above and place into your Documents/Arduino/libaries/ folder or install from ZIP

3. The library is configured to detect CPU speeds over 50Mhz and use lwIP automatically, but users can edit RF24BoardConfig.h and #define USE_LWIP as required

4. Enjoy!!! 

 

 

 

 

 

 

 

 

 

Wednesday

Automation etc with Node Red - How to make your Dashboard2 chart data persistent using a SQLite database

 How to make your chart data persistent using a SQLite database

Reliable charts and graphs with Node Red

 So I've been using Node Red for quite some time now as part of my general IoT network, involving wireless radio modules and numerous sensors etc. One main drawback of using Node Red, is that by default, it doesn't store data long term, and your charts etc will go blank after a restart or shutdown.

 Using a SQLite database combined with Node Red, I've been able to store information for the long term that persists even after restarts and shutdowns and this is how I did it.

 

Above is an image of a simple Node Red flow, logging and retrieving information from a database.

  So first things first, I will go through the process of the above flow:

1. Arduino and other sensors send in data over MQTT (Purple "houseTemp" and "houseHum") 

2. We need to combine the information into a single record and insert it into a database. (Light orange "Filter Dups & Insert")

 3. The data is then logged to a SQLite database

.4 At the same time, we select data from the database, so we can insert the newest data into some charts

5.  The results of that selection are fed directly into some charts:

 

 

 Detailed Process & Code

1. An Arduino sends in a message via MQTT with the msg.topic "houseTemp" and a float that represents the temperature (msg.payload), and another message with the msg.topic "houseHum" and a float that represents the humidity as the msg.payload.

2.  Then we combine the 2 results into 1, and insert the data using a function node:

 let temp = context.get('temp3') || null;

let hum = context.get('hum3') || null;
let ctr = context.get('ctr3') || 0;

if (msg.topic == "houseTemp") {
   context.set('temp3', msg.payload);
} else {
   context.set('hum3', msg.payload);
}

let sendMsg = false;

ctr = ctr + 1;

if (ctr >= 2) {
   ctr = 0;
   sendMsg = true;
}
context.set('ctr3', ctr);

msg.topic = "INSERT INTO HOUSETEMP (TIMESTAMP, TEMPERATURE, HUMIDITY) VALUES (" + Date.now() + ", " + temp + ", " + hum + ")";

if (sendMsg == true) {   
if (hum != null && temp != null) {
      return msg;
   }
} else {
   return;
} 

3. The data is logged to a SQL database, per the "INSERT" command in the previous function. 

4. Lets "select" or retrieve all the data including the data that was just logged:

msg.topic = "SELECT * FROM HOUSETEMP ORDER BY TIMESTAMP DESC LIMIT 1000";
return msg;
 
4. The database node responds immediately to the previous function, returning data
 
5. Display data in the charts:

 The main things to consider are having all of your variable names correct, and
 using the correct "properties" configuration in your Chart Node.

 

General DB Maintenance: 

In order to create a table, you need to add an "inject" node and set the msg.topic to something like:

CREATE TABLE HOUSETEMP ( TIMESTAMP INT PRIMARY KEY NOT NULL, TEMPERATURE float NOT NULL, HUMIDITY float NOT NULL)

 Since we are using a Linux timestamp, we can use the following formula to clean up old data via another "inject" node:

DELETE FROM HOUSETEMP WHERE TIMESTAMP < strftime('%s', 'now', '-14 days'); 

  

 Overview:

This generally works pretty well and keeps the graphs & charts up to date with good data, storing it for up to 2 weeks. Of course, this is a heavy-handed approach, replacing all the chart data each time. A better approach is identified below, using an external MySQL server to offload activity.

A bit better solution would be to make the SELECT function node only return 1 record at a time. Then, add a blank inject node that triggers only once on startup, that both resets the charts ( send JSON msg.payload of []  ), and loads all existing data into the charts. The arrays coming out of the database at the end would need to be reversed as well, so the newest data is at the end of the array.

This is a much less intensive way to go about it, but a little more complicated to set up. 

 

Saturday

RF24: An advanced example for the Arduino Uno Q

 RF24: An advanced example for the Arduino Uno Q

 A new take on the RF24 GettingStarted example

In testing out the RF24 library and related features, I managed to get a few different things working together on the Arduino Uno Q to provide a more advanced example of RF24 interaction. 


 

 The main thing the sketch does is transfer data over RF24 radio link along with a standard Arduino device running the RF24 GettingStarted sketch included with the RF24 library.

Then, any data received is displayed in the Serial Monitor, Python Console and an associated webpage to demonstrate usage of incoming data etc.

 A button is included on the webpage that allows users to toggle the LED matrix on/off, which demonstrates how to pass data from Webpage to Python to Microcontroller. 

All in all its a simple concept, but it did take some figuring to work out how the functions and stuff all relate through JavaScript, HTML, Python, C++ etc.

My Arduino Q sketches can all be found here:

https://github.com/TMRh20/Sketches/tree/master/ArduinoQ 

For a limited time, a live real-time demo of a similar sketch will be available online.

The main functionality is tied into 4 files:

sketch/sketch.ino - The Arduino sketch handles radio input/output & passes its data to Python

python/main.py - The middleman between the webserver and the Arduino sketch

assets/app.js - JavaScript handling, communicates between index.html and Python via websockets

assets/index.html - The main webpage, provides variables that can be modified via JavaScript

Thursday

Trying out the Arduino Uno Q - A quick and dirty overview

 Trying out the Arduino Uno Q - A quick and dirty overview

 Love it or hate it, it... exists 

 With the release of the new Arduino Uno Q board, I decided to get one and try it out. After a few days of playing around and experimentation I have to say I'm less than impressed.


 The concept seems to be a solid one, combining a standard Micro-Processor Unit (MPU) with a Microcontroller Unit (MCU), but the execution has been a little rough.

 The first and main thing to probably address is the Bridge concept, which is a way for users to make the MCU 'talk' to the MPU. It is driven by a serial connection running at 115200 baud, using RPC, which altogether is far too slow to pass copious amounts of data, or do it really quickly. On the other hand, it can be used to pass information between programs, be it Python to Python or C++ (Arduino) to Python.

 One of the first things I tried, of course, is running RF24 radio based applications. It appears to work OK initially with the core RF24 driver and RF24Network, but once I got into the RF24Mesh layers, I started to notice problems. I thought it was basic speed issues, but it turned out to be a radio power supply related issue it seems. After changing out the radio and calling 'radio.setPALevel(RF24_PA_MIN,0);', it worked.

Next, I attempted to create a basic TUN network interface in Linux using Python, to see about creating a RF24Gateway like interaction, but realized quickly that this too was outside the general capabilities of the device. It runs a Python virtual environment within a Docker container, with no apparent way to configure things, so I can't seem to get it working. That means an RF24Gateway style library is out of the question for now.

It seems that so much of what I've tried do to so far just doesn't work. There was also a forced, breaking update that happened recently, to version 3.0, where users have to manually download a new version of App Lab in order to program their devices.

 One essential thing to note, is that when the App Lab stops responding, or the Serial/Monitor output gets corrupted, I need to close App Lab, and run `arduino-app-cli system cleanup` from the command line to get it working again.

 Some of the features still seem promising, the ability to easily incorporate "Bricks" and features into your programs, and the underlying software for the MPU is Debian/Linux along with Arduino, so you can still do a lot with it. 

I don't think I'll get another one, but I will definitely be playing around with the one I've got for a while. 

In the meantime, I've included a new example in the RF24 core library that users can try with the Arduino Uno Q that allows users to configure the radio and print debug information.

I've also added an example sketch to go along with the stock RF24 GettingStarted example here:

https://github.com/TMRh20/Sketches/tree/master/ArduinoQ 

 

Playing around with the Arduino Uno R4 Minima, Uno R4 Wifi and Uno Q

Playing around with the Arduino Uno R4 Minima, Uno R4 Wifi and Uno Q Stepping up to a new level of micro-controller     Thanks to the fine p...