diff --git a/src/modules/SX1261.cpp b/src/modules/SX1261.cpp new file mode 100644 index 00000000..06e37d73 --- /dev/null +++ b/src/modules/SX1261.cpp @@ -0,0 +1,50 @@ +#include "SX1261.h" + +SX1261::SX1261(Module* mod) + : SX1262(mod) { + +} + +int16_t SX1261::setOutputPower(int8_t power) { + // check allowed power range + if (!((power >= -17) && (power <= 14))) { + return(ERR_INVALID_OUTPUT_POWER); + } + + // get current OCP configuration + uint8_t ocp = 0; + int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1); + if (state != ERR_NONE) { + return(state); + } + + state = setOptimalLowPowerPaConfig(&power); + if (state != ERR_NONE) { + return(state); + } + + // 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); +} + +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); + // changing the PaConfig means output power is now scaled so we get 3 dB less than requested. + // see datasheet table 13-21 and comments in setOptimalHiPowerPaConfig. + *inOutPower -= 3; + } + return state; +} diff --git a/src/modules/SX1261.h b/src/modules/SX1261.h index cb8a5758..48667055 100644 --- a/src/modules/SX1261.h +++ b/src/modules/SX1261.h @@ -8,9 +8,29 @@ //SX126X_CMD_SET_PA_CONFIG #define SX126X_PA_CONFIG_SX1261 0x01 -#define SX126X_PA_CONFIG_SX1262 0x00 // TODO: implement SX1261 class -using SX1261 = SX1262; +class SX1261 : public SX1262 { + public: + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1261(Module* mod); + + /*! + \brief Sets output power. Allowed values are in range from -17 to 14 dBm. + + \param power Output power to be set in dBm. + + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); + + private: + int16_t setOptimalLowPowerPaConfig(int8_t* inOutPower); +}; + #endif diff --git a/src/modules/SX1262.cpp b/src/modules/SX1262.cpp index 0bcce47d..73731972 100644 --- a/src/modules/SX1262.cpp +++ b/src/modules/SX1262.cpp @@ -85,28 +85,32 @@ 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); } // get current OCP configuration uint8_t ocp = 0; int16_t state = readRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1); - if(state != ERR_NONE) { + if (state != ERR_NONE) { return(state); } - // enable high power PA for output power higher than 14 dBm - if(power > 13) { - SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262); - } else { - SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1261); + // this function sets the optimal PA settings + // and adjusts power based on the PA settings chosen + // so that output power matches requested power. + state = SX126x::setOptimalHiPowerPaConfig(&power); + if (state != ERR_NONE) { + return(state); } // set output power // TODO power ramp time configuration - SX126x::setTxParams(power); + state = SX126x::setTxParams(power); + if (state != ERR_NONE) { + return(state); + } // restore OCP configuration - return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); + return writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1); } diff --git a/src/modules/SX1262.h b/src/modules/SX1262.h index 88a49576..b9a26a5f 100644 --- a/src/modules/SX1262.h +++ b/src/modules/SX1262.h @@ -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 diff --git a/src/modules/SX1268.cpp b/src/modules/SX1268.cpp index c0b01a80..3ffb9a2a 100644 --- a/src/modules/SX1268.cpp +++ b/src/modules/SX1268.cpp @@ -89,13 +89,19 @@ int16_t SX1268::setOutputPower(int8_t power) { return(state); } - // enable high power PA - SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268); + // enable optimal PA - this changes the value of power. + state = SX126x::setOptimalHiPowerPaConfig(&power); + if (state != ERR_NONE) { + return(state); + } // set output power // TODO power ramp time configuration - SX126x::setTxParams(power); + state = SX126x::setTxParams(power); + if (state != ERR_NONE) { + return(state); + } // restore OCP configuration - return(writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1)); + return writeRegister(SX126X_REG_OCP_CONFIGURATION, &ocp, 1); } diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp index e47ad31c..3868e098 100644 --- a/src/modules/SX126x.cpp +++ b/src/modules/SX126x.cpp @@ -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. +int16_t SX126x::setOptimalHiPowerPaConfig(int8_t * inOutPower) +{ + // 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 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); + // datasheet instructs request 22 dBm for 20 dBm actual output power + *inOutPower += 2; + } else if (*inOutPower >= 15) { + state = SX126x::setPaConfig(0x02, SX126X_PA_CONFIG_SX1262_8, 0x03); + // datasheet instructs request 22 dBm for 17 dBm actual output power + *inOutPower += 5; + } else { + state = SX126x::setPaConfig(0x02, SX126X_PA_CONFIG_SX1262_8, 0x02); + // datasheet instructs request 22 dBm for 14 dBm actual output power. + *inOutPower += 8; + } + 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) { diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h index 641d6445..4c3dc61c 100644 --- a/src/modules/SX126x.h +++ b/src/modules/SX126x.h @@ -152,6 +152,7 @@ //SX126X_CMD_SET_PA_CONFIG #define SX126X_PA_CONFIG_HP_MAX 0x07 #define SX126X_PA_CONFIG_PA_LUT 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 +740,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);