/ RNode_Firmware_CE_G2 / sx127x.cpp
sx127x.cpp
1 // Copyright Sandeep Mistry, Mark Qvist and Jacob Eva. 2 // Licensed under the MIT license. 3 4 #include "Boards.h" 5 6 #if MODEM == SX1276 7 #include "sx127x.h" 8 9 #if MCU_VARIANT == MCU_ESP32 10 #if MCU_VARIANT == MCU_ESP32 and !defined(CONFIG_IDF_TARGET_ESP32S3) 11 #include "hal/wdt_hal.h" 12 #endif 13 #define ISR_VECT IRAM_ATTR 14 #else 15 #define ISR_VECT 16 #endif 17 18 // Registers 19 #define REG_FIFO_7X 0x00 20 #define REG_OP_MODE_7X 0x01 21 #define REG_FRF_MSB_7X 0x06 22 #define REG_FRF_MID_7X 0x07 23 #define REG_FRF_LSB_7X 0x08 24 #define REG_PA_CONFIG_7X 0x09 25 #define REG_OCP_7X 0x0b 26 #define REG_LNA_7X 0x0c 27 #define REG_FIFO_ADDR_PTR_7X 0x0d 28 #define REG_FIFO_TX_BASE_ADDR_7X 0x0e 29 #define REG_FIFO_RX_BASE_ADDR_7X 0x0f 30 #define REG_FIFO_RX_CURRENT_ADDR_7X 0x10 31 #define REG_IRQ_FLAGS_7X 0x12 32 #define REG_RX_NB_BYTES_7X 0x13 33 #define REG_MODEM_STAT_7X 0x18 34 #define REG_PKT_SNR_VALUE_7X 0x19 35 #define REG_PKT_RSSI_VALUE_7X 0x1a 36 #define REG_RSSI_VALUE_7X 0x1b 37 #define REG_MODEM_CONFIG_1_7X 0x1d 38 #define REG_MODEM_CONFIG_2_7X 0x1e 39 #define REG_PREAMBLE_MSB_7X 0x20 40 #define REG_PREAMBLE_LSB_7X 0x21 41 #define REG_PAYLOAD_LENGTH_7X 0x22 42 #define REG_MODEM_CONFIG_3_7X 0x26 43 #define REG_FREQ_ERROR_MSB_7X 0x28 44 #define REG_FREQ_ERROR_MID_7X 0x29 45 #define REG_FREQ_ERROR_LSB_7X 0x2a 46 #define REG_RSSI_WIDEBAND_7X 0x2c 47 #define REG_DETECTION_OPTIMIZE_7X 0x31 48 #define REG_HIGH_BW_OPTIMIZE_1_7X 0x36 49 #define REG_DETECTION_THRESHOLD_7X 0x37 50 #define REG_SYNC_WORD_7X 0x39 51 #define REG_HIGH_BW_OPTIMIZE_2_7X 0x3a 52 #define REG_DIO_MAPPING_1_7X 0x40 53 #define REG_VERSION_7X 0x42 54 #define REG_TCXO_7X 0x4b 55 #define REG_PA_DAC_7X 0x4d 56 57 // Modes 58 #define MODE_LONG_RANGE_MODE_7X 0x80 59 #define MODE_SLEEP_7X 0x00 60 #define MODE_STDBY_7X 0x01 61 #define MODE_TX_7X 0x03 62 #define MODE_RX_CONTINUOUS_7X 0x05 63 #define MODE_RX_SINGLE_7X 0x06 64 65 // PA config 66 #define PA_BOOST_7X 0x80 67 68 // IRQ masks 69 #define IRQ_TX_DONE_MASK_7X 0x08 70 #define IRQ_RX_DONE_MASK_7X 0x40 71 #define IRQ_PAYLOAD_CRC_ERROR_MASK_7X 0x20 72 73 #define SYNC_WORD_7X 0x12 74 #define MAX_PKT_LENGTH 255 75 76 extern SPIClass SPI; 77 78 sx127x::sx127x() : 79 _spiSettings(8E6, MSBFIRST, SPI_MODE0), 80 _ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), 81 _frequency(0), _packetIndex(0), _preinit_done(false), _onReceive(NULL) { setTimeout(0); } 82 83 void sx127x::setSPIFrequency(uint32_t frequency) { _spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0); } 84 void sx127x::setPins(int ss, int reset, int dio0, int busy) { _ss = ss; _reset = reset; _dio0 = dio0; _busy = busy; } 85 uint8_t ISR_VECT sx127x::readRegister(uint8_t address) { return singleTransfer(address & 0x7f, 0x00); } 86 void sx127x::writeRegister(uint8_t address, uint8_t value) { singleTransfer(address | 0x80, value); } 87 void sx127x::standby() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_STDBY_7X); } 88 void sx127x::sleep() { writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_SLEEP_7X); } 89 void sx127x::setSyncWord(uint8_t sw) { writeRegister(REG_SYNC_WORD_7X, sw); } 90 void sx127x::enableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) | 0x04); } 91 void sx127x::disableCrc() { writeRegister(REG_MODEM_CONFIG_2_7X, readRegister(REG_MODEM_CONFIG_2_7X) & 0xfb); } 92 void sx127x::enableTCXO() { uint8_t tcxo_reg = readRegister(REG_TCXO_7X); writeRegister(REG_TCXO_7X, tcxo_reg | 0x10); } 93 void sx127x::disableTCXO() { uint8_t tcxo_reg = readRegister(REG_TCXO_7X); writeRegister(REG_TCXO_7X, tcxo_reg & 0xEF); } 94 void sx127x::explicitHeaderMode() { _implicitHeaderMode = 0; writeRegister(REG_MODEM_CONFIG_1_7X, readRegister(REG_MODEM_CONFIG_1_7X) & 0xfe); } 95 void sx127x::implicitHeaderMode() { _implicitHeaderMode = 1; writeRegister(REG_MODEM_CONFIG_1_7X, readRegister(REG_MODEM_CONFIG_1_7X) | 0x01); } 96 byte sx127x::random() { return readRegister(REG_RSSI_WIDEBAND_7X); } 97 void sx127x::flush() { } 98 99 bool sx127x::preInit() { 100 pinMode(_ss, OUTPUT); 101 digitalWrite(_ss, HIGH); 102 103 #if BOARD_MODEL == BOARD_T3S3 104 SPI.begin(pin_sclk, pin_miso, pin_mosi, pin_cs); 105 #else 106 SPI.begin(); 107 #endif 108 109 // Check modem version 110 uint8_t version; 111 long start = millis(); 112 while (((millis() - start) < 500) && (millis() >= start)) { 113 version = readRegister(REG_VERSION_7X); 114 if (version == 0x12) { break; } 115 delay(100); 116 } 117 118 if (version != 0x12) { return false; } 119 _preinit_done = true; 120 return true; 121 } 122 123 uint8_t ISR_VECT sx127x::singleTransfer(uint8_t address, uint8_t value) { 124 uint8_t response; 125 126 digitalWrite(_ss, LOW); 127 SPI.beginTransaction(_spiSettings); 128 SPI.transfer(address); 129 response = SPI.transfer(value); 130 SPI.endTransaction(); 131 digitalWrite(_ss, HIGH); 132 133 return response; 134 } 135 136 int sx127x::begin(long frequency) { 137 if (_reset != -1) { 138 pinMode(_reset, OUTPUT); 139 digitalWrite(_reset, LOW); 140 delay(10); 141 digitalWrite(_reset, HIGH); 142 delay(10); 143 } 144 145 if (_busy != -1) { pinMode(_busy, INPUT); } 146 if (!_preinit_done) { if (!preInit()) { return false; } } 147 148 sleep(); 149 setFrequency(frequency); 150 151 // Set base addresses 152 writeRegister(REG_FIFO_TX_BASE_ADDR_7X, 0); 153 writeRegister(REG_FIFO_RX_BASE_ADDR_7X, 0); 154 155 // Set LNA boost and auto AGC 156 writeRegister(REG_LNA_7X, readRegister(REG_LNA_7X) | 0x03); 157 writeRegister(REG_MODEM_CONFIG_3_7X, 0x04); 158 159 setSyncWord(SYNC_WORD_7X); 160 enableCrc(); 161 setTxPower(2); 162 163 standby(); 164 165 return 1; 166 } 167 168 void sx127x::end() { sleep(); SPI.end(); _preinit_done = false; } 169 170 int sx127x::beginPacket(int implicitHeader) { 171 standby(); 172 173 if (implicitHeader) { implicitHeaderMode(); } 174 else { explicitHeaderMode(); } 175 176 // Reset FIFO address and payload length 177 writeRegister(REG_FIFO_ADDR_PTR_7X, 0); 178 writeRegister(REG_PAYLOAD_LENGTH_7X, 0); 179 180 return 1; 181 } 182 183 int sx127x::endPacket() { 184 // Enter TX mode 185 writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_TX_7X); 186 187 // Wait for TX completion 188 while ((readRegister(REG_IRQ_FLAGS_7X) & IRQ_TX_DONE_MASK_7X) == 0) { 189 yield(); 190 } 191 192 // Clear TX complete IRQ 193 writeRegister(REG_IRQ_FLAGS_7X, IRQ_TX_DONE_MASK_7X); 194 return 1; 195 } 196 197 bool sx127x::dcd() { 198 bool carrier_detected = false; 199 uint8_t status = readRegister(REG_MODEM_STAT_7X); 200 if ((status & SIG_DETECT) == SIG_DETECT) { carrier_detected = true; } 201 if ((status & SIG_SYNCED) == SIG_SYNCED) { carrier_detected = true; } 202 return carrier_detected; 203 } 204 205 uint8_t sx127x::currentRssiRaw() { 206 uint8_t rssi = readRegister(REG_RSSI_VALUE_7X); 207 return rssi; 208 } 209 210 int ISR_VECT sx127x::currentRssi() { 211 int rssi = (int)readRegister(REG_RSSI_VALUE_7X) - RSSI_OFFSET; 212 if (_frequency < 820E6) rssi -= 7; 213 return rssi; 214 } 215 216 uint8_t sx127x::packetRssiRaw() { 217 uint8_t pkt_rssi_value = readRegister(REG_PKT_RSSI_VALUE_7X); 218 return pkt_rssi_value; 219 } 220 221 int ISR_VECT sx127x::packetRssi(uint8_t pkt_snr_raw) { 222 int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET; 223 int pkt_snr = ((int8_t)pkt_snr_raw)*0.25; 224 225 if (_frequency < 820E6) pkt_rssi -= 7; 226 227 if (pkt_snr < 0) { 228 pkt_rssi += pkt_snr; 229 } else { 230 // Slope correction is (16/15)*pkt_rssi, 231 // this estimation looses one floating point 232 // operation, and should be precise enough. 233 pkt_rssi = (int)(1.066 * pkt_rssi); 234 } 235 return pkt_rssi; 236 } 237 238 int ISR_VECT sx127x::packetRssi() { 239 int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE_7X) - RSSI_OFFSET; 240 int pkt_snr = packetSnr(); 241 242 if (_frequency < 820E6) pkt_rssi -= 7; 243 244 if (pkt_snr < 0) { pkt_rssi += pkt_snr; } 245 else { 246 // Slope correction is (16/15)*pkt_rssi, 247 // this estimation looses one floating point 248 // operation, and should be precise enough. 249 pkt_rssi = (int)(1.066 * pkt_rssi); 250 } 251 return pkt_rssi; 252 } 253 254 uint8_t ISR_VECT sx127x::packetSnrRaw() { return readRegister(REG_PKT_SNR_VALUE_7X); } 255 256 float ISR_VECT sx127x::packetSnr() { return ((int8_t)readRegister(REG_PKT_SNR_VALUE_7X)) * 0.25; } 257 258 long sx127x::packetFrequencyError() { 259 int32_t freqError = 0; 260 freqError = static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MSB_7X) & B111); 261 freqError <<= 8L; 262 freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MID_7X)); 263 freqError <<= 8L; 264 freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_LSB_7X)); 265 266 if (readRegister(REG_FREQ_ERROR_MSB_7X) & B1000) { // Sign bit is on 267 freqError -= 524288; // B1000'0000'0000'0000'0000 268 } 269 270 const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14) 271 const float fError = ((static_cast<float>(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); 272 273 return static_cast<long>(fError); 274 } 275 276 size_t sx127x::write(uint8_t byte) { return write(&byte, sizeof(byte)); } 277 278 size_t sx127x::write(const uint8_t *buffer, size_t size) { 279 int currentLength = readRegister(REG_PAYLOAD_LENGTH_7X); 280 if ((currentLength + size) > MAX_PKT_LENGTH) { size = MAX_PKT_LENGTH - currentLength; } 281 282 for (size_t i = 0; i < size; i++) { writeRegister(REG_FIFO_7X, buffer[i]); } 283 writeRegister(REG_PAYLOAD_LENGTH_7X, currentLength + size); 284 285 return size; 286 } 287 288 int ISR_VECT sx127x::available() { return (readRegister(REG_RX_NB_BYTES_7X) - _packetIndex); } 289 290 int ISR_VECT sx127x::read() { 291 if (!available()) { return -1; } 292 _packetIndex++; 293 return readRegister(REG_FIFO_7X); 294 } 295 296 int sx127x::peek() { 297 if (!available()) { return -1; } 298 299 // Remember current FIFO address, read, and then reset address 300 int currentAddress = readRegister(REG_FIFO_ADDR_PTR_7X); 301 uint8_t b = readRegister(REG_FIFO_7X); 302 writeRegister(REG_FIFO_ADDR_PTR_7X, currentAddress); 303 304 return b; 305 } 306 307 void sx127x::onReceive(void(*callback)(int)) { 308 _onReceive = callback; 309 310 if (callback) { 311 pinMode(_dio0, INPUT); 312 writeRegister(REG_DIO_MAPPING_1_7X, 0x00); 313 314 #ifdef SPI_HAS_NOTUSINGINTERRUPT 315 SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); 316 #endif 317 318 attachInterrupt(digitalPinToInterrupt(_dio0), sx127x::onDio0Rise, RISING); 319 320 } else { 321 detachInterrupt(digitalPinToInterrupt(_dio0)); 322 323 #ifdef SPI_HAS_NOTUSINGINTERRUPT 324 SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0)); 325 #endif 326 } 327 } 328 329 void sx127x::receive(int size) { 330 if (size > 0) { 331 implicitHeaderMode(); 332 writeRegister(REG_PAYLOAD_LENGTH_7X, size & 0xff); 333 } else { explicitHeaderMode(); } 334 335 writeRegister(REG_OP_MODE_7X, MODE_LONG_RANGE_MODE_7X | MODE_RX_CONTINUOUS_7X); 336 } 337 338 void sx127x::setTxPower(int level, int outputPin) { 339 // Setup according to RFO or PA_BOOST output pin 340 if (PA_OUTPUT_RFO_PIN == outputPin) { 341 if (level < 0) { level = 0; } 342 else if (level > 14) { level = 14; } 343 344 writeRegister(REG_PA_DAC_7X, 0x84); 345 writeRegister(REG_PA_CONFIG_7X, 0x70 | level); 346 347 } else { 348 if (level < 2) { level = 2; } 349 else if (level > 17) { level = 17; } 350 351 writeRegister(REG_PA_DAC_7X, 0x84); 352 writeRegister(REG_PA_CONFIG_7X, PA_BOOST_7X | (level - 2)); 353 } 354 } 355 356 uint8_t sx127x::getTxPower() { byte txp = readRegister(REG_PA_CONFIG_7X); return txp; } 357 358 void sx127x::setFrequency(unsigned long frequency) { 359 _frequency = frequency; 360 uint32_t frf = ((uint64_t)frequency << 19) / 32000000; 361 362 writeRegister(REG_FRF_MSB_7X, (uint8_t)(frf >> 16)); 363 writeRegister(REG_FRF_MID_7X, (uint8_t)(frf >> 8)); 364 writeRegister(REG_FRF_LSB_7X, (uint8_t)(frf >> 0)); 365 366 optimizeModemSensitivity(); 367 } 368 369 uint32_t sx127x::getFrequency() { 370 uint8_t msb = readRegister(REG_FRF_MSB_7X); 371 uint8_t mid = readRegister(REG_FRF_MID_7X); 372 uint8_t lsb = readRegister(REG_FRF_LSB_7X); 373 374 uint32_t frf = ((uint32_t)msb << 16) | ((uint32_t)mid << 8) | (uint32_t)lsb; 375 uint64_t frm = (uint64_t)frf*32000000; 376 uint32_t frequency = (frm >> 19); 377 378 return frequency; 379 } 380 381 void sx127x::setSpreadingFactor(int sf) { 382 if (sf < 6) { sf = 6; } 383 else if (sf > 12) { sf = 12; } 384 385 if (sf == 6) { 386 writeRegister(REG_DETECTION_OPTIMIZE_7X, 0xc5); 387 writeRegister(REG_DETECTION_THRESHOLD_7X, 0x0c); 388 } else { 389 writeRegister(REG_DETECTION_OPTIMIZE_7X, 0xc3); 390 writeRegister(REG_DETECTION_THRESHOLD_7X, 0x0a); 391 } 392 393 writeRegister(REG_MODEM_CONFIG_2_7X, (readRegister(REG_MODEM_CONFIG_2_7X) & 0x0f) | ((sf << 4) & 0xf0)); 394 handleLowDataRate(); 395 } 396 397 long sx127x::getSignalBandwidth() { 398 byte bw = (readRegister(REG_MODEM_CONFIG_1_7X) >> 4); 399 switch (bw) { 400 case 0: return 7.8E3; 401 case 1: return 10.4E3; 402 case 2: return 15.6E3; 403 case 3: return 20.8E3; 404 case 4: return 31.25E3; 405 case 5: return 41.7E3; 406 case 6: return 62.5E3; 407 case 7: return 125E3; 408 case 8: return 250E3; 409 case 9: return 500E3; } 410 411 return 0; 412 } 413 414 void sx127x::setSignalBandwidth(long sbw) { 415 int bw; 416 if (sbw <= 7.8E3) { 417 bw = 0; 418 } else if (sbw <= 10.4E3) { 419 bw = 1; 420 } else if (sbw <= 15.6E3) { 421 bw = 2; 422 } else if (sbw <= 20.8E3) { 423 bw = 3; 424 } else if (sbw <= 31.25E3) { 425 bw = 4; 426 } else if (sbw <= 41.7E3) { 427 bw = 5; 428 } else if (sbw <= 62.5E3) { 429 bw = 6; 430 } else if (sbw <= 125E3) { 431 bw = 7; 432 } else if (sbw <= 250E3) { 433 bw = 8; 434 } else /*if (sbw <= 250E3)*/ { 435 bw = 9; 436 } 437 438 writeRegister(REG_MODEM_CONFIG_1_7X, (readRegister(REG_MODEM_CONFIG_1_7X) & 0x0f) | (bw << 4)); 439 handleLowDataRate(); 440 optimizeModemSensitivity(); 441 } 442 443 void sx127x::setCodingRate4(int denominator) { 444 if (denominator < 5) { denominator = 5; } 445 else if (denominator > 8) { denominator = 8; } 446 int cr = denominator - 4; 447 writeRegister(REG_MODEM_CONFIG_1_7X, (readRegister(REG_MODEM_CONFIG_1_7X) & 0xf1) | (cr << 1)); 448 } 449 450 void sx127x::setPreambleLength(long preamble_symbols) { 451 long length = preamble_symbols - 4; 452 writeRegister(REG_PREAMBLE_MSB_7X, (uint8_t)(length >> 8)); 453 writeRegister(REG_PREAMBLE_LSB_7X, (uint8_t)(length >> 0)); 454 } 455 456 extern bool lora_low_datarate; 457 void sx127x::handleLowDataRate() { 458 int sf = (readRegister(REG_MODEM_CONFIG_2_7X) >> 4); 459 if ( long( (1<<sf) / (getSignalBandwidth()/1000)) > 16) { 460 // Set auto AGC and LowDataRateOptimize 461 writeRegister(REG_MODEM_CONFIG_3_7X, (1<<3)|(1<<2)); 462 lora_low_datarate = true; 463 } else { 464 // Only set auto AGC 465 writeRegister(REG_MODEM_CONFIG_3_7X, (1<<2)); 466 lora_low_datarate = false; 467 } 468 } 469 470 void sx127x::optimizeModemSensitivity() { 471 byte bw = (readRegister(REG_MODEM_CONFIG_1_7X) >> 4); 472 uint32_t freq = getFrequency(); 473 474 if (bw == 9 && (410E6 <= freq) && (freq <= 525E6)) { 475 writeRegister(REG_HIGH_BW_OPTIMIZE_1_7X, 0x02); 476 writeRegister(REG_HIGH_BW_OPTIMIZE_2_7X, 0x7f); 477 } else if (bw == 9 && (820E6 <= freq) && (freq <= 1020E6)) { 478 writeRegister(REG_HIGH_BW_OPTIMIZE_1_7X, 0x02); 479 writeRegister(REG_HIGH_BW_OPTIMIZE_2_7X, 0x64); 480 } else { 481 writeRegister(REG_HIGH_BW_OPTIMIZE_1_7X, 0x03); 482 } 483 } 484 485 void ISR_VECT sx127x::handleDio0Rise() { 486 int irqFlags = readRegister(REG_IRQ_FLAGS_7X); 487 488 // Clear IRQs 489 writeRegister(REG_IRQ_FLAGS_7X, irqFlags); 490 if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK_7X) == 0) { 491 _packetIndex = 0; 492 int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH_7X) : readRegister(REG_RX_NB_BYTES_7X); 493 writeRegister(REG_FIFO_ADDR_PTR_7X, readRegister(REG_FIFO_RX_CURRENT_ADDR_7X)); 494 if (_onReceive) { _onReceive(packetLength); } 495 writeRegister(REG_FIFO_ADDR_PTR_7X, 0); 496 } 497 } 498 499 void ISR_VECT sx127x::onDio0Rise() { sx127x_modem.handleDio0Rise(); } 500 501 sx127x sx127x_modem; 502 503 #endif