Introduction

Interface ESP8266 with AdaFruit LoRa RFM69HCW

Do you want to build a low-powered mesh network using Arduino? If so, keep reading – this post will teach you how to interface the ESP8266 with an AdaFruit RFM69HCW transceiver. By the end of this tutorial, you’ll be able to send data between two nodes over a long distance. Let’s get started!

Think of LoRa as the future of wireless networking. Developed by Semtech, this new technology enables long range and low power communications for many different applications including M2M or IoT networks that are public/multi tenant in nature with connection strengths between individual nodes on these types network vary depending upon requirements desired out put tone should be witty

Hardware Introduction

ESP8266 MODULE

Espressif’s ESP8266EX delivers a highly integrated Wi-Fi SoC solution to meet users’ continuous demands for efficient power usage, compact design and reliable performance in the Internet of Things industry. 

With the complete and self-contained Wi-Fi networking capabilities, ESP8266EX can perform either as a standalone application or as the slave to a host MCU. When ESP8266EX hosts the application, it promptly boots up from the flash. The integrated high speed cache helps to increase the system performance and optimize the system memory. Also, ESP8266EX can be applied to any microcontroller design as a Wi-Fi adapter through SPI/SDIO or UART interfaces. 

ESP8266EX integrates antenna switches, RF balun, power amplifier, low noise receive amplifier, filters and power management modules. The compact design minimizes the PCB size and requires minimal external circuitries. 

Besides the Wi-Fi functionalities, ESP8266EX also integrates an enhanced version of Tensilica’s L106 Diamond series 32-bit processor and on-chip SRAM. It can be interfaced with external sensors and other devices through the GPIOs. Software Development Kit (SDK) provides sample codes for various applications. 

Espressif Systems’ Smart Connectivity Platform (ESCP) enables sophisticated features including:

  • Fast switch between sleep and wakeup mode for energy-efficient purpose.
  • Adaptive radio biasing for low-power operation.
  • Advance signal processing.
  • Spur cancellation and RF coexistence mechanisms for common cellular, Bluetooth, DDR, LVDS, LCD interference mitigation.
Sơ đồ chân ESP8266 - Nên sử dụng chân nào

Features

Graphical user interface, application

Description automatically generated

ESP8266 Processor

The ESP8266EX integrates a Tensilica L106 32-bit RISC processor, which achieves extra low power consumption and reaches a maximum clock speed of 160 MHz. The Real-Time

Operating System (RTOS) and Wi-Fi stack allow 80% of the processing power to be

available for user application programming and development. The CPU includes the

interfaces as below:

Programmable RAM/ROM interfaces (iBus), which can be connected with memory

controller, and can also be used to visit flash.

Data RAM interface (dBus), which can be connected with a memory controller.

AHB interface which can be used to visit the register. 

Memory

ESP8266EX Wi-Fi SoC integrated memory controller and memory units including SRAMand ROM. MCU can access the memory units through iBus, dBus, and AHB interfaces. All Memory units can be accessed upon request, while a memory arbiter will decide the running sequence according to the time when these requests are received by the

processor. 

Power

ESP8266EX is designed with advanced power management technologies and intended for mobile devices, wearable electronics and the Internet of Things applications. The low-power architecture operates in the following modes:

 • Active mode: The chip radio is powered on. The chip can receive, transmit, or listen. 

• Modem-sleep mode: The CPU is operational. The Wi-Fi and radio are disabled. • Light-sleep mode: The CPU and all peripherals are paused. Any wake-up events (MAC, host, RTC timer, or external interrupts) will wake up the chip.

 • Deep-sleep mode: Only the RTC is operational and all other parts of the chip are powered off.

ESP8266 Analog Pin Description

Sensor 

Adafruit-RFM-69-Lora
Adafruit-RFM-69-Lora Module

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:

● High Sensitivity: down to -120 dBm at 1.2 kbps 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 16
#define RFM95_RST 27

// 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");
    }
  }
}

FOR RECEIVER:

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

#define RFM95_CS 16
#define RFM95_RST 27

// 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:

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

#define RFM95_CS 16
#define RFM95_RST 27

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.

#define RF95_FREQ 915.0

Define the RF module frequency as 915 (for receiver it must match with Tx’s Frequency).

RH_RF95 rf95(RFM95_CS, RFM95_INT);

Instantiate the radio driver with the RFM95_CS and RFM95_INT

#define LED 13

Define the LED pin as 13 inorder to make the LED blink both on receiving and also transmitting.

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

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

Set the Baud Rate as 9600. And give the delay for 100ms.

  Serial.println("Arduino LoRa RX Test!");

Serially print the message ‘Arduino LoRa RX Test!’

digitalWrite(RFM95_RST, LOW);
  delay(10);
  digitalWrite(RFM95_RST, HIGH);
  delay(10);

Manually reset the module by making the RST as High and Low and also by giving the delay for around 10ms.

if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);

When the LoRa initializing is not high then print the serial message ‘LoRa radio init failed’

if (!rf95.setFrequency(RF95_FREQ)) {
    Serial.println("setFrequency failed");
    while (1);
  }
  Serial.print("Set Freq to: "); Serial.println(RF95_FREQ);

If the RF set frequency does not match with that of Tx/Rx then print the message ‘setFrequency Failed’. Then also print the value of RF95 frequency value to which it has to set again. 

 rf95.setTxPower(23, false);

Set the txpower as 23dBm as it uses the PA_BOOST.

Coming to the loop of transmitter and receiver:

TRANSMISSION CODE:

If you are using the transmitter, this code will wait 1 second

{
  delay(1000); // Wait 1 second between transmits, could also 'sleep' here!
  Serial.println("Transmitting...");

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.

char radiopacket[20] = "Hello World #      ";
  itoa(packetnum++, radiopacket+13, 10);
  Serial.print("Sending "); Serial.println(radiopacket);
  radiopacket[19] = 0;

 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.

Serial.println("Sending..."); delay(10);
  rf95.send((uint8_t *)radiopacket, 20);

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!

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

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.

RECEIVER CODE:

 if (rf95.available())
  {
    // Should be a message for us now   
    uint8_t buf[RH_RF95_MAX_MESSAGE_LEN];
    uint8_t len = sizeof(buf);

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’

    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);

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. 

GITHUB LINK

https://github.com/iottrends/iottrends/tree/main/LoRa%20Modules/Adafruit%20RFM69HCW

5 1 vote
Article Rating
Previous articleHow to Interface Arduino with NRF24L01
Next articleHow to Interface Raspberry Pi-ZERO with AdaFruit LoRa RFM69HCW
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments