jgromes / RadioLib

Universal wireless communication library for embedded devices
https://jgromes.github.io/RadioLib/
MIT License
1.59k stars 399 forks source link

SX1278, Incorrect receiving data in FSK mode #438

Closed DawKaw closed 2 years ago

DawKaw commented 2 years ago

I am trying to correctly communicate between the two SX1278 in FSK mode, but it fails. The first frame is received correctly. All the bytes go there, but not the next time. On subsequent frames, the byte informing about the frame length sticks to the beginning of the received buffer, and the last byte is lost. Such a phenomenon does not occur in LoRa mode.

I am using:

Transmitter repeatly sending "48 65 6C 6C 6F" (Hello). Receiver after restart, received first frame correctly, but not next. Below receiver side serial output:

[SX1278] Data(5):48 65 6C 6C 6F , RSSI:-42.00 dBm, SNR:0.00 dB, Frequency error:0.00 Hz [SX1278] Data(5):5 48 65 6C 6C, RSSI:-47.00 dBm, SNR:0.00 dB, Frequency error:0.00 Hz [SX1278] Data(5):5 48 65 6C 6C , RSSI:-46.50 dBm, SNR:0.00 dB, Frequency error:0.00 Hz [SX1278] Data(5):5 48 65 6C 6C, RSSI:-46.50 dBm, SNR:0.00 dB, Frequency error:0.00 Hz

Transmitting side code:

#include <RadioLib.h>
//TX

// SX1278 has the following connections:
// NSS pin:   10 -> 17
// DIO0 pin:  2
// RESET pin: 9  -> 4
// DIO1 pin:  3  -> 5
//                        cs,irq,rst,gpio
SX1278 radio = new Module(17, 2, 4, 5);
//SX1278 radio = new Module(10, 2, 9, 3);

volatile float freq = 434.0; //MHz
volatile unsigned int counter = 0;

//#define LORA

void setup() {
  Serial.begin(115200);

  // initialize SX1278 with default settings
  Serial.print(F("[SX1278] Initializing ... "));

#ifdef LORA
  //                      freq, bw,  spr, cr, syncWord,              power, preambLen, gain
  int state = radio.begin(freq, 20.8, 9,  8, RADIOLIB_SX127X_SYNC_WORD, 10, 8,         0);
#else
  //                         freq, br,  fDev, rxBw,  power, preambLen, ook
  //int state = radio.beginFSK(freq, 2.4, 5.0,  125.0, 10,    64,         false);
  int state = radio.beginFSK(freq, 4.8, 4.95,  12.5, 10,    32,         false);

#endif
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

Serial.print("SX1278 ver: ");
Serial.println(radio.getChipVersion());

#ifndef LORA 
  uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67}; 
  state = radio.setSyncWord(syncWord, 4);
  if (state != RADIOLIB_ERR_NONE) {
    Serial.print(F("Unable to set configuration, code "));
    Serial.println(state);
    while (true);
  }
  radio.setDataShaping(RADIOLIB_SHAPING_0_5);
  //radio.fixedPacketLengthMode(0);
#endif

}

void loop() {

  //String s = "Hello World " + String(counter);
  //int state = radio.transmit(s);

  //                    H     e     l     l     o
  byte byteArr[5] = {0x48, 0x65, 0x6C, 0x6C, 0x6F};
  int state = radio.transmit(byteArr, sizeof(byteArr));
  Serial.print(counter++);  

  if (state == RADIOLIB_ERR_NONE) {
    // the packet was successfully transmitted
    Serial.println(F(", success!"));

  } else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
    // the supplied packet was longer than 256 bytes
    Serial.println(F("too long!"));

  } else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
    // timeout occurred while transmitting packet
    Serial.println(F("timeout!"));

  } else {
    // some other error occurred
    Serial.print(F("failed, code "));
    Serial.println(state);

  }

  // wait for a second before transmitting again
  delay(2000);
}

Receiving side code:

#include <RadioLib.h>
//RX

// SX1278 has the following connections:
// NSS pin:   10 -> 17
// DIO0 pin:  2
// RESET pin: 9  -> 4
// DIO1 pin:  3  -> 5
//                        cs,irq,rst,gpio
SX1278 radio = new Module(17, 2, 4, 5);
//SX1278 radio = new Module(10, 2, 9, 3);

volatile float freq = 434.0 - 0.0004;//MHz
volatile bool receivedFlag = false;
volatile bool enableInterrupt = true;

#if defined(ESP8266) || defined(ESP32)
  ICACHE_RAM_ATTR
#endif
void IRQ_flag(void) {
  // check if the interrupt is enabled
  if(!enableInterrupt) return;

  // we got a packet, set the flag
  receivedFlag = true;
}

//#define LORA

void setup() {
  Serial.begin(115200);

  // initialize SX1278 with default settings
  Serial.print(F("[SX1278] Initializing ... "));
#ifdef LORA 
  //                      freq, bw,  spr, cr, syncWord,              power, preambLen, gain
  int state = radio.begin(freq, 20.8,  9, 8, RADIOLIB_SX127X_SYNC_WORD, 10, 8,         0);
#else
  //                         freq, br,  fDev, rxBw,  power, preambLen, ook
  int state = radio.beginFSK(freq, 4.8, 4.95,  12.5, 10,    32,       false);

#endif
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

Serial.print("SX1278 ver: ");
Serial.println(radio.getChipVersion());

#ifndef LORA 
  uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67};
  state = radio.setSyncWord(syncWord, 4);
  if (state != RADIOLIB_ERR_NONE) {
    Serial.print(F("Unable to set configuration, code "));
    Serial.println(state);
    while (true);
  }
#endif

  // set the function that will be called
  // when new packet is received
  radio.setDio0Action(IRQ_flag);

  state = radio.startReceive();
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("StartReceive success!"));
  } else {
    Serial.print(F("StartReceive failed, code "));
    Serial.println(state);
    while (true);
  }
}

void loop() {
// check if the flag is set
  if(receivedFlag) {
    // disable the interrupt service routine while
    // processing the data
    enableInterrupt = false;

    // reset flag
    receivedFlag = false;

    //// you can read received data as an Arduino String
    //String str;
    //int state = radio.readData(str);

    #define ARR_SIZE 5
    // you can also read received data as byte array
    byte byteArr[ARR_SIZE];
    int state = radio.readData(byteArr, ARR_SIZE);

    if (state == RADIOLIB_ERR_NONE) {
      // packet was successfully received
      //Serial.println(F("[SX1278] Received packet!"));

      // print data of the packet
      Serial.print("[SX1278] Data(");
      Serial.print((int)radio.getPacketLength());
      Serial.print("):");
      //Serial.print(str);
       for (int i=0; i<sizeof(byteArr); i++){
         Serial.print(byteArr[i], HEX);
         Serial.print(" ");
       }

      // print RSSI (Received Signal Strength Indicator)
      Serial.print(F(", RSSI:"));
      Serial.print(radio.getRSSI());
      Serial.print(F(" dBm"));

      // print SNR (Signal-to-Noise Ratio)
      Serial.print(F(", SNR:"));
      Serial.print(radio.getSNR());
      Serial.print(F(" dB"));

      // print frequency error
      Serial.print(F(", Frequency error:"));
      Serial.print(radio.getFrequencyError());
      //Serial.print(radio.getAFCError());
      Serial.print(F(" Hz"));

    } else if (state == RADIOLIB_ERR_CRC_MISMATCH) {
      // packet was received, but is malformed
      Serial.print(F(", CRC error!"));

    } else {
      // some other error occurred
      Serial.print(F(" Failed, code "));
      Serial.println(state);

    }
    Serial.println();

    // put module back to listen mode
    radio.startReceive();

    // we're ready to receive more packets,
    // enable interrupt service routine
    enableInterrupt = true;
  }
}

Here manual decoded transmision: ManualDecodedFSK

jgromes commented 2 years ago

That's odd, I'll take a look at it.

PS: The manual dedcoding must have taken quite some time - I suggest giving Universal Radio Hacker a go ;)

jgromes commented 2 years ago

Found out what's the issue - you're calling getPacketLength() after readData(), which is not a use case I expected. Internally, getPacketLength() retrieves packet length of the last received packet from the radio, and is called by readData(). However, once readData() is called, the packet is considered processed (the FIFO gets emptied etc.) and if you call getPacketLength() again, you're basically doing it before another packet arrives.

The solution is to simply call getPacketLength(false), which will return cached value of the last received packet and will not perform length update.

Alternatively, call getPacketLength() prior to calling readData(), which is the expected way to use the method (usually, you first need to know how much data you received, before you try to read them).

DawKaw commented 2 years ago

Thank you very much for your help. I didn't know that the getPacketLength() function affected the received buffer in this way. I corrected the code according to your tip, everything works fine. I was confused that in LoRa mode, receiving was still working properly.

Ps. I like the way your code is written.

jgromes commented 2 years ago

The difference is that in FSK mode, packet length gets pulled from the same FIFO buffer as data. In LoRa mode, packet length is handled differently.

Thanks, I'm glad you like it!