Implemented optimal PA settings for SX1268.

Ensured OCP is always restored when changing power.
Slight refactor to avoid duplicated SX1262 / SX1268 code.
This commit is contained in:
BarryPSmith 2019-11-12 10:28:14 -08:00
parent 5b04badb36
commit 621da8a11d
7 changed files with 93 additions and 69 deletions

View file

@ -14,27 +14,33 @@ int16_t SX1261::setOutputPower(int8_t power) {
return(state); return(state);
} }
// set PA config for optimal consumption as described in section 13-21 of the datasheet: state = setOptimalLowPowerPaConfig(&power);
// the final column of Table 13-21 suggests that the value passed in SetTxParams is actually scaled depending on the parameters of setPaConfig. However, testing suggests this isn't the case.
if (power > 10) { // set output power
// TODO power ramp time configuration
if (state == ERR_NONE) {
state = SX126x::setTxParams(power);
}
// restore OCP configuration
int16_t state2 = writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
if (state != ERR_NONE) {
return state;
} else {
return state2;
}
}
int16_t SX1261::setOptimalLowPowerPaConfig(int8_t* inOutPower)
{
int16_t state;
if (*inOutPower > 10) {
state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1261, 0x00); state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1261, 0x00);
} }
else { else {
state = SX126x::setPaConfig(0x01, SX126X_PA_CONFIG_SX1261, 0x00); state = SX126x::setPaConfig(0x01, SX126X_PA_CONFIG_SX1261, 0x00);
*inOutPower -= 4;
} }
if (state != ERR_NONE) { return state;
return(state);
}
// TODO investigate if better power efficiency can be achieved using undocumented even lower settings
// set output power
// TODO power ramp time configuration
state = SX126x::setTxParams(power);
if (state != ERR_NONE) {
return state;
}
// restore OCP configuration
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1));
} }

View file

@ -6,23 +6,23 @@
#include "SX126x.h" #include "SX126x.h"
#include "SX1262.h" #include "SX1262.h"
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262 0x00
// TODO: implement SX1261 class // TODO: implement SX1261 class
class SX1261 : public SX1262 { class SX1261 : public SX1262 {
public: public:
/*! /*!
\brief Default constructor. \brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio. \param mod Instance of Module that will be used to communicate with the radio.
*/ */
SX1261(Module* mod) SX1261(Module* mod)
: SX1262(mod) { : SX1262(mod) {
} }
int16_t setOutputPower(int8_t power); int16_t setOutputPower(int8_t power);
private:
int16_t setOptimalLowPowerPaConfig(int8_t* inOutPower);
}; };

View file

@ -85,7 +85,7 @@ int16_t SX1262::setFrequency(float freq, bool calibrate) {
int16_t SX1262::setOutputPower(int8_t power) { int16_t SX1262::setOutputPower(int8_t power) {
// check allowed power range // check allowed power range
if (!((power >= -17) && (power <= 22))) { if (!(power >= -17 && power <= 22)) {
return(ERR_INVALID_OUTPUT_POWER); return(ERR_INVALID_OUTPUT_POWER);
} }
@ -96,42 +96,22 @@ int16_t SX1262::setOutputPower(int8_t power) {
return(state); return(state);
} }
int8_t scaledPower; // this function sets the optimal PA settings
// set PA config for optimal consumption as described in section 13-21 of the datasheet: // and scales our requested power based
// the final column of Table 13-21 suggests that the value passed in SetTxParams state = SX126x::setOptimalHiPowerPaConfig(&power);
// is actually scaled depending on the parameters of setPaConfig.
// Testing confirms this is approximately right
if (power >= 21) {
state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262, SX126X_PA_CONFIG_HP_MAX/*0x07*/);
scaledPower = power;
}
else if (power >= 18) {
state = SX126x::setPaConfig(0x03, SX126X_PA_CONFIG_SX1262, 0x05);
scaledPower = power + 2;
}
else if (power >= 15) {
state = SX126x::setPaConfig(0x02, SX126X_PA_CONFIG_SX1262, 0x03);
scaledPower = power + 5;
}
else {
state = SX126x::setPaConfig(0x02, SX126X_PA_CONFIG_SX1262, 0x02);
scaledPower = power + 8;
}
if (state != ERR_NONE) {
return(state);
}
// TODO investigate if better power efficiency can be achieved using undocumented even lower settings
// note that we set SX126X_PA_CONFIG_SX1262 for all power levels - setting SX126X_PA_CONFIG_SX1261 causes no output (on the nameless module I have).
// set output power // set output power
// TODO power ramp time configuration // TODO power ramp time configuration
state = SX126x::setTxParams(scaledPower); if (state == ERR_NONE) {
if (state != ERR_NONE) { state = SX126x::setTxParams(power);
return state;
} }
// restore OCP configuration // restore OCP configuration
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); int16_t state2 = writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
if (state != ERR_NONE) {
return state;
} else {
return state2;
}
} }

View file

@ -6,8 +6,6 @@
#include "SX126x.h" #include "SX126x.h"
//SX126X_CMD_SET_PA_CONFIG //SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262 0x00
/*! /*!
\class SX1262 \class SX1262

View file

@ -78,6 +78,9 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) {
int16_t SX1268::setOutputPower(int8_t power) { int16_t SX1268::setOutputPower(int8_t power) {
// check allowed power range // check allowed power range
// TODO with optimal PA config
// it's likely possible this could be expanded to go down to -17 just like for SX1262.
// but the datasheet doesn't explicitly state that and I don't have SX1268 unit to test with
if(!((power >= -9) && (power <= 22))) { if(!((power >= -9) && (power <= 22))) {
return(ERR_INVALID_OUTPUT_POWER); return(ERR_INVALID_OUTPUT_POWER);
} }
@ -89,13 +92,21 @@ int16_t SX1268::setOutputPower(int8_t power) {
return(state); return(state);
} }
// enable high power PA // enable optimal PA
SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268); state = SX126x::setOptimalHiPowerPaConfig(&power);
// set output power // set output power
// TODO power ramp time configuration // TODO power ramp time configuration
SX126x::setTxParams(power); if (state == ERR_NONE) {
state = SX126x::setTxParams(power);
}
// restore OCP configuration // restore OCP configuration
return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); int16_t state2 = writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1);
if (state != ERR_NONE) {
return state;
} else {
return state2;
}
} }

View file

@ -1127,6 +1127,32 @@ int16_t SX126x::setTxParams(uint8_t power, uint8_t rampTime) {
return(SPIwriteCommand(SX126X_CMD_SET_TX_PARAMS, data, 2)); return(SPIwriteCommand(SX126X_CMD_SET_TX_PARAMS, data, 2));
} }
// set PA config for optimal consumption as described in section 13-21 of the datasheet:
// the final column of Table 13-21 suggests that the value passed in SetTxParams
// is actually scaled depending on the parameters of setPaConfig.
// Testing confirms this is approximately right
int16_t SX126x::setOptimalHiPowerPaConfig(int8_t* inOutPower)
{
int16_t state;
if (*inOutPower >= 21) {
state = SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262_8, SX126X_PA_CONFIG_HP_MAX/*0x07*/);
}
else if (*inOutPower >= 18) {
state = SX126x::setPaConfig(0x03, SX126X_PA_CONFIG_SX1262_8, 0x05);
*inOutPower += 2;
}
else if (*inOutPower >= 15) {
state = SX126x::setPaConfig(0x02, SX126X_PA_CONFIG_SX1262_8, 0x03);
*inOutPower += 5;
}
else {
state = SX126x::setPaConfig(0x02, SX126X_PA_CONFIG_SX1262_8, 0x02);
*inOutPower += 8;
}
// TODO investigate if better power efficiency can be achieved using undocumented even lower settings
return state;
}
int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) { int16_t SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro) {
// calculate symbol length and enable low data rate optimization, if needed // calculate symbol length and enable low data rate optimization, if needed
if(ldro == 0xFF) { if(ldro == 0xFF) {

View file

@ -152,6 +152,8 @@
//SX126X_CMD_SET_PA_CONFIG //SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_HP_MAX 0x07 #define SX126X_PA_CONFIG_HP_MAX 0x07
#define SX126X_PA_CONFIG_PA_LUT 0x01 #define SX126X_PA_CONFIG_PA_LUT 0x01
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262_8 0x00
//SX126X_CMD_SET_RX_TX_FALLBACK_MODE //SX126X_CMD_SET_RX_TX_FALLBACK_MODE
#define SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode #define SX126X_RX_TX_FALLBACK_MODE_FS 0x40 // 7 0 after Rx/Tx go to: FS mode
@ -739,6 +741,7 @@ class SX126x: public PhysicalLayer {
int16_t calibrateImage(uint8_t* data); int16_t calibrateImage(uint8_t* data);
uint8_t getPacketType(); uint8_t getPacketType();
int16_t setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U); int16_t setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U);
int16_t setOptimalHiPowerPaConfig(int8_t* inOutPower);
int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF);
int16_t setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev); int16_t setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev);
int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength = 0xFF, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_STANDARD); int16_t setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength = 0xFF, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_STANDARD);