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);
}
// 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. However, testing suggests this isn't the case.
if (power > 10) {
state = setOptimalLowPowerPaConfig(&power);
// 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);
}
else {
state = SX126x::setPaConfig(0x01, SX126X_PA_CONFIG_SX1261, 0x00);
*inOutPower -= 4;
}
if (state != ERR_NONE) {
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));
return state;
}

View file

@ -6,23 +6,23 @@
#include "SX126x.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
class SX1261 : public SX1262 {
public:
/*!
\brief Default constructor.
public:
/*!
\brief Default constructor.
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1261(Module* mod)
: SX1262(mod) {
}
\param mod Instance of Module that will be used to communicate with the radio.
*/
SX1261(Module* 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) {
// check allowed power range
if (!((power >= -17) && (power <= 22))) {
if (!(power >= -17 && power <= 22)) {
return(ERR_INVALID_OUTPUT_POWER);
}
@ -96,42 +96,22 @@ int16_t SX1262::setOutputPower(int8_t power) {
return(state);
}
int8_t scaledPower;
// 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
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).
// this function sets the optimal PA settings
// and scales our requested power based
state = SX126x::setOptimalHiPowerPaConfig(&power);
// set output power
// TODO power ramp time configuration
state = SX126x::setTxParams(scaledPower);
if (state != ERR_NONE) {
return state;
if (state == ERR_NONE) {
state = SX126x::setTxParams(power);
}
// 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"
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262 0x00
/*!
\class SX1262

View file

@ -78,6 +78,9 @@ int16_t SX1268::setFrequency(float freq, bool calibrate) {
int16_t SX1268::setOutputPower(int8_t power) {
// 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))) {
return(ERR_INVALID_OUTPUT_POWER);
}
@ -89,13 +92,21 @@ int16_t SX1268::setOutputPower(int8_t power) {
return(state);
}
// enable high power PA
SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268);
// enable optimal PA
state = SX126x::setOptimalHiPowerPaConfig(&power);
// set output power
// TODO power ramp time configuration
SX126x::setTxParams(power);
if (state == ERR_NONE) {
state = SX126x::setTxParams(power);
}
// 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));
}
// 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) {
// calculate symbol length and enable low data rate optimization, if needed
if(ldro == 0xFF) {

View file

@ -152,6 +152,8 @@
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_HP_MAX 0x07
#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
#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);
uint8_t getPacketType();
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 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);