* 'master' of https://github.com/jgromes/RadioLib:
  Comment and error checking cleanup. Fixed power adjustment for SX1261
  Removed memory allocation and copying from SX126X read* and write* functions
  Implemented optimal PA settings for SX1268. Ensured OCP is always restored when changing power. Slight refactor to avoid duplicated SX1262 / SX1268 code.
  Fixed link to ESP32 package index
  Implemented power scaling in setOutputPower, in accordance with datasheet.
  Missed SX1261 PA Config flag in previous commit
  Adjusted setPaConfig in SX126x setOutputPower.
This commit is contained in:
Federico Maggi 2019-11-13 16:28:23 +01:00
commit f9a746cf82
8 changed files with 143 additions and 58 deletions

View file

@ -29,7 +29,7 @@ before_install:
- sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# install 3rd party boards
- arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://dl.espressif.com/dl/package_esp32_index.json,https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json" --save-prefs 2>&1
- arduino --pref "boardsmanager.additional.urls=http://arduino.esp8266.com/stable/package_esp8266com_index.json,https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json,https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json" --save-prefs 2>&1
- if [[ "$BOARD" =~ "esp8266:esp8266:" ]]; then
arduino --install-boards esp8266:esp8266;
export SKIP_PAT='(HTTP|MQTT).*ino';

50
src/modules/SX1261.cpp Normal file
View file

@ -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;
}

View file

@ -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

View file

@ -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);
}

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

@ -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);
}

View file

@ -1036,18 +1036,8 @@ int16_t SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMa
}
int16_t SX126x::writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
#ifdef STATIC_ONLY
uint8_t dat[STATIC_ARRAY_SIZE + 2];
#else
uint8_t* dat = new uint8_t[2 + numBytes];
#endif
dat[0] = (uint8_t)((addr >> 8) & 0xFF);
dat[1] = (uint8_t)(addr & 0xFF);
memcpy(dat + 2, data, numBytes);
int16_t state = SPIwriteCommand(SX126X_CMD_WRITE_REGISTER, dat, 2 + numBytes);
#ifndef STATIC_ONLY
delete[] dat;
#endif
uint8_t cmd[] = { SX126X_CMD_WRITE_REGISTER, (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
int16_t state = SPIwriteCommand(cmd, 3, data, numBytes);
return(state);
}
@ -1057,34 +1047,15 @@ int16_t SX126x::readRegister(uint16_t addr, uint8_t* data, uint8_t numBytes) {
}
int16_t SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
#ifdef STATIC_ONLY
uint8_t dat[STATIC_ARRAY_SIZE + 1];
#else
uint8_t* dat = new uint8_t[1 + numBytes];
#endif
dat[0] = offset;
memcpy(dat + 1, data, numBytes);
int16_t state = SPIwriteCommand(SX126X_CMD_WRITE_BUFFER, dat, 1 + numBytes);
#ifndef STATIC_ONLY
delete[] dat;
#endif
uint8_t cmd[] = { SX126X_CMD_WRITE_BUFFER, offset };
int16_t state = SPIwriteCommand(cmd, 2, data, numBytes);
return(state);
}
int16_t SX126x::readBuffer(uint8_t* data, uint8_t numBytes) {
// offset will be always set to 0 (one extra NOP is sent)
#ifdef STATIC_ONLY
uint8_t dat[STATIC_ARRAY_SIZE + 1];
#else
uint8_t* dat = new uint8_t[1 + numBytes];
#endif
dat[0] = SX126X_CMD_NOP;
memcpy(dat + 1, data, numBytes);
int16_t state = SPIreadCommand(SX126X_CMD_READ_BUFFER, dat, 1 + numBytes);
memcpy(data, dat + 1, numBytes);
#ifndef STATIC_ONLY
delete[] dat;
#endif
uint8_t cmd[] = { SX126X_CMD_READ_BUFFER, SX126X_CMD_NOP };
int16_t state = SPIreadCommand(cmd, 2, data, numBytes);
return(state);
}
@ -1127,6 +1098,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) {
@ -1265,14 +1262,20 @@ int16_t SX126x::config(uint8_t modem) {
return(ERR_NONE);
}
int16_t SX126x::SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
return(SX126x::SPItransfer(cmd, cmdLen, true, data, NULL, numBytes, waitForBusy));
}
int16_t SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
uint8_t cmdBuffer[] = {cmd};
return(SX126x::SPItransfer(cmdBuffer, 1, true, data, NULL, numBytes, waitForBusy));
return(SX126x::SPItransfer(&cmd, 1, true, data, NULL, numBytes, waitForBusy));
}
int16_t SX126x::SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
return(SX126x::SPItransfer(cmd, cmdLen, false, NULL, data, numBytes, waitForBusy));
}
int16_t SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
uint8_t cmdBuffer[] = {cmd};
return(SX126x::SPItransfer(cmdBuffer, 1, false, NULL, data, numBytes, waitForBusy));
return(SX126x::SPItransfer(&cmd, 1, false, NULL, data, numBytes, waitForBusy));
}
int16_t SX126x::SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout) {

View file

@ -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);
@ -769,7 +771,9 @@ class SX126x: public PhysicalLayer {
// common low-level SPI interface
int16_t SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIwriteCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPIreadCommand(uint8_t* cmd, uint8_t cmdLen, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
int16_t SPItransfer(uint8_t* cmd, uint8_t cmdLen, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy, uint32_t timeout = 5000);
};