Networking and Communications

MCUs and communications explored

  1. NodeMCU ESP8266 to NodeMCU ESP8266 via Wifi (successful)
  2. XIAO RP2040 to XIAO RP2040 via I2C (partial)
  3. NodeMCU ESP8266 to NodeMCU ESP8266 via I2C (unsuccessful)
  4. Arduino Uno to Uno via I2C (successful)
  5. XIAO RP2040 to Arduino Uno via I2C (successful)

NodeMCU ESP8266 to NodeMCU ESP8266 via Wifi


This was the first combination I attempted. I was not familiar with I2C or SPI, while I have worked with the NodeMCU in the past, however cursorily.

I used this page as my primary guide.

Steps :

  1. Find your ip address, gateway, and DNS

    Use "arp -a" on the command prompt to get a list of devices on your network - i.e. a list of addresses already taken. If you are on your home Wifi, this is unlikely to be a large list and randomly picking an id would work, but best to be sure. Use "ipconfig" on the commmand prompt to get your network data - your gateway and DNS Subnet addresses, mainly.

    Network IP Info

    You will use these 3 - an unused ip address, the gateway ip address and the DNS address - in the code to follow. You will also - obviously - need your Wifi network Name and Password.

  2. Code for the Main Node

    Node Main

    Update the places in the code for the following data

    • IPAddress ip()
    • IPAddress gateway()
    • IPAddress subnet()
    • ssid = "Your_Wifi_Network_Name"
    • password = "Your_Wifi_Password"

    These first three are applied in the WiFi.config() function to fix the IP Address. A dynamic IP would mean that the Secondary codes as well as every reference to the Main IP elsewhere would need t be re-written all the time. Bad idea. The ssid and password are used in the WiFi.begin() function to connect to the network.

    Please note that the numbers are comma-separated, like arguments to a function, and not dot-separated like the usual IP Address format.

    The code for the Main Node is from the above link itself, my file of it is uploaded here. (The code still refers to the older nomenclature of master-Slave that I will eventually change, but for now I chose to not mess with it.)

    The Main Node acts as the server that communicates with the Secondary, as well as serves a webpage at it's address. The webpage shows the status and offers an interface to control the LEDs on both the MCUs, Main and Secondary.

    To be entirely honest, while I have gone through the code and understood the major functions, I have not yet isolated the sections enough to play with it further. I am familiar with HTML but haven't yet added controls and responses for more than the one Secondary.

    There is another variable NUM_SLAVES, that is currently set to 1 but should be updated to whatever the relevant number of Secondarydevices is.

  3. Code for the Secondary Node

    Node Secondary

    For the Secondary as well, update the places in the code for the following data - ssid = "Your_Wifi_Network_Name" - password = "Your_Wifi_Password"

    • IPAddress server() Server takes the IP address of the Main Node from the previous step, the one used in IPAddress ip() Please note that the numbers are comma-separated, like arguments to a function, and not dot-separated like the usual IP Address format.

    The code for the secondary is simpler - the Setup() function for all the WiFi init, and the requestMaster() function that constantly pings the Main node and recieves and handles data from it.

  4. Individual Addressing

    The Server Node takes a unique IP address for the rest of the network. Each node can be individually addressed using it's "name", i.e. the line String nom = "this_node_name", used for the Main as well as Secondary nodes.

Hiccups :

  • The NodeMCU DOES NOT SHOW UP in the Ports list. I used the Device Manager in Windows to verify that a device was attached, and then just selected the port and pushed. This was a very annoying waste of time involving multiple shutdowns, driver re-installs, and what have you.
    I installed these CP210x USB to UART Bridge drivers from SILabs though I am not sure if they helped or not. Just putting them here for ref.
    NetworkSc2

  • Verify that your device is a v1.0 or a v0.9, since the IDE offers them separately. Most should be v1.0 but best be safe.

On the way : Main working

Network1 Testing Blink for the NodeMCU

--

After managing to get to this point, but not yet figuring deeper, I decided to explore SPI and I2C as well. I was looking at the data sheets and pin diagrams and figured, how hard can it be. As usual, Yes and No.

I primarily followed this Instructable that shows I2C between 2 Arduino Unos. Looking at the code and wiring, I felt that this was friendly enough to try.

XIAO RP2040 to XIAO RP2040 via I2C

I decided to try the I2C using 2 XIAO RP2040 boards, since I had them on hand and those are the MCUs I would like to continue working with. Following the above Instructable, I connected the GNDs, SDAs and SCLs of both boards respectively.


Network2

Network3

XIAO RP2040 Master
XIAO RP2040 Secondary

XIAO RP2040 Master RGB
XIAO RP2040 Secondary RGB

The code mainly consists of the Main incrementing a variable cyclically from 0-5, sending it over I2C to the Secondary, and the Secondary blinking in accordance to the value. I initially used the same code as the Instructable, then edited it to change the RGB Led colours instead of Blink times. The idea was that the Main cycles through 6 colours based on a conditional, and the Secondary receives the same value and makes a similar set of decisions, plus flashes White when no data is being received. The ideal outcome should have been both boards flashing in sync, with the Secondary flashing white at the end of each cycle when the Main delays and resets the variable.

NetworkSc1 NetworkSc3

The first hiccup here was a compiling error, and the code simply wouldn't go forward, let alone upload. The solution was pointed out to me as a Github forum post by Suhas Labade of the Vigyan Ashram, Pune. Apparently this is a common issue with a recent update, and downgrading your Board from v.3.xx to v2.61 solves it.

To quickly update the code from basic Blink options to the RGB LED variations, I referred back to my own code from earlier. I mistakenly believed I had lost it since it was not available in the Arduino IDE Sketchbook, and sat about rewriting it; after a while, a search across my filesystem found it in a different set of folders. This was a lesson on - not organizing well, I think I lost it out of the sketch book because I organized too well - but of organizing intuitively, of finding thengs where you know you will look for them. Remembering where you put things helps, ofcourse. And a full system search using Everything is the final resort, whcih is waht worked in my case.

I also did NOT solder the berg pins to the boards, since I hope to solder the boards to larger dev-boards that I will make. I simply inserted the pins into the board and the breadboard underneath, holding everything in place and making contact. Since I was obviously worried about the effectiveness of this, I made sure to check the contacts using a Multimeter.

Eventually, the Main worked, and the LED blinked in colour, and the serial monitor showed the relevant output. The Secondary, however, only flashed red or sometimes white, and never synced. When (I suspect) the I2C connection came in, something stopped the Secondary from continuing, stopping the Serial Monitor output, as well as freezing the LED colour to red (the first value) or white (the catch-all 'else' condition). I don't know if this is a code problem (it may be, the delay timings on both modules may be creating some unintended misfirings), an oversight in my understanding of how the I2C works, or something else entirely.

Anyway, realising that while there was some effect but not effective enough, I decided to go for a simpler option, and tried the I2C between 2 NODEMCUs.

Round 2

(A few weeks later..) I tried again, this time with 2 XIAOs, one on my devboard and one with direct header pins soldered on. While each still functions perfectly independently with the respective code, they do not seem to be interacting.

Network08

I am also running them both separately, the main from a battery and the secondary from the laptop USB since it is also writing to the Serial monitor, since I don't want them to interfere.

Network09

The primary flashes it's LED colours in sequence according to it's code, and the secondary flashes it's LED with White (the catch-all 'else' condition in it's code) but stubbornly refuses to correspond it's LED colours with that of the main.

The other quirks I have observed but cannot explain are, one, that trying to access the serial monitor when everything is firing hangs the Arduino IDE (it doesn't grey out like other Windows hanging but still becomes unresponsive), and the Main flashes at a faster rate when the Secondary is not connected, and slower by 2x when the Secondary is connected i.e. there is an extra delay triggered in the Main's code.

Once again, there is some effect but nothing workable.

I can't explain this. I intend to reach out to people or check out the documentation of people who are using the XIAO RP2040 + I2C + Arduino IDE and have managed to do this.

Round 3

Network11 Network12

I looked up, read up and generally tried a lot of things. This time around, I added pullup resistors to the SDA and SCL connections on both sides to make sure the signals weren't getting noisy.

However, the XIAO RP2040 - XIAO RP2040 I2C seems doomed any way you cut it. I believe there is some underlying issue with the XIAO. There are old forum posts and discussions about I2C issues, that do seem to be solved now, but my issues persist. Anyway, I am once again giving up on this to try something that has a better chance of success.

NodeMCU ESP8266 to NodeMCU ESP8266 via I2C (unsuccessful)

Node Main I2C
Node Secondary I2C

I used this page as a starting point in the I2C connection attempt for the NodeMCUs. It starts off with a NodeMCU Main and an Uno Secondary. The code is fairly the same as the Instructable in the previous section as far as essential functions and structure is concerned.

Network4

Network5

Once I got individual code uploaded and was sure the two board worked on their own, I got the wiring done as well. This was more certain than with the XIAOs, since the NodeMCUsalready had header pins and I could just use F-F jumpers between them. With the NodeMCU, the D0 and D1 pins have been used as the I2C SDA, SCL pins.

After several attempts and changes, this still didn't work. Apparently, atleast upto a point, the NodeMCU had a bug/specification that did not allow it to be a Secondary, only a Main. The forums are a little mixed on whether this has been corrected, workarounds, etc.

So after a while, I simply decided to go back to basics and replicate a known working version instead of trying to figure things out from scratch.

Arduino Uno to Uno via I2C (successful)

I went back to the first Instructable above, pulled out a couple of ArduinoUnos from where they were hiding, and wired them up. I also used my updated code to have a more interesting and unmistakably evident series of blinks and Serial outputs. After a few rounds of debugging ordinary bugs, this version finally worked. I eventually complexified the code to go from basic blinks to better serial outputs, to adding an RGB LED to be a better indicator, and also incase I had to run this off a battery instead of being connected to a PC, when the Serial Monitor would not be available.


Network7
NetworkSc4
NetworkSc5

  1. Code for the Main : Uno Main I2C

    The code, as before, mainly consists of the Main incrementing a variable cyclically from 0-5, sending it over I2C to the Secondary, and the Secondary blinking in accordance to the value.

  2. Code for the Secondary :

    Uno Secondary I2C

    For the secondary, instead of the basic blink sequence that altered duration, I changed a few things. A Serial.println() was added to have the output show up on the Serial monitor. I also had a prewired RGB LED board from an older project sitting around, so I added new code to light up the RGB Led based on the incoming values.

  3. Wiring :

    The Uno uses the A4 and A5 pins for SDA and SCL respectively, so those were connected, as well as a common GND. The Secondary also had 4 pins connected to the RGB Led terminals.

  4. Individual Addressing :

    Individual addressing is handled in the code by writing the address indicator.
    In the code for Main, Wire.beginTransmission(9) addresses the device called '9'.
    In the code for the Secondary, Wire.begin(9) indicates that this Secondary is the device at the address 9.

  5. Connecting more devices :

    This should be simple enough in principle. Each of the SDAs have to be connected to each other, as well as each of the SCLs, and all the devices should have a common ground. Individual addresses in the code should take care of identification and workings of the I2C.

XIAO RP2040 to Uno (successful)

I finally gave up on making the XIAO-XIAO connect, and decided to try controlling an Uno from the XIAO.

One has to be careful here, since the XIAO operates at 3.3 V while the Uno operates at 5 V. The I2C connection operates at whatever the Master is operating at. So the XIAO being the Primary or Master would work for the Uno but not the other way !

Anyway, I uploaded tweaked versions of the code from above, and lo and behold ! the Uno was reacting to the XIAO.

Attempt 1 : Colour matching

I programmed the XIAO to generate a series from 0-5 like in the example above, and have it's WS2812 light up accordingly, while also sending that value via I2C to the Uno. The Uno was programmed to receive the I2C incoming and light up the attached RGB Led accordingly. This generally worked except for the fact that the XIAO and the Uno were operating with different durations of the LED lighting up and so you could not really see them sync. However, it is evident from the Serial Monitor and the RGB LED's change in colour.

Network13

However, I was atleast relieved that this combination works.

XiaoRPMaster_RGB_v2.ino
Uno_Secondary_v2.ino

Next, I decided to tackle the sync issue by making the cause-and-effect of the I2C communication more evident.

Attempt 2 : Switch control

Instead of internal code to generate the numbers, I added a Switch to the XIAO and added code to send a number when the switch was pressed. The Uno would receive the number and light up and blink the RGB Led accordingly with one colour (blue with fast blinking), while otherwise it would be the default red with a long, slow blinking cycle. I set the Master to blink green, for balance in the RGB universe.

Network14

Network15

Connections :
The connections for this are shown below. TinkerCAD lacks the XIAO and other advanced components, and Fritzing is not free, so this was the easiest to just doodle up on paper like I do to work out connections, etc.

Network16

Network17

Essentially,

I2C
- SDA (D4) [XIAO] to SDA (A4) [Uno]
- SCL (D5) [XIAO] to SDA (A5) [Uno]
- common GND
- 3.9K Ohms resistors, 2, between SDA-3V3 to act as pull-ups

RGB LED connected to the Uno
- Pins 9, 10, 11 and GND to the RGB Led

Switch connected to the XIAO
- Switch between 3V3 and D0 - Resistor 370 Ohms between D0 and GND

Code :
XiaoRPMaster_RGB_swt.ino
Uno_Secondary_v3.ino

Reflections

There's a lot to still figure out. But some things would have made the journey easier. Some of these are pretty elementary, but bear repeating just the same.

  • Improve file organization
  • Improve hardware organization. When I had to find multiple units of the same board, I spent quite some time looking through my stuff, and this was rather frustrating.
  • Use a USB hub. I quickly ran out of USB ports on my Laptop to keep multiple boards running in parallel. Also, identifying which Board is which Port got a bit tricky at times. I finally pulled out a powerbank and moved each board to it once it had the necessary code uploaded, leaving only one board on the laptop with the Serial Monitor, etc.

  • use pull-up resistors anyway

For the future

  • Use some I2C or SPI peripherals, like an SD Card reader and an OLED screen to display it's contents or other visuals
  • Use SPI for communication. Here is a possible resource.
  • understand and expand the Wifi connections of the NodeMCU
  • Use the ESP32 as well. I ordered these along with the NodeMCUs, but I've spent most of the time on the I2C now, so this is still left.
  • Move the Uno-Uno demo to multiple Nanos, more than 2 ideally.
  • For a more robust demonstration, as well as utility, inputs from one should trigger outputs on another. Button press to LED, or random number generation to LED, or motors in sync, etc.

**Other Resources / Bookmarking for later **

Interesting Series of posts on Connecting multiple MCUs