makes GPIO_PIN_RST optional for the sx1276
[ExpressLRS.git] / src / lib / SX127xDriver / SX127x.cpp
blob9a88b2ad180acc602b83e7a5f0a86af33b2bf184
1 #include "SX127x.h"
2 #include "logging.h"
4 SX127xHal hal;
6 void inline SX127xDriver::nullCallback(void) {}
7 SX127xDriver *SX127xDriver::instance = NULL;
9 void (*SX127xDriver::RXdoneCallback)() = &nullCallback;
10 void (*SX127xDriver::TXdoneCallback)() = &nullCallback;
12 void (*SX127xDriver::TXtimeout)() = &nullCallback;
13 void (*SX127xDriver::RXtimeout)() = &nullCallback;
15 volatile WORD_ALIGNED_ATTR uint8_t SX127xDriver::TXdataBuffer[TXRXBuffSize] = {0};
16 volatile WORD_ALIGNED_ATTR uint8_t SX127xDriver::RXdataBuffer[TXRXBuffSize] = {0};
18 const uint8_t SX127x_AllowedSyncwords[105] =
19 {0, 5, 6, 7, 11, 12, 13, 15, 18,
20 21, 23, 26, 29, 30, 31, 33, 34,
21 37, 38, 39, 40, 42, 44, 50, 51,
22 54, 55, 57, 58, 59, 61, 63, 65,
23 67, 68, 71, 77, 78, 79, 80, 82,
24 84, 86, 89, 92, 94, 96, 97, 99,
25 101, 102, 105, 106, 109, 111, 113, 115,
26 117, 118, 119, 121, 122, 124, 126, 127,
27 129, 130, 138, 143, 161, 170, 172, 173,
28 175, 180, 181, 182, 187, 190, 191, 192,
29 193, 196, 199, 201, 204, 205, 208, 209,
30 212, 213, 219, 220, 221, 223, 227, 229,
31 235, 239, 240, 242, 243, 246, 247, 255};
33 //////////////////////////////////////////////
35 SX127xDriver::SX127xDriver()
37 instance = this;
40 bool SX127xDriver::Begin()
42 DBGLN("SX127x Driver Begin");
43 hal.IsrCallback = &SX127xDriver::IsrCallback;
44 hal.init();
46 if (DetectChip())
48 ConfigLoraDefaults();
49 return true;
51 else
53 return false;
57 void SX127xDriver::End()
59 SetMode(SX127x_OPMODE_SLEEP);
60 hal.end();
61 TXdoneCallback = &nullCallback; // remove callbacks
62 RXdoneCallback = &nullCallback;
65 void SX127xDriver::ConfigLoraDefaults()
67 hal.writeRegister(SX127X_REG_OP_MODE, SX127x_OPMODE_SLEEP);
68 hal.writeRegister(SX127X_REG_OP_MODE, ModFSKorLoRa); //must be written in sleep mode
69 SetMode(SX127x_OPMODE_STANDBY);
71 hal.writeRegister(SX127X_REG_PAYLOAD_LENGTH, PayloadLength);
72 SetSyncWord(currSyncWord);
73 hal.writeRegister(SX127X_REG_FIFO_TX_BASE_ADDR, SX127X_FIFO_TX_BASE_ADDR_MAX);
74 hal.writeRegister(SX127X_REG_FIFO_RX_BASE_ADDR, SX127X_FIFO_RX_BASE_ADDR_MAX);
75 hal.setRegValue(SX127X_REG_DIO_MAPPING_1, 0b11000000, 7, 6); //undocumented "hack", looking at Table 18 from datasheet SX127X_REG_DIO_MAPPING_1 = 11 appears to be unspported by infact it generates an intterupt on both RXdone and TXdone, this saves switching modes.
76 hal.writeRegister(SX127X_REG_LNA, SX127X_LNA_BOOST_ON);
77 hal.writeRegister(SX1278_REG_MODEM_CONFIG_3, SX1278_AGC_AUTO_ON | SX1278_LOW_DATA_RATE_OPT_OFF);
78 hal.setRegValue(SX127X_REG_OCP, SX127X_OCP_ON | SX127X_OCP_150MA, 5, 0); //150ma max current
79 SetPreambleLength(SX127X_PREAMBLE_LENGTH_LSB);
80 hal.setRegValue(SX127X_REG_INVERT_IQ, (uint8_t)IQinverted, 6, 6);
83 void SX127xDriver::SetBandwidthCodingRate(SX127x_Bandwidth bw, SX127x_CodingRate cr)
85 if ((currBW != bw) || (currCR != cr))
87 if (currSF == SX127x_SF_6) // set SF6 optimizations
89 hal.writeRegister(SX127X_REG_MODEM_CONFIG_1, bw | cr | SX1278_HEADER_IMPL_MODE);
90 hal.setRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_OFF, 2, 2);
92 else
94 if (headerExplMode)
96 hal.writeRegister(SX127X_REG_MODEM_CONFIG_1, bw | cr | SX1278_HEADER_EXPL_MODE);
98 else
100 hal.writeRegister(SX127X_REG_MODEM_CONFIG_1, bw | cr | SX1278_HEADER_IMPL_MODE);
103 if (crcEnabled)
105 hal.setRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_ON, 2, 2);
107 else
109 hal.setRegValue(SX127X_REG_MODEM_CONFIG_2, SX1278_RX_CRC_MODE_OFF, 2, 2);
113 if (bw == SX127x_BW_500_00_KHZ)
115 //datasheet errata reconmendation http://caxapa.ru/thumbs/972894/SX1276_77_8_ErrataNote_1.1_STD.pdf
116 hal.writeRegister(0x36, 0x02);
117 hal.writeRegister(0x3a, 0x64);
119 else
121 hal.writeRegister(0x36, 0x03);
123 currCR = cr;
124 currBW = bw;
128 bool SyncWordOk(uint8_t syncWord)
130 for (unsigned int i = 0; i < sizeof(SX127x_AllowedSyncwords); i++)
132 if (syncWord == SX127x_AllowedSyncwords[i])
134 return true;
137 return false;
140 void SX127xDriver::SetSyncWord(uint8_t syncWord)
142 uint8_t _syncWord = syncWord;
144 while (SyncWordOk(_syncWord) == false)
146 _syncWord++;
149 if(syncWord != _syncWord){
150 DBGLN("Using syncword: %d instead of: %d", _syncWord, syncWord);
153 hal.writeRegister(SX127X_REG_SYNC_WORD, _syncWord);
154 currSyncWord = _syncWord;
157 void SX127xDriver::SetOutputPower(uint8_t Power)
159 SetMode(SX127x_OPMODE_STANDBY);
160 #if defined(USE_SX1276_RFO_HF)
161 hal.writeRegister(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_RFO | SX127X_MAX_OUTPUT_POWER | Power);
162 #else
163 hal.writeRegister(SX127X_REG_PA_CONFIG, SX127X_PA_SELECT_BOOST | SX127X_MAX_OUTPUT_POWER | Power);
164 #endif
165 currPWR = Power;
168 void SX127xDriver::SetPreambleLength(uint8_t PreambleLen)
170 if (currPreambleLen != PreambleLen)
172 hal.writeRegister(SX127X_REG_PREAMBLE_LSB, PreambleLen);
173 currPreambleLen = PreambleLen;
177 void SX127xDriver::SetSpreadingFactor(SX127x_SpreadingFactor sf)
179 if (currSF != sf)
181 hal.setRegValue(SX127X_REG_MODEM_CONFIG_2, sf | SX127X_TX_MODE_SINGLE, 7, 3);
182 if (sf == SX127x_SF_6)
184 hal.setRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_6, 2, 0);
185 hal.writeRegister(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_6);
187 else
189 hal.setRegValue(SX127X_REG_DETECT_OPTIMIZE, SX127X_DETECT_OPTIMIZE_SF_7_12, 2, 0);
190 hal.writeRegister(SX127X_REG_DETECTION_THRESHOLD, SX127X_DETECTION_THRESHOLD_SF_7_12);
192 currSF = sf;
196 void ICACHE_RAM_ATTR SX127xDriver::SetFrequencyHz(uint32_t freq)
198 currFreq = freq;
199 SetMode(SX127x_OPMODE_STANDBY);
201 int32_t FRQ = ((uint32_t)((double)freq / (double)FREQ_STEP));
203 uint8_t FRQ_MSB = (uint8_t)((FRQ >> 16) & 0xFF);
204 uint8_t FRQ_MID = (uint8_t)((FRQ >> 8) & 0xFF);
205 uint8_t FRQ_LSB = (uint8_t)(FRQ & 0xFF);
207 WORD_ALIGNED_ATTR uint8_t outbuff[3] = {FRQ_MSB, FRQ_MID, FRQ_LSB}; //check speedup
209 hal.writeRegisterBurst(SX127X_REG_FRF_MSB, outbuff, sizeof(outbuff));
212 void ICACHE_RAM_ATTR SX127xDriver::SetFrequencyReg(uint32_t freq)
214 currFreq = freq;
215 SetMode(SX127x_OPMODE_STANDBY);
217 uint8_t FRQ_MSB = (uint8_t)((freq >> 16) & 0xFF);
218 uint8_t FRQ_MID = (uint8_t)((freq >> 8) & 0xFF);
219 uint8_t FRQ_LSB = (uint8_t)(freq & 0xFF);
221 WORD_ALIGNED_ATTR uint8_t outbuff[3] = {FRQ_MSB, FRQ_MID, FRQ_LSB}; //check speedup
223 hal.writeRegisterBurst(SX127X_REG_FRF_MSB, outbuff, sizeof(outbuff));
226 bool SX127xDriver::DetectChip()
228 uint8_t i = 0;
229 bool flagFound = false;
230 while ((i < 3) && !flagFound)
232 uint8_t version = hal.readRegister(SX127X_REG_VERSION);
233 DBG("%x", version);
234 if (version == 0x12)
236 flagFound = true;
238 else
240 DBGLN(" not found! (%d of 3 tries) REG_VERSION == 0x%x", i+1, version);
241 delay(200);
242 i++;
246 if (!flagFound)
248 DBGLN(" not found!");
249 return false;
251 else
253 DBGLN(" found! (match by REG_VERSION == 0x12)");
255 hal.setRegValue(SX127X_REG_OP_MODE, SX127x_OPMODE_SLEEP, 2, 0);
256 return true;
259 /////////////////////////////////////TX functions/////////////////////////////////////////
261 void ICACHE_RAM_ATTR SX127xDriver::TXnbISR()
263 currOpmode = SX127x_OPMODE_STANDBY; //goes into standby after transmission
264 //TXdoneMicros = micros();
265 TXdoneCallback();
268 void ICACHE_RAM_ATTR SX127xDriver::TXnb()
270 // if (currOpmode == SX127x_OPMODE_TX)
271 // {
272 // DBGLN("abort TX");
273 // return; // we were already TXing so abort. this should never happen!!!
274 // }
275 SetMode(SX127x_OPMODE_STANDBY);
276 hal.TXenable();
278 //TXstartMicros = micros();
279 //HeadRoom = TXstartMicros - TXdoneMicros;
281 hal.writeRegister(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_TX_BASE_ADDR_MAX);
282 hal.writeRegisterFIFO(TXdataBuffer, PayloadLength);
284 SetMode(SX127x_OPMODE_TX);
287 ///////////////////////////////////RX Functions Non-Blocking///////////////////////////////////////////
289 void ICACHE_RAM_ATTR SX127xDriver::RXnbISR()
291 hal.readRegisterFIFO(RXdataBuffer, PayloadLength);
292 LastPacketRSSI = GetLastPacketRSSI();
293 LastPacketSNR = GetLastPacketSNR();
294 RXdoneCallback();
297 void ICACHE_RAM_ATTR SX127xDriver::RXnb()
299 // if (currOpmode == SX127x_OPMODE_RXCONTINUOUS)
300 // {
301 // DBGLN("abort RX");
302 // return; // we were already TXing so abort
303 // }
304 SetMode(SX127x_OPMODE_STANDBY);
305 hal.RXenable();
306 hal.writeRegister(SX127X_REG_FIFO_ADDR_PTR, SX127X_FIFO_RX_BASE_ADDR_MAX);
307 SetMode(SX127x_OPMODE_RXCONTINUOUS);
310 void ICACHE_RAM_ATTR SX127xDriver::SetMode(SX127x_RadioOPmodes mode)
311 { //if radio is not already in the required mode set it to the requested mod
312 if (currOpmode != mode)
314 hal.writeRegister(ModFSKorLoRa | SX127X_REG_OP_MODE, mode);
315 currOpmode = mode;
319 void SX127xDriver::Config(SX127x_Bandwidth bw, SX127x_SpreadingFactor sf, SX127x_CodingRate cr, uint32_t freq, uint8_t preambleLen, bool InvertIQ, uint8_t PayloadLength)
321 Config(bw, sf, cr, freq, preambleLen, currSyncWord, InvertIQ, PayloadLength);
324 void SX127xDriver::Config(SX127x_Bandwidth bw, SX127x_SpreadingFactor sf, SX127x_CodingRate cr, uint32_t freq, uint8_t preambleLen, uint8_t syncWord, bool InvertIQ, uint8_t PayloadLength)
326 PayloadLength = PayloadLength;
327 IQinverted = InvertIQ;
328 ConfigLoraDefaults();
329 SetPreambleLength(preambleLen);
330 SetOutputPower(currPWR);
331 SetSpreadingFactor(sf);
332 SetBandwidthCodingRate(bw, cr);
333 SetFrequencyReg(freq);
336 uint32_t ICACHE_RAM_ATTR SX127xDriver::GetCurrBandwidth()
338 switch (currBW)
340 case SX127x_BW_7_80_KHZ:
341 return 7.8E3;
342 case SX127x_BW_10_40_KHZ:
343 return 10.4E3;
344 case SX127x_BW_15_60_KHZ:
345 return 15.6E3;
346 case SX127x_BW_20_80_KHZ:
347 return 20.8E3;
348 case SX127x_BW_31_25_KHZ:
349 return 31.25E3;
350 case SX127x_BW_41_70_KHZ:
351 return 41.7E3;
352 case SX127x_BW_62_50_KHZ:
353 return 62.5E3;
354 case SX127x_BW_125_00_KHZ:
355 return 125E3;
356 case SX127x_BW_250_00_KHZ:
357 return 250E3;
358 case SX127x_BW_500_00_KHZ:
359 return 500E3;
361 return -1;
364 uint32_t ICACHE_RAM_ATTR SX127xDriver::GetCurrBandwidthNormalisedShifted() // this is basically just used for speedier calc of the freq offset, pre compiled for 32mhz xtal
367 switch (currBW)
369 case SX127x_BW_7_80_KHZ:
370 return 1026;
371 case SX127x_BW_10_40_KHZ:
372 return 769;
373 case SX127x_BW_15_60_KHZ:
374 return 513;
375 case SX127x_BW_20_80_KHZ:
376 return 385;
377 case SX127x_BW_31_25_KHZ:
378 return 256;
379 case SX127x_BW_41_70_KHZ:
380 return 192;
381 case SX127x_BW_62_50_KHZ:
382 return 128;
383 case SX127x_BW_125_00_KHZ:
384 return 64;
385 case SX127x_BW_250_00_KHZ:
386 return 32;
387 case SX127x_BW_500_00_KHZ:
388 return 16;
390 return -1;
394 * Set the PPMcorrection register to adjust data rate to frequency error
395 * @param offset is in Hz or FREQ_STEP (FREQ_HZ_TO_REG_VAL) units, whichever
396 * was used to SetFrequencyHz/SetFrequencyReg
398 void ICACHE_RAM_ATTR SX127xDriver::SetPPMoffsetReg(int32_t offset)
400 int8_t offsetPPM = (offset * 1e6 / currFreq) * 95 / 100;
401 hal.writeRegister(SX127x_PPMOFFSET, (uint8_t)offsetPPM);
404 bool ICACHE_RAM_ATTR SX127xDriver::GetFrequencyErrorbool()
406 return (hal.readRegister(SX127X_REG_FEI_MSB) & 0b1000) >> 3; // returns true if pos freq error, neg if false
409 int32_t ICACHE_RAM_ATTR SX127xDriver::GetFrequencyError()
412 WORD_ALIGNED_ATTR uint8_t reg[3] = {0x0, 0x0, 0x0};
413 hal.readRegisterBurst(SX127X_REG_FEI_MSB, sizeof(reg), reg);
415 uint32_t RegFei = ((reg[0] & 0b0111) << 16) + (reg[1] << 8) + reg[2];
417 int32_t intFreqError = RegFei;
419 if ((reg[0] & 0b1000) >> 3)
421 intFreqError -= 524288; // Sign bit is on
424 int32_t fErrorHZ = (intFreqError >> 3) * (SX127xDriver::GetCurrBandwidthNormalisedShifted()); // bit shift hackery so we don't have to use floaty bois; the >> 3 is intentional and is a simplification of the formula on page 114 of sx1276 datasheet
425 fErrorHZ >>= 4;
427 return fErrorHZ;
430 uint8_t ICACHE_RAM_ATTR SX127xDriver::UnsignedGetLastPacketRSSI()
432 return (hal.getRegValue(SX127X_REG_PKT_RSSI_VALUE));
435 int8_t ICACHE_RAM_ATTR SX127xDriver::GetLastPacketRSSI()
437 return (-157 + hal.getRegValue(SX127X_REG_PKT_RSSI_VALUE));
440 int8_t ICACHE_RAM_ATTR SX127xDriver::GetCurrRSSI()
442 return (-157 + hal.getRegValue(SX127X_REG_RSSI_VALUE));
445 int8_t ICACHE_RAM_ATTR SX127xDriver::GetLastPacketSNR()
447 int8_t rawSNR = (int8_t)hal.getRegValue(SX127X_REG_PKT_SNR_VALUE);
448 return (rawSNR / 4);
451 uint8_t ICACHE_RAM_ATTR SX127xDriver::GetIrqFlags()
453 return hal.getRegValue(SX127X_REG_IRQ_FLAGS);
456 void ICACHE_RAM_ATTR SX127xDriver::ClearIrqFlags()
458 hal.writeRegister(SX127X_REG_IRQ_FLAGS, 0b11111111);
461 // int16_t MeasureNoiseFloor() TODO disabled for now
462 // {
463 // int NUM_READS = RSSI_FLOOR_NUM_READS * FHSSgetChannelCount();
464 // float returnval = 0;
466 // for (uint32_t freq = 0; freq < FHSSgetChannelCount(); freq++)
467 // {
468 // FHSSsetCurrIndex(freq);
469 // Radio.SetMode(SX127X_CAD);
471 // for (int i = 0; i < RSSI_FLOOR_NUM_READS; i++)
472 // {
473 // returnval = returnval + Radio.GetCurrRSSI();
474 // delay(5);
475 // }
476 // }
477 // returnval = returnval / NUM_READS;
478 // return (returnval);
479 // }
481 // uint8_t SX127xDriver::RunCAD() TODO
482 // {
483 // SetMode(SX127X_STANDBY);
485 // hal.setRegValue(SX127X_REG_DIO_MAPPING_1, SX127X_DIO0_CAD_DONE | SX127X_DIO1_CAD_DETECTED, 7, 4);
487 // SetMode(SX127X_CAD);
488 // ClearIrqFlags();
490 // uint32_t startTime = millis();
492 // while (!digitalRead(SX127x_dio0))
493 // {
494 // if (millis() > (startTime + 500))
495 // {
496 // return (CHANNEL_FREE);
497 // }
498 // else
499 // {
500 // //yield();
501 // if (digitalRead(SX127x_dio1))
502 // {
503 // ClearIrqFlags();
504 // return (PREAMBLE_DETECTED);
505 // }
506 // }
507 // }
509 // ClearIrqFlags();
510 // return (CHANNEL_FREE);
511 // }
513 void ICACHE_RAM_ATTR SX127xDriver::IsrCallback()
515 uint8_t irqStatus = instance->GetIrqFlags();
516 instance->ClearIrqFlags();
517 if ((irqStatus & SX127X_CLEAR_IRQ_FLAG_TX_DONE))
518 instance->TXnbISR();
519 else if ((irqStatus & SX127X_CLEAR_IRQ_FLAG_RX_DONE))
520 instance->RXnbISR();