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 (+15dBm and +22dBm). 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 +14dBm transmission for CE area and +20dBm 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 14dBm and sometime I’ve totally different experience measuring consumption at 93mA @ 14dBm / 63mA @ 8dBm / 55mA @ 5dBm. 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.


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 14dBm) 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 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,
.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() {
// LMIC init
// Reset the MAC state. Session and pending data transfers will be discarded.
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.dn2Dr = SF9;

// Start job (sending automatically starts OTAA too)
  • 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)


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 14dBm 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.

36 thoughts on “HopeRF RFM95 and arduino a low cost LoRaWan solution

  1. 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)”

  2. 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.

  3. 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!

    • 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 !

  4. Hello
    I have followed the guide you show here. But my node only performs the join and sends the first data packet, when sending the second packet I get this error: /Applications/Arduino.app/Contents/Java/libraries/arduino-lmic-master/src/lmic/radio. c: 429
    Do you know what it is and how can I solve it?
    I am using a nano v.3, but Chinese version.

  5. Hello.
    I followed this tutorial but unfortunately I get this error while compiling:

    ‘LMIC_getSessionKeys’ was not declared in this scope

    …but I’m not quite sure how and where I need to declare this variable.

    I’m looking forward to hear from you soon.
    Thank you

  6. First of all, thank you very much for this information, I got my arduino nano(compatible V3) to work in one go. although it took me a day, but that is on me.

    I was wondering however if you have an explanation for why it would connect to the TTN instantly, but sometimes just won’t sent the message. I am really new to this and tried to find information on the internet which ranged from busy servers to weather. but since it has no problem to connect i just wonder why it would sometimes not send data for a day, and then 10 minutes straight to just continue not sending data.

    I know you might not have enough information to state what it could be, but if you have a hint, i would like to further experiment with it.

    Thank you very much for the article!

  7. Hello,i am using sx1276 Ic along with Arduino Uno and Ultrasonic sensor(HC-SR04).
    By using this all try to get the distance of any obstacle on My cloud(THE THINGS NETWORK)
    I finely processing “HELLO WORLD” program .
    But the merging code(Ultrasonic with the Ic1276) is doesn’t respond on THE THINGS NETWORK.
    Can you please give me any referance?

  8. Hi, according to the specs (rfm95) then the input volt is max 3.9V.
    Wont an input level of +5 (MOSI, SCK) from the arduino damage the RFM chip on the long run?

  9. Hi.
    I have the SX1278 with me and I tried the same procedure but it gave me an error. My questions are

    1. The library states that it will also work with SX1278, I have changed the config file but can’t get it to work. Has anyone tried this with SX1278 and got it working?

    -I have just purchased the SX1276 and it is on the way, but again

    2. I am from India and the open band here is from 865Mhz to 866Mhz so does the library provide option for these non-standard frequency bands?


    • there are some ways to make it running for sure.
      you can try with my stm32 Iot Sdk on github. little modification for make it running

  10. Hi Any help appreciated here – my code compiles but I get an error on the serial monitor:

    I’ve checked all the steps many times and Google’d a ton of threads. Most seem to suggest a pinout issue – but I know for sure thats not my issue.

    I have a nano v3 and an RFM95W

    • From my experience with RFM95’s, it sounds like you have a dead LoRa module. I’d try using another one and seeing how that goes.

      • Hi Albert!
        i got the same error, i already try many solution suggested but it still error. i checked my pin mapping and configuration and I know for sure thats not my issue. can you or anyone else tell me how to check is it my lora module dead or not?

        *sorry if my english bad, im not native and still learning

    • Hi Andrew,
      Did you find the issue?
      I’m having the same error on the serial monitor, and I’d like to know if I have a dead LoRa module, as Albert suggests, or could be something else.

      • Do you still have this error? I solved with the PinMap settings

      • A little late, but I have today found a solution to this issue (at least in my case). In essence, it is to connect TWO ground wires (the one next to ANA and the one next to MISO) on the RFM95 (they can be to a common ground).

        My set up is:
        3.3v Nano (CH340G clone)
        HopeRF RFM95W (Australia)

        Physical pins as specified above. lmic_pins as follows:

        .nss = 6, // (D6)
        .rxtx = LMIC_UNUSED_PIN,
        .rst = 5, // (D5),
        .dio = { 3, 4, LMIC_UNUSED_PIN} // (D3, D4)

        Connection to the Things Network did not appear to require the addition of the LMIC_setupChannel line(s) – which in fact failed to compile due to an undeclared variable (DR_SF12)

        That simple thing took all day, but immediately connected to TNN and was able to join as required.

        Thanks for the great article too, it was a huge help in getting this setup.

  11. Pingback: First steps with LoRa Radio Node (Arduino) - disk91.com - technology blogdisk91.com – technology blog

  12. Excellent! I wish to show thanks to you just for bailing me out of this particular trouble.As a result of checking through the net and meeting techniques that were not productive, I thought my life was done.

  13. Hello, I’m doing a internship at a certain tech company and my goal is to make a working LoRa network, I have used your guide but I’m stuck on something (which has been mentioned by a hand few of people in the comments

    Now, I got multiple RFM95W chips, and so far both my setups have given me this error, do you have any idea what this error entails? (cause I don’t think it means “broken chip” as they can connect to eachother through another example without issue)

    Thanks for your time (if you still frequent this website)

    • I’m currently not working on that board to investigate this issue. You can eventually try to use a previous version of LMIC (the one I was using) and you should not have it. Or, potentially verify the different step of this tutorial. If you find a solution, please comment to share it with next one coming with a such issue.

    • Thank you for your point on dB / dBm, this typo exists in different blog post … usually people know that in RF we are talking about dBm. I’m going to fix it.

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.