A Wireless Breakout Board for Rapid Prototyping

Sanskar Biswal
TheTeamMavericks
Published in
11 min readApr 15, 2020
Fig.1 Internet of Things

Internet of Things has reached a tipping point, both in terms of evolution as well as its adoption by consumers. Today, there are several renowned groups dedicated to researching the various fields of IoT. More importantly, the research in IoT is not limited to highly funded labs alone. Student in under-graduate and graduate degrees work on several projects which in some form or other make use of IoT. Several DIY developers make hundreds of projects each month, which utilize the power of IoT in unique ways. These projects are not designed to meet the market requirements or handle a client base, they are simply fun to make and solve some very individualist goals.

IoT is so prevalent that the new 5G telecom technology was developed with IoT implementation in mind. However, widespread implementation of 5G is still several years out in most of the countries in the world. Until such a time that 5G is more accessible, the traditional technologies will continue to be the mainstream for developers.

The Hardware Problem

Most IoT projects today are developed either by hobbyists or college student. The content of this blog is directed towards this segment of developers. If you are someone who has ever built a functional IoT project, then your workflow would be somewhat like this

Fig 2. Workflow of Prototyping

When designing any solution for IoT application, there is a lot of testing and often times you need to go back to the drawing board. The average DIY developer makes use of breadboard and bare-bones coding to test and then implement. This means making connections and reconnecting sensors every time.

When you are done with one project and want to move onto a new project, then you have to repeat the entire cumbersome process, all over. IoT devices also need to be wireless and operate a low latency. Consider the scenario where you need to equip several IoT modules. So now to send their data to your cloud server, each node will have to be connected to the network. Not only does this drastically increase the power consumption of your project, it becomes extremely cumbersome to maintain and grow out while prototyping.

The Solution

Since there was so much repetitive work being done in terms of designing a node and connecting it to the server, I thought that it would be really helpful to design a module for use in IoT development. The inspiration for building this came from when I needed a final year project of my Engineering degree and having worked on several projects throughout my four years in college, I came up with this project.

The developed module needed to have the following features:

  • Wireless: IoT devices need to be wireless, else they lose their advantage
  • Power Efficient: The module needs to be usable for long duration of time, possibly half a year on a single battery.
  • Versatile: The biggest hurdle when developing a prototype is that different sensors require different circuit connections. To ease the process of development, it is imperative that the single module, could interface a wide variety of sensors.
  • Compact: The designed module will need to be small, such that it could be easy to place in real-world situations without consuming too much space.

With these design goals, I set about making the schematic for the IoT Module. But before we get into the technical details, we need to first specify some common terminology that will be used through out this blog post.

Terminology

  • Node: A node will be a single wireless module. It will be the PCB which houses the wireless connectivity module as well as the IC which does the main processing at the node.
  • Parent-Node: This will be a wireless node connected to several other nodes, which collects data from those nodes. In networking terminology, this is the Master while the remaining nodes are Slaves.
  • Transducer: In a traditional sense, transducers convert one form of energy to another. The design I intended to develop needed to not just take inputs from sensors, but also be able to control motors.

Selecting the Components and Basic Designing

Since we are developing a break-out board for prototyping, this means that the hardware needs to work for multiple use-cases. How, this is achieved is explained later in the blog.

Fig.3 Operational Schematic

The main components on the Node are:

  • Micro Controller Unit
  • Ports for Sensor Interface
  • Wireless tx/rx
  • Power Input

For the Micro Controller (MCU), I have opted to use ATtiny85. It is a small and compact IC with very low power consumption. The standby usage is around 100 nA. Additionally, since we will be interfacing only one sensor/actuator to each node, the available 8-pins are more than sufficient.

For wireless communication, it was important to choose a module that was not only power efficient, but also provided long range connectivity and one to many connections. This was so that the parent node could have many child Nodes. The parent node, will collect all data and send the collective data to a cloud based processor. nRF24L01 was a good option. It gave a base range of about 100 m and could form several parent-child connections, to generate a mesh. It uses hexadecimal addressing, so the configuration topology of the child-nodes could be updated in real-time.

Fig.4 nRF24L01 Networking parameters

Finally, we will use a USB-Mini A (female connector) to power the entire system. This will ensure that the system can be powered from a USB outlet as well as from AA-Cell pack with USB-Mini (male-type) Plug. The power will directly be delivered to the VCC of the Sensor Port, MCU and RF module. Thus, those devices will always be on. Therefore, the power management will have to rely on managing the Active State of module operations.

Power Calculations

Before we can estimate the net power used, we need to predict the average power consumed by each of our components. In our design, 3 modules use the available power. The MCU, RF module and the Sensor.

As per the ATtiny85 datasheet, the active state current used is 100 uA. This value is very negligible.

Table.1 Power Consumption in nRF24L01

The nRF24L01 on the other hand is the real power consumer in the design. On the side here is the power consumption from its datasheet. While transmitting, it consumes around 8 mA.

A sensor on the other hand varies quite widely. However, it by some trial and error, I calculated that it averages around 4–5 mA of power. This brings the total power consumed by the entire system to around 12 mA, when receiving or transmitting, and around 5 mA, when in idle mode.

Thus, to reduce the net power consumption, we will need to increase the time the device spends in idle state, or reduce the power consumption. The latter is not very easy to to do, so naturally we will have to figure out a method to transmit data on a selective basis.

PCB Schematic for Node

Fig.5 Schematic of Node (developed in Circuit Studio)

With all design parameter and modules determined, the next step in the process is to make the PCB design and schematics. Designing an IoT module which can be used for wireless communication as well as accommodate a wide variety of sensors was challenging.

Making the Design Versatile for Prototyping

As seen in the figure below, the ATtiny85, other than VCC and GND, has 6 pins. Out of these, 3 pins act as SPI interface between nRF24L01, as SCK, MISO and MOSI. The pin configuration is based on the following schematic.

Fig.6 PIN Connections

Thus, pins 5,6,7 are MOSI,MISO and SCK respectively. Of the remaining 3 pins, pin-1 cannot be programmed. Thus, pin-2 and pin-3 are left for interfacing with the sensors and motors. This might appear very few, but try recollecting which sensor might require more than 2 data I/O pins. The configurations on the sensor is

{(VCC)-(Data I/O)-(Data I/O)-(GND)}

Most sensors have one or maximum two, I/O pins. Except for camera devices, most sensors will work with this configuration, as seen from the schematic.

Fig.7 PCB Design (2-Layer)

Configuring the Input Scheme

Inputs to Pin-2 and Pin-3 can be of the following configurations:

  • Input / Output
  • Digital / Analog

Thus, we select preset EEPROM addresses to hold these values. In addition, some special values are selected, like address of the node, which the nRF24L01 will use to identify and communicate with the node. One variable is to hold the time period at which data will be transmitted from the Node to the Parent Node. The table I used is as follows:

Table.2 EEPROM Address Table

Node Programming

The programming for the Node is done for the Node and Parent. The programming is done using Arduino IDE. To program ATtiny85 using Arduino, follow this link (https://create.arduino.cc/projecthub/arjun/programming-attiny85-with-arduino-uno-afb829).

Node-Side Code

#define CE_PIN 5
#define CSN_PIN 5 //Since we are using 1 pin configuration we will use same pin for both CE and CSN

#include <RF24.h>
#include<EEPROM.h>

// Address 400 => Self Address
RF24 radio(CE_PIN, CSN_PIN);

uint16_t address = 0x05;
unsigned long payload1 = 0; //for pin 3
unsigned long payload2 = 100; //for pin 2

// pin init
// 4 -> pin3 in ATtiny85
// 3 -> pin2 in ATtiny85
// A3 -> pin2
// A2 -> pin3
int pin3 = 4;
int pin2 = 3;
// Structure of Tx Data
struct txData{
unsigned long p3Data;
unsigned long p2Data;
};
// Structure of I/O pin configuration
struct ioConfig{
byte p3Mode[1];
byte p2Mode[1];
int p3Dir;
int p2Dir;
};
// Structure of Rx Data
/*
* opCode = 1 => Address Update
* opCode = 2 => Pin Update
* opCode = 3 => Time Period Update
*/
struct rxData{
int opCode;
ioConfig pinConfig;
uint16_t addr;
unsigned long t_period;
};

struct txData tData;
struct rxData rData;
struct ioConfig configIO;
void setup() {
//setupPIR();
// Inital Function
int initState;
EEPROM.get(398,initState);
if(initState!=-1){
defaultSetup(); // Setup Defaults in First Run
}else{
EEPROM.get(400,address); // update target address with stored address
}
// Setup Config
setupIO();
// Radio Config
radio.begin(); // Start up the radio
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(15,15); // Max delay between retries & number of retries
radio.openWritingPipe(address); // Write to device address 'SimpleNode'
}

void loop(void){
// pin3 Input
if(configIO.p3Mode[0]=="D"){
tData.p3Data = digitalRead(pin3);
}else if(configIO.p3Mode[0]=="A"){
tData.p3Data = analogRead(pin3);
}
// pin2 Input
if(configIO.p2Mode[0]=="D"){
tData.p2Data = digitalRead(pin2);
}else if(configIO.p3Mode[0]=="A"){
tData.p2Data = analogRead(pin2);
}
// Send Sensor Data
radio.stopListening();
bool ok = radio.write( &tData, sizeof(txData) ); //Send data to 'Receiver' ever second
radio.startListening();
// Listen to Data from Parent
if(radio.available()){
radio.read(&rData, sizeof(rxData));
}
// Preprocess Data
int op = rData.opCode;
switch(op){
// Address Update
case 1:
EEPROM.put(400, rData.addr); // Updates on Next Power up
break;
case 2:
configIO = rData.pinConfig;
break;
case 3:
EEPROM.put(420, rData.t_period);
break;
default:
break;
}
delay(1000);
}

// ================================ //
// ======== Extra Functions ======= //
// ================================ //
void defaultSetup(){
// Node Address is stored at 400th loc
uint16_t addr = 0x05;
int initState = -1;
byte p3Mode[1] = "D"; // Digital
byte p2Mode[1] = "H"; // Output HIGH Always
int p3Dir = 1; //Input
int p2Dir = 0; //Output
unsigned long tP = 1000; // 1s as default
EEPROM.put(398, initState);
EEPROM.put(400, addr);
EEPROM.put(420, tP);
EEPROM.put(424, p3Mode);
EEPROM.put(425, p2Mode);
EEPROM.put(426, p3Dir);
EEPROM.put(428, p2Dir);
// Set for PIR Sensor+
}
void setupIO(){
EEPROM.get(424, configIO.p3Mode);
EEPROM.get(425, configIO.p2Mode);
EEPROM.get(426, configIO.p3Dir);
EEPROM.get(428, configIO.p2Dir);
// Set pin 3;
switch(configIO.p3Dir){
// Output Mode
case 0:
pinMode(pin3, OUTPUT);
if(configIO.p3Mode[0]=="H"){
digitalWrite(pin3, HIGH);
}
break;
// Input Mode
case 1:
pinMode(pin3, INPUT);
break;
// Default
default:
break;
}
// Set pin 2;
switch(configIO.p2Dir){
// Output Mode
case 0:
pinMode(pin2, OUTPUT);
if(configIO.p2Mode[0]=="H"){
digitalWrite(pin2, HIGH);
}
break;
// Input Mode
case 1:
pinMode(pin2, INPUT);
break;
// Default
default:
break;
}
// set INIT to Completed State
int initComplete = -1;
EEPROM.put(398, initComplete);
}

Parent-Node Code

#define CE_PIN 10
#define CSN_PIN 9

#include <SPI.h>
#include <RF24.h>
#include<nRF24L01.h>

RF24 radio(CE_PIN, CSN_PIN);

uint16_t address = 0x05;

// Structure of Received Data
struct rxData{
unsigned long p3Data;
unsigned long p2Data;
};
// IO Config
struct ioConfig{
byte p3Mode[1];
byte p2Mode[1];
int p3Dir;
int p2Dir;
};
// Structure of Transmitted Data
struct txData{
int opCode;
ioConfig configIO;
uint16_t addr;
unsigned long t_period;
};
struct rxData rData;
struct txData tData;
void setup() {
Serial.begin(115200);
radio.begin(); // Start up the radio
radio.setAutoAck(1); // Ensure autoACK is enabled
radio.setRetries(15,15); // Max delay between retries & number of retries
radio.openReadingPipe(1, address); // Write to device address 'SimpleNode'
radio.startListening();
}

void loop(){
radio.stopListening();
radio.startListening();
// Check Availability
Serial.println(radio.available());
if(radio.available()){
radio.read(&rData, sizeof(rxData));
}
Serial.print("Pin3 Data : ");
Serial.println(rData.p3Data);

Serial.print("Pin2 Data : ");
Serial.println(rData.p2Data);
//Serial.println("Data Recieved");
//Serial.println(rData.p3Data+" "+rData.p2Data);
delay(1000);
}

Conclusion

Once programming is done, it is now time to test the project. This code is configured for working with a PIR Sensor. Upload the code to the ATtiny85. Then connect all components to the PCB. Finally, upload the Parent Node code to a normal Arduino UNO. The received data should be visible on the COM Port.

Fig.8 Prototype (with scale reference)

This project achieved the following objectives:

  • The common Node module can be used as a wireless transmitter for single and double input sensor. They can be digital or analog. The Node is also capable of driving digital or analog outputs; ie: the Node is extremely versatile.
  • If the Node is set to transmit data at once every minute, the Node can operate on 2-AA-cells for around 400 days.
  • The dimensions of the PCB-Node is (2.5 cm * 3 cm). It is extremely compact. The cells and the sensors will be the largest units.
  • Development is not only reliant on software specification. These too can be made easy by a simple UI to configuring the Node.

The project was developed for a college project and there remains a few tweaks to make it production ready, but it works amazingly well for the purpose of prototyping.

Useful Links:

--

--

Sanskar Biswal
TheTeamMavericks

Electronics Engineer | Firmware Developer | Programmer | Poet | Writer