jgromes / RadioLib

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

Invalid calibrateImage parameters prevent initializing with 915MHz frequency on SX126x-based STM32WLx #1096

Closed vimalb closed 5 months ago

vimalb commented 5 months ago

Observed Issue

When using RadioLib v6.4.0 or newer with stm32duino/Arduino_Core_STM32 2.7.1 (latest) on a STM32WLE5CC-based module, radio.begin(915.0, ...) fails with state -707.

Same exact code works correctly with RadioLib v6.3.0 or older (up to 5.6.0 when support for STM32WLx was added). Same exact code also happens to work correctly with RadioLib v6.4.0 and newer if using a different frequency, eg: radio.begin(868.0, ...)

Suspected Cause

I believe I have narrowed down to this change introduced in 6.4.0: [SX126x] Allow custom band calibration Relevant commit: https://github.com/jgromes/RadioLib/commit/3478d908196469ee34461365e2f5c107651e8dae

In RadioLib 6.3.0, setting frequency 915.0 would trigger image calibration with parameters [0xE1,0xE9] which are the recommended values from the SX1261/1262 datasheet section 9.2.1 and Table 9.2.

In RadioLib 6.4.0 and later, setting frequency 915.0 triggers image calibration with calculated parameters [0xE3,0xE6] Calling RADIOLIB_SX126X_CMD_CALIBRATE_IMAGE with those parameters fails with state -707.

Of note, in RadioLib 6.4.0 and later, setting frequency 868.0 will calculate parameters [0xD7,0xDB] which happen to be identical to the datasheet recommended values for 863 - 870 ISM band.

Proposed Fixes

The main issue here is the default calibration formula generates invalid calibration image parameters for center frequency 915.0.

One option to fix it is reverting to the old lookup-table and using only datasheet-recommended calibration image parameters by default (and having a separate codepath for generating and sending custom calibration parameters.

Another option is to tweaking the formula to generate only valid calibration image parameters. I do not see any actual references to valid calibration parameter ranges - literally the datasheet says "Contact your Semtech representative for the other optimal calibration settings outside of the given frequency bands." as opposed to providing a formula.

However with a bit of trial and error with in the ISM band range, I may have stumbled onto a pattern - if both the begin and end image calibration parameters are odd, then calibration succeeds. Output from a quick test program I wrote is attached here: calibrate-image-parameters-test.txt

Assuming this is true, adjusting the formula to ensure both parameters are odd should make it valid for pretty much any frequency in the ISM bands. However IMO I would not by-default calculate and use parameters that aren't explicitly recommended by the datasheet.

Reproducer

#include <RadioLib.h>

STM32WLx radio = new STM32WLx_Module();

static const uint32_t rfswitch_pins[] = {PB8, PC13, RADIOLIB_NC};
static const Module::RfSwitchMode_t rfswitch_table[] = {
  {STM32WLx::MODE_IDLE,  {LOW,  LOW}},
  {STM32WLx::MODE_RX,    {HIGH, LOW}},
  {STM32WLx::MODE_TX_LP, {LOW,  HIGH}},
  {STM32WLx::MODE_TX_HP, {LOW,  HIGH}},
  END_OF_MODE_TABLE,
};

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

  radio.setRfSwitchTable(rfswitch_pins, rfswitch_table);

  Serial.print(F("[STM32WL] Initializing ... "));
  int state = radio.begin(915.0, 250.0, 7, 5, 0x34, 14, 8, 0);
  if (state == RADIOLIB_ERR_NONE) {
    Serial.println(F("success!"));
  } else {
    Serial.print(F("failed, code "));
    Serial.println(state);
  }

}

void loop() {
}

Other Notes

vimalb commented 5 months ago

Apologies - it appears this issue is fixed on master branch in https://github.com/jgromes/RadioLib/commit/5d741779a1badda90f20b7e6a320f958c6069ef9

Looks like someone else had encountered same issue.

Might still be worthwhile to update calibrateImageRejection formula in SX126x.cpp to round both parameters to an odd value, but since is no longer part of the default codepath for the basic beginner use cases, I could go either way.

int16_t SX126x::calibrateImageRejection(float freqMin, float freqMax) {
  // calculate the calibration coefficients and calibrate image
  uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)ceil((freqMax + 1.0f) / 4.0f) };
  data[0] = data[0]%2 ? data[0] : data[0]-1;
  data[1] = data[1]%2 ? data[1] : data[1]+1;
  return(this->calibrateImage(data));
}
jgromes commented 5 months ago

Looks like someone else had encountered same issue.

Yes, this has been reported (as part of a rather long discussion) here: #1051 (specifically https://github.com/jgromes/RadioLib/discussions/1051#discussioncomment-9013278)

if both the begin and end image calibration parameters are odd, then calibration succeeds. Output from a quick test program I wrote is attached here:

That's interesting, thank you for investigating this! Unforuntately since the Semtech LoRa developer forum went down it's been rather tricky to discuss this with anyone. I think I will implement rounding to an odd number with a note/warning that this has not been confirmed by the manufacturer.