Lopy and RFM95 communication
-
Hi,
I am trying to communicate an Arduino Pro Mini with RFM95 module (acting as a transmiter) and a Lopy (acting as a receiver).
Inspired by this thread I've come to these two pieces of code:
- Arduino
#include <SPI.h> #include <RH_RF95.h> #define FREQUENCY 868.0 struct tpayload { uint32_t deviceid; //4 byte seq; //1 byte indicator1; //1 byte indicator2; //1 byte stype; //1 long svalue; //4 byte check; //1 }; tpayload payload; RH_RF95 rf95; // Chip Select=D10, INT Pin = D2 void setup() { Serial.begin(115200); if (!rf95.init()) { Serial.println("init failed"); } else { Serial.print("init OK - "); Serial.print(FREQUENCY); Serial.println("mhz"); } payload.seq = 0; payload.deviceid = 8512; payload.indicator1 = 1; payload.indicator1 = 2; payload.stype = 2; payload.svalue = -10; rf95.setModemConfig(RH_RF95::Bw125Cr45Sf128); rf95.setTxPower(23, false); rf95.setPreambleLength(8); rf95.setFrequency(868.0); } void loop() { payload.seq++; if (payload.seq == 0) payload.seq++; // to avoid division by zero at the next line payload.check = payload.deviceid % payload.seq; // you need this to discard corrupted messages uint16_t now = micros(); rf95.send( (const uint8_t*)&payload, sizeof(payload)); Serial.print("Sent "); Serial.println(payload.seq); delay(5000); }- Lopy
import struct import socket from network import LoRa import time import gc LORA_MSG_FORMAT = "LLBBBBlB" class incoming_message: def __init__(self, data): self.control, self.deviceID, self.Seq, self.indicator1, self.indicator2, self.stype, self.svalue, self.check = struct.unpack(LORA_MSG_FORMAT, data) #self.control is something added from RFM95. Just discard it. Your message starts from the 5th byte class server: def __init__(self): cfg_mode = LoRa.LORA cfg_freq = 868000000 # accepts values between 863000000 and 870000000 in the 868 band cfg_bandwidth=LoRa.BW_125KHZ # LoRa.BW_125KHZ or LoRa.BW_250KHZ cfg_sf = 7 # Accepts values between 6 and 12. Ver Datasheet semtech SX1272 # 6 = 64 Chips/Symbol # 7 = 128 Chips/Symbol # 8 = 256 Chips/Symbol # 9 = 512 Chips/Symbol # 10 = 1024 Chips/Symbol # 11 = 2048 Chips/Symbol # 12 = 4096 Chips/Symbol cfg_preamble=8 #configures the number of pre-amble symbols. The default value is 8 cfg_coding_rate=LoRa.CODING_4_5 #LoRa.CODING_4_5, LoRa.CODING_4_6, LoRa.CODING_4_7 or LoRa.CODING_4_8 cfg_power_mode=LoRa.ALWAYS_ON #LoRa.ALWAYS_ON, LoRa.TX_ONLY or LoRa.SLEEP #medium range: bandwidth=LoRa.BW_250KHZ,coding_rate=LoRa.CODING_4_5,sf=7 #fast short range: bandwidth=LoRa.BW_500KHZ,coding_rate=LoRa.CODING_4_5,sf=7 #slow long range: bandwidth=LoRa.BW_125KHZ,coding_rate=LoRa.CODING_4_8,sf=9 #very slow long range: bandwidth=LoRa.BW_125KHZ,coding_rate=LoRa.CODING_4_8,sf=12 self.lora = LoRa(mode=cfg_mode, tx_power=14, # It accepts between 2 and 14 for the 868 band frequency=cfg_freq, bandwidth=cfg_bandwidth, sf=cfg_sf, preamble=cfg_preamble, coding_rate=cfg_coding_rate, rx_iq=True, tx_iq=False, # disables TX IQ inversion power_mode=cfg_power_mode, public=False) self.lora.init(mode=cfg_mode, frequency=cfg_freq, tx_power=14, # It accepts between 2 and 14 for the 868 band bandwidth=cfg_bandwidth, sf=cfg_sf, preamble=cfg_preamble, coding_rate=cfg_coding_rate, power_mode=cfg_power_mode, tx_iq=False, # disables TX IQ inversion rx_iq=True, # enables RX IQ inversion public=False) self.lora_sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW) self.lora_sock.setblocking(False) def update(self): raw_data = self.lora_sock.recv(61) if raw_data: try: msg = incoming_message(raw_data) if msg.deviceID % msg.Seq == msg.check: print("msg received. devid:", msg.deviceID, " seq:", msg.Seq) else: print("msg check failed") except: print("msg failed to parse") else: # print("pass") pass def test_server(): srv = server() cnt=0 while True: cnt=cnt+1 if (cnt%1000==0): print(cnt) srv.update() test_server()But, unfortunately, it is not working. I mean, Lopy is not apparently receiving anything. Any hints?
The project will be sensor on the Arduino side that will send data periodically to the Lopy that will act as a gateway to my local network. But now I'm in the early stage, meaning trying to communicate both devices.
Thanks a lot.
-
@joseperez said in Lopy and RFM95 communication:
I never tried this sort communication because the Radiohead library is very low level and even the "raw" LoRa on the LoPy is slightly more defined but at a minimum I'd expect you need to set the sync word to match your LoPy setting of public=(True|False) via register RH_RF95_REG_39_SYNC_WORD and also your rx_iq, tx_iq settings should match what's set via RH_RF95_REG_33_INVERT_IQ.
I cannot implement/test this at the moment, but maybe you can look into these areas and find suitable values?
-
OK. Thank you. I'll look into it. One more silly question: Where can I find the source code of the Lora library so that I can see details on the implementation?
-
Hi @joseperez,
A good place to start would be here: https://github.com/pycom/pycom-micropython-sigfox/blob/master/esp32/mods/modlora.c
-
After some investigation, no results. I choose to investigate what are the register values the RFM95 has by default and then configure Lopy to align to those values.
I mean, for the RH_RF95_REG_39_SYNC_WORD in Lopy library we have ...
if (init_data->public) { Radio.Write(REG_LR_SYNCWORD, LORA_MAC_PUBLIC_SYNCWORD); } else { Radio.Write(REG_LR_SYNCWORD, LORA_MAC_PRIVATE_SYNCWORD); }So I printed what is the value of that register and found that the default value is 0x12 which corresponds to LORA_MAC_PRIVATE_SYNCWORD so in the Lopy Lora we must initialize with Public=False.
For the IQ_Inversion we have:
// In SX1272Send case MODEM_LORA: { if( SX1272.Settings.LoRa.TxIqInverted == true ) { SX1272Write( REG_LR_INVERTIQ, ( ( SX1272Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_ON ) ); SX1272Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_ON ); } else { SX1272Write( REG_LR_INVERTIQ, ( ( SX1272Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF ) ); SX1272Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_OFF ); }// In SX1272SetRx: case MODEM_LORA: { if( SX1272.Settings.LoRa.RxIqInverted == true ) { SX1272Write( REG_LR_INVERTIQ, ( ( SX1272Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_ON | RFLR_INVERTIQ_TX_OFF ) ); SX1272Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_ON ); } else { SX1272Write( REG_LR_INVERTIQ, ( ( SX1272Read( REG_LR_INVERTIQ ) & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF ) ); SX1272Write( REG_LR_INVERTIQ2, RFLR_INVERTIQ2_OFF ); }And after getting the register values it turns out that Tx_invertIQ and Rx_InvertIQ should be set as False.
This is the code for Arduino....
#include <SPI.h> #include <RH_RF95.h> #define FREQUENCY 868.0 #define REG_LR_INVERTIQ 0x33 #define REG_LR_INVERTIQ2 0x3B #define RFLR_INVERTIQ2_ON 0x19 #define RFLR_INVERTIQ2_OFF 0x1D // From sx1272Regs-LoRa.h #define RFLR_INVERTIQ_RX_ON 0x40 // Bit 6 ON #define RFLR_INVERTIQ_RX_OFF 0x00 // Bit 0 OFF #define RFLR_INVERTIQ_TX_MASK 0xFE // Selects bit 0 #define RFLR_INVERTIQ_RX_MASK 0xBF // Selects bit 6 #define RFLR_INVERTIQ_TX_OFF 0x01 // Bit 0 ON #define RFLR_INVERTIQ_TX_ON 0x00 // Bit 0 OFF struct tpayload { uint32_t deviceid; //4 byte seq; //1 byte indicator1; //1 byte indicator2; //1 byte stype; //1 long svalue; //4 byte check; //1 }; tpayload payload; RH_RF95 rf95; // Chip Select=D10, INT Pin = D2 void setup() { Serial.begin(115200); if (!rf95.init()) { Serial.println("init failed"); } else { Serial.print("init OK - "); Serial.print(FREQUENCY); Serial.println("mhz"); } payload.seq = 0; payload.deviceid = 8512; payload.indicator1 = 1; payload.indicator1 = 2; payload.stype = 2; payload.svalue = -10; rf95.setModemConfig(RH_RF95::Bw125Cr45Sf128); rf95.setTxPower(23, false); rf95.setPreambleLength(8); rf95.setFrequency(868.0); // Prints 0x12 so LORA_MAC_PRIVATE_SYNCWORD=0x12 then Public=False Serial.print("REG_LR_SYNCWORD: "); Serial.println(rf95.spiRead(0x39),HEX); byte iq=rf95.spiRead(REG_LR_INVERTIQ); byte iq2=rf95.spiRead(REG_LR_INVERTIQ2); // TxIqInverted == false, RxIqInverted==false byte iq_tx=(( iq & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF ); byte iq_rx=(( iq & RFLR_INVERTIQ_TX_MASK & RFLR_INVERTIQ_RX_MASK ) | RFLR_INVERTIQ_RX_OFF | RFLR_INVERTIQ_TX_OFF ); // All values are 0x27, so TxIqInverted == false, RxIqInverted==false Serial.print("REG_LR_INVERTIQ: "); Serial.println(iq,HEX); Serial.println(iq_tx,HEX); Serial.println(iq_rx,HEX); // It prints 0x1D so it's RFLR_INVERTIQ2_OFF Serial.print("REG_LR_INVERTIQ2: "); Serial.println(iq2,HEX); } void loop() { payload.seq++; if (payload.seq == 0) payload.seq++; // to avoid division by zero at the next line payload.check = payload.deviceid % payload.seq; // you need this to discard corrupted messages uint16_t now = micros(); rf95.send( (const uint8_t*)&payload, sizeof(payload)); Serial.print("Sent "); Serial.println(payload.seq); delay(5000); }And this is for the Lopy....
import struct import socket from network import LoRa import time import gc LORA_MSG_FORMAT = "LLBBBBlB" class incoming_message: def __init__(self, data): self.control, self.deviceID, self.Seq, self.indicator1, self.indicator2, self.stype, self.svalue, self.check = struct.unpack(LORA_MSG_FORMAT, data) #self.control is something added from RFM95. Just discard it. Your message starts from the 5th byte class server: def __init__(self): cfg_mode = LoRa.LORA cfg_freq = 868000000 # accepts values between 863000000 and 870000000 in the 868 band cfg_bandwidth=LoRa.BW_125KHZ # LoRa.BW_125KHZ or LoRa.BW_250KHZ cfg_sf = 7 # Accepts values between 6 and 12. Ver Datasheet semtech SX1272 # 6 = 64 Chips/Symbol # 7 = 128 Chips/Symbol # 8 = 256 Chips/Symbol # 9 = 512 Chips/Symbol # 10 = 1024 Chips/Symbol # 11 = 2048 Chips/Symbol # 12 = 4096 Chips/Symbol cfg_preamble=8 #configures the number of pre-amble symbols. The default value is 8 cfg_coding_rate=LoRa.CODING_4_5 #LoRa.CODING_4_5, LoRa.CODING_4_6, LoRa.CODING_4_7 or LoRa.CODING_4_8 cfg_power_mode=LoRa.ALWAYS_ON #LoRa.ALWAYS_ON, LoRa.TX_ONLY or LoRa.SLEEP #medium range: bandwidth=LoRa.BW_250KHZ,coding_rate=LoRa.CODING_4_5,sf=7 #fast short range: bandwidth=LoRa.BW_500KHZ,coding_rate=LoRa.CODING_4_5,sf=7 #slow long range: bandwidth=LoRa.BW_125KHZ,coding_rate=LoRa.CODING_4_8,sf=9 #very slow long range: bandwidth=LoRa.BW_125KHZ,coding_rate=LoRa.CODING_4_8,sf=12 self.lora = LoRa(mode=cfg_mode, tx_power=14, # It accepts between 2 and 14 for the 868 band frequency=cfg_freq, bandwidth=cfg_bandwidth, sf=cfg_sf, preamble=cfg_preamble, coding_rate=cfg_coding_rate, rx_iq=False, tx_iq=False, power_mode=cfg_power_mode, public=False) self.lora.init(mode=cfg_mode, frequency=cfg_freq, tx_power=14, # It accepts between 2 and 14 for the 868 band bandwidth=cfg_bandwidth, sf=cfg_sf, preamble=cfg_preamble, coding_rate=cfg_coding_rate, power_mode=cfg_power_mode, tx_iq=False, rx_iq=False, public=False) self.lora_sock = socket.socket(socket.AF_LORA, socket.SOCK_RAW) self.lora_sock.setblocking(False) def update(self): raw_data = self.lora_sock.recv(61) if raw_data: try: msg = incoming_message(raw_data) if msg.deviceID % msg.Seq == msg.check: print("msg received. devid:", msg.deviceID, " seq:", msg.Seq) else: print("msg check failed") except: print("msg failed to parse") else: # print("pass") pass def test_server(): srv = server() cnt=0 while True: cnt=cnt+1 if (cnt%1000==0): print(cnt) srv.update() test_server()But, as I said earlier, no results. So it may be caused by other settings or "way to communicate".
-
Were you able to resolve this issue and achieve communication between the LoPy and the RF95?
Hello! It looks like you're interested in this conversation, but you don't have an account yet.
Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.
With your input, this post could be even better 💗
Register Login