Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/modules/LR2021/LR2021.h
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,17 @@ class LR2021: public LRxxxx {
*/
int16_t setOutputPower(int8_t power, uint32_t rampTimeUs);

/*!
\brief Sets custom PA configuration table.
\param table Pointer to user-provided PA configuration table.
The table MUST containt exactly RADIOLIB_LR2021_PA_TABLE_LEN entries,
one per each half-dBm step. The table is not copied, only reference to it is stored.
Set to NULL to return back to the default tables.
\param highFreq Whether this PA configuration is for the low-frequency sub-GHz PA (false),
or the high-frequency 2.4 GHz PA (true).
*/
void setPaTable(LR2021PaTableEntry_t* table, bool highFreq);

/*!
\brief Check if output power is configurable.
This method is needed for compatibility with PhysicalLayer::checkOutputPower.
Expand Down Expand Up @@ -729,6 +740,9 @@ class LR2021: public LRxxxx {
uint16_t bitRateFlrc = 0;
uint8_t codingRateFlrc = 0;

// pointers to PA lookup tables - may be overridden by the user
LR2021PaTableEntry_t* paOptTable[2] = { nullptr, nullptr };

int16_t modSetup(float freq, float tcxoVoltage, uint8_t modem);
bool findChip(void);
int16_t config(uint8_t modem);
Expand Down
2 changes: 1 addition & 1 deletion src/modules/LR2021/LR2021_cmds_radio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ int16_t LR2021::setPaConfig(uint8_t pa, uint8_t paLfMode, uint8_t paLfDutyCycle,
}

int16_t LR2021::setTxParams(int8_t txPower, uint8_t rampTime) {
uint8_t buff[] = { (uint8_t)(txPower * 2), rampTime };
uint8_t buff[] = { (uint8_t)txPower, rampTime };
return(this->SPIcommand(RADIOLIB_LR2021_CMD_SET_TX_PARAMS, true, buff, sizeof(buff)));
}

Expand Down
1 change: 1 addition & 0 deletions src/modules/LR2021/LR2021_commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@
#define RADIOLIB_LR2021_PA_HIGH_POWER (0x01UL << 0) // 1 0 high-power

// RADIOLIB_LR2021_CMD_SET_PA_CONFIG
#define RADIOLIB_LR2021_PA_TABLE_LEN (32)
#define RADIOLIB_LR2021_PA_LF_MODE_FSM (0x00UL << 0) // 1 0 PA LF mode: full single-ended mode
#define RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED (0x06UL << 0) // 7 4 PA LF duty cycle: PA not used
#define RADIOLIB_LR2021_PA_LF_SLICES_UNUSED (0x07UL << 0) // 3 0 PA LF slices: PA not used
Expand Down
94 changes: 89 additions & 5 deletions src/modules/LR2021/LR2021_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,76 @@
// maximum number of allowed frontend calibration attempts
#define RADIOLIB_LR2021_MAX_CAL_ATTEMPTS (10)

static const LR2021PaTableEntry_t paOptTableLf[RADIOLIB_LR2021_PA_TABLE_LEN] = {
{ .paDutyCycle = 1, .paSlices = 1, .paVal = 8 },
{ .paDutyCycle = 2, .paSlices = 2, .paVal = 1 },
{ .paDutyCycle = 2, .paSlices = 2, .paVal = 3 },
{ .paDutyCycle = 2, .paSlices = 2, .paVal = 5 },
{ .paDutyCycle = 1, .paSlices = 2, .paVal = 13 },
{ .paDutyCycle = 2, .paSlices = 1, .paVal = 13 },
{ .paDutyCycle = 2, .paSlices = 2, .paVal = 11 },
{ .paDutyCycle = 2, .paSlices = 2, .paVal = 13 },
{ .paDutyCycle = 3, .paSlices = 1, .paVal = 12 },
{ .paDutyCycle = 1, .paSlices = 1, .paVal = 18 },
{ .paDutyCycle = 1, .paSlices = 1, .paVal = 20 },
{ .paDutyCycle = 1, .paSlices = 1, .paVal = 23 },
{ .paDutyCycle = 1, .paSlices = 1, .paVal = 27 },
{ .paDutyCycle = 1, .paSlices = 1, .paVal = 33 },
{ .paDutyCycle = 1, .paSlices = 2, .paVal = 26 },
{ .paDutyCycle = 1, .paSlices = 2, .paVal = 31 },
{ .paDutyCycle = 1, .paSlices = 3, .paVal = 27 },
{ .paDutyCycle = 1, .paSlices = 1, .paVal = 37 },
{ .paDutyCycle = 1, .paSlices = 2, .paVal = 40 },
{ .paDutyCycle = 2, .paSlices = 1, .paVal = 38 },
{ .paDutyCycle = 2, .paSlices = 2, .paVal = 39 },
{ .paDutyCycle = 2, .paSlices = 4, .paVal = 40 },
{ .paDutyCycle = 2, .paSlices = 7, .paVal = 41 },
{ .paDutyCycle = 3, .paSlices = 2, .paVal = 39 },
{ .paDutyCycle = 3, .paSlices = 3, .paVal = 39 },
{ .paDutyCycle = 3, .paSlices = 6, .paVal = 38 },
{ .paDutyCycle = 4, .paSlices = 3, .paVal = 37 },
{ .paDutyCycle = 4, .paSlices = 5, .paVal = 37 },
{ .paDutyCycle = 4, .paSlices = 7, .paVal = 38 },
{ .paDutyCycle = 5, .paSlices = 3, .paVal = 37 },
{ .paDutyCycle = 5, .paSlices = 6, .paVal = 37 },
{ .paDutyCycle = 6, .paSlices = 7, .paVal = 35 },
};

static const LR2021PaTableEntry_t paOptTableHf[RADIOLIB_LR2021_PA_TABLE_LEN] = {
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -38 }, // -19
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -36 }, // -18
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -34 }, // -17
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -32 }, // -16
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -30 }, // -15
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -28 }, // -14
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -26 }, // -13
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -24 }, // -12
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -22 }, // -11
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -20 }, // -10
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -18 }, // -9
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -16 }, // -8
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -14 }, // -7
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -12 }, // -6
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -10 }, // -5
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -8 }, // -4
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -6 }, // -3
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -4 }, // -2
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = -2 }, // -1
{ .paDutyCycle = 14, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 4 }, // 0
{ .paDutyCycle = 14, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 6 }, // 1
{ .paDutyCycle = 12, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 7 }, // 2
{ .paDutyCycle = 9, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 8 }, // 3
{ .paDutyCycle = 9, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 10 }, // 4
{ .paDutyCycle = 15, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 15 }, // 5
{ .paDutyCycle = 14, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 16 }, // 6
{ .paDutyCycle = 14, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 18 }, // 7
{ .paDutyCycle = 15, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 21 }, // 8
{ .paDutyCycle = 14, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 22 }, // 9
{ .paDutyCycle = 14, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 24 }, // 10
{ .paDutyCycle = 10, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 24 }, // 11
{ .paDutyCycle = 0, .paSlices = RADIOLIB_LR2021_PA_LF_SLICES_UNUSED, .paVal = 24 }, // 12
};

int16_t LR2021::setFrequency(float freq) {
return(this->setFrequency(freq, false));
}
Expand Down Expand Up @@ -81,20 +151,34 @@ int16_t LR2021::setOutputPower(int8_t power, uint32_t rampTimeUs) {
RADIOLIB_ASSERT(state);

//! \TODO: [LR2021] how and when to configure OCP?
//! \TODO: [LR2021] Determine the optimal PA configuration

// poitners to default tables
LR2021PaTableEntry_t* defaultTables[] = {
const_cast<LR2021PaTableEntry_t*>(paOptTableLf),
const_cast<LR2021PaTableEntry_t*>(paOptTableHf),
};

// if the user pointers are not set, use the appropriate (LF/HF) default table
LR2021PaTableEntry_t* table = this->paOptTable[this->highFreq] ? this->paOptTable[this->highFreq] : defaultTables[this->highFreq];

// update PA config
const LR2021PaTableEntry_t* paCfg = this->highFreq ? &table[power + 19] : &table[power + 9];
state = setPaConfig(this->highFreq,
RADIOLIB_LR2021_PA_LF_MODE_FSM,
RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED,
RADIOLIB_LR2021_PA_LF_SLICES_UNUSED,
RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED);
this->highFreq ? RADIOLIB_LR2021_PA_LF_DUTY_CYCLE_UNUSED : paCfg->paDutyCycle,
paCfg->paSlices,
this->highFreq ? (paCfg->paDutyCycle + RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED) : RADIOLIB_LR2021_PA_HF_DUTY_CYCLE_UNUSED);
RADIOLIB_ASSERT(state);

// set output power
state = setTxParams(power, roundRampTime(rampTimeUs));
state = setTxParams(paCfg->paVal, roundRampTime(rampTimeUs));
return(state);
}

void LR2021::setPaTable(LR2021PaTableEntry_t* table, bool highFreq) {
this->paOptTable[highFreq] = table;
}

int16_t LR2021::checkOutputPower(int8_t power, int8_t* clipped) {
if(this->highFreq) {
if(clipped) {
Expand Down
11 changes: 11 additions & 0 deletions src/modules/LR2021/LR2021_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,17 @@ struct LR2021LoRaSideDetector_t {
uint8_t syncWord;
};

/*!
\struct paTableEntry_t
\brief This structure is used as entry in the PA lookup table,
to optimize PA configuration for minimum power consumption.
*/
struct __attribute__((packed)) LR2021PaTableEntry_t {
uint8_t paDutyCycle: 4;
uint8_t paSlices: 4;
int8_t paVal;
};

#endif

#endif
Loading