[SX126x] Add experimental BPSK support

pull/1608/merge
jgromes 2025-10-21 20:16:22 +01:00
rodzic f6f72f9963
commit 1de98370eb
11 zmienionych plików z 154 dodań i 4 usunięć

Wyświetl plik

@ -227,6 +227,7 @@ setCrcFiltering KEYWORD2
beginFSK4 KEYWORD2
# SX126x-specific
beginBPSK KEYWORD2
setTCXO KEYWORD2
setDio2AsRfSwitch KEYWORD2
getTimeOnAir KEYWORD2

Wyświetl plik

@ -49,6 +49,24 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
return(state);
}
int16_t SX1262::beginBPSK(float freq, float br, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::beginBPSK(br, tcxoVoltage, useRegulatorLDO);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = SX126x::fixPaClamping();
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t SX1262::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO);

Wyświetl plik

@ -63,6 +63,20 @@ class SX1262: public SX126x {
*/
virtual int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
/*!
\brief Initialization method for BPSK modem.
NOTE: Proceed with caution! BPSK support in SX126x is epxerimental and poorly documented!
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param br FSK bit rate in kbps. Defaults to 600 bps, only 100 and 600 bps is supported
\param power Output power in dBm. Defaults to 10 dBm.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V.
If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
To use XTAL, either set this value to 0, or set SX126x::XTAL to true.
\param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
\returns \ref status_codes
*/
virtual int16_t beginBPSK(float freq = 434.0, float br = 0.6, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
/*!
\brief Initialization method for LR-FHSS modem. This modem only supports transmission!
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.

Wyświetl plik

@ -49,6 +49,24 @@ int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t
return(state);
}
int16_t SX1268::beginBPSK(float freq, float br, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::beginBPSK(br, tcxoVoltage, useRegulatorLDO);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = SX126x::fixPaClamping();
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t SX1268::beginLRFHSS(float freq, uint8_t bw, uint8_t cr, bool narrowGrid, int8_t power, float tcxoVoltage, bool useRegulatorLDO) {
// execute common part
int16_t state = SX126x::beginLRFHSS(bw, cr, narrowGrid, tcxoVoltage, useRegulatorLDO);

Wyświetl plik

@ -61,7 +61,21 @@ class SX1268: public SX126x {
\returns \ref status_codes
*/
int16_t beginFSK(float freq = 434.0, float br = 4.8, float freqDev = 5.0, float rxBw = 156.2, int8_t power = 10, uint16_t preambleLength = 16, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
/*!
\brief Initialization method for BPSK modem.
NOTE: Proceed with caution! BPSK support in SX126x is epxerimental and poorly documented!
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.
\param br FSK bit rate in kbps. Defaults to 600 bps, only 100 and 600 bps is supported.
\param power Output power in dBm. Defaults to 10 dBm.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V.
If you are seeing -706/-707 error codes, it likely means you are using non-0 value for module with XTAL.
To use XTAL, either set this value to 0, or set SX126x::XTAL to true.
\param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
\returns \ref status_codes
*/
virtual int16_t beginBPSK(float freq = 434.0, float br = 0.6, int8_t power = 10, float tcxoVoltage = 1.6, bool useRegulatorLDO = false);
/*!
\brief Initialization method for LR-FHSS modem. This modem only supports transmission!
\param freq Carrier frequency in MHz. Defaults to 434.0 MHz.

Wyświetl plik

@ -120,6 +120,22 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
return(state);
}
int16_t SX126x::beginBPSK(float br, float tcxoVoltage, bool useRegulatorLDO) {
// set module properties and perform initial setup
int16_t state = this->modSetup(tcxoVoltage, useRegulatorLDO, RADIOLIB_SX126X_PACKET_TYPE_BPSK);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setBitRate(br);
RADIOLIB_ASSERT(state);
// set publicly accessible settings that are not a part of begin method
state = setDio2AsRfSwitch(true);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t SX126x::beginLRFHSS(uint8_t bw, uint8_t cr, bool narrowGrid, float tcxoVoltage, bool useRegulatorLDO) {
this->lrFhssGridNonFcc = narrowGrid;
@ -898,8 +914,21 @@ RadioLibTime_t SX126x::getTimeOnAir(size_t len) {
dataRate.lrFhss.narrowGrid = this->lrFhssGridNonFcc;
packetConfig.lrFhss.hdrCount = this->lrFhssHdrCount;
} else if(type == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
// BPSK is so experimental it does not have a specific data rate structure
// so just reuse FSK
modem = RADIOLIB_MODEM_FSK;
dataRate.fsk.bitRate = RADIOLIB_SX126X_CRYSTAL_FREQ * 32.0f * 1000.0f / (float)this->bitRate;
dataRate.fsk.freqDev = 0;
packetConfig.fsk.preambleLength = 0;
packetConfig.fsk.syncWordLength = 0;
packetConfig.fsk.crcLength = 0;
} else {
return(RADIOLIB_ERR_WRONG_MODEM);
}
return(calculateTimeOnAir(modem, dataRate, packetConfig, len));
@ -1015,7 +1044,16 @@ int16_t SX126x::stageMode(RadioModeType_t mode, RadioModeConfig_t* cfg) {
} else if(modem == RADIOLIB_SX126X_PACKET_TYPE_GFSK) {
state = setPacketParamsFSK(this->preambleLengthFSK, this->preambleDetLength, this->crcTypeFSK, this->syncWordLength, RADIOLIB_SX126X_GFSK_ADDRESS_FILT_OFF, this->whitening, this->packetType, cfg->transmit.len);
} else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
uint16_t rampUp = RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_600_BPS;
uint16_t rampDown = RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_600_BPS;
if(this->bitRate == 100) {
rampUp = RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_100_BPS;
rampDown = RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_100_BPS;
}
state = setPacketParamsBPSK(cfg->transmit.len, rampUp, rampDown, 8*cfg->transmit.len);
} else if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
return(RADIOLIB_ERR_UNKNOWN);

Wyświetl plik

@ -86,6 +86,15 @@ class SX126x: public PhysicalLayer {
*/
int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float tcxoVoltage, bool useRegulatorLDO = false);
/*!
\brief Initialization method for BPSK modem.
\param br FSK bit rate in kbps. Only 100 and 600 bps is supported.
\param tcxoVoltage TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip.
\param useRegulatorLDO Whether to use only LDO regulator (true) or DC-DC regulator (false). Defaults to false.
\returns \ref status_codes
*/
int16_t beginBPSK(float br, float tcxoVoltage, bool useRegulatorLDO = false);
/*!
\brief Initialization method for LR-FHSS modem. This modem only supports transmission!
\param bw LR-FHSS bandwidth, one of RADIOLIB_SX126X_LR_FHSS_BW_* values.
@ -817,8 +826,10 @@ class SX126x: public PhysicalLayer {
int16_t setTxParams(uint8_t power, uint8_t rampTime);
int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro);
int16_t setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, uint32_t freqDev);
int16_t setModulationParamsBPSK(uint32_t br, uint8_t sh = RADIOLIB_SX126X_BPSK_PULSE_SHAPE);
int16_t setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ);
int16_t setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetectorLen, uint8_t crcType, uint8_t syncWordLen, uint8_t addrCmp, uint8_t whiten, uint8_t packType = RADIOLIB_SX126X_GFSK_PACKET_VARIABLE, uint8_t payloadLen = 0xFF);
int16_t setPacketParamsBPSK(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t payloadLenBits);
int16_t setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00);
int16_t setRegulatorMode(uint8_t mode);
uint8_t getStatus();

Wyświetl plik

@ -202,6 +202,11 @@ int16_t SX126x::setModulationParamsFSK(uint32_t br, uint8_t sh, uint8_t rxBw, ui
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, 8));
}
int16_t SX126x::setModulationParamsBPSK(uint32_t br, uint8_t sh) {
const uint8_t data[] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF), sh};
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_MODULATION_PARAMS, data, sizeof(data)));
}
int16_t SX126x::setPacketParams(uint16_t preambleLen, uint8_t crcType, uint8_t payloadLen, uint8_t hdrType, uint8_t invertIQ) {
int16_t state = fixInvertedIQ(invertIQ);
RADIOLIB_ASSERT(state);
@ -216,6 +221,19 @@ int16_t SX126x::setPacketParamsFSK(uint16_t preambleLen, uint8_t preambleDetecto
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, 9));
}
int16_t SX126x::setPacketParamsBPSK(uint8_t payloadLen, uint16_t rampUpDelay, uint16_t rampDownDelay, uint16_t payloadLenBits) {
const uint8_t data[] = { payloadLen,
(uint8_t)((rampUpDelay >> 8) & 0xFF), (uint8_t)(rampUpDelay & 0xFF),
(uint8_t)((rampDownDelay >> 8) & 0xFF), (uint8_t)(rampDownDelay & 0xFF),
(uint8_t)((payloadLenBits >> 8) & 0xFF), (uint8_t)(payloadLenBits & 0xFF)
};
// this one is a bit different, it seems to be split into command transaction and then a register write
int16_t state = this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS, data, sizeof(uint8_t));
RADIOLIB_ASSERT(state);
return(this->writeRegister(RADIOLIB_SX126X_REG_BPSK_PACKET_PARAMS, &data[1], sizeof(data) - sizeof(uint8_t)));
}
int16_t SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
const uint8_t data[2] = {txBaseAddress, rxBaseAddress};
return(this->mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2));

Wyświetl plik

@ -160,6 +160,7 @@
//RADIOLIB_SX126X_CMD_SET_PACKET_TYPE
#define RADIOLIB_SX126X_PACKET_TYPE_GFSK 0x00 // 7 0 packet type: GFSK
#define RADIOLIB_SX126X_PACKET_TYPE_LORA 0x01 // 7 0 LoRa
#define RADIOLIB_SX126X_PACKET_TYPE_BPSK 0x02 // 7 0 BPSK
#define RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS 0x03 // 7 0 LR-FHSS
//RADIOLIB_SX126X_CMD_SET_TX_PARAMS
@ -218,6 +219,7 @@
#define RADIOLIB_SX126X_LORA_CR_4_8_LI 0x07 // 7 0 4/8, long interleaver
#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF 0x00 // 7 0 LoRa low data rate optimization: disabled
#define RADIOLIB_SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON 0x01 // 7 0 enabled
#define RADIOLIB_SX126X_BPSK_PULSE_SHAPE 0x16 // 7 0 BSPK pulse shape double OSR, RRC, BT=0.7
//RADIOLIB_SX126X_CMD_SET_PACKET_PARAMS
#define RADIOLIB_SX126X_GFSK_PREAMBLE_DETECT_OFF 0x00 // 7 0 GFSK minimum preamble length before reception starts: detector disabled
@ -243,6 +245,12 @@
#define RADIOLIB_SX126X_LORA_CRC_ON 0x01 // 7 0 enabled
#define RADIOLIB_SX126X_LORA_IQ_STANDARD 0x00 // 7 0 LoRa IQ setup: standard
#define RADIOLIB_SX126X_LORA_IQ_INVERTED 0x01 // 7 0 inverted
#define RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_NONE 0x0000 // 15 0 BPSK ramp-up time optimization: none
#define RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_100_BPS 0x370F // 15 0 for 100 bps
#define RADIOLIB_SX126X_BPSK_RAMP_UP_TIME_600_BPS 0x092F // 15 0 for 600 bps
#define RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_NONE 0x0000 // 15 0 BPSK ramp-down time optimization: none
#define RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_100_BPS 0x1D70 // 15 0 for 100 bps
#define RADIOLIB_SX126X_BPSK_RAMP_DOWN_TIME_600_BPS 0x04E1 // 15 0 for 600 bps
//RADIOLIB_SX126X_CMD_SET_CAD_PARAMS
#define RADIOLIB_SX126X_CAD_ON_1_SYMB 0x00 // 7 0 number of symbols used for CAD: 1

Wyświetl plik

@ -217,12 +217,18 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) {
int16_t SX126x::setBitRate(float br) {
// check active modem
uint8_t modem = getPacketType();
if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) && (modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS)) {
if((modem != RADIOLIB_SX126X_PACKET_TYPE_GFSK) &&
(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) &&
(modem != RADIOLIB_SX126X_PACKET_TYPE_BPSK)) {
return(RADIOLIB_ERR_WRONG_MODEM);
}
if(modem != RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
if(modem == RADIOLIB_SX126X_PACKET_TYPE_LR_FHSS) {
RADIOLIB_CHECK_RANGE(br, 0.6f, 300.0f, RADIOLIB_ERR_INVALID_BIT_RATE);
} else if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
// this should be just either 100 or 600 bps, not the range
// but the BPSK support is so experimental it probably does not matter
RADIOLIB_CHECK_RANGE(br, 0.1f, 0.6f, RADIOLIB_ERR_INVALID_BIT_RATE);
}
// calculate raw bit rate value
@ -232,6 +238,9 @@ int16_t SX126x::setBitRate(float br) {
this->bitRate = brRaw;
// update modulation parameters
if(modem == RADIOLIB_SX126X_PACKET_TYPE_BPSK) {
return(setModulationParamsBPSK(this->bitRate));
}
return(setModulationParamsFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
}

Wyświetl plik

@ -6,6 +6,7 @@
#if !RADIOLIB_EXCLUDE_SX126X
// SX126X register map
#define RADIOLIB_SX126X_REG_BPSK_PACKET_PARAMS 0x00F0
#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_0 0x029F // SX1268 datasheet v1.1, section 9.6
#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_1 0x02A0 // SX1268 datasheet v1.1, section 9.6
#define RADIOLIB_SX126X_REG_RX_GAIN_RETENTION_2 0x02A1 // SX1268 datasheet v1.1, section 9.6