diff --git a/src/modules/SX1262.cpp b/src/modules/SX1262.cpp index 0e8a6377..9aad7281 100644 --- a/src/modules/SX1262.cpp +++ b/src/modules/SX1262.cpp @@ -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); } - diff --git a/src/modules/SX126x.cpp b/src/modules/SX126x.cpp index 324531ff..4fa6477d 100644 --- a/src/modules/SX126x.cpp +++ b/src/modules/SX126x.cpp @@ -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) { diff --git a/src/modules/SX126x.h b/src/modules/SX126x.h index c3d9cab5..909e32f8 100644 --- a/src/modules/SX126x.h +++ b/src/modules/SX126x.h @@ -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);