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:
Mon Jul 18 21:13:50 2016 +0000
Revision:
26:4876e515ff4c
Parent:
23:1df3dddcb43e
Child:
27:da6341d9d5b1
FSK/OOK TX shutdown time corrected on PacketSent event.

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