HopeRF RFM95 and arduino a low cost LoRaWan solution

The HopeRF RFM95w module proposes to access LoRa at low cost. Its unitary price is around 4€ on shop like aliexpress. A version with a shield is also existing. Its name is Lora1276-C1 from niceRF. These different transceivers are using Semtech SX1276 chip. It makes this kind of chip interesting for regional low cost LoRaWAN design in association with a MCU. Here we are going to use it with an Arduino platform.

The Semtech SX1276 chip

What is the difference between the different Semtech chip for LoRa ? The SX1276 was the first version of Semtech’s LoRa chips. The SX126x Semtech’s family chip has been released in January 2018. This new version, including SX1262, has lower (50%) consumption in reception. It also offers higher transmission power (+15db and +22dB). The SX1262 is smaller with 4x4mm.

So the RFM95w module is using the first version of Semtech LoRa chip. Actually, most of the transceiver are using this chip, so it is not a negative comment.

The SX1276 chip proposes a +14dB transmission for CE area and +20dB for FCC area. The datasheet can be found on Semtech website.

The RFM95w Module

The HopeRF RFM95w module is a LoRa transceiver implementing the SX1276 chip. There is nothing more than a SX1276 standard design on it. this is why you can find different brand proposing equivalent circuit. Some with shield, some without.

The design is specific for each of the LoRa usual frequencies. So a module will be able to cover a specific zone: Europe, America, Asia.

Important point to notice: according to my tests, the RFM95 does not have RFO power amplifier. It only rely on PA_Boost. The module datasheet is really unclear on that point. Depending on the board I’ve used I has been able to have transmission at 50mA for 14dB and sometime I’ve totally different experience measuring consumption at 93mA @ 14dB / 63mA @ 8dB / 55mA @ 5dB. The reason is not yet establish, a bad antenna adaptation could be one of the reason. Not sure it is the only one.

The transceiver is LoRa and not LoRaWAN. It means the RFM95w do not implement the LoRaWan stack and you need to use a MCU to implement it.

For the comparison a Murata CMWX1ZZABZ transceiver is implementing the LoRaWan stack on the STM32 incorporated MCU and is able to switch its frequency with a software configuration. This is why this solution have a higher cost with a factor of 2.

The RFM95w soldering is easy thanks to 2mm pcb pads. This solution will be loved by makers. The 2mm spacing does not fit with the standard 2.54 breadboard’s spacing. Luckily the pcb have the same footprint as the ESP8266. You can use the easy to find ESP8266’s adapter plate to use it on a breadboard. This type of adapter plate is on amazon, ebay, aliexpress for 0.2€. You need to remove the resistors soldered on the PCB plate.

If you don’t have a adapter plate you can easily breakout the module pin thanks to the pin hole. I directly connect female net to be able to plug them on the Arduino board. you will prefer male connector if you want to connect them to a breadboard.

The RFM95w powering is 3.3Volts. The module documentation is accessible on the HopeRF website.

Cabling

I did look at Mobilefish tutorial to make this blog-post. So most of the following element will come from this source. I’ve made modifications sounding better in my point of view. I also add some personal feedback and comments.

At first, Arduino is powered with 5V when the Semtech chip only supports 3.9V as max voltage and usually works with 3.3V. You can cable the module to the Arduino 3.3V but you need to know this powering source is coming from the FTDI (USB) chip and will not be supplied when a battery is in use. The Arduino’s 3.3V power source is also limited to 50mA. For FCC (basically higher than 14dB) usage you will need to use another power supply to provide the right currant.

On top of this point the Arduino’s GPIO is 5V when the module does not support a such voltage. You can also use a tension divider bridge on the output signals MOSI, SLK, NSS and RESET. You can also select the Adafruit RFM95w module, it is integrating the level shifter and DCDC powering.

As a consequence, by connecting your module to an Arduino as I’ll describe it in the next lines you understand you have a risk to make it burned or to see its lifetime largely reduced due to this over-voltage.

The best solution are to use a 3.3V MCU (like a STM32) or to add a level changer module operating a voltage conversion for the I/Os.

HopeRF RFM95 LoRa transceiver moduleArduino PinHopeRF RFM95 LoRa transceiver moduleArduino Pin
ANT GND
GNDGNDDIO5
DIO3RESET5
DIO4NSS6
3.3V3.3VSCK13
DIO03MOSI11
DIO14MISO12
DIO2GND
  • ANT is the antenna Pin. On this pin I’m connecting a SW868-TH13 antenna.
  • GND can be connected to any of the GND pad (connecting all is always better)
  • DIO0 is used by RFM95w module to trigger RxDone/TxDone status.
  • DIO1 is used by RFM95w module to trigger RxTimeout and other kind of errors status.
  • NSS, MOSI, MISO, SCLK are for SPI communication. NSS is the chip select signal. Arduino is the master.
  • Reset is resetting the RFM95w module.

This is the Arduino Nano circuit where you can plug the RFM95w pin according to the previous table mapping.

Software library

Arduino UNO / Nano do not have a large memory available. You need to use a specific LoRaWan library with a reduced footprint. The IBM LMIC library (LoRaMAC in C) has been ported on Arduino. You can check Matthis Kooijman port on github.

Add the library in the Arduino IDE going on Sketch >> Include Library >> Manage Libraries. Then search for LMIC and select MCCI LoraWAN LMIC library by IBM,Matthis Kooijman… Select the last version and click on install.

Now you can see in the example a directory related to the library. Open TTN-OTAA example to getting started. Save it with a new name.

You now need to get the DEVEUI, APPEUI and APPKEY from TheThingsNetwork console and set the sketch according to it. To get these different parameters, you can take a look to TheThingsNetwork tutorial.

You need to be careful on the byte order. DEVEUI and APPEUI are little-endian and you nee to put them in reverse order compared to what you get in the TTN console. APPKEY is a byte block so you directly write it in the same order as in the TTN console.


// This EUI must be in little-endian format, so least-significant-byte
// first. When copying an EUI from ttnctl output, this means to reverse
// the bytes. For TTN issued EUIs the last bytes should be 0xD5, 0xB3,
// 0x70.
static const u1_t PROGMEM APPEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x7E, 0xD5, 0xB3, 0x70 };
void os_getArtEui (u1_t* buf) { memcpy_P(buf, APPEUI, 8);}

// This should also be in little endian format, see above.
static const u1_t PROGMEM DEVEUI[8]={ 0x00, 0x00, 0x00, 0x00, 0x20, 0xBB, 0xB2, 0x00 };
void os_getDevEui (u1_t* buf) { memcpy_P(buf, DEVEUI, 8);}

// This key should be in big endian format (or, since it is not really a
// number but a block of memory, endianness does not really apply). In
// practice, a key taken from ttnctl can be copied as-is.
static const u1_t PROGMEM APPKEY[16] = { 0xC5,0x1F,0x11,0x90,0x96,0xEF,0xC4,0x44,0x39,0x58,0x00,0x00,0x00,0x00,0x00,0x00 };
void os_getDevKey (u1_t* buf) { memcpy_P(buf, APPKEY, 16);}

Now, you need to configure the pin mapping:

// Pin mapping
// Rq : dio2 is not used (it is needed only for FSK)
// pin 7 will be affected but nor used.
const lmic_pinmap lmic_pins = {
.nss = 6,
.rxtx = LMIC_UNUSED_PIN,
.rst = 5,
.dio = {3, 4, LMIC_UNUSED_PIN},
};

Before compiling the sketch we need to setup the LMIC library. To select the chip used and the zone (the frequencies) you need to edit the configuration file located in the Library directory named: project_config/lmic_project_config.h. In this file you will un-comment the right lines and comment others. On top of the sketch you can ass the following lines:

// Ensure the setting is correct in the LMIC config file located in
// LMIC library/project_config/lmic_project_config.h
// These two defines have no more effect than creating an error if
// the library setting is not correct
#define CFG_eu868 1
#define CFG_sx1276_radio 1

In the project’s sketch you need to add the configuration related to TheThingsNetworks:

void setup() {
Serial.begin(9600);
Serial.println(F("Starting"));
// LMIC init
os_init();
// Reset the MAC state. Session and pending data transfers will be discarded.
LMIC_reset();
LMIC_setClockError(MAX_CLOCK_ERROR * 2 / 100);
LMIC_setupChannel(0, 868100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(1, 868300000, DR_RANGE_MAP(DR_SF12, DR_SF7B), BAND_CENTI); // g-band
LMIC_setupChannel(2, 868500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(3, 867100000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(4, 867300000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(5, 867500000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(6, 867700000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(7, 867900000, DR_RANGE_MAP(DR_SF12, DR_SF7), BAND_CENTI); // g-band
LMIC_setupChannel(8, 868800000, DR_RANGE_MAP(DR_FSK, DR_FSK), BAND_MILLI); // g2-band

LMIC_setLinkCheckMode(0);
LMIC.dn2Dr = SF9;
LMIC_setDrTxpow(DR_SF7,14);

// Start job (sending automatically starts OTAA too)
do_send(&sendjob);
}
  • LMIC_setClockError modify the timing duration to support Arduino internal oscillator lack of precision. You need to add this line or not depending on your clock precision.
  • LMIC_setupChannel defines the different channels for TTN network. These channels are depending on the zone where you are. If not set, only the 3 default channels will be available.

Now you can compile and transmit the sketch to the Arduino board. You can follow the sketch processing on the Arduino console. The board will JOIN the network and then send a message every minutes (+/- couple of seconds)

Conclusion

The RFM95w module is low cost and easy to use with Arduino board working powered with 3.3V. Arduino Nano or UNO are not the best choice because you need to manage a 3.3V supply plus GPIO level adaptation even if, as you have seen above, it works with 5V GPIO and FTDI powering at 14dB transmission.

The LMIC LoRaWan implementation is basic but offer a small memory footprint. It works well if you are not looking for all the LoRaWan features.

This entry was posted in IoT, LoRa and tagged , , , . Bookmark the permalink.

10 Responses to HopeRF RFM95 and arduino a low cost LoRaWan solution

  1. Tigran says:

    Hi, could you send me or upload into post a whole sketch ?

  2. Ruben G Elmo says:

    Just cloned the project you made. My issue is that the RFM95 sends data only once… and then stuck like “Starting
    Packet queued
    14335786: EV_TXCOMPLETE (includes waiting for RX windows)”

  3. Robert Hancock says:

    Followed your instructions to the letter and get this compile error.

    […]

    /Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/main.cpp:46: undefined reference to `loop’
    collect2: error: ld returned 1 exit status
    Using library MCCI_LoRaWAN_LMIC_library at version 2.3.2 in folder: /Users/roberthancock/Documents/Arduino/libraries/MCCI_LoRaWAN_LMIC_library
    Using library SPI at version 1.0 in folder: /Applications/Arduino.app/Contents/Java/hardware/arduino/avr/libraries/SPI
    exit status 1
    Error compiling for board Arduino Pro or Pro Mini.

  4. Robert Hancock says:

    Can you suggest modifications for connecting RFM95 to Atmega 328P Arduino Pro or Pro Mini?

  5. Robert Hancock says:

    Sorry to say this, but the Sketch you suggest DOES NOT compile. It produces significant errors—did you debug it?

    Compile error #1
    /Users/roberthancock/Desktop/ttn-otaatest/ttn-otaatest.ino: In function ‘void onEvent(ev_t)’:
    /Users/roberthancock/Desktop/ttn-otaatest/ttn-otaatest.ino:122:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    for (int i = 0; i < sizeof(artKey); ++i) {
    ~~^~~~~~~~~

    Compile error #2
    /Users/roberthancock/Desktop/ttn-otaatest/ttn-otaatest.ino:127:27: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
    for (int i = 0; i < sizeof(nwkKey); ++i) {
    ~~^~~~~~~~~

    Compile error #3
    #pragma message: Board not supported — use an explicit pinmap
    #pragma message("Board not supported — use an explicit pinmap")

    Compile error #4 (and most serious)
    /var/folders/wg/cvn1t_xj5qzdjb0ktl5hfkjm0000gn/T//ccgRj2Wc.ltrans0.ltrans.o: In function 'main':
    /Applications/Arduino.app/Contents/Java/hardware/arduino/avr/cores/arduino/main.cpp:46: undefined reference to `loop'

    Thanks for the useful site, but some feedback/fixes would be nice!

    • Paul says:

      Yes it compile and works … if you correctly import the blog post elements into a sketch and correctly configure the LMIC library it works well.
      Here you have : 2 warning (we do not really care)
      1 error related to the “Board not supported” corresponding to a mis-setting in your LMIC lib
      1 error related to ” undefined reference to ‘loop’ … I’m not sure I have to say an Arduino Sketch MUST have a loop() { … } function defined.

      For helping you starting with RFM95, you can refer to this github example : https://github.com/disk91/arduino-lora-radio-node-demo (it has been made for LoRaNode)

      [Side note] => on a blog, there is no value on spamming the author with your question sent 10 times. I understand that you have some difficulties to solve your issues, but I have the right to be in vacation sometimes 😉 Have fun !

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.