Driver library for SX1272/SX1276 transceivers

Dependents:   LORA_RX LORA_TX WindConcentrator hid_test ... more

/media/uploads/dudmuck/lora.png

Driver library for SX1272 and SX1276 radio transceivers.

This device uses CSS modulation to provide much improved link budget. The RF hardware is same as in FSK devices, just with added LoRa spread-spectrum modem.

This library provides functions to configure radio chip and transmit & receive packets.

Using This Library

Library function service_radio() must be called continuously from main loop, to service interrupts from radio.

/media/uploads/dudmuck/sx1272rf1_connector_300.jpg

Board Specific implementation

FunctionPointer for rf_switch callback allows the program to implement control of RF switch unique to their board. Example options are:

  • SKY13373 for external power amplifier implementation. Requires two DigitalOut pins.
  • SKY13350 using PA_BOOST. requires two DigitalOut pins.
  • PE4259-63: controlled directly by radio chip, no software function needed. However, in the case of SX1276MB1xAS, the RXTX pin on IO2 should be driven by this callback function when R16 is installed (without R15) on this shield board.

Some configurations may need to force the use of RFO or PA_BOOST, or a board could offer both options. The rf_switch function pointer callback should support the implementation choice on the board.

further reading

Committer:
dudmuck
Date:
Thu Jul 28 00:57:22 2016 +0000
Revision:
27:da6341d9d5b1
Parent:
26:4876e515ff4c
Child:
31:b66d7a057b22
hw_reset working under pullup condition.  PLL registers defined.    PaRamp register defined. FSK modulation shaping supported.  FSK continuous TX mode supporting DIO0 high level.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 2:fdae76e1215e 1 #include "sx127x_lora.h"
dudmuck 2:fdae76e1215e 2
dudmuck 2:fdae76e1215e 3 /* SX127x driver
dudmuck 2:fdae76e1215e 4 * Copyright (c) 2013 Semtech
dudmuck 2:fdae76e1215e 5 *
dudmuck 2:fdae76e1215e 6 * Licensed under the Apache License, Version 2.0 (the "License");
dudmuck 2:fdae76e1215e 7 * you may not use this file except in compliance with the License.
dudmuck 2:fdae76e1215e 8 * You may obtain a copy of the License at
dudmuck 2:fdae76e1215e 9 *
dudmuck 2:fdae76e1215e 10 * http://www.apache.org/licenses/LICENSE-2.0
dudmuck 2:fdae76e1215e 11 *
dudmuck 2:fdae76e1215e 12 * Unless required by applicable law or agreed to in writing, software
dudmuck 2:fdae76e1215e 13 * distributed under the License is distributed on an "AS IS" BASIS,
dudmuck 2:fdae76e1215e 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dudmuck 2:fdae76e1215e 15 * See the License for the specific language governing permissions and
dudmuck 2:fdae76e1215e 16 * limitations under the License.
dudmuck 2:fdae76e1215e 17 */
dudmuck 2:fdae76e1215e 18
dudmuck 3:3bf2515b1eed 19 SX127x_lora::SX127x_lora(SX127x& r) : m_xcvr(r)
dudmuck 2:fdae76e1215e 20 {
dudmuck 19:1ee6ef1ab73f 21 if (!m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 19:1ee6ef1ab73f 22 enable();
dudmuck 19:1ee6ef1ab73f 23
dudmuck 2:fdae76e1215e 24 RegModemConfig.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG);
dudmuck 2:fdae76e1215e 25 RegModemConfig2.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG2);
dudmuck 17:59279bc8cdab 26 RegTest33.octet = m_xcvr.read_reg(REG_LR_TEST33); // invert_i_q
dudmuck 17:59279bc8cdab 27 RegDriftInvert.octet = m_xcvr.read_reg(REG_LR_DRIFT_INVERT);
dudmuck 19:1ee6ef1ab73f 28 RegGainDrift.octet = m_xcvr.read_reg(REG_LR_GAIN_DRIFT);
dudmuck 19:1ee6ef1ab73f 29
dudmuck 19:1ee6ef1ab73f 30 if (m_xcvr.type == SX1276) {
dudmuck 19:1ee6ef1ab73f 31 RegAutoDrift.octet = m_xcvr.read_reg(REG_LR_SX1276_AUTO_DRIFT);
dudmuck 19:1ee6ef1ab73f 32 }
dudmuck 27:da6341d9d5b1 33
dudmuck 27:da6341d9d5b1 34
dudmuck 2:fdae76e1215e 35 }
dudmuck 2:fdae76e1215e 36
dudmuck 2:fdae76e1215e 37 SX127x_lora::~SX127x_lora()
dudmuck 2:fdae76e1215e 38 {
dudmuck 2:fdae76e1215e 39 }
dudmuck 2:fdae76e1215e 40
dudmuck 2:fdae76e1215e 41 void SX127x_lora::write_fifo(uint8_t len)
dudmuck 2:fdae76e1215e 42 {
dudmuck 2:fdae76e1215e 43 int i;
dudmuck 2:fdae76e1215e 44
dudmuck 2:fdae76e1215e 45 m_xcvr.m_cs = 0;
dudmuck 2:fdae76e1215e 46 m_xcvr.m_spi.write(REG_FIFO | 0x80); // bit7 is high for writing to radio
dudmuck 2:fdae76e1215e 47
dudmuck 2:fdae76e1215e 48 for (i = 0; i < len; i++) {
dudmuck 2:fdae76e1215e 49 m_xcvr.m_spi.write(m_xcvr.tx_buf[i]);
dudmuck 2:fdae76e1215e 50 }
dudmuck 2:fdae76e1215e 51 m_xcvr.m_cs = 1;
dudmuck 2:fdae76e1215e 52 }
dudmuck 2:fdae76e1215e 53
dudmuck 2:fdae76e1215e 54 void SX127x_lora::read_fifo(uint8_t len)
dudmuck 2:fdae76e1215e 55 {
dudmuck 2:fdae76e1215e 56 int i;
dudmuck 2:fdae76e1215e 57
dudmuck 2:fdae76e1215e 58 m_xcvr.m_cs = 0;
dudmuck 2:fdae76e1215e 59 m_xcvr.m_spi.write(REG_FIFO); // bit7 is low for reading from radio
dudmuck 2:fdae76e1215e 60 for (i = 0; i < len; i++) {
dudmuck 2:fdae76e1215e 61 m_xcvr.rx_buf[i] = m_xcvr.m_spi.write(0);
dudmuck 2:fdae76e1215e 62 }
dudmuck 2:fdae76e1215e 63 m_xcvr.m_cs = 1;
dudmuck 2:fdae76e1215e 64 }
dudmuck 2:fdae76e1215e 65
dudmuck 2:fdae76e1215e 66 void SX127x_lora::enable()
dudmuck 2:fdae76e1215e 67 {
dudmuck 2:fdae76e1215e 68 m_xcvr.set_opmode(RF_OPMODE_SLEEP);
dudmuck 2:fdae76e1215e 69
dudmuck 2:fdae76e1215e 70 m_xcvr.RegOpMode.bits.LongRangeMode = 1;
dudmuck 2:fdae76e1215e 71 m_xcvr.write_reg(REG_OPMODE, m_xcvr.RegOpMode.octet);
dudmuck 2:fdae76e1215e 72
dudmuck 2:fdae76e1215e 73 m_xcvr.RegDioMapping1.bits.Dio0Mapping = 0; // DIO0 to RxDone
dudmuck 2:fdae76e1215e 74 m_xcvr.RegDioMapping1.bits.Dio1Mapping = 0;
dudmuck 2:fdae76e1215e 75 m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
dudmuck 27:da6341d9d5b1 76
dudmuck 27:da6341d9d5b1 77 RegTest31.octet = m_xcvr.read_reg(REG_LR_TEST31);
dudmuck 27:da6341d9d5b1 78 RegTest31.bits.if_freq_auto = 0; // improved RX spurious rejection
dudmuck 27:da6341d9d5b1 79 m_xcvr.write_reg(REG_LR_TEST31, RegTest31.octet);
dudmuck 2:fdae76e1215e 80
dudmuck 2:fdae76e1215e 81 m_xcvr.set_opmode(RF_OPMODE_STANDBY);
dudmuck 2:fdae76e1215e 82 }
dudmuck 2:fdae76e1215e 83
dudmuck 2:fdae76e1215e 84 uint8_t SX127x_lora::getCodingRate(bool from_rx)
dudmuck 2:fdae76e1215e 85 {
dudmuck 2:fdae76e1215e 86 if (from_rx) {
dudmuck 2:fdae76e1215e 87 // expected RegModemStatus was read on RxDone interrupt
dudmuck 2:fdae76e1215e 88 return RegModemStatus.bits.RxCodingRate;
dudmuck 2:fdae76e1215e 89 } else { // transmitted coding rate...
dudmuck 2:fdae76e1215e 90 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 91 return RegModemConfig.sx1276bits.CodingRate;
dudmuck 2:fdae76e1215e 92 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 93 return RegModemConfig.sx1272bits.CodingRate;
dudmuck 2:fdae76e1215e 94 else
dudmuck 2:fdae76e1215e 95 return 0;
dudmuck 2:fdae76e1215e 96 }
dudmuck 2:fdae76e1215e 97 }
dudmuck 2:fdae76e1215e 98
dudmuck 2:fdae76e1215e 99
dudmuck 2:fdae76e1215e 100
dudmuck 2:fdae76e1215e 101 void SX127x_lora::setCodingRate(uint8_t cr)
dudmuck 2:fdae76e1215e 102 {
dudmuck 2:fdae76e1215e 103 if (!m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 2:fdae76e1215e 104 return;
dudmuck 2:fdae76e1215e 105
dudmuck 2:fdae76e1215e 106 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 107 RegModemConfig.sx1276bits.CodingRate = cr;
dudmuck 2:fdae76e1215e 108 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 109 RegModemConfig.sx1272bits.CodingRate = cr;
dudmuck 2:fdae76e1215e 110 else
dudmuck 2:fdae76e1215e 111 return;
dudmuck 2:fdae76e1215e 112
dudmuck 2:fdae76e1215e 113 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 114 }
dudmuck 2:fdae76e1215e 115
dudmuck 2:fdae76e1215e 116
dudmuck 2:fdae76e1215e 117
dudmuck 2:fdae76e1215e 118 bool SX127x_lora::getHeaderMode(void)
dudmuck 2:fdae76e1215e 119 {
dudmuck 26:4876e515ff4c 120 if (m_xcvr.type == SX1276) {
dudmuck 26:4876e515ff4c 121 RegModemConfig.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG);
dudmuck 2:fdae76e1215e 122 return RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
dudmuck 26:4876e515ff4c 123 } else if (m_xcvr.type == SX1272) {
dudmuck 26:4876e515ff4c 124 RegModemConfig.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG);
dudmuck 2:fdae76e1215e 125 return RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
dudmuck 26:4876e515ff4c 126 } else
dudmuck 2:fdae76e1215e 127 return false;
dudmuck 2:fdae76e1215e 128 }
dudmuck 2:fdae76e1215e 129
dudmuck 2:fdae76e1215e 130 void SX127x_lora::setHeaderMode(bool hm)
dudmuck 2:fdae76e1215e 131 {
dudmuck 2:fdae76e1215e 132 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 133 RegModemConfig.sx1276bits.ImplicitHeaderModeOn = hm;
dudmuck 2:fdae76e1215e 134 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 135 RegModemConfig.sx1272bits.ImplicitHeaderModeOn = hm;
dudmuck 2:fdae76e1215e 136 else
dudmuck 2:fdae76e1215e 137 return;
dudmuck 2:fdae76e1215e 138
dudmuck 2:fdae76e1215e 139 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 140 }
dudmuck 2:fdae76e1215e 141
dudmuck 2:fdae76e1215e 142
dudmuck 2:fdae76e1215e 143 uint8_t SX127x_lora::getBw(void)
dudmuck 2:fdae76e1215e 144 {
dudmuck 2:fdae76e1215e 145 if (m_xcvr.type == SX1276)
dudmuck 2:fdae76e1215e 146 return RegModemConfig.sx1276bits.Bw;
dudmuck 2:fdae76e1215e 147 else if (m_xcvr.type == SX1272)
dudmuck 2:fdae76e1215e 148 return RegModemConfig.sx1272bits.Bw;
dudmuck 2:fdae76e1215e 149 else
dudmuck 2:fdae76e1215e 150 return 0;
dudmuck 2:fdae76e1215e 151 }
dudmuck 15:3f3fc6792f97 152
dudmuck 15:3f3fc6792f97 153 int SX127x_lora::get_freq_error_Hz()
dudmuck 15:3f3fc6792f97 154 {
dudmuck 15:3f3fc6792f97 155 int freq_error;
dudmuck 15:3f3fc6792f97 156 float f, khz = 0;
dudmuck 15:3f3fc6792f97 157 freq_error = m_xcvr.read_reg(REG_LR_TEST28);
dudmuck 15:3f3fc6792f97 158 freq_error <<= 8;
dudmuck 15:3f3fc6792f97 159 freq_error += m_xcvr.read_reg(REG_LR_TEST29);
dudmuck 15:3f3fc6792f97 160 freq_error <<= 8;
dudmuck 15:3f3fc6792f97 161 freq_error += m_xcvr.read_reg(REG_LR_TEST2A);
dudmuck 15:3f3fc6792f97 162 if (freq_error & 0x80000) { // 20bit value is negative
dudmuck 15:3f3fc6792f97 163 //signed 20bit to 32bit
dudmuck 15:3f3fc6792f97 164 freq_error |= 0xfff00000;
dudmuck 15:3f3fc6792f97 165 }
dudmuck 15:3f3fc6792f97 166 f = freq_error / (float)XTAL_FREQ;
dudmuck 15:3f3fc6792f97 167 f *= (float)0x1000000; // 2^24
dudmuck 15:3f3fc6792f97 168 if (m_xcvr.type == SX1272) {
dudmuck 15:3f3fc6792f97 169 switch (RegModemConfig.sx1272bits.Bw) {
dudmuck 15:3f3fc6792f97 170 case 0: khz = 125; break;
dudmuck 15:3f3fc6792f97 171 case 1: khz = 250; break;
dudmuck 15:3f3fc6792f97 172 case 2: khz = 500; break;
dudmuck 15:3f3fc6792f97 173 }
dudmuck 15:3f3fc6792f97 174 } else if (m_xcvr.type == SX1276) {
dudmuck 15:3f3fc6792f97 175 switch (RegModemConfig.sx1276bits.Bw) {
dudmuck 15:3f3fc6792f97 176 case 0: khz = 7.8; break;
dudmuck 15:3f3fc6792f97 177 case 1: khz = 10.4; break;
dudmuck 15:3f3fc6792f97 178 case 2: khz = 15.6; break;
dudmuck 15:3f3fc6792f97 179 case 3: khz = 20.8; break;
dudmuck 15:3f3fc6792f97 180 case 4: khz = 31.25; break;
dudmuck 15:3f3fc6792f97 181 case 5: khz = 41.7; break;
dudmuck 15:3f3fc6792f97 182 case 6: khz = 62.5; break;
dudmuck 15:3f3fc6792f97 183 case 7: khz = 125; break;
dudmuck 15:3f3fc6792f97 184 case 8: khz = 250; break;
dudmuck 15:3f3fc6792f97 185 case 9: khz = 500; break;
dudmuck 15:3f3fc6792f97 186 }
dudmuck 15:3f3fc6792f97 187 }
dudmuck 15:3f3fc6792f97 188 f *= khz / 500;
dudmuck 15:3f3fc6792f97 189 return (int)f;
dudmuck 15:3f3fc6792f97 190 }
dudmuck 15:3f3fc6792f97 191
dudmuck 10:7382c260c4b1 192 float SX127x_lora::get_symbol_period()
dudmuck 10:7382c260c4b1 193 {
dudmuck 10:7382c260c4b1 194 float khz = 0;
dudmuck 10:7382c260c4b1 195
dudmuck 10:7382c260c4b1 196 if (m_xcvr.type == SX1276) {
dudmuck 10:7382c260c4b1 197 switch (RegModemConfig.sx1276bits.Bw) {
dudmuck 10:7382c260c4b1 198 case 0: khz = 7.8; break;
dudmuck 10:7382c260c4b1 199 case 1: khz = 10.4; break;
dudmuck 10:7382c260c4b1 200 case 2: khz = 15.6; break;
dudmuck 10:7382c260c4b1 201 case 3: khz = 20.8; break;
dudmuck 10:7382c260c4b1 202 case 4: khz = 31.25; break;
dudmuck 10:7382c260c4b1 203 case 5: khz = 41.7; break;
dudmuck 10:7382c260c4b1 204 case 6: khz = 62.5; break;
dudmuck 10:7382c260c4b1 205 case 7: khz = 125; break;
dudmuck 10:7382c260c4b1 206 case 8: khz = 250; break;
dudmuck 10:7382c260c4b1 207 case 9: khz = 500; break;
dudmuck 10:7382c260c4b1 208 }
dudmuck 10:7382c260c4b1 209 } else if (m_xcvr.type == SX1272) {
dudmuck 10:7382c260c4b1 210 switch (RegModemConfig.sx1272bits.Bw) {
dudmuck 10:7382c260c4b1 211 case 0: khz = 125; break;
dudmuck 10:7382c260c4b1 212 case 1: khz = 250; break;
dudmuck 10:7382c260c4b1 213 case 2: khz = 500; break;
dudmuck 10:7382c260c4b1 214 }
dudmuck 10:7382c260c4b1 215 }
dudmuck 10:7382c260c4b1 216
dudmuck 10:7382c260c4b1 217 // return symbol duration in milliseconds
dudmuck 10:7382c260c4b1 218 return (1 << RegModemConfig2.sx1276bits.SpreadingFactor) / khz;
dudmuck 10:7382c260c4b1 219 }
dudmuck 2:fdae76e1215e 220
dudmuck 16:3de8e1c465eb 221 void SX127x_lora::setBw_KHz(int khz)
dudmuck 16:3de8e1c465eb 222 {
dudmuck 16:3de8e1c465eb 223 uint8_t bw = 0;
dudmuck 16:3de8e1c465eb 224
dudmuck 16:3de8e1c465eb 225 if (m_xcvr.type == SX1276) {
dudmuck 16:3de8e1c465eb 226 if (khz <= 8) bw = 0;
dudmuck 16:3de8e1c465eb 227 else if (khz <= 11) bw = 1;
dudmuck 16:3de8e1c465eb 228 else if (khz <= 16) bw = 2;
dudmuck 16:3de8e1c465eb 229 else if (khz <= 21) bw = 3;
dudmuck 16:3de8e1c465eb 230 else if (khz <= 32) bw = 4;
dudmuck 16:3de8e1c465eb 231 else if (khz <= 42) bw = 5;
dudmuck 16:3de8e1c465eb 232 else if (khz <= 63) bw = 6;
dudmuck 16:3de8e1c465eb 233 else if (khz <= 125) bw = 7;
dudmuck 16:3de8e1c465eb 234 else if (khz <= 250) bw = 8;
dudmuck 16:3de8e1c465eb 235 else if (khz <= 500) bw = 9;
dudmuck 16:3de8e1c465eb 236 } else if (m_xcvr.type == SX1272) {
dudmuck 16:3de8e1c465eb 237 if (khz <= 125) bw = 0;
dudmuck 16:3de8e1c465eb 238 else if (khz <= 250) bw = 1;
dudmuck 16:3de8e1c465eb 239 else if (khz <= 500) bw = 2;
dudmuck 16:3de8e1c465eb 240 }
dudmuck 16:3de8e1c465eb 241
dudmuck 16:3de8e1c465eb 242 setBw(bw);
dudmuck 16:3de8e1c465eb 243 }
dudmuck 16:3de8e1c465eb 244
dudmuck 2:fdae76e1215e 245 void SX127x_lora::setBw(uint8_t bw)
dudmuck 2:fdae76e1215e 246 {
dudmuck 2:fdae76e1215e 247 if (!m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 2:fdae76e1215e 248 return;
dudmuck 2:fdae76e1215e 249
dudmuck 19:1ee6ef1ab73f 250 if (m_xcvr.type == SX1276) {
dudmuck 2:fdae76e1215e 251 RegModemConfig.sx1276bits.Bw = bw;
dudmuck 10:7382c260c4b1 252 if (get_symbol_period() > 16)
dudmuck 10:7382c260c4b1 253 RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
dudmuck 10:7382c260c4b1 254 else
dudmuck 10:7382c260c4b1 255 RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
dudmuck 19:1ee6ef1ab73f 256 m_xcvr.write_reg(REG_LR_MODEMCONFIG3, RegModemConfig3.octet);
dudmuck 10:7382c260c4b1 257 } else if (m_xcvr.type == SX1272) {
dudmuck 2:fdae76e1215e 258 RegModemConfig.sx1272bits.Bw = bw;
dudmuck 10:7382c260c4b1 259 if (get_symbol_period() > 16)
dudmuck 2:fdae76e1215e 260 RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
dudmuck 2:fdae76e1215e 261 else
dudmuck 2:fdae76e1215e 262 RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
dudmuck 2:fdae76e1215e 263 } else
dudmuck 2:fdae76e1215e 264 return;
dudmuck 2:fdae76e1215e 265
dudmuck 2:fdae76e1215e 266 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 267 }
dudmuck 2:fdae76e1215e 268
dudmuck 2:fdae76e1215e 269
dudmuck 2:fdae76e1215e 270
dudmuck 2:fdae76e1215e 271 uint8_t SX127x_lora::getSf(void)
dudmuck 2:fdae76e1215e 272 {
dudmuck 2:fdae76e1215e 273 // spreading factor same between sx127[26]
dudmuck 2:fdae76e1215e 274 return RegModemConfig2.sx1276bits.SpreadingFactor;
dudmuck 2:fdae76e1215e 275 }
dudmuck 2:fdae76e1215e 276
dudmuck 2:fdae76e1215e 277 void SX127x_lora::set_nb_trig_peaks(int n)
dudmuck 2:fdae76e1215e 278 {
dudmuck 13:1953e70522aa 279 /* TODO: different requirements for RX_CONTINUOUS vs RX_SINGLE */
dudmuck 2:fdae76e1215e 280 RegTest31.bits.detect_trig_same_peaks_nb = n;
dudmuck 2:fdae76e1215e 281 m_xcvr.write_reg(REG_LR_TEST31, RegTest31.octet);
dudmuck 2:fdae76e1215e 282 }
dudmuck 2:fdae76e1215e 283
dudmuck 2:fdae76e1215e 284
dudmuck 2:fdae76e1215e 285 void SX127x_lora::setSf(uint8_t sf)
dudmuck 2:fdae76e1215e 286 {
dudmuck 2:fdae76e1215e 287 if (!m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 19:1ee6ef1ab73f 288 return;
dudmuck 19:1ee6ef1ab73f 289
dudmuck 2:fdae76e1215e 290 // write register at 0x37 with value 0xc if at SF6
dudmuck 2:fdae76e1215e 291 if (sf < 7)
dudmuck 2:fdae76e1215e 292 m_xcvr.write_reg(REG_LR_DETECTION_THRESHOLD, 0x0c);
dudmuck 2:fdae76e1215e 293 else
dudmuck 2:fdae76e1215e 294 m_xcvr.write_reg(REG_LR_DETECTION_THRESHOLD, 0x0a);
dudmuck 2:fdae76e1215e 295
dudmuck 2:fdae76e1215e 296 RegModemConfig2.sx1276bits.SpreadingFactor = sf; // spreading factor same between sx127[26]
dudmuck 2:fdae76e1215e 297 m_xcvr.write_reg(REG_LR_MODEMCONFIG2, RegModemConfig2.octet);
dudmuck 2:fdae76e1215e 298
dudmuck 2:fdae76e1215e 299 if (m_xcvr.type == SX1272) {
dudmuck 10:7382c260c4b1 300 if (get_symbol_period() > 16)
dudmuck 2:fdae76e1215e 301 RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
dudmuck 2:fdae76e1215e 302 else
dudmuck 2:fdae76e1215e 303 RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
dudmuck 2:fdae76e1215e 304 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 305 } else if (m_xcvr.type == SX1276) {
dudmuck 10:7382c260c4b1 306 if (get_symbol_period() > 16)
dudmuck 2:fdae76e1215e 307 RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
dudmuck 2:fdae76e1215e 308 else
dudmuck 2:fdae76e1215e 309 RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
dudmuck 2:fdae76e1215e 310 m_xcvr.write_reg(REG_LR_MODEMCONFIG3, RegModemConfig3.octet);
dudmuck 2:fdae76e1215e 311 }
dudmuck 2:fdae76e1215e 312 }
dudmuck 2:fdae76e1215e 313
dudmuck 2:fdae76e1215e 314
dudmuck 2:fdae76e1215e 315
dudmuck 2:fdae76e1215e 316 bool SX127x_lora::getRxPayloadCrcOn(void)
dudmuck 2:fdae76e1215e 317 {
dudmuck 26:4876e515ff4c 318 /* RxPayloadCrcOn enables CRC generation in transmitter */
dudmuck 26:4876e515ff4c 319 /* in implicit mode, this bit also enables CRC in receiver */
dudmuck 26:4876e515ff4c 320 if (m_xcvr.type == SX1276) {
dudmuck 26:4876e515ff4c 321 RegModemConfig2.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG2);
dudmuck 2:fdae76e1215e 322 return RegModemConfig2.sx1276bits.RxPayloadCrcOn;
dudmuck 26:4876e515ff4c 323 } else if (m_xcvr.type == SX1272) {
dudmuck 26:4876e515ff4c 324 RegModemConfig.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG);
dudmuck 2:fdae76e1215e 325 return RegModemConfig.sx1272bits.RxPayloadCrcOn;
dudmuck 26:4876e515ff4c 326 } else
dudmuck 2:fdae76e1215e 327 return 0;
dudmuck 2:fdae76e1215e 328 }
dudmuck 2:fdae76e1215e 329
dudmuck 2:fdae76e1215e 330
dudmuck 2:fdae76e1215e 331 void SX127x_lora::setRxPayloadCrcOn(bool on)
dudmuck 2:fdae76e1215e 332 {
dudmuck 2:fdae76e1215e 333 if (m_xcvr.type == SX1276) {
dudmuck 2:fdae76e1215e 334 RegModemConfig2.sx1276bits.RxPayloadCrcOn = on;
dudmuck 2:fdae76e1215e 335 m_xcvr.write_reg(REG_LR_MODEMCONFIG2, RegModemConfig2.octet);
dudmuck 2:fdae76e1215e 336 } else if (m_xcvr.type == SX1272) {
dudmuck 2:fdae76e1215e 337 RegModemConfig.sx1272bits.RxPayloadCrcOn = on;
dudmuck 2:fdae76e1215e 338 m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
dudmuck 2:fdae76e1215e 339 }
dudmuck 2:fdae76e1215e 340 }
dudmuck 2:fdae76e1215e 341
dudmuck 2:fdae76e1215e 342
dudmuck 2:fdae76e1215e 343
dudmuck 2:fdae76e1215e 344 bool SX127x_lora::getAgcAutoOn(void)
dudmuck 2:fdae76e1215e 345 {
dudmuck 2:fdae76e1215e 346 if (m_xcvr.type == SX1276) {
dudmuck 2:fdae76e1215e 347 RegModemConfig3.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG3);
dudmuck 2:fdae76e1215e 348 return RegModemConfig3.sx1276bits.AgcAutoOn;
dudmuck 2:fdae76e1215e 349 } else if (m_xcvr.type == SX1272) {
dudmuck 2:fdae76e1215e 350 RegModemConfig2.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG2);
dudmuck 2:fdae76e1215e 351 return RegModemConfig2.sx1272bits.AgcAutoOn;
dudmuck 2:fdae76e1215e 352 } else
dudmuck 2:fdae76e1215e 353 return 0;
dudmuck 2:fdae76e1215e 354 }
dudmuck 2:fdae76e1215e 355
dudmuck 2:fdae76e1215e 356 void SX127x_lora::setAgcAutoOn(bool on)
dudmuck 2:fdae76e1215e 357 {
dudmuck 2:fdae76e1215e 358 if (m_xcvr.type == SX1276) {
dudmuck 2:fdae76e1215e 359 RegModemConfig3.sx1276bits.AgcAutoOn = on;
dudmuck 2:fdae76e1215e 360 m_xcvr.write_reg(REG_LR_MODEMCONFIG3, RegModemConfig3.octet);
dudmuck 2:fdae76e1215e 361 } else if (m_xcvr.type == SX1272) {
dudmuck 2:fdae76e1215e 362 RegModemConfig2.sx1272bits.AgcAutoOn = on;
dudmuck 2:fdae76e1215e 363 m_xcvr.write_reg(REG_LR_MODEMCONFIG2, RegModemConfig2.octet);
dudmuck 2:fdae76e1215e 364 }
dudmuck 2:fdae76e1215e 365
dudmuck 2:fdae76e1215e 366 }
dudmuck 2:fdae76e1215e 367
dudmuck 17:59279bc8cdab 368 void SX127x_lora::invert_tx(bool inv)
dudmuck 17:59279bc8cdab 369 {
dudmuck 17:59279bc8cdab 370 RegTest33.bits.chirp_invert_tx = !inv;
dudmuck 17:59279bc8cdab 371 m_xcvr.write_reg(REG_LR_TEST33, RegTest33.octet);
dudmuck 17:59279bc8cdab 372 }
dudmuck 17:59279bc8cdab 373
dudmuck 17:59279bc8cdab 374 void SX127x_lora::invert_rx(bool inv)
dudmuck 17:59279bc8cdab 375 {
dudmuck 17:59279bc8cdab 376 RegTest33.bits.invert_i_q = inv;
dudmuck 17:59279bc8cdab 377 m_xcvr.write_reg(REG_LR_TEST33, RegTest33.octet);
dudmuck 17:59279bc8cdab 378 /**/
dudmuck 17:59279bc8cdab 379 RegDriftInvert.bits.invert_timing_error_per_symbol = !RegTest33.bits.invert_i_q;
dudmuck 17:59279bc8cdab 380 m_xcvr.write_reg(REG_LR_DRIFT_INVERT, RegDriftInvert.octet);
dudmuck 17:59279bc8cdab 381 }
dudmuck 17:59279bc8cdab 382
dudmuck 2:fdae76e1215e 383 void SX127x_lora::start_tx(uint8_t len)
dudmuck 7:927a05f84ede 384 {
dudmuck 2:fdae76e1215e 385 // DIO0 to TxDone
dudmuck 2:fdae76e1215e 386 if (m_xcvr.RegDioMapping1.bits.Dio0Mapping != 1) {
dudmuck 2:fdae76e1215e 387 m_xcvr.RegDioMapping1.bits.Dio0Mapping = 1;
dudmuck 2:fdae76e1215e 388 m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
dudmuck 2:fdae76e1215e 389 }
dudmuck 2:fdae76e1215e 390
dudmuck 2:fdae76e1215e 391 // set FifoPtrAddr to FifoTxPtrBase
dudmuck 2:fdae76e1215e 392 m_xcvr.write_reg(REG_LR_FIFOADDRPTR, m_xcvr.read_reg(REG_LR_FIFOTXBASEADDR));
dudmuck 2:fdae76e1215e 393
dudmuck 2:fdae76e1215e 394 // write PayloadLength bytes to fifo
dudmuck 2:fdae76e1215e 395 write_fifo(len);
dudmuck 7:927a05f84ede 396
dudmuck 2:fdae76e1215e 397 m_xcvr.set_opmode(RF_OPMODE_TRANSMITTER);
dudmuck 2:fdae76e1215e 398 }
dudmuck 2:fdae76e1215e 399
dudmuck 27:da6341d9d5b1 400 void SX127x_lora::start_rx(chip_mode_e mode)
dudmuck 2:fdae76e1215e 401 {
dudmuck 2:fdae76e1215e 402 if (!m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 12:bda42457c34a 403 return; // fsk mode
dudmuck 12:bda42457c34a 404 if (m_xcvr.RegOpMode.sx1276LORAbits.AccessSharedReg)
dudmuck 12:bda42457c34a 405 return; // fsk page
dudmuck 13:1953e70522aa 406
dudmuck 19:1ee6ef1ab73f 407 if (m_xcvr.type == SX1276) {
dudmuck 19:1ee6ef1ab73f 408 if (RegModemConfig.sx1276bits.Bw == 9) { // if 500KHz bw: improved tolerance of reference frequency error
dudmuck 19:1ee6ef1ab73f 409 if (RegAutoDrift.bits.freq_to_time_drift_auto) {
dudmuck 19:1ee6ef1ab73f 410 RegAutoDrift.bits.freq_to_time_drift_auto = 0;
dudmuck 19:1ee6ef1ab73f 411 m_xcvr.write_reg(REG_LR_SX1276_AUTO_DRIFT, RegAutoDrift.octet);
dudmuck 19:1ee6ef1ab73f 412 }
dudmuck 19:1ee6ef1ab73f 413 if (m_xcvr.HF) {
dudmuck 19:1ee6ef1ab73f 414 // > 525MHz
dudmuck 19:1ee6ef1ab73f 415 if (RegGainDrift.bits.freq_to_time_drift != 0x24) {
dudmuck 19:1ee6ef1ab73f 416 RegGainDrift.bits.freq_to_time_drift = 0x24;
dudmuck 19:1ee6ef1ab73f 417 m_xcvr.write_reg(REG_LR_GAIN_DRIFT, RegGainDrift.octet);
dudmuck 19:1ee6ef1ab73f 418 }
dudmuck 19:1ee6ef1ab73f 419 } else {
dudmuck 19:1ee6ef1ab73f 420 // < 525MHz
dudmuck 19:1ee6ef1ab73f 421 if (RegGainDrift.bits.freq_to_time_drift != 0x3f) {
dudmuck 19:1ee6ef1ab73f 422 RegGainDrift.bits.freq_to_time_drift = 0x3f;
dudmuck 19:1ee6ef1ab73f 423 m_xcvr.write_reg(REG_LR_GAIN_DRIFT, RegGainDrift.octet);
dudmuck 19:1ee6ef1ab73f 424 }
dudmuck 19:1ee6ef1ab73f 425 }
dudmuck 19:1ee6ef1ab73f 426
dudmuck 19:1ee6ef1ab73f 427 } else {
dudmuck 19:1ee6ef1ab73f 428 if (!RegAutoDrift.bits.freq_to_time_drift_auto) {
dudmuck 19:1ee6ef1ab73f 429 RegAutoDrift.bits.freq_to_time_drift_auto = 1;
dudmuck 19:1ee6ef1ab73f 430 m_xcvr.write_reg(REG_LR_SX1276_AUTO_DRIFT, RegAutoDrift.octet);
dudmuck 19:1ee6ef1ab73f 431 }
dudmuck 19:1ee6ef1ab73f 432 }
dudmuck 19:1ee6ef1ab73f 433 } // ... if (m_xcvr.type == SX1276)
dudmuck 19:1ee6ef1ab73f 434
dudmuck 19:1ee6ef1ab73f 435 // RX_CONTINUOUS: false detections vs missed detections tradeoff
dudmuck 19:1ee6ef1ab73f 436 switch (RegModemConfig2.sx1276bits.SpreadingFactor) {
dudmuck 19:1ee6ef1ab73f 437 case 6:
dudmuck 19:1ee6ef1ab73f 438 set_nb_trig_peaks(3);
dudmuck 19:1ee6ef1ab73f 439 break;
dudmuck 19:1ee6ef1ab73f 440 case 7:
dudmuck 19:1ee6ef1ab73f 441 set_nb_trig_peaks(4);
dudmuck 19:1ee6ef1ab73f 442 break;
dudmuck 19:1ee6ef1ab73f 443 default:
dudmuck 19:1ee6ef1ab73f 444 set_nb_trig_peaks(5);
dudmuck 19:1ee6ef1ab73f 445 break;
dudmuck 19:1ee6ef1ab73f 446 }
dudmuck 19:1ee6ef1ab73f 447
dudmuck 27:da6341d9d5b1 448 m_xcvr.set_opmode(mode);
dudmuck 2:fdae76e1215e 449
dudmuck 2:fdae76e1215e 450 if (m_xcvr.RegDioMapping1.bits.Dio0Mapping != 0) {
dudmuck 2:fdae76e1215e 451 m_xcvr.RegDioMapping1.bits.Dio0Mapping = 0; // DIO0 to RxDone
dudmuck 2:fdae76e1215e 452 m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
dudmuck 2:fdae76e1215e 453 }
dudmuck 2:fdae76e1215e 454
dudmuck 2:fdae76e1215e 455 m_xcvr.write_reg(REG_LR_FIFOADDRPTR, m_xcvr.read_reg(REG_LR_FIFORXBASEADDR));
dudmuck 2:fdae76e1215e 456 }
dudmuck 2:fdae76e1215e 457
dudmuck 23:1df3dddcb43e 458 int SX127x_lora::get_pkt_rssi()
dudmuck 2:fdae76e1215e 459 {
dudmuck 23:1df3dddcb43e 460 if (m_xcvr.type == SX1276) {
dudmuck 23:1df3dddcb43e 461 if (m_xcvr.HF)
dudmuck 23:1df3dddcb43e 462 return RegPktRssiValue - 157;
dudmuck 23:1df3dddcb43e 463 else
dudmuck 23:1df3dddcb43e 464 return RegPktRssiValue - 164;
dudmuck 23:1df3dddcb43e 465 } else
dudmuck 2:fdae76e1215e 466 return RegPktRssiValue - 125;
dudmuck 2:fdae76e1215e 467 }
dudmuck 2:fdae76e1215e 468
dudmuck 23:1df3dddcb43e 469 int SX127x_lora::get_current_rssi()
dudmuck 23:1df3dddcb43e 470 {
dudmuck 23:1df3dddcb43e 471 uint8_t v = m_xcvr.read_reg(REG_LR_RSSIVALUE);
dudmuck 23:1df3dddcb43e 472 if (m_xcvr.type == SX1276) {
dudmuck 23:1df3dddcb43e 473 if (m_xcvr.HF)
dudmuck 23:1df3dddcb43e 474 return v - 157;
dudmuck 23:1df3dddcb43e 475 else
dudmuck 23:1df3dddcb43e 476 return v - 164;
dudmuck 23:1df3dddcb43e 477 } else
dudmuck 23:1df3dddcb43e 478 return v - 125;
dudmuck 23:1df3dddcb43e 479 }
dudmuck 23:1df3dddcb43e 480
dudmuck 2:fdae76e1215e 481 service_action_e SX127x_lora::service()
dudmuck 2:fdae76e1215e 482 {
dudmuck 2:fdae76e1215e 483 if (m_xcvr.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER) {
dudmuck 2:fdae76e1215e 484 if (poll_vh) {
dudmuck 2:fdae76e1215e 485 RegIrqFlags.octet = m_xcvr.read_reg(REG_LR_IRQFLAGS);
dudmuck 2:fdae76e1215e 486 if (RegIrqFlags.bits.ValidHeader) {
dudmuck 2:fdae76e1215e 487 RegIrqFlags.octet = 0;
dudmuck 2:fdae76e1215e 488 RegIrqFlags.bits.ValidHeader = 1;
dudmuck 2:fdae76e1215e 489 m_xcvr.write_reg(REG_LR_IRQFLAGS, RegIrqFlags.octet);
dudmuck 2:fdae76e1215e 490 printf("VH\r\n");
dudmuck 2:fdae76e1215e 491 }
dudmuck 2:fdae76e1215e 492 }
dudmuck 2:fdae76e1215e 493 }
dudmuck 7:927a05f84ede 494
dudmuck 2:fdae76e1215e 495 if (m_xcvr.dio0 == 0)
dudmuck 2:fdae76e1215e 496 return SERVICE_NONE;
dudmuck 2:fdae76e1215e 497
dudmuck 2:fdae76e1215e 498 switch (m_xcvr.RegDioMapping1.bits.Dio0Mapping) {
dudmuck 2:fdae76e1215e 499 case 0: // RxDone
dudmuck 2:fdae76e1215e 500 /* user checks for CRC error in IrqFlags */
dudmuck 2:fdae76e1215e 501 RegIrqFlags.octet = m_xcvr.read_reg(REG_LR_IRQFLAGS); // save flags
dudmuck 2:fdae76e1215e 502 RegHopChannel.octet = m_xcvr.read_reg(REG_LR_HOPCHANNEL);
dudmuck 2:fdae76e1215e 503 //printf("[%02x]", RegIrqFlags.octet);
dudmuck 2:fdae76e1215e 504 m_xcvr.write_reg(REG_LR_IRQFLAGS, RegIrqFlags.octet); // clear flags in radio
dudmuck 2:fdae76e1215e 505
dudmuck 2:fdae76e1215e 506 /* any register of interest on received packet is read(saved) here */
dudmuck 2:fdae76e1215e 507 RegModemStatus.octet = m_xcvr.read_reg(REG_LR_MODEMSTAT);
dudmuck 2:fdae76e1215e 508 RegPktSnrValue = m_xcvr.read_reg(REG_LR_PKTSNRVALUE);
dudmuck 2:fdae76e1215e 509 RegPktRssiValue = m_xcvr.read_reg(REG_LR_PKTRSSIVALUE);
dudmuck 2:fdae76e1215e 510 RegRxNbBytes = m_xcvr.read_reg(REG_LR_RXNBBYTES);
dudmuck 2:fdae76e1215e 511
dudmuck 2:fdae76e1215e 512 m_xcvr.write_reg(REG_LR_FIFOADDRPTR, m_xcvr.read_reg(REG_LR_FIFORXCURRENTADDR));
dudmuck 2:fdae76e1215e 513 read_fifo(RegRxNbBytes);
dudmuck 2:fdae76e1215e 514 return SERVICE_READ_FIFO;
dudmuck 2:fdae76e1215e 515 case 1: // TxDone
dudmuck 2:fdae76e1215e 516 RegIrqFlags.octet = 0;
dudmuck 2:fdae76e1215e 517 RegIrqFlags.bits.TxDone = 1;
dudmuck 2:fdae76e1215e 518 m_xcvr.write_reg(REG_LR_IRQFLAGS, RegIrqFlags.octet);
dudmuck 2:fdae76e1215e 519 return SERVICE_TX_DONE;
dudmuck 2:fdae76e1215e 520 } // ...switch (RegDioMapping1.bits.Dio0Mapping)
dudmuck 2:fdae76e1215e 521
dudmuck 2:fdae76e1215e 522 return SERVICE_ERROR;
dudmuck 12:bda42457c34a 523 }
dudmuck 12:bda42457c34a 524