Skip to content

Week 15. Networking and Communications (Apr 26)

Week 15 Assignment

  • design, build, and connect wired or wireless node(s) with network or bus addresses

nRF24l01 Tranceiver Module

The goal I had for this week was to use my ATTiny1614 boards which I made in input week to transmit and receive serial values of through the nRF24l01 transceiver module. This will serve as a proof of concept of radio communication for my final project. The reason I had chose this radio over the other ones is because I have seen many Fab Academy students use it. Here are just a few people who I found in my research who have used this in the past: Student 1, Student 2, Student 3.

Here I have linked the datasheet for this particular radio.

Testing With Arduino

Before actually networking anything, I did some deeper research on the nRF24l01 tranceiver module by looking at a few tutorials on how to use the mdoule with an Arduino. I found a few good tutorials online, including this one by HowToMechatronics and this one on the Arduino forums.

From researching these sites and the datasheet, I learned that the nRF24l01 tranceiver uses SPI to connect with the Arduino, and then can talk to other radios wirelessly. It normally operates at 3.3V, but it is 5V tolerant, meaning you can use it with an Arduino. There are also multiple different kinds of nRF24l01 modules, all of which have these pins (this information comes from this site).

Pin Usage Function
VCC Power Powers the module using 3.3V
GND Ground Connected to the Ground of the system
MISO Master In Slave Out For the module to send data from the MCU
MOSI Master Out Slave In For the module to receive data from the MCU
SCK Serial Clock Provides the clock pulse using which the SPI communication works
CE Chip Enable Used to enable SPI communication
CSN Chip Select Not This pin must be kept high or it will disable the SPI
IRQ Interupt An active low pin and is used only if interrupt is required (usually not necessary)

Here is the pinout of the nRF24l01, which shows you how the pins are oriented.

Between the two different kinds, I used the nRF24l01+PA+LNA which includes an onboard antenna and has a greater range of communication. As an initial test, I decided to replicate the first example from the Arduino forums tutorial walkthrough of the nRF24l01. This basically had me hook up a button to one arduino and transmit the button state through one radio to the other, then receive the data and print it on the Serial Monitor of the other Arduino. Here was the project schematic/layout.

First I watched this video which showed me how the tutorial was supposed to function.

Then I physically wired up all the components together. I did modify the end goal of the example for my own purposes from blinking an LED to just receiving the button state in the serial monitor. My logic was that if I could get the data printed on the serial monitor, that would count as a success. On one arduino I had

  • a nRF24l01 tranceiver

  • a breadboard

  • a button

  • a 10k ohm resistor

On the other arduino, I only had the radio. Here is how it looked with the radio wired to the Arduino.

Now it was time to run the code, which I borrowed from the tutorial. First, I had to download the RF24 library and import it into Arduino IDE so that I could use an nRF24l01 with Arduino. Here is the link to the github page for the library.

Then I first uploaded the transmitter code onto one of the Arduinos. This is the code for the transmitter

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(9, 10); // CE, CSN         
const byte address[6] = "00001";     //Byte of array representing the address. This is the address where we will send the data. This should be same on the receiving side.
int button_pin = 2;
boolean button_state = 0;
void setup() {
pinMode(button_pin, INPUT);
radio.begin();                  //Starting the Wireless communication
radio.openWritingPipe(address); //Setting the address where we will send the data
radio.setPALevel(RF24_PA_MIN);  //You can set it as minimum or maximum depending on the distance between the transmitter and receiver.
radio.stopListening();          //This sets the module as transmitter
}
void loop()
{
button_state = digitalRead(button_pin);
if(button_state == HIGH)
{
const char text[] = "Your Button State is HIGH";
radio.write(&text, sizeof(text));                  //Sending the message to receiver
}
else
{
const char text[] = "Your Button State is LOW";
radio.write(&text, sizeof(text));                  //Sending the message to receiver 
}
radio.write(&button_state, sizeof(button_state));  //Sending the message to receiver 
delay(1000);
}

After uploading this code to the transmitter I then went to upload code to the receiver. Here is the receiver code which I modified to not include the LED.

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(9, 10); // CE, CSN
const byte address[6] = "00001";
boolean button_state = 0;
void setup() {
pinMode(6, OUTPUT);
Serial.begin(9600);
radio.begin();
radio.openReadingPipe(0, address);   //Setting the address at which we will receive the data
radio.setPALevel(RF24_PA_MIN);       //You can set this as minimum or maximum depending on the distance between the transmitter and receiver.
radio.startListening();              //This sets the module as receiver
}
void loop()
{
if (radio.available())              //Looking for the data.
{
char text[32] = "";                 //Saving the incoming data
radio.read(&text, sizeof(text));    //Reading the data
radio.read(&button_state, sizeof(button_state));    //Reading the data
if(button_state == HIGH)
{
Serial.println(text);
}
else
{
Serial.println(text);}
}
delay(5);
}

Luckily, it worked. As you can see in the video below, the message from the button is received and the message changes depending on if the button is pressed or not.

At this point, I felt confident that I was ready to replace the Arduino in the system with a PCB.

Communication With ATTiny1614

Note: For the transmitting end, I decided to use an ATTiny1614 board which I had designed and fabricated myself, but for the receiving end, I decided to use an Arduino. This does still meet the requirements of the assignment, which stipulate that: You can use use arduino/commercial boards for networking, as long as one of the boards is of your own design and fabrication.

Once I had successfully sent and received a message using the Arduino and nRF24l01 modules, I was ready to use a PCB to try and produce the same result. The PCB I was using happened to be the same board I used last week for joystick inputs. Because I knew that the networking assignment was coming up, I had added functionality to support the radio on the same board. You can revisit the Week 14: Input Week documentation for more information on the PCB design and milling of that board.

As a reminder, the board looks like this

The PCB layout of the board looks like this. Here you can clearly see the traces going to the radio, where I utilized the MISO, MOSI, SCK, VCC, GND, and two unconnected pins for CE and CSN to route to the 2x4 pin header

The first step I took to program the board through UPDI was to first prepare the Arduino which was going to act as a programmer. First I tested that the Arduino worked by flashing a basic blink to it.

Then I uploaded the jtag2updi sketch, turning it into a UPDI programmer for the ATtiny1614.

After turning the Arduino into a UPDI programmer, it was now time to test the radio communication abilities with the board.

I got the code I used for communication from this tutorial by HowToMechatronics, obviously with some modifications to fit my system.

Here is the transmitter code after my modifications. I have added comments here unpacking each section of the code.

#include <SPI.h>                  // including libraries
#include <nRF24L01.h>
#include <RF24.h>
RF24 radio(1, 0); // CE, CSN     // initializes the radio with pin 1 as CE, pin 0 as CSN
const byte address[6] = "00001"; // defines the address of the radio
void setup() {
radio.begin();                  // Starting the wireless communication
radio.openWritingPipe(address); // Setting the address 
radio.setPALevel(RF24_PA_MIN);  // Depending on networking distance
radio.stopListening();          // This sets the module as transmitter
}
void loop()
{
const char text[] = "Hello";  // The text that's being sent
radio.write(&text, sizeof(text));  // Sending the message to receiver 

delay(1000);
}

Here you can see I’ve modified the pin numbers to pins 1 and 0, since those are the pins which I’ve connected the CE and CSN pins on my board. Here’s a video of me uploading the transmitter code to the ATTiny1614, which went relatively smoothly with no issue.

Here was the receiver code, which also came from the same tutorial.

x#include <SPI.h> // include libraries
#include <nRF24L01.h>
#include <RF24.h>

RF24 radio(9, 10); // CE, CSN // initialize radio with pins 9 and 10 of arduino

const byte address[6] = "00001"; // receiving address, must be same as transmitter

void setup() {
  Serial.begin(9600);
  radio.begin();      // start radio communication
  radio.openReadingPipe(0, address); // opens a reading/receiving pipe, or communication channel
  radio.setPALevel(RF24_PA_MIN); // set communication distance at minimum
  radio.startListening(); // listens for data that is being transmitted
}

void loop() {
  if (radio.available()) { // if the radio is available
    char text[32] = "";
    radio.read(&text, sizeof(text)); // read in the data and store it into a 32 byte array
    Serial.println(text); // print the text being received
    delay(300);
  }
}

The first time I tried to upload the code and read the output, I got this very odd error. As you can see in the video, I am able to see it printing out a newline every time, which is a good sign, but I am not able to read what it’s actually printing.

After trying to reupload without success, I then went online to try and search for solutions, and I ended up stumbling upon this forum discussion about the Attiny412 and NRF24l01. From this resource I learned that I was using too high of a SCK frequency, as I had set it at 20 MHz when the actual module maxed out at a 10MHz frequency. Thus I changed this factor to 8 MHz when uploading the Tx sketch.

This was the crucial change that made it work. Here is the serial output of the radio with the ATTiny1614.

Week 15 Group Work

This week Pari, Aarush, and I worked together to network Arduino boards together using the I2C protocol. Prior to the networking we received a short lecture on I2C from a lab guru Dr. Harris.

Next we started with networking two arduinos, where we got some inspiration from this helpful arduino tutorial.

First we uploaded this peripheral sender code to their peripheral arduino.

// Wire Master Writer
#include <Wire.h>

void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
}

void loop()
{
  Wire.beginTransmission(8); // transmit to device #4
  Wire.write("hello");          
  Wire.endTransmission();    // stop transmitting
  delay(500);
}

Then we uploaded this controller reader code to the master arduino.

// Wire Controller Reader
#include <Wire.h>

void setup() {
  Wire.begin();        // join i2c bus (address optional for master)
  Serial.begin(9600);  // start serial for output
}

void loop() {
  Wire.requestFrom(8, 6);    // request 6 bytes from peripheral device #8

  while (Wire.available()) { // peripheral may send less than requested
    char c = Wire.read(); // receive a byte as character
    Serial.print(c);         // print the character
  }

  delay(500);
}

After connecting the peripheral sender arduino to a 9V power supply, we found success. As you can see the message is sent from one arduino to the other using I2C.

Next we moved on to the next hurdle, which was getting 3 arduinos networked with 1 master and 2 peripherals. Just like we had done with two arduinos, we connected another Arduino’s SDA and SCL pins with the rest of them, and also configured a common ground between the three. Here’s a photo of the wiring.

Using the same method as before but simply adding another peripheral sender, we found success with 3 arduinos. We had to keep in mind to use a different address for the third arduino so both I2C input data could be read at the same time

Click here to access the group site for the week

Week 15 Files

Click here to access my files for this week


Last update: June 6, 2023