Introduction

Arduino with Adafruit LoRa RFM69HCW

LoRa technology was developed by a company called Semtech and it is a new wireless protocol designed specifically for long-range, low-power communications. LoRa stands for Long Range Radio and is mainly targeted for M2M and IoT networks. This technology will enable public or multi-tenant networks to connect a number of applications running on the same network. LoRa Alliance was formed to standardize LPWAN (Low Power Wide Area Networks) for IoT and is a non-profit association which features membership from a number of key market shareholders such as CISCO, actility, MicroChip, IBM, STMicro, SEMTECH, Orange mobile and many more. This alliance is key to providing interoperability among multiple nationwide networks.I will also post some tutorial links where I have interfaced Adafruit AdaFruit LoRa RFM69HCW with other microcontrollers. If you have any queries about it, ask in the comments and I will resolve it.

Hardware Introduction

Arduino UNO R3

Arduino Uno is a microcontroller board based on the ATmega328P (datasheet). It has 14 digital input/output pins (of which 6 can be used as PWM outputs), 6 analog inputs, a 16 MHz ceramic resonator (CSTCE16M0V53-R0), a USB connection, a power jack, an ICSP header and a reset button. It contains everything needed to support the microcontroller; simply connect it to a computer with a USB cable or power it with a AC-to-DC adapter or battery to get started. You can tinker with your Uno without worrying too much about doing something wrong, worst case scenario you can replace the chip for a few dollars and start over again.

“Uno” means one in Italian and was chosen to mark the release of Arduino Software (IDE) 1.0. The Uno board and version 1.0 of Arduino Software (IDE) were the reference versions of Arduino, now evolved to newer releases. The Uno board is the first in a series of USB Arduino boards, and the reference model for the Arduino platform; for an extensive list of current, past or outdated boards see the Arduino index of boards.

Picture 1. Arduino UNO R3 pin out

Arduino Features

Processor

  • ATMega328P Processor

Memory

  • AVR CPU at up to 16 MHz
  • 32KB Flash
  • 2KB SRAM
  • 1KB EEPROM

Security

  • Power On Reset (POR)
  • Brown Out Detection (BOD)

Power

  • 2.7-5.5 Volts

Peripherals

  • 2x 8-bit Timer/Counter with a dedicated period register and compare channels
  • 1x 16-bit Timer/Counter with a dedicated period register, input capture and compare channels
  • 1x USART with fractional baud rate generator and start-of-frame detection
  • 1x controller/peripheral Serial Peripheral Interface (SPI)
  • 1x Dual mode controller/peripheral I2C
  • 1x Analog Comparator (AC) with a scalable reference input
  • Watchdog Timer with separate on-chip oscillator
  • Six PWM channels
  • Interrupt and wake-up on pin change

Arduino Analog Pin Description

Arduino Digital Pin Description

Sensor 

Adafruit LoRa RFM69HCW (Sensor Description) 

The RFM69HCW is a transceiver module capable of operation over a wide frequency range, including the 315,433,868 and 915MHz license-free ISM (Industry Scientific and Medical) frequency bands. All major RF communication parameters are programmable and most of them  can  be  dynamically set.  The  RFM69HCW  offers  the unique advantage of programmable narrow-band and wide- band communication modes.The RFM69HCW is optimized for low power consumption while offering high RF output power and channelized operation. Compliance  ETSI and FCC regulations.

In order to better use RFM69HCW modules, this specification also involves a large number of the parameters and functions of its core chip RF69H’s,including those IC pins which are not leaded out. All of these can help customers gain a better understanding of the performance of RFM69HCW modules, and enhance the application skills.

Adafruit LoRa RFM69HCW specification:

  • 20 dBm – 100 mW Power Output Capability
  • High Sensitivity: down to -120 dBm at 1.2 kbps
  • High Selectivity: 16-tap FIR Channel Filter
  • Bullet-proof front end: IIP3 = -18 dBm, IIP2 = +35 dBm,80 dB Blocking Immunity, no Image
  • Frequency response
  • Low current: Rx = 16 mA, 100nA register retention
  • Programmable Pout: -18 to +20 dBm in 1dB steps
  • Constant RF performance over voltage range of module
  • FSK Bit rates up to 300 kb/s
  • Fully integrated synthesizer with a resolution of 61 Hz
  • FSK, GFSK, MSK, GMSK and OOK modulations
  • Built-in Bit Synchronizer performing Clock Recovery
  • Incoming Sync Word Recognition
  • 115 dB+ Dynamic Range RSSI
  • Automatic RF Sense with ultra-fast AFC
  • Packet engine with CRC-16, AES-128, 66-byte FIFO
  • Built-in temperature sensor
  • Module Size:16X16mm

Operating specifications:

All pins going into the breakout have level shifting circuitry to make them 3-5V logic level safe. Use whatever logic level is on Vin!

SCK – This is the SPI Clock pin, its an input to the chip

MISO – this is the Microcontroller In Serial Out pin, for data sent from the radio to your processor, 3.3V logic level

MOSI – this is the Microcontroller Out Serial In pin, for data sent from your processor to the radio

CS – this is the Chip Select pin, drop it low to start an SPI transaction. Its an input to the chip

RST – this is the Reset pin for the radio. It’s pulled high by default which is reset. Pull LOW to turn on the radio

G0 – the radio’s “GPIO 0” pin, also known as the IRQ pin, used for interrupt request notification from the radio to the microcontroller, 3.3V logic level

Schematic Diagram

Pin Connection Table:

Source Code

FOR TRANSMITTER: 

#include <SPI.h>
#include <RH_RF95.h>

#define RFM95_CS 10
#define RFM95_RST 9
#define RFM95_INT 2

// Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 915.0

// Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);

// Blinky on receipt
#define LED 13

void setup() 
{
  pinMode(LED, OUTPUT);     
  pinMode(RFM95_RST, OUTPUT);
  digitalWrite(RFM95_RST, HIGH);

  while (!Serial);
  Serial.begin(9600);
  delay(100);

  Serial.println("Arduino LoRa RX Test!");
  
  // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);

  while (!rf95.init()) {
    Serial.println("LoRa radio init failed");
    while (1);
  }
  Serial.println("LoRa radio init OK!");

  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
  if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);

  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on

  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 
  // you can set transmitter powers from 5 to 23 dBm:
  rf95.setTxPower(23, false);
}

void loop()
{
  if (rf95.available())
  {
    // Should be a message for us now   
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    
    if (rf95.recv(buf, &len))
    {
      digitalWrite(LED, HIGH);
      RH_RF95::printBuffer("Received: ", buf, len);
      Serial.print("Got: ");
      Serial.println((char*)buf);
       Serial.print("RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);
      
      // Send a reply
      uint8_t data[] = "And hello back to you";
      rf95.send(data, sizeof(data));
      rf95.waitPacketSent();
      Serial.println("Sent a reply");
      digitalWrite(LED, LOW);
    }
    else
    {
      Serial.println("Receive failed");
    }
  }
}

RECEIVER Code for LoRa:

#include <SPI.h>
#include <RH_RF95.h>

#define RFM95_CS 10
#define RFM95_RST 9
#define RFM95_INT 2

// Change to 434.0 or other frequency, must match RX's freq!
#define RF95_FREQ 915.0

// Singleton instance of the radio driver
RH_RF95 rf95(RFM95_CS, RFM95_INT);

// Blinky on receipt
#define LED 13

void setup() 
{
  pinMode(LED, OUTPUT);     
  pinMode(RFM95_RST, OUTPUT);
  digitalWrite(RFM95_RST, HIGH);

  while (!Serial);
  Serial.begin(9600);
  delay(100);

  Serial.println("Arduino LoRa RX Test!");
  
  // manual reset
  digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);

  while (!rf95.init()) {
    Serial.println("LoRa radio init failed");
    while (1);
  }
  Serial.println("LoRa radio init OK!");

  // Defaults after init are 434.0MHz, modulation GFSK_Rb250Fd250, +13dbM
  if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);

  // Defaults after init are 434.0MHz, 13dBm, Bw = 125 kHz, Cr = 4/5, Sf = 128chips/symbol, CRC on

  // The default transmitter power is 13dBm, using PA_BOOST.
  // If you are using RFM95/96/97/98 modules which uses the PA_BOOST transmitter pin, then 
  // you can set transmitter powers from 5 to 23 dBm:
  rf95.setTxPower(23, false);
}

void loop()
{
  if (rf95.available())
  {
    // Should be a message for us now   
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    
    if (rf95.recv(buf, &len))
    {
      digitalWrite(LED, HIGH);
      RH_RF95::printBuffer("Received: ", buf, len);
      Serial.print("Got: ");
      Serial.println((char*)buf);
       Serial.print("RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);
      
      // Send a reply
      uint8_t data[] = "And hello back to you";
      rf95.send(data, sizeof(data));
      rf95.waitPacketSent();
      Serial.println("Sent a reply");
      digitalWrite(LED, LOW);
    }
    else
    {
      Serial.println("Receive failed");
    }
  }
}

CODE EXPLANATION:

For both Transmitter and Receiver the void Setup Code will be the same. Import the libraries SPI and RF_RH95. Define the pins and initialize.

Coming the loop of transmitter and receiver:

Lora TRANSMISSION CODE Explanation:

void loop()
{
  delay(1000); // Wait 1 second between transmits, could also 'sleep' here!
  Serial.println("Transmitting..."); // Send a message to rf95_server
  
  char radiopacket[20] = "Hello World #      ";
  itoa(packetnum++, radiopacket+13, 10);
  Serial.print("Sending "); Serial.println(radiopacket);
  radiopacket[19] = 0;
  
  Serial.println("Sending..."); delay(10);
  rf95.send((uint8_t *)radiopacket, 20);

  Serial.println("Waiting for packet to complete..."); delay(10);
  rf95.waitPacketSent();

If you are using the transmitter, this code will wait 1 second, then transmit a packet with “Hello World #” and an incrementing packet number. Its pretty simple, the delay does the waiting, you can replace that with low power sleep code. Then it generates the packet and appends a number that increases every tx. Then it simply calls send to transmit the data, and passes in the array of data and the length of the data.

Note that this does not do any addressing or subnetworking – if you want to make sure the packet goes to a particular radio, you may have to add an identifier/address byte on your own!

Then you call waitPacketSent() to wait until the radio is done transmitting. You will not get an automatic acknowledgement from the other radio unless it knows to send back a packet. Think of it like the ‘UDP’ of radio – the data is sent, but it’s not certain it was received! Also, there will not be any automatic retries.

Lora RECEIVER CODE Explanation:

void loop()
{
  if (rf95.available())
  {
    // Should be a message for us now   
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);
    
    if (rf95.recv(buf, &len))
    {
      digitalWrite(LED, HIGH);
      RH_RF95::printBuffer("Received: ", buf, len);
      Serial.print("Got: ");
      Serial.println((char*)buf);
       Serial.print("RSSI: ");
      Serial.println(rf95.lastRssi(), DEC);

The Receiver has the same exact setup code, but the loop is different.Instead of transmitting, it is constantly checking if there’s any data packets that have been received. available() will return true if a packet with proper error-correction was received. If so, the receiver prints it out in hex and also as a ‘character string’

It also prints out the RSSI which is the receiver signal strength indicator. This number will range from about -15 to about -100. The larger the number (-15 being the highest you’ll likely see) the stronger the signal.

Once done it will automatically reply, which is a way for the radios to know that there was an acknowledgement. 

5 1 vote
Article Rating
Previous articleHow to Interface Arduino with Adafruit GPS
Next articleHow to Interface Raspberry Pi-ZERO with Adafruit GPS Module
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments