jgromes / RadioLib

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

SX1262 IQ Inversion Fix Command Failing #516

Closed TJ178 closed 2 years ago

TJ178 commented 2 years ago

Just trying to get my SX1262MB2CAS shield working w/ an Arduino Uno. One of the commands is failing during the begin command.

The only thing modified here is the radio.begin call, which I believe is setup correctly for my module.

/*
   RadioLib SX126x Ping-Pong Example

   For default module settings, see the wiki page
   https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem

   For full API reference, see the GitHub Pages
   https://jgromes.github.io/RadioLib/
*/

// include the library
#include <RadioLib.h>

// uncomment the following only on one
// of the nodes to initiate the pings
//#define INITIATING_NODE

// SX1262 has the following connections:
// NSS pin:   10
// DIO1 pin:  2
// NRST pin:  3
// BUSY pin:  9
SX1262 radio = new Module(10, 2, 3, 9);

// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1262 radio = RadioShield.ModuleA;

// or using CubeCell
//SX1262 radio = new Module(RADIOLIB_ONBOARD_MODULE);

// save transmission states between loops
int transmissionState = RADIOLIB_ERR_NONE;

// flag to indicate transmission or reception state
bool transmitFlag = false;

// disable interrupt when it's not needed
volatile bool enableInterrupt = true;

// flag to indicate that a packet was sent or received
volatile bool operationDone = false;

// this function is called when a complete packet
// is transmitted or received by the module
// IMPORTANT: this function MUST be 'void' type
//            and MUST NOT have any arguments!
void setFlag(void) {
  // check if the interrupt is enabled
  if (!enableInterrupt) {
    return;
  }

  // we sent aor received  packet, set the flag
  operationDone = true;
}

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

  // initialize SX1262 with default settings
  Serial.print(F("[SX1262] Initializing ... "));
  int state = radio.begin(915.0, 125.0, 9, 5, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, 10, 8, 0, false);
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }

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

#if defined(INITIATING_NODE)
  // send the first packet on this node
  Serial.print(F("[SX1262] Sending first packet ... "));
  transmissionState = radio.startTransmit("Hello World!");
  transmitFlag = true;
#else
  // start listening for LoRa packets on this node
  Serial.print(F("[SX1262] Starting to listen ... "));
  state = radio.startReceive();
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
    while (true);
  }
#endif
}

void loop() {
  // check if the previous operation finished
  if (operationDone) {
    // disable the interrupt service routine while
    // processing the data
    enableInterrupt = false;

    // reset flag
    operationDone = false;

    if (transmitFlag) {
      // the previous operation was transmission, listen for response
      // print the result
      if (transmissionState == RADIOLIB_ERR_NONE) {
        // packet was successfully sent
        Serial.println(F("transmission finished!"));

      } else {
        Serial.print(F("failed, code "));
        Serial.println(transmissionState);

      }

      // listen for response
      radio.startReceive();
      transmitFlag = false;

    } else {
      // the previous operation was reception
      // print data and send another packet
      String str;
      int state = radio.readData(str);

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

        // print data of the packet
        Serial.print(F("[SX1262] Data:\t\t"));
        Serial.println(str);

        // print RSSI (Received Signal Strength Indicator)
        Serial.print(F("[SX1262] RSSI:\t\t"));
        Serial.print(radio.getRSSI());
        Serial.println(F(" dBm"));

        // print SNR (Signal-to-Noise Ratio)
        Serial.print(F("[SX1262] SNR:\t\t"));
        Serial.print(radio.getSNR());
        Serial.println(F(" dB"));

      }

      // wait a second before transmitting again
      delay(1000);

      // send another one
      Serial.print(F("[SX1262] Sending another packet ... "));
      transmissionState = radio.startTransmit("Hello World!");
      transmitFlag = true;
    }

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

  }
}

Hardware setup Since the Arduino UNO is 5V logic level, there are some logic level shifters in between the transmitter and MCU ANT_SW is permanently connected to 3V3. Otherwise, everything is connected to the correct pins specified in the sketch image

Debug mode output

[SX1262] Initializing ... M SX126x
CMD 80  
DATW    0   A2  

CMD 80  
DATW    0   A2  

CMD 8F  
DATW    0   A2  0   A2  

CMD 8A  
DATW    1   A2  

CMD 93  
DATW    20  A2  

CMD 88  
DATW    3   A2  16  A2  A   A2  0   A2  0   A2  0   A2  0   A2  

CMD 2   
DATW    3   A2  FF  A2  

CMD 8   
DATW    0   A2  0   A2  0   A2  0   A2  0   A2  0   A2  0   A2  0   A2  

CMD 89  
DATW    7F  A2  

CMD 11  
DATR    0   A2  0   1   

Symbol length: 4.10 ms
CMD 8B  
DATW    9   A2  4   A1  1   45  0   45  

CMD 11  
DATR    0   A2  0   1   

CMD D   7   40  
DATW    14  45  24  45  

CMD 11  
DATR    0   A2  0   1   

CMD 1D  7   36  
DATR    0   80  0   28  

CMD D   7   36  
DATW    28  8A  

failed, code -707

Additional info:

I tried to debug this a bit, looks like it's failing the IQ Polarity fix that's described in chapter 15.4 of the datasheet for the sx1262.

I'm not 100% sure of my radio.begin settings, so perhaps I'm doing something wrong? Any help would be appreciated.

Thank you!

homewsn commented 2 years ago

I noticed that the branches are mixed up here The datasheet says: Bit 2 at address 0x0736 must be set to: • “0” when using inverted IQ polarity (see the SetPacketParam(...) command) • “1” when using standard IQ polarity

jgromes commented 2 years ago

@TJ178 the begin() method arguments look fine, the only thing I am slightly unsure of is the ANT connection. The device is returning RADIOLIB_SX126X_STATUS_CMD_FAILED, and unfortunately the datasheet doesn't go into much details about what does it mean or how to solve it.

I could disable the errata fix for non-inverted IQ, so it would be disabled by default. Again, the datasheet doesn't go into much detail about when exactly is this workaround needed, and what are the consequences.

@homewsn you're right, it seems that is indeed swapped. I'll fix that, however, I don't see how that would break this only for certain setups. Maybe @TJ178 can try it out and see if it helps or not.

TJ178 commented 2 years ago

Just tried out the fix, changed the function to below. Still not working but at least the status code changed to RADIOLIB_ERR_SPI_CMD_INVALID

int16_t SX126x::fixInvertedIQ(uint8_t iqConfig) {
  // fixes IQ configuration for inverted IQ
  // see SX1262/SX1268 datasheet, chapter 15 Known Limitations, section 15.4 for details

  // read current IQ configuration
  uint8_t iqConfigCurrent = 0;
  int16_t state = readRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1);
  RADIOLIB_ASSERT(state);

  // set correct IQ configuration
  if(iqConfig == RADIOLIB_SX126X_LORA_IQ_INVERTED) {
    iqConfigCurrent &= 0xFB;
  } else {
    iqConfigCurrent |= 0x04;
  }

  // update with the new value
  return(writeRegister(RADIOLIB_SX126X_REG_IQ_CONFIG, &iqConfigCurrent, 1));
}

Here's the last few lines of the debug again:

Symbol length: 4.10 ms
CMD 8B  
DATW    9   A2  4   A1  1   45  0   45  

CMD 11  
DATR    0   A2  0   1   

CMD D   7   40  
DATW    14  45  24  45  

CMD 11  
DATR    0   A2  0   1   

CMD 1D  7   36  
DATR    0   80  0   28  

CMD D   7   36  
DATW    2C  89  

failed, code -706
jgromes commented 2 years ago

I was reading through the debug output again, and noticed something I missed on the first read:

Symbol length: 4.10 ms
CMD 8B  
DATW    9   A2  4   A1  1   45  0   45  

The status here changes, from 0xA2 (standby RC mode) to 0x45 (FS mode, data available to host). That's really strange, because it seems to imply the device randomly changed its operation mode. What's even more strange, 0xA2 happens to be 0x45 if you reverse the bits.

Which level shifters are you using?

TJ178 commented 2 years ago

They are the Sparkfun ones. I figured they wouldn't be the problem since it was communicating at all, but I wouldn't be surprised if they were the issue.

jgromes commented 2 years ago

Looks like a BSS138, those are actually decent (one of the few that are actually bi-directional).

One more thought, though it's a bit far-fetched - could you try setting the last argument of the begin() method to true?

TJ178 commented 2 years ago

Just tried making that last argument true, no change unfortunately.

jgromes commented 2 years ago

@TJ178 I tried replicating this issue with a Dorji DRF1262G, connected to Arduino Uno via a BSS138 level shifter. Unfortunately I was not able to replicate this issue, it seems like something specific to either the shield, or your hardware setup. Beacuse of that, I will close this issue now, though feel free to reopen if you find out some new information.