Skip to content

Commit

Permalink
[SX126x] Calibrate image based on frequency change (#1292)
Browse files Browse the repository at this point in the history
  • Loading branch information
jgromes committed Oct 27, 2024
1 parent 28360f9 commit b8b1afd
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 78 deletions.
45 changes: 7 additions & 38 deletions src/modules/SX126x/SX1262.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "SX1262.h"
#include <math.h>

#if !RADIOLIB_EXCLUDE_SX126X

SX1262::SX1262(Module* mod) : SX126x(mod) {
Expand Down Expand Up @@ -66,49 +68,16 @@ int16_t SX1262::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid,
}

int16_t SX1262::setFrequency(float freq) {
return(setFrequency(freq, true));
return(setFrequency(freq, false));
}

int16_t SX1262::setFrequency(float freq, bool calibrate) {
int16_t SX1262::setFrequency(float freq, bool skipCalibration) {
RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY);

// calibrate image rejection
if(calibrate) {
uint8_t data[2] = { 0, 0 };

// try to match the frequency ranges
int freqBand = (int)freq;
if((freqBand >= 902) && (freqBand <= 928)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2;
} else if((freqBand >= 863) && (freqBand <= 870)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2;
} else if((freqBand >= 779) && (freqBand <= 787)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2;
} else if((freqBand >= 470) && (freqBand <= 510)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2;
} else if((freqBand >= 430) && (freqBand <= 440)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2;
}

int16_t state;
if(data[0]) {
// matched with predefined ranges, do the calibration
state = SX126x::calibrateImage(data);

} else {
// if nothing matched, try custom calibration - the may or may not work
RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom");
state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f);

}

// check if we need to recalibrate image
if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) {
int16_t state = this->calibrateImage(freq);
RADIOLIB_ASSERT(state);

}

// set frequency
Expand Down
8 changes: 6 additions & 2 deletions src/modules/SX126x/SX1262.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,22 @@ class SX1262: public SX126x {

/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
Will automatically perform image calibration if the frequency changes by
more than RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq) override;

/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
Will automatically perform image calibration if the frequency changes by
more than RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ.
\param freq Carrier frequency to be set in MHz.
\param calibrate Run image calibration.
\param skipCalibration Skip automated image calibration.
\returns \ref status_codes
*/
int16_t setFrequency(float freq, bool calibrate);
int16_t setFrequency(float freq, bool skipCalibration);

/*!
\brief Sets output power. Allowed values are in range from -9 to 22 dBm.
Expand Down
39 changes: 7 additions & 32 deletions src/modules/SX126x/SX1268.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
#include "SX1268.h"
#include <math.h>

#if !RADIOLIB_EXCLUDE_SX126X

SX1268::SX1268(Module* mod) : SX126x(mod) {
Expand Down Expand Up @@ -66,44 +68,17 @@ int16_t SX1268::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid,
}

int16_t SX1268::setFrequency(float freq) {
return(setFrequency(freq, true));
return(setFrequency(freq, false));
}

/// \todo integers only (all modules - frequency, data rate, bandwidth etc.)
int16_t SX1268::setFrequency(float freq, bool calibrate) {
int16_t SX1268::setFrequency(float freq, bool skipCalibration) {
RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY);

// calibrate image rejection
if(calibrate) {
uint8_t data[2] = { 0, 0 };

// try to match the frequency ranges
int freqBand = (int)freq;
if((freqBand >= 779) && (freqBand <= 787)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2;
} else if((freqBand >= 470) && (freqBand <= 510)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2;
} else if((freqBand >= 430) && (freqBand <= 440)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2;
}

int16_t state;
if(data[0]) {
// matched with predefined ranges, do the calibration
state = SX126x::calibrateImage(data);

} else {
// if nothing matched, try custom calibration - the may or may not work
RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom");
state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f);

}

// check if we need to recalibrate image
if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) {
int16_t state = this->calibrateImage(freq);
RADIOLIB_ASSERT(state);

}

// set frequency
Expand Down
8 changes: 6 additions & 2 deletions src/modules/SX126x/SX1268.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,22 @@ class SX1268: public SX126x {

/*!
\brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz.
Will automatically perform image calibration if the frequency changes by
more than RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG MHz.
\param freq Carrier frequency to be set in MHz.
\returns \ref status_codes
*/
int16_t setFrequency(float freq) override;

/*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz.
Will automatically perform image calibration if the frequency changes by
more than RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ.
\param freq Carrier frequency to be set in MHz.
\param calibrate Run image calibration.
\param skipCalibration Skip automated image calibration.
\returns \ref status_codes
*/
int16_t setFrequency(float freq, bool calibrate);
int16_t setFrequency(float freq, bool skipCalibration);

/*!
\brief Sets output power. Allowed values are in range from -9 to 22 dBm.
Expand Down
42 changes: 40 additions & 2 deletions src/modules/SX126x/SX126x.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1954,6 +1954,43 @@ int16_t SX126x::setRfFrequency(uint32_t frf) {
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4));
}

int16_t SX126x::calibrateImage(float freq) {
uint8_t data[2] = { 0, 0 };

// try to match the frequency ranges
int freqBand = (int)freq;
if((freqBand >= 902) && (freqBand <= 928)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_902_MHZ_2;
} else if((freqBand >= 863) && (freqBand <= 870)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_863_MHZ_2;
} else if((freqBand >= 779) && (freqBand <= 787)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_779_MHZ_2;
} else if((freqBand >= 470) && (freqBand <= 510)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_470_MHZ_2;
} else if((freqBand >= 430) && (freqBand <= 440)) {
data[0] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_1;
data[1] = RADIOLIB_SX126X_CAL_IMG_430_MHZ_2;
}

int16_t state;
if(data[0]) {
// matched with predefined ranges, do the calibration
state = SX126x::calibrateImage(data);

} else {
// if nothing matched, try custom calibration - the may or may not work
RADIOLIB_DEBUG_BASIC_PRINTLN("Failed to match predefined frequency range, trying custom");
state = SX126x::calibrateImageRejection(freq - 4.0f, freq + 4.0f);

}

return(state);
}

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) };
Expand Down Expand Up @@ -2103,8 +2140,9 @@ int16_t SX126x::clearDeviceErrors() {

int16_t SX126x::setFrequencyRaw(float freq) {
// calculate raw value
this->frf = (freq * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
return(setRfFrequency(this->frf));
this->freqMHz = freq;
uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
return(setRfFrequency(frf));
}

int16_t SX126x::fixSensitivity() {
Expand Down
12 changes: 11 additions & 1 deletion src/modules/SX126x/SX126x.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@
#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB
#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_1 0xE1
#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9
#define RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ (20.0)

//RADIOLIB_SX126X_CMD_SET_PA_CONFIG
#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07
Expand Down Expand Up @@ -1195,6 +1196,15 @@ class SX126x: public PhysicalLayer {
*/
int16_t setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = RADIOLIB_SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = RADIOLIB_SX126X_PA_CONFIG_PA_LUT);

/*!
\brief Perform image rejection calibration for the specified frequency.
Will try to use Semtech-defined presets first, and if none of them matches,
custom iamge calibration will be attempted using calibrateImageRejection.
\param freq Frequency to perform the calibration for.
\returns \ref status_codes
*/
int16_t calibrateImage(float freq);

/*!
\brief Perform image rejection calibration for the specified frequency band.
WARNING: Use at your own risk! Setting incorrect values may lead to decreased performance
Expand Down Expand Up @@ -1246,6 +1256,7 @@ class SX126x: public PhysicalLayer {
#endif
const char* chipType = NULL;
uint8_t bandwidth = 0;
float freqMHz = 0;

// Allow subclasses to define different TX modes
uint8_t txMode = Module::MODE_TX;
Expand Down Expand Up @@ -1276,7 +1287,6 @@ class SX126x: public PhysicalLayer {

uint32_t tcxoDelay = 0;
uint8_t pwr = 0;
uint32_t frf = 0;

size_t implicitLen = 0;
uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;
Expand Down
3 changes: 2 additions & 1 deletion src/modules/SX126x/SX126x_LR_FHSS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,8 @@ int16_t SX126x::setLRFHSSHop(uint8_t index) {
uint32_t nb_channel_in_grid = this->lrFhssGridNonFcc ? 8 : 52;
uint32_t grid_offset = (1 + (this->lrFhssNgrid % 2)) * (nb_channel_in_grid / 2);
uint32_t grid_in_pll_steps = this->lrFhssGridNonFcc ? 4096 : 26624;
uint32_t freq_raw = this->frf - freq_table * grid_in_pll_steps - grid_offset * 512;
uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
uint32_t freq_raw = frf - freq_table * grid_in_pll_steps - grid_offset * 512;

if((this->lrFhssHopNum < this->lrFhssHdrCount)) {
if((((this->lrFhssHdrCount - this->lrFhssHopNum) % 2) == 0)) {
Expand Down

0 comments on commit b8b1afd

Please sign in to comment.