/ 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