Sunday

Streaming Audio over WiFi using the Arduino Uno R4 WiFi, AutoAnalogAudio Library & VLC

Streaming Audio over WiFi using the Arduino Uno R4 WiFi, AutoAnalogAudio Library & VLC

 Pushing the system to its internal limits

 With recent developments regarding the AutoAnalogAudio library and the Uno R4 WiFi, I was able to get an audio stream to play on VLC over WiFi from a microphone attached to the Uno R4. This was a little bit of a challenge due to the inherent limitations of the R4, but I was able to make it function.

 In short, the attached ESP32 that handles WiFi is connected to the main RA4M1 chip via a Serial bridge, running at 115200 baud. This pretty much limits the associated audio stream to lower quality 8Khz 8-bit samples. A modification is possible, but with out-of-the-box behaviour, my tests show that 9Khz 8-bit audio is the upper limit. 

I've included an example into the AutoAnalogAudio library to demonstrate this behaviour, compressing the 14-bit output of the ADC (microphone input) into 8-bit samples using PCMU encoding and sending them directly to VLC Media Player in RTP format over UDP.

 To configure the example, one would need to enter their WiFi credentials into the associated secrets.h file. This helps to establish the WiFi connection used for audio streaming to a computer. With the PC running VLC on the same WiFi network, users then need to determine the IP Address of the VLC machine and enter it into their sketch as targetIP.

Once those two things are done, just run the example with a microphone connected to pin A1 on the Arduino Uno R4 WiFi. Then open VLC and open a Network Stream at  rtp://@:5004

The audio is lower quality, only really good for voice transmission, but as stated, users can override this behaviour by modifying the ESP32 core for the Uno R4 WiFi and configuring the bridge to run at a faster speed. 

Version 1.55.1 of the AutoAnalogAudio library has been released including support for nRF54L15 and Uno/Nano R4 boards, and can be installed via the Arduino Library Manager.

Thursday

The RF24Mesh Users Guide

 The RF24Mesh Users Guide

         How to manage & administer RF24Mesh based networks

 If you are reading this, it is assumed you are using are or interested in using the RF24 Communication stack at some level, including the RF24Mesh library. This guide should apply whether you are using RF24Mesh directly, or using the RF24Ethernet/RF24Gateway libraries and attempts to provide a good general understanding of the basic concepts RF24Mesh was built around.

 What is RF24Mesh? 

 RF24Mesh is a wireless networking library designed to automate the mundane networking tasks that don't require user intervention, including addressing assignment & reassignment, DNS style lookups and general communication tasks. The underlying libraries, RF24 and RF24Network provide many wireless networking and communication features, and RF24Mesh ties them all together with automation.

The RF24Mesh library works using pre-assigned and unique NodeIDs, which can be thought of similar to static IP addresses. These NodeIDs are statically assigned, so any individual node can be identified for communication purposes. At a lower layer, the system uses RF24Network addresses, which are dynamic, changing regularly to accommodate nodes at any level of the network. These addresses represent the physical placement in the network, and are used for direct communication after completing a NodeID lookup, which returns the RF24Network address.

The overall goal of RF24Mesh is to allow users to create and deploy wireless networks based on RF24, RF52 and/or RF54 radios, in short order, and to have them communicate on an ongoing basis, changing physical locations and/or distance as required. Networking tasks are automated to a degree that human intervention should not be required for very long periods of time.

Everything is configured around a central "Master" node, which needs to remain online and active, since it keeps track of all nodes on the network and handles addressing look-ups, which are similar to DNS requests on a purely TCP/IP based network. 

How to set it up?

Arduino: Just download and install the RF24Mesh library via the Arduino Library Manager. As mentioned above, each device must be assigned a static NodeID, but once that is done, everything else can be automated. The network will support NodeIDs ranging from 2 to 253, with nodeID 1 and 0 typically reserved for the "Master" node, which keeps track of all NodeIDs and related addresses.

Linux: See the documentation link below, there is an installer available for Linux based devices which streamlines the installation process. 

Nodes do not need to be in range of the Master node for operation, they just need to be in range of another node that does have connectivity to the Master node. Operating nodes will automatically route traffic on behalf of other nodes. The network is built in layers, with the master at layer 0, and subsequent layers 1 to 4. This means that a given node can be as far away as 4 hops from the master, with traffic routed automatically through other nodes.  

 What can I do with RF24Mesh?

 The RF24Mesh library can handle many different communication scenarios, but was built with a focus on IoT systems, allowing users to create large-scale sensor networks or command & control scenarios. When using RF52 based radios, users can incorporate encryption into their networks directly as well. When using the RF24Ethernet or RF24Gateway libraries with RF24Mesh, encryption must be implemented at a higher level, using technologies like SSL, SSH, TLS, etc.

 Users can securely and reliably receive data from multiple sensors and control devices with a simple API and interface, customizing their system to the Nth degree.

 Tips & Tricks

 When using RF24Mesh, there is a need to continuously verify connectivity and renew addresses when nodes move around or simply lose wireless connectivity, and these features are incorporated into the examples. Nodes typically verify connectivity with a direct parent node, assuming that if the parent node remains connected, it has connectivity to the Master node. 

No matter what layer users are working at, RF24Mesh or RF24Ethernet/RF24Gateway, the mesh library generally works the same. With RF24Ethernet/RF24Gateway, users can utilize standard networking tools over the wireless network, including TCP/IP, UDP etc, making use of protocols like MQTT, SSH or HTTP. The network still functions using the underlying communication protocols, allowing users to send very small RF24Mesh or RF24Network messages, while handling large TCP/IP or UDP packets at the same time.

 This configuration allows the smallest of devices, including ATTiny devices, to be configured as routing nodes, with more powerful devices like Arduino Uno, Nano, Mega etc functioning as fully operational RF24Mesh or RF24Ethernet nodes. Larger devices capable of running Linux would make use of the RF24Gateway and/or RF24Mesh libraries directly.

RF24Mesh also allocates memory on the Master node dynamically for storing NodeID & RF24Network address combinations. The default is to configure the memory space for up to 10 nodes. Users can edit the RF24Mesh_config.h file, and set  #define MESH_MEM_ALLOC_SIZE 10 to a higher number to increase the memory allocated for storing node information. This is typically recommended when running the master node on a non-linux device so that memory is not continuously being allocated and re-allocated as nodes join the network.

In the case of devices that only receive data, and don't verify connectivity that often, users can un-comment #define RF24MESH_CONN_CHECK_TYPE RF24MESH_CONN_CHECK_MASTER in the RF24Mesh_config.h file, to ensure they are verifying connectivity with the Master node, instead of just a parent node. This also prevents some temporary DOS attacks from being possible, but does increase network traffic. 

In the case of users that require static nodes, RF24Network can be used directly at the same time as RF24Mesh. On the master node, users just need to define a static address for the static nodes, and they will function as RF24Network nodes on the RF24Mesh network, but will need to remain in the same physical location/maintain connectivity themselves. 

Linux vs Arduino

The code-base for Linux devices is a little more advanced than the Arduino code-base, but functions very similarly. The main difference is that on Linux devices, the default behaviour is to save the Address list (NodeIDs and RF24Network addresses) to file periodically. On Arduino devices the list is not saved by default, but this can be implemented quite easily if desired. This is important to understand, because on reboot, a Linux based network (Linux Master Node) will resume operations using the preexisting address assignments. An Arduino based network (Arduino Master Node) will resume operations using blank address assignments, meaning every node will need to re-join the network. Typically, nodes should verify connectivity every 30 seconds or so at least, so the Master node should remain off for at least 30-seconds in that case, to ensure all nodes refresh/renew their addresses. On a Linux based master node, a file dhcplist.txt is created, and can be deleted prior to startup to force a fresh startup.

The other important difference between Linux & Arduino devices revolves around fragmentation and re-assembly of large packets. A Linux based device will cache and store fragments for each individual node, while Arduino devices will only receive and cache fragments for a single node at a time, making Linux the system of choice for operating RF24Mesh master nodes that handle very large payloads and multiple devices transmitting at the same times.  

 How to get started?

 You have to start somewhere, and I would generally recommend installing RF24Mesh directly, and testing out some of the provided examples. It helps later to have a good understanding of the basic operation and features, including the use of NodeIDs, RF24Network addresses, and the difference between the two.

Users can then move on to trying out the more complex libraries, like RF24Ethernet and RF24Gateway, which use complex underlying code to provide a simple and seamless communication system based on TCP/IP and UDP. 

 The documentation is available at https://nrf24.github.io/RF24Mesh/ 

Sunday

Audio Playback on the Uno R4 using the 12-bit DAC and the AutoAnalogAudio Library

Audio Playback on the Uno R4 using the 12-bit DAC and the AutoAnalogAudio Library

Having some fun with audio reproduction 

 Since recently receiving some Uno R4 and Uno R4 WiFi boards, I just started playing around with audio reproduction. It seems they are not directly I2S capable, but do have ADC and DAC functionality. So far, I've gotten audio playback working via the DAC on Analog Pin 0.



I attempted to get mp3 playback working as well, but the R4 just doesn't have the available memory for decoding, so it will just be wav files and similar for now.

Initial results are pretty good, playing anywhere from 8 to 16-bit audio at 16KHz to 44.1KHz from SD card with ease. I've connected an analog amplifier directly to the output pin (A0), and results are so far good.

Next up will be the ADC, then onto figuring out other methods, including possibly hacking an I2S signal and output using the SPI peripheral.

For now, the code is available in the UnoR4Support branch of the AutoAnalogAudio library, so users can switch to that branch and download the ZIP if wanting to test it out.

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. 

 

Streaming Audio over WiFi using the Arduino Uno R4 WiFi, AutoAnalogAudio Library & VLC

Streaming Audio over WiFi using the Arduino Uno R4 WiFi, AutoAnalogAudio Library & VLC  Pushing the system to its internal limits  With ...