[SX126x] Fixed config
This commit is contained in:
parent
56b636f54f
commit
ba82497c8e
3 changed files with 168 additions and 64 deletions
|
@ -1,27 +1,33 @@
|
|||
#include "SX1262.h"
|
||||
|
||||
SX1262::SX1262(Module* mod) : SX126x(mod) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, int8_t power, float currentLimit, uint16_t preambleLength) {
|
||||
// execute common part
|
||||
int16_t state = SX126x::begin(bw, sf, cr, syncWord, currentLimit, preambleLength);
|
||||
int16_t state = SX126x::begin(bw, sf, cr, syncWord, preambleLength);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
// configure publicly accessible settings
|
||||
state = setFrequency(freq);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
state = setOutputPower(power);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
// OCP must be configured after PA
|
||||
state = SX126x::setCurrentLimit(currentLimit);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
@ -30,7 +36,7 @@ int16_t SX1262::setFrequency(float freq) {
|
|||
if((freq < 150.0) || (freq > 960.0)) {
|
||||
return(ERR_INVALID_FREQUENCY);
|
||||
}
|
||||
|
||||
|
||||
// set frequency
|
||||
return(SX126x::setFrequencyRaw(freq));
|
||||
}
|
||||
|
@ -40,17 +46,16 @@ int16_t SX1262::setOutputPower(int8_t power) {
|
|||
if(!((power >= -17) && (power <= 22))) {
|
||||
return(ERR_INVALID_OUTPUT_POWER);
|
||||
}
|
||||
|
||||
|
||||
// enable high power PA for output power higher than 14 dBm
|
||||
if(power > 14) {
|
||||
if(power > 13) {
|
||||
SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1262);
|
||||
} else {
|
||||
SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1261);
|
||||
}
|
||||
|
||||
|
||||
// set output power
|
||||
// TODO power ramp time configuration
|
||||
SX126x::setTxParams(power);
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,48 +12,51 @@ SX126x::SX126x(Module* mod) : PhysicalLayer(SX126X_CRYSTAL_FREQ, SX126X_DIV_EXPO
|
|||
_preambleLength = 8;
|
||||
}
|
||||
|
||||
int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength) {
|
||||
int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength) {
|
||||
// set module properties
|
||||
_mod->init(USE_SPI, INT_BOTH);
|
||||
pinMode(_mod->getRx(), INPUT);
|
||||
|
||||
pinMode(_mod->getTx(), INPUT);
|
||||
|
||||
// reset module
|
||||
reset();
|
||||
|
||||
// get status and errors
|
||||
getStatus();
|
||||
getDeviceErrors();
|
||||
|
||||
// set mode to standby
|
||||
standby();
|
||||
|
||||
|
||||
// configure settings not accessible by API
|
||||
config();
|
||||
|
||||
|
||||
// configure publicly accessible settings
|
||||
int16_t state = setBandwidth(bw);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
state = setSpreadingFactor(sf);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
state = setCodingRate(cr);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
state = setSyncWord(syncWord);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
state = setCurrentLimit(currentLimit);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
state = setPreambleLength(preambleLength);
|
||||
if(state != ERR_NONE) {
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
|
@ -70,7 +73,7 @@ int16_t SX126x::transmitDirect(uint32_t frf) {
|
|||
if(frf != 0) {
|
||||
setRfFrequency(frf);
|
||||
}
|
||||
|
||||
|
||||
// start transmitting
|
||||
uint8_t data[] = {SX126X_CMD_NOP};
|
||||
SPIwriteCommand(SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1);
|
||||
|
@ -84,10 +87,10 @@ int16_t SX126x::receiveDirect() {
|
|||
int16_t SX126x::sleep() {
|
||||
uint8_t data[] = {SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF};
|
||||
SPIwriteCommand(SX126X_CMD_SET_SLEEP, data, 1);
|
||||
|
||||
|
||||
// wait for SX126x to safely enter sleep mode
|
||||
delayMicroseconds(500);
|
||||
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
|
@ -97,6 +100,16 @@ int16_t SX126x::standby(uint8_t mode) {
|
|||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
void SX126x::reset() {
|
||||
delay(10);
|
||||
pinMode(_mod->getTx(), OUTPUT);
|
||||
digitalWrite(_mod->getTx(), LOW);
|
||||
delay(20);
|
||||
digitalWrite(_mod->getTx(), HIGH);
|
||||
pinMode(_mod->getTx(), INPUT);
|
||||
delay(10);
|
||||
}
|
||||
|
||||
int16_t SX126x::setBandwidth(float bw) {
|
||||
// check active modem
|
||||
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
|
||||
|
@ -127,7 +140,7 @@ int16_t SX126x::setBandwidth(float bw) {
|
|||
} else {
|
||||
return(ERR_INVALID_BANDWIDTH);
|
||||
}
|
||||
|
||||
|
||||
// update modulation parameters
|
||||
_bwKhz = bw;
|
||||
setModulationParams(_sf, _bw, _cr);
|
||||
|
@ -139,12 +152,12 @@ int16_t SX126x::setSpreadingFactor(uint8_t sf) {
|
|||
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
|
||||
// check allowed spreading factor values
|
||||
if(!((sf >= 5) && (sf <= 12))) {
|
||||
return(ERR_INVALID_SPREADING_FACTOR);
|
||||
}
|
||||
|
||||
|
||||
// update modulation parameters
|
||||
_sf = sf;
|
||||
setModulationParams(_sf, _bw, _cr);
|
||||
|
@ -156,12 +169,12 @@ int16_t SX126x::setCodingRate(uint8_t cr) {
|
|||
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
|
||||
// check allowed spreading factor values
|
||||
if(!((cr >= 5) && (cr <= 8))) {
|
||||
return(ERR_INVALID_CODING_RATE);
|
||||
}
|
||||
|
||||
|
||||
// update modulation parameters
|
||||
_cr = cr - 4;
|
||||
setModulationParams(_sf, _bw, _cr);
|
||||
|
@ -173,7 +186,7 @@ int16_t SX126x::setSyncWord(uint16_t syncWord) {
|
|||
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
|
||||
// update register
|
||||
uint8_t data[2] = {(uint8_t)((syncWord >> 8) & 0xFF), (uint8_t)(syncWord & 0xFF)};
|
||||
writeRegister(SX126X_REG_LORA_SYNC_WORD_MSB, data, 2);
|
||||
|
@ -183,7 +196,7 @@ int16_t SX126x::setSyncWord(uint16_t syncWord) {
|
|||
int16_t SX126x::setCurrentLimit(float currentLimit) {
|
||||
// calculate raw value
|
||||
uint8_t rawLimit = (uint8_t)(currentLimit / 2.5);
|
||||
|
||||
|
||||
// update register
|
||||
writeRegister(SX126X_REG_OCP_CONFIGURATION, &rawLimit, 1);
|
||||
return(ERR_NONE);
|
||||
|
@ -202,6 +215,7 @@ float SX126x::getDataRate() {
|
|||
|
||||
int16_t SX126x::setFrequencyDeviation(float freqDev) {
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
void SX126x::setTx(uint32_t timeout) {
|
||||
|
@ -219,7 +233,7 @@ void SX126x::setCad() {
|
|||
}
|
||||
|
||||
void SX126x::setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax, uint8_t paLut) {
|
||||
uint8_t data[4] = {paDutyCycle, deviceSel, hpMax, paLut};
|
||||
uint8_t data[4] = {paDutyCycle, hpMax, deviceSel, paLut};
|
||||
SPIwriteCommand(SX126X_CMD_SET_PA_CONFIG, data, 4);
|
||||
}
|
||||
|
||||
|
@ -273,7 +287,7 @@ void SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldr
|
|||
} else {
|
||||
_ldro = ldro;
|
||||
}
|
||||
|
||||
|
||||
uint8_t data[4] = {sf, bw, cr, _ldro};
|
||||
SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 4);
|
||||
}
|
||||
|
@ -284,9 +298,40 @@ void SX126x::setPacketParams(uint16_t preambleLength, uint8_t payloadLength, uin
|
|||
}
|
||||
|
||||
uint8_t SX126x::getStatus() {
|
||||
uint8_t data[1];
|
||||
/*uint8_t data[1];
|
||||
SPIreadCommand(SX126X_CMD_GET_STATUS, data, 1);
|
||||
return(data[0]);
|
||||
return(data[0]);*/
|
||||
|
||||
// get pointer to used SPI interface
|
||||
SPIClass* spi = _mod->getSpi();
|
||||
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
// TODO timeout
|
||||
while(digitalRead(_mod->getRx()));
|
||||
|
||||
// start transfer
|
||||
digitalWrite(_mod->getCs(), LOW);
|
||||
spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
// send command byte
|
||||
spi->transfer(SX126X_CMD_GET_STATUS);
|
||||
DEBUG_PRINT(SX126X_CMD_GET_STATUS, HEX);
|
||||
DEBUG_PRINT('\t');
|
||||
|
||||
// get status
|
||||
uint8_t status = spi->transfer(SX126X_CMD_NOP) & 0b01111110;
|
||||
DEBUG_PRINTLN(status, HEX);
|
||||
|
||||
// stop transfer
|
||||
spi->endTransaction();
|
||||
digitalWrite(_mod->getCs(), HIGH);
|
||||
|
||||
// wait for BUSY to go high and then low
|
||||
// TODO timeout
|
||||
delayMicroseconds(1);
|
||||
while(digitalRead(_mod->getRx()));
|
||||
|
||||
return(status);
|
||||
}
|
||||
|
||||
uint8_t SX126x::getRssiInt() {
|
||||
|
@ -295,8 +340,41 @@ uint8_t SX126x::getRssiInt() {
|
|||
return(data[0]);
|
||||
}
|
||||
|
||||
int16_t SX126x::setFrequencyRaw(float freq) {
|
||||
// TODO CalibrateImage
|
||||
uint16_t SX126x::getDeviceErrors() {
|
||||
uint8_t data[2];
|
||||
SPIreadCommand(SX126X_CMD_GET_DEVICE_ERRORS, data, 2);
|
||||
uint16_t opError = (((uint16_t)data[0] & 0xFF) << 8) & ((uint16_t)data[1]);
|
||||
return(opError);
|
||||
}
|
||||
|
||||
void SX126x::clearDeviceErrors() {
|
||||
uint8_t data[1] = {SX126X_CMD_NOP};
|
||||
SPIwriteCommand(SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 1);
|
||||
}
|
||||
|
||||
int16_t SX126x::setFrequencyRaw(float freq, bool calibrate) {
|
||||
// calibrate image
|
||||
if(calibrate) {
|
||||
uint8_t data[2];
|
||||
if(freq > 900.0) {
|
||||
data[0] = SX126X_CAL_IMG_902_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_902_MHZ_2;
|
||||
} else if(freq > 850.0) {
|
||||
data[0] = SX126X_CAL_IMG_863_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_863_MHZ_2;
|
||||
} else if(freq > 770.0) {
|
||||
data[0] = SX126X_CAL_IMG_779_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_779_MHZ_2;
|
||||
} else if(freq > 460.0) {
|
||||
data[0] = SX126X_CAL_IMG_470_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_470_MHZ_2;
|
||||
} else {
|
||||
data[0] = SX126X_CAL_IMG_430_MHZ_1;
|
||||
data[1] = SX126X_CAL_IMG_430_MHZ_2;
|
||||
}
|
||||
SPIwriteCommand(SX126X_CMD_CALIBRATE_IMAGE, data, 2);
|
||||
}
|
||||
|
||||
// calculate raw value
|
||||
uint32_t frf = (freq * (uint32_t(1) << SX126X_DIV_EXPONENT)) / SX126X_CRYSTAL_FREQ;
|
||||
setRfFrequency(frf);
|
||||
|
@ -304,15 +382,32 @@ int16_t SX126x::setFrequencyRaw(float freq) {
|
|||
}
|
||||
|
||||
int16_t SX126x::config() {
|
||||
// set LoRa mode
|
||||
// set DIO2 as RF switch
|
||||
uint8_t* data = new uint8_t[1];
|
||||
data[0] = SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL;
|
||||
SPIwriteCommand(SX126X_DIO2_AS_RF_SWITCH, data, 1);
|
||||
|
||||
// set regulator mode
|
||||
data[0] = SX126X_REGULATOR_DC_DC;
|
||||
SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1);
|
||||
|
||||
// set buffer base address
|
||||
delete[] data;
|
||||
data = new uint8_t[2];
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x00;
|
||||
SPIwriteCommand(SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2);
|
||||
|
||||
// set LoRa mode
|
||||
delete[] data;
|
||||
data = new uint8_t[1];
|
||||
data[0] = SX126X_PACKET_TYPE_LORA;
|
||||
SPIwriteCommand(SX126X_CMD_SET_PACKET_TYPE, data, 1);
|
||||
|
||||
|
||||
// set Rx/Tx fallback mode to STDBY_RC
|
||||
data[0] = SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
|
||||
SPIwriteCommand(SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
|
||||
|
||||
|
||||
// set CAD parameters
|
||||
delete[] data;
|
||||
data = new uint8_t[7];
|
||||
|
@ -324,8 +419,7 @@ int16_t SX126x::config() {
|
|||
data[5] = 0x00;
|
||||
data[6] = 0x00;
|
||||
SPIwriteCommand(SX126X_CMD_SET_CAD_PARAMS, data, 7);
|
||||
delete[] data;
|
||||
|
||||
|
||||
return(ERR_NONE);
|
||||
}
|
||||
|
||||
|
@ -340,20 +434,20 @@ void SX126x::SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool w
|
|||
void SX126x::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dataIn, uint8_t numBytes, bool waitForBusy) {
|
||||
// get pointer to used SPI interface
|
||||
SPIClass* spi = _mod->getSpi();
|
||||
|
||||
|
||||
// ensure BUSY is low (state meachine ready)
|
||||
// TODO timeout
|
||||
while(digitalRead(_mod->getRx()));
|
||||
|
||||
|
||||
// start transfer
|
||||
digitalWrite(_mod->getCs(), LOW);
|
||||
spi->beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0));
|
||||
|
||||
|
||||
// send command byte
|
||||
spi->transfer(cmd);
|
||||
DEBUG_PRINT(cmd, HEX);
|
||||
DEBUG_PRINT('\t');
|
||||
|
||||
|
||||
// send/receive all bytes
|
||||
if(write) {
|
||||
for(uint8_t n = 0; n < numBytes; n++) {
|
||||
|
@ -380,11 +474,11 @@ void SX126x::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* dat
|
|||
}
|
||||
DEBUG_PRINTLN();
|
||||
}
|
||||
|
||||
|
||||
// stop transfer
|
||||
spi->endTransaction();
|
||||
digitalWrite(_mod->getCs(), HIGH);
|
||||
|
||||
|
||||
// wait for BUSY to go high and then low
|
||||
// TODO timeout
|
||||
if(waitForBusy) {
|
||||
|
|
|
@ -165,6 +165,8 @@
|
|||
#define SX126X_IRQ_PREAMBLE_DETECTED 0b0000000100 // 2 2 preamble detected
|
||||
#define SX126X_IRQ_RX_DONE 0b0000000010 // 1 1 packet received
|
||||
#define SX126X_IRQ_TX_DONE 0b0000000001 // 0 0 packet transmission completed
|
||||
#define SX126X_IRQ_ALL 0b1111111111 // 9 0 all interrupts
|
||||
#define SX126X_IRQ_NONE 0b0000000000 // 9 0 no interrupts
|
||||
|
||||
//SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL
|
||||
#define SX126X_DIO2_AS_IRQ 0x00 // 7 0 DIO2 configuration: IRQ
|
||||
|
@ -316,19 +318,20 @@ class SX126x: public PhysicalLayer {
|
|||
// introduce PhysicalLayer overloads
|
||||
using PhysicalLayer::transmit;
|
||||
using PhysicalLayer::receive;
|
||||
|
||||
|
||||
// constructor
|
||||
SX126x(Module* mod);
|
||||
|
||||
|
||||
// basic methods
|
||||
int16_t begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, float currentLimit, uint16_t preambleLength);
|
||||
int16_t begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength);
|
||||
int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0);
|
||||
int16_t receive(uint8_t* data, size_t len);
|
||||
int16_t transmitDirect(uint32_t frf = 0);
|
||||
int16_t receiveDirect();
|
||||
int16_t sleep();
|
||||
int16_t standby(uint8_t mode = SX126X_STANDBY_RC);
|
||||
|
||||
void reset();
|
||||
|
||||
// configuration methods
|
||||
int16_t setBandwidth(float bw);
|
||||
int16_t setSpreadingFactor(uint8_t sf);
|
||||
|
@ -338,7 +341,7 @@ class SX126x: public PhysicalLayer {
|
|||
int16_t setPreambleLength(uint16_t preambleLength);
|
||||
float getDataRate();
|
||||
int16_t setFrequencyDeviation(float freqDev);
|
||||
|
||||
|
||||
protected:
|
||||
// SX1276x SPI command implementations
|
||||
void setTx(uint32_t timeout = 0);
|
||||
|
@ -350,23 +353,25 @@ class SX126x: public PhysicalLayer {
|
|||
void clearIrqStatus(uint16_t clearIrqParams = 0xFFFF);
|
||||
void setRfFrequency(uint32_t frf);
|
||||
uint8_t getPacketType();
|
||||
void setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_80U);
|
||||
void setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_40U);
|
||||
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF);
|
||||
void setPacketParams(uint16_t preambleLength, uint8_t payloadLength, uint8_t crcType, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_STANDARD);
|
||||
void setPacketParams(uint16_t preambleLength, uint8_t payloadLength, uint8_t crcType, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_INVERTED);
|
||||
uint8_t getStatus();
|
||||
uint8_t getRssiInt();
|
||||
|
||||
int16_t setFrequencyRaw(float freq);
|
||||
|
||||
uint16_t getDeviceErrors();
|
||||
void clearDeviceErrors();
|
||||
|
||||
int16_t setFrequencyRaw(float freq, bool calibrate = true);
|
||||
|
||||
private:
|
||||
Module* _mod;
|
||||
|
||||
|
||||
uint8_t _bw, _sf, _cr, _ldro, _payloadLength, _crcType;
|
||||
uint16_t _preambleLength;
|
||||
float _bwKhz;
|
||||
|
||||
|
||||
int16_t config();
|
||||
|
||||
|
||||
// common low-level SPI interface
|
||||
void SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
|
||||
void SPIreadCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);
|
||||
|
|
Loading…
Add table
Reference in a new issue