[SX126x] Calibrate image based on frequency change (#1292)

This commit is contained in:
jgromes 2024-10-27 07:40:10 +00:00
parent 28360f9b0f
commit b8b1afdae1
7 changed files with 79 additions and 78 deletions

View file

@ -1,4 +1,6 @@
#include "SX1262.h" #include "SX1262.h"
#include <math.h>
#if !RADIOLIB_EXCLUDE_SX126X #if !RADIOLIB_EXCLUDE_SX126X
SX1262::SX1262(Module* mod) : SX126x(mod) { SX1262::SX1262(Module* mod) : SX126x(mod) {
@ -66,49 +68,16 @@ int16_t SX1262::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid,
} }
int16_t SX1262::setFrequency(float freq) { 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); RADIOLIB_CHECK_RANGE(freq, 150.0, 960.0, RADIOLIB_ERR_INVALID_FREQUENCY);
// calibrate image rejection // check if we need to recalibrate image
if(calibrate) { if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) {
uint8_t data[2] = { 0, 0 }; int16_t state = this->calibrateImage(freq);
// 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);
}
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
} }
// set frequency // set frequency

View file

@ -81,6 +81,8 @@ class SX1262: public SX126x {
/*! /*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. \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 freq Carrier frequency to be set in MHz.
\returns \ref status_codes \returns \ref status_codes
*/ */
@ -88,11 +90,13 @@ class SX1262: public SX126x {
/*! /*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. \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 freq Carrier frequency to be set in MHz.
\param calibrate Run image calibration. \param skipCalibration Skip automated image calibration.
\returns \ref status_codes \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. \brief Sets output power. Allowed values are in range from -9 to 22 dBm.

View file

@ -1,4 +1,6 @@
#include "SX1268.h" #include "SX1268.h"
#include <math.h>
#if !RADIOLIB_EXCLUDE_SX126X #if !RADIOLIB_EXCLUDE_SX126X
SX1268::SX1268(Module* mod) : SX126x(mod) { SX1268::SX1268(Module* mod) : SX126x(mod) {
@ -66,44 +68,17 @@ int16_t SX1268::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid,
} }
int16_t SX1268::setFrequency(float freq) { int16_t SX1268::setFrequency(float freq) {
return(setFrequency(freq, true)); return(setFrequency(freq, false));
} }
/// \todo integers only (all modules - frequency, data rate, bandwidth etc.) /// \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); RADIOLIB_CHECK_RANGE(freq, 410.0, 810.0, RADIOLIB_ERR_INVALID_FREQUENCY);
// calibrate image rejection // check if we need to recalibrate image
if(calibrate) { if(!skipCalibration && (fabsf(freq - this->freqMHz) >= RADIOLIB_SX126X_CAL_IMG_FREQ_TRIG_MHZ)) {
uint8_t data[2] = { 0, 0 }; int16_t state = this->calibrateImage(freq);
// 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);
}
RADIOLIB_ASSERT(state); RADIOLIB_ASSERT(state);
} }
// set frequency // set frequency

View file

@ -80,6 +80,8 @@ class SX1268: public SX126x {
/*! /*!
\brief Sets carrier frequency. Allowed values are in range from 410.0 to 810.0 MHz. \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. \param freq Carrier frequency to be set in MHz.
\returns \ref status_codes \returns \ref status_codes
*/ */
@ -87,11 +89,13 @@ class SX1268: public SX126x {
/*! /*!
\brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. \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 freq Carrier frequency to be set in MHz.
\param calibrate Run image calibration. \param skipCalibration Skip automated image calibration.
\returns \ref status_codes \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. \brief Sets output power. Allowed values are in range from -9 to 22 dBm.

View file

@ -1954,6 +1954,43 @@ int16_t SX126x::setRfFrequency(uint32_t frf) {
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_RF_FREQUENCY, data, 4)); 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) { int16_t SX126x::calibrateImageRejection(float freqMin, float freqMax) {
// calculate the calibration coefficients and calibrate image // 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) }; uint8_t data[] = { (uint8_t)floor((freqMin - 1.0f) / 4.0f), (uint8_t)ceil((freqMax + 1.0f) / 4.0f) };
@ -2103,8 +2140,9 @@ int16_t SX126x::clearDeviceErrors() {
int16_t SX126x::setFrequencyRaw(float freq) { int16_t SX126x::setFrequencyRaw(float freq) {
// calculate raw value // calculate raw value
this->frf = (freq * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ; this->freqMHz = freq;
return(setRfFrequency(this->frf)); uint32_t frf = (this->freqMHz * (uint32_t(1) << RADIOLIB_SX126X_DIV_EXPONENT)) / RADIOLIB_SX126X_CRYSTAL_FREQ;
return(setRfFrequency(frf));
} }
int16_t SX126x::fixSensitivity() { int16_t SX126x::fixSensitivity() {

View file

@ -201,6 +201,7 @@
#define RADIOLIB_SX126X_CAL_IMG_863_MHZ_2 0xDB #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_1 0xE1
#define RADIOLIB_SX126X_CAL_IMG_902_MHZ_2 0xE9 #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 //RADIOLIB_SX126X_CMD_SET_PA_CONFIG
#define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07 #define RADIOLIB_SX126X_PA_CONFIG_HP_MAX 0x07
@ -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); 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. \brief Perform image rejection calibration for the specified frequency band.
WARNING: Use at your own risk! Setting incorrect values may lead to decreased performance WARNING: Use at your own risk! Setting incorrect values may lead to decreased performance
@ -1246,6 +1256,7 @@ class SX126x: public PhysicalLayer {
#endif #endif
const char* chipType = NULL; const char* chipType = NULL;
uint8_t bandwidth = 0; uint8_t bandwidth = 0;
float freqMHz = 0;
// Allow subclasses to define different TX modes // Allow subclasses to define different TX modes
uint8_t txMode = Module::MODE_TX; uint8_t txMode = Module::MODE_TX;
@ -1276,7 +1287,6 @@ class SX126x: public PhysicalLayer {
uint32_t tcxoDelay = 0; uint32_t tcxoDelay = 0;
uint8_t pwr = 0; uint8_t pwr = 0;
uint32_t frf = 0;
size_t implicitLen = 0; size_t implicitLen = 0;
uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD; uint8_t invertIQEnabled = RADIOLIB_SX126X_LORA_IQ_STANDARD;

View file

@ -355,7 +355,8 @@ int16_t SX126x::setLRFHSSHop(uint8_t index) {
uint32_t nb_channel_in_grid = this->lrFhssGridNonFcc ? 8 : 52; 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_offset = (1 + (this->lrFhssNgrid % 2)) * (nb_channel_in_grid / 2);
uint32_t grid_in_pll_steps = this->lrFhssGridNonFcc ? 4096 : 26624; 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->lrFhssHopNum < this->lrFhssHdrCount)) {
if((((this->lrFhssHdrCount - this->lrFhssHopNum) % 2) == 0)) { if((((this->lrFhssHdrCount - this->lrFhssHopNum) % 2) == 0)) {