From 5c2bd2bc320c10287f70f7bc4a66216fe82c0d83 Mon Sep 17 00:00:00 2001 From: jgromes Date: Mon, 3 Jun 2019 10:41:39 +0200 Subject: [PATCH] [SX126x] Added SX1268 implementation --- src/modules/SX1262.cpp | 29 +++++++++++- src/modules/SX1262.h | 4 +- src/modules/SX1268.cpp | 104 +++++++++++++++++++++++++++++++++++++++++ src/modules/SX1268.h | 90 +++++++++++++++++++++++++++++++++-- src/modules/SX126x.cpp | 47 +++++-------------- src/modules/SX126x.h | 6 +-- 6 files changed, 235 insertions(+), 45 deletions(-) create mode 100644 src/modules/SX1268.cpp diff --git a/src/modules/SX1262.cpp b/src/modules/SX1262.cpp index e46a3431..218751ab 100644 --- a/src/modules/SX1262.cpp +++ b/src/modules/SX1262.cpp @@ -58,12 +58,39 @@ int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t return(state); } -int16_t SX1262::setFrequency(float freq) { +int16_t SX1262::setFrequency(float freq, bool calibrate) { // check frequency range if((freq < 150.0) || (freq > 960.0)) { return(ERR_INVALID_FREQUENCY); } + int16_t state = ERR_NONE; + + // 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; + } + state = SX126x::calibrateImage(data); + if(state != ERR_NONE) { + return(state); + } + } + // set frequency return(SX126x::setFrequencyRaw(freq)); } diff --git a/src/modules/SX1262.h b/src/modules/SX1262.h index 88fa961f..88a49576 100644 --- a/src/modules/SX1262.h +++ b/src/modules/SX1262.h @@ -78,9 +78,11 @@ class SX1262: public SX126x { \param freq Carrier frequency to be set in MHz. + \param calibrate Run image calibration. + \returns \ref status_codes */ - int16_t setFrequency(float freq); + int16_t setFrequency(float freq, bool calibrate = true); /*! \brief Sets output power. Allowed values are in range from -17 to 22 dBm. diff --git a/src/modules/SX1268.cpp b/src/modules/SX1268.cpp new file mode 100644 index 00000000..95718f0c --- /dev/null +++ b/src/modules/SX1268.cpp @@ -0,0 +1,104 @@ +#include "SX1268.h" + +SX1268::SX1268(Module* mod) : SX126x(mod) { + +} + +int16_t SX1268::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, 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); +} +int16_t SX1268::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping) { + // execute common part + int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, dataShaping); + 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); +} + +int16_t SX1268::setFrequency(float freq, bool calibrate) { + // check frequency range + if((freq < 410.0) || (freq > 810.0)) { + return(ERR_INVALID_FREQUENCY); + } + + int16_t state = ERR_NONE; + + // calibrate image + if(calibrate) { + uint8_t data[2]; + 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; + } + state = SX126x::calibrateImage(data); + if(state != ERR_NONE) { + return(state); + } + } + + // set frequency + return(SX126x::setFrequencyRaw(freq)); +} + +int16_t SX1268::setOutputPower(int8_t power) { + // check allowed power range + if(!((power >= -9) && (power <= 22))) { + return(ERR_INVALID_OUTPUT_POWER); + } + + // enable high power PA + SX126x::setPaConfig(0x04, SX126X_PA_CONFIG_SX1268); + + // set output power + // TODO power ramp time configuration + SX126x::setTxParams(power); + return(ERR_NONE); +} diff --git a/src/modules/SX1268.h b/src/modules/SX1268.h index 8f00ecd5..9c05529d 100644 --- a/src/modules/SX1268.h +++ b/src/modules/SX1268.h @@ -4,13 +4,93 @@ #include "TypeDef.h" #include "Module.h" #include "SX126x.h" -#include "SX1262.h" //SX126X_CMD_SET_PA_CONFIG -#define SX126X_PA_CONFIG_SX1261 0x01 -#define SX126X_PA_CONFIG_SX1262 0x00 +#define SX126X_PA_CONFIG_SX1268 0x00 -// TODO: implement SX1268 class -using SX1268 = SX1262; +/*! + \class SX1268 + + \brief Derived class for %SX1268 modules. +*/ +class SX1268: public SX126x { + public: + /*! + \brief Default constructor. + + \param mod Instance of Module that will be used to communicate with the radio. + */ + SX1268(Module* mod); + + // basic methods + + /*! + \brief Initialization method for LoRa modem. + + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + + \param bw LoRa bandwidth in kHz. Defaults to 125.0 kHz. + + \param sf LoRa spreading factor. Defaults to 9. + + \param cr LoRa coding rate denominator. Defaults to 7 (coding rate 4/7). + + \param syncWord 2-byte LoRa sync word. Defaults to SX126X_SYNC_WORD_PRIVATE (0x1424). + + \param power Output power in dBm. Defaults to 14 dBm. + + \param currentLimit Current protection limit in mA. Defaults to 60.0 mA. + + \param preambleLength LoRa preamble length in symbols.Defaults to 8 symbols. + + \returns \ref status_codes + */ + int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint16_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8); + + /*! + \brief Initialization method for FSK modem. + + \param freq Carrier frequency in MHz. Defaults to 434.0 MHz. + + \param br FSK bit rate in kbps. Defaults to 48.0 kbps. + + \param freqDev Frequency deviation from carrier frequency in kHz. Defaults to 50.0 kHz. + + \param rxBw Receiver bandwidth in kHz. Defaults to 156.2 kHz. + + \param power Output power in dBm. Defaults to 14 dBm. + + \param currentLimit Current protection limit in mA. Defaults to 60.0 mA. + + \parma preambleLength FSK preamble length in bits. Defaults to 16 bits. + + \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5. + + \returns \ref status_codes + */ + int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 156.2, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 16, float dataShaping = 0.5); + + // configuration methods + + /*! + \brief Sets carrier frequency. Allowed values are in range from 150.0 to 960.0 MHz. + + \param freq Carrier frequency to be set in MHz. + + \param calibrate Run image calibration. + + \returns \ref status_codes + */ + int16_t setFrequency(float freq, bool calibrate = true); + + /*! + \brief Sets output power. Allowed values are in range from -17 to 22 dBm. + + \param power Output power to be set in dBm. + + \returns \ref status_codes + */ + int16_t setOutputPower(int8_t power); +}; #endif diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp index ca18bbc8..05274763 100644 --- a/src/modules/SX126x.cpp +++ b/src/modules/SX126x.cpp @@ -576,9 +576,9 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) { uint32_t freqDevRaw = (uint32_t)(((freqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (SX126X_CRYSTAL_FREQ * 1000000.0)); // check modulation parameters - if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) { + /*if(2 * freqDevRaw + _br > _rxBwKhz * 1000.0) { return(ERR_INVALID_MODULATION_PARAMETERS); - } + }*/ _freqDev = freqDevRaw; // update modulation parameters @@ -600,9 +600,9 @@ int16_t SX126x::setBitRate(float br) { uint32_t brRaw = (uint32_t)((SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0)); // check modulation parameters - if(2 * _freqDev + brRaw > _rxBwKhz * 1000.0) { + /*if(2 * _freqDev + brRaw > _rxBwKhz * 1000.0) { return(ERR_INVALID_MODULATION_PARAMETERS); - } + }*/ _br = brRaw; // update modulation parameters @@ -616,9 +616,9 @@ int16_t SX126x::setRxBandwidth(float rxBw) { } // check modulation parameters - if(2 * _freqDev + _br > rxBw * 1000.0) { + /*if(2 * _freqDev + _br > rxBw * 1000.0) { return(ERR_INVALID_MODULATION_PARAMETERS); - } + }*/ _rxBwKhz = rxBw; // check alowed receiver bandwidth values @@ -968,6 +968,10 @@ int16_t SX126x::setRfFrequency(uint32_t frf) { return(SPIwriteCommand(SX126X_CMD_SET_RF_FREQUENCY, data, 4)); } +int16_t SX126x::calibrateImage(uint8_t* data) { + return(SPIwriteCommand(SX126X_CMD_CALIBRATE_IMAGE, data, 2)); +} + uint8_t SX126x::getPacketType() { uint8_t data = 0xFF; SPIreadCommand(SX126X_CMD_GET_PACKET_TYPE, &data, 1); @@ -1047,34 +1051,7 @@ int16_t SX126x::clearDeviceErrors() { return(SPIwriteCommand(SX126X_CMD_CLEAR_DEVICE_ERRORS, data, 1)); } -int16_t SX126x::setFrequencyRaw(float freq, bool calibrate) { - int16_t state = ERR_NONE; - - // 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; - } - state = SPIwriteCommand(SX126X_CMD_CALIBRATE_IMAGE, data, 2); - if(state != ERR_NONE) { - return(state); - } - } - +int16_t SX126x::setFrequencyRaw(float freq) { // calculate raw value uint32_t frf = (freq * (uint32_t(1) << SX126X_DIV_EXPONENT)) / SX126X_CRYSTAL_FREQ; setRfFrequency(frf); @@ -1184,7 +1161,7 @@ int16_t SX126x::SPItransfer(uint8_t cmd, bool write, uint8_t* dataOut, uint8_t* DEBUG_PRINT('\t'); // variable to save error during SPI transfer - uint8_t status; + uint8_t status = 0; // send/receive all bytes if(write) { diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h index 9bcd6187..a9a84b4b 100644 --- a/src/modules/SX126x.h +++ b/src/modules/SX126x.h @@ -150,7 +150,6 @@ //SX126X_CMD_SET_PA_CONFIG #define SX126X_PA_CONFIG_HP_MAX 0x07 -#define SX126X_PA_CONFIG_SX1268 0x01 #define SX126X_PA_CONFIG_PA_LUT 0x01 //SX126X_CMD_SET_RX_TX_FALLBACK_MODE @@ -366,7 +365,7 @@ class SX126x: public PhysicalLayer { \param rxBw Receiver bandwidth in kHz. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz. - \parma preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535. + \param preambleLength FSK preamble length in bits. Allowed values range from 0 to 65535. \param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Allowed values are 0.3, 0.5, 0.7 and 1.0. Set to 0 to disable shaping. @@ -692,6 +691,7 @@ class SX126x: public PhysicalLayer { uint16_t getIrqStatus(); int16_t clearIrqStatus(uint16_t clearIrqParams = SX126X_IRQ_ALL); int16_t setRfFrequency(uint32_t frf); + int16_t calibrateImage(uint8_t* data); uint8_t getPacketType(); int16_t setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U); int16_t setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF); @@ -704,7 +704,7 @@ class SX126x: public PhysicalLayer { uint16_t getDeviceErrors(); int16_t clearDeviceErrors(); - int16_t setFrequencyRaw(float freq, bool calibrate = true); + int16_t setFrequencyRaw(float freq); private: Module* _mod;