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:
Wayne Roberts
Date:
Fri Jul 10 09:23:52 2020 -0700
Revision:
36:af9b41b1e285
Parent:
33:4b9fd8969428
run on mbed-6

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Wayne Roberts 33:4b9fd8969428 1 #include "sx12xx.h"
dudmuck 0:27aa8733f85d 2
dudmuck 0:27aa8733f85d 3 /* SX127x driver
dudmuck 0:27aa8733f85d 4 * Copyright (c) 2013 Semtech
dudmuck 0:27aa8733f85d 5 *
dudmuck 0:27aa8733f85d 6 * Licensed under the Apache License, Version 2.0 (the "License");
dudmuck 0:27aa8733f85d 7 * you may not use this file except in compliance with the License.
dudmuck 0:27aa8733f85d 8 * You may obtain a copy of the License at
dudmuck 0:27aa8733f85d 9 *
dudmuck 0:27aa8733f85d 10 * http://www.apache.org/licenses/LICENSE-2.0
dudmuck 0:27aa8733f85d 11 *
dudmuck 0:27aa8733f85d 12 * Unless required by applicable law or agreed to in writing, software
dudmuck 0:27aa8733f85d 13 * distributed under the License is distributed on an "AS IS" BASIS,
dudmuck 0:27aa8733f85d 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dudmuck 0:27aa8733f85d 15 * See the License for the specific language governing permissions and
dudmuck 0:27aa8733f85d 16 * limitations under the License.
dudmuck 0:27aa8733f85d 17 */
dudmuck 0:27aa8733f85d 18
dudmuck 29:b72ac28d59e9 19 SX127x::SX127x(PinName dio_0, PinName dio_1, PinName cs, SPI& spi_r, PinName rst) :
dudmuck 29:b72ac28d59e9 20 dio0(dio_0), dio1(dio_1), m_cs(cs), m_spi(spi_r), reset_pin(rst)
dudmuck 0:27aa8733f85d 21 {
dudmuck 0:27aa8733f85d 22 reset_pin.input();
dudmuck 0:27aa8733f85d 23 m_cs = 1;
dudmuck 0:27aa8733f85d 24 m_spi.format(8, 0);
dudmuck 1:7dc60eb4c7ec 25 m_spi.frequency(3000000);
dudmuck 0:27aa8733f85d 26
dudmuck 0:27aa8733f85d 27 init();
dudmuck 0:27aa8733f85d 28 }
dudmuck 0:27aa8733f85d 29
dudmuck 0:27aa8733f85d 30 SX127x::~SX127x()
dudmuck 0:27aa8733f85d 31 {
dudmuck 0:27aa8733f85d 32 set_opmode(RF_OPMODE_SLEEP);
dudmuck 0:27aa8733f85d 33 }
dudmuck 0:27aa8733f85d 34
dudmuck 0:27aa8733f85d 35 void SX127x::init()
dudmuck 0:27aa8733f85d 36 {
dudmuck 0:27aa8733f85d 37 type = SX_NONE;
dudmuck 0:27aa8733f85d 38
dudmuck 0:27aa8733f85d 39 RegOpMode.octet = read_reg(REG_OPMODE);
dudmuck 0:27aa8733f85d 40 RegPaConfig.octet = read_reg(REG_PACONFIG);
dudmuck 0:27aa8733f85d 41 RegDioMapping1.octet = read_reg(REG_DIOMAPPING1);
dudmuck 0:27aa8733f85d 42 RegDioMapping2.octet = read_reg(REG_DIOMAPPING2);
dudmuck 0:27aa8733f85d 43
dudmuck 0:27aa8733f85d 44 get_type();
dudmuck 0:27aa8733f85d 45
dudmuck 4:d987ac2836bf 46 if (type == SX1272) {
dudmuck 4:d987ac2836bf 47 // turn on PA BOOST, eval boards are wired for this connection
dudmuck 4:d987ac2836bf 48 RegPaConfig.bits.PaSelect = 1;
dudmuck 4:d987ac2836bf 49 write_reg(REG_PACONFIG, RegPaConfig.octet);
dudmuck 4:d987ac2836bf 50 }
dudmuck 24:cad6e7ce6928 51
dudmuck 24:cad6e7ce6928 52 RegLna.octet = read_reg(REG_LNA);
dudmuck 25:fa867fb9d2f6 53 RegLna.bits.LnaBoostHF = 3;
dudmuck 25:fa867fb9d2f6 54 write_reg(REG_LNA, RegLna.octet);
dudmuck 0:27aa8733f85d 55 }
dudmuck 0:27aa8733f85d 56
dudmuck 0:27aa8733f85d 57 void SX127x::get_type()
dudmuck 0:27aa8733f85d 58 {
dudmuck 0:27aa8733f85d 59 RegOpMode.octet = read_reg(REG_OPMODE);
dudmuck 10:7382c260c4b1 60
dudmuck 10:7382c260c4b1 61 /* SX1272 starts in FSK mode on powerup, RegOpMode bit3 will be set for BT1.0 in FSK */
dudmuck 10:7382c260c4b1 62 if (!RegOpMode.bits.LongRangeMode) {
dudmuck 10:7382c260c4b1 63 set_opmode(RF_OPMODE_SLEEP);
Wayne Roberts 36:af9b41b1e285 64 #if (MBED_MAJOR_VERSION < 6)
Wayne Roberts 36:af9b41b1e285 65 ThisThread::sleep_for(10);
Wayne Roberts 36:af9b41b1e285 66 #else
Wayne Roberts 36:af9b41b1e285 67 ThisThread::sleep_for(10ms);
Wayne Roberts 36:af9b41b1e285 68 #endif
dudmuck 10:7382c260c4b1 69 RegOpMode.bits.LongRangeMode = 1;
dudmuck 10:7382c260c4b1 70 write_reg(REG_OPMODE, RegOpMode.octet);
Wayne Roberts 36:af9b41b1e285 71 #if (MBED_MAJOR_VERSION < 6)
Wayne Roberts 36:af9b41b1e285 72 ThisThread::sleep_for(10);
Wayne Roberts 36:af9b41b1e285 73 #else
Wayne Roberts 36:af9b41b1e285 74 ThisThread::sleep_for(10ms);
Wayne Roberts 36:af9b41b1e285 75 #endif
dudmuck 10:7382c260c4b1 76 RegOpMode.octet = read_reg(REG_OPMODE);
dudmuck 10:7382c260c4b1 77 }
dudmuck 10:7382c260c4b1 78
dudmuck 0:27aa8733f85d 79 if (RegOpMode.sx1276LORAbits.LowFrequencyModeOn)
dudmuck 0:27aa8733f85d 80 type = SX1276;
dudmuck 0:27aa8733f85d 81 else {
dudmuck 0:27aa8733f85d 82 RegOpMode.sx1276LORAbits.LowFrequencyModeOn = 1;
dudmuck 0:27aa8733f85d 83 write_reg(REG_OPMODE, RegOpMode.octet);
dudmuck 0:27aa8733f85d 84 RegOpMode.octet = read_reg(REG_OPMODE);
dudmuck 0:27aa8733f85d 85 if (RegOpMode.sx1276LORAbits.LowFrequencyModeOn)
dudmuck 0:27aa8733f85d 86 type = SX1276;
dudmuck 0:27aa8733f85d 87 else
dudmuck 0:27aa8733f85d 88 type = SX1272;
dudmuck 0:27aa8733f85d 89 }
dudmuck 0:27aa8733f85d 90 }
dudmuck 1:7dc60eb4c7ec 91
dudmuck 1:7dc60eb4c7ec 92 void
dudmuck 1:7dc60eb4c7ec 93 SX127x::ReadBuffer( uint8_t addr, uint8_t *buffer, uint8_t size )
dudmuck 1:7dc60eb4c7ec 94 {
dudmuck 1:7dc60eb4c7ec 95 uint8_t i;
dudmuck 1:7dc60eb4c7ec 96
dudmuck 1:7dc60eb4c7ec 97 m_cs = 0;
dudmuck 1:7dc60eb4c7ec 98
dudmuck 1:7dc60eb4c7ec 99 m_spi.write(addr); // bit7 is low for reading from radio
dudmuck 1:7dc60eb4c7ec 100
dudmuck 1:7dc60eb4c7ec 101 for( i = 0; i < size; i++ )
dudmuck 1:7dc60eb4c7ec 102 {
dudmuck 1:7dc60eb4c7ec 103 buffer[i] = m_spi.write(0x00);
dudmuck 1:7dc60eb4c7ec 104 }
dudmuck 1:7dc60eb4c7ec 105
dudmuck 1:7dc60eb4c7ec 106 m_cs = 1;
dudmuck 1:7dc60eb4c7ec 107 }
dudmuck 1:7dc60eb4c7ec 108
dudmuck 0:27aa8733f85d 109 uint8_t SX127x::read_reg(uint8_t addr)
dudmuck 0:27aa8733f85d 110 {
dudmuck 0:27aa8733f85d 111 uint8_t ret;
dudmuck 0:27aa8733f85d 112 // Select the device by seting chip select low
dudmuck 0:27aa8733f85d 113 m_cs = 0;
dudmuck 0:27aa8733f85d 114
dudmuck 0:27aa8733f85d 115 m_spi.write(addr); // bit7 is low for reading from radio
dudmuck 0:27aa8733f85d 116
dudmuck 0:27aa8733f85d 117 // Send a dummy byte to receive the contents of register
dudmuck 0:27aa8733f85d 118 ret = m_spi.write(0x00);
dudmuck 0:27aa8733f85d 119
dudmuck 0:27aa8733f85d 120 // Deselect the device
dudmuck 0:27aa8733f85d 121 m_cs = 1;
dudmuck 0:27aa8733f85d 122
dudmuck 0:27aa8733f85d 123 return ret;
dudmuck 0:27aa8733f85d 124 }
dudmuck 0:27aa8733f85d 125
dudmuck 2:fdae76e1215e 126 int16_t SX127x::read_s16(uint8_t addr)
dudmuck 2:fdae76e1215e 127 {
dudmuck 2:fdae76e1215e 128 int16_t ret;
dudmuck 2:fdae76e1215e 129 // Select the device by seting chip select low
dudmuck 2:fdae76e1215e 130 m_cs = 0;
dudmuck 2:fdae76e1215e 131
dudmuck 2:fdae76e1215e 132 m_spi.write(addr); // bit7 is low for reading from radio
dudmuck 2:fdae76e1215e 133
dudmuck 2:fdae76e1215e 134 // Send a dummy byte to receive the contents of register
dudmuck 2:fdae76e1215e 135 ret = m_spi.write(0x00);
dudmuck 2:fdae76e1215e 136 ret <<= 8;
dudmuck 2:fdae76e1215e 137 ret += m_spi.write(0x00);
dudmuck 2:fdae76e1215e 138
dudmuck 2:fdae76e1215e 139 // Deselect the device
dudmuck 2:fdae76e1215e 140 m_cs = 1;
dudmuck 2:fdae76e1215e 141
dudmuck 2:fdae76e1215e 142 return ret;
dudmuck 2:fdae76e1215e 143 }
dudmuck 2:fdae76e1215e 144
dudmuck 0:27aa8733f85d 145 uint16_t SX127x::read_u16(uint8_t addr)
dudmuck 0:27aa8733f85d 146 {
dudmuck 0:27aa8733f85d 147 uint16_t ret;
dudmuck 0:27aa8733f85d 148 // Select the device by seting chip select low
dudmuck 0:27aa8733f85d 149 m_cs = 0;
dudmuck 0:27aa8733f85d 150
dudmuck 0:27aa8733f85d 151 m_spi.write(addr); // bit7 is low for reading from radio
dudmuck 0:27aa8733f85d 152
dudmuck 0:27aa8733f85d 153 // Send a dummy byte to receive the contents of register
dudmuck 0:27aa8733f85d 154 ret = m_spi.write(0x00);
dudmuck 0:27aa8733f85d 155 ret <<= 8;
dudmuck 0:27aa8733f85d 156 ret += m_spi.write(0x00);
dudmuck 0:27aa8733f85d 157
dudmuck 0:27aa8733f85d 158 // Deselect the device
dudmuck 0:27aa8733f85d 159 m_cs = 1;
dudmuck 0:27aa8733f85d 160
dudmuck 0:27aa8733f85d 161 return ret;
dudmuck 0:27aa8733f85d 162 }
dudmuck 0:27aa8733f85d 163
dudmuck 4:d987ac2836bf 164 void SX127x::write_u16(uint8_t addr, uint16_t data)
dudmuck 4:d987ac2836bf 165 {
dudmuck 4:d987ac2836bf 166 m_cs = 0; // Select the device by seting chip select low
dudmuck 4:d987ac2836bf 167
dudmuck 4:d987ac2836bf 168 m_spi.write(addr | 0x80); // bit7 is high for writing to radio
dudmuck 4:d987ac2836bf 169 m_spi.write((data >> 8) & 0xff);
dudmuck 4:d987ac2836bf 170 m_spi.write(data & 0xff);
dudmuck 4:d987ac2836bf 171
dudmuck 4:d987ac2836bf 172 m_cs = 1; // Deselect the device
dudmuck 4:d987ac2836bf 173 }
dudmuck 4:d987ac2836bf 174
dudmuck 4:d987ac2836bf 175 void SX127x::write_u24(uint8_t addr, uint32_t data)
dudmuck 0:27aa8733f85d 176 {
dudmuck 0:27aa8733f85d 177 m_cs = 0; // Select the device by seting chip select low
dudmuck 0:27aa8733f85d 178
dudmuck 0:27aa8733f85d 179 m_spi.write(addr | 0x80); // bit7 is high for writing to radio
dudmuck 0:27aa8733f85d 180 m_spi.write((data >> 16) & 0xff);
dudmuck 0:27aa8733f85d 181 m_spi.write((data >> 8) & 0xff);
dudmuck 0:27aa8733f85d 182 m_spi.write(data & 0xff);
dudmuck 0:27aa8733f85d 183
dudmuck 0:27aa8733f85d 184 m_cs = 1; // Deselect the device
dudmuck 0:27aa8733f85d 185
dudmuck 0:27aa8733f85d 186 if (addr == REG_FRFMSB) {
dudmuck 0:27aa8733f85d 187 if (data < 0x8340000) // < 525MHz
dudmuck 0:27aa8733f85d 188 HF = false;
dudmuck 0:27aa8733f85d 189 else
dudmuck 0:27aa8733f85d 190 HF = true;
dudmuck 0:27aa8733f85d 191 }
dudmuck 0:27aa8733f85d 192 }
dudmuck 0:27aa8733f85d 193
dudmuck 0:27aa8733f85d 194 void SX127x::write_reg(uint8_t addr, uint8_t data)
dudmuck 0:27aa8733f85d 195 {
dudmuck 0:27aa8733f85d 196 m_cs = 0; // Select the device by seting chip select low
dudmuck 0:27aa8733f85d 197
dudmuck 0:27aa8733f85d 198 m_spi.write(addr | 0x80); // bit7 is high for writing to radio
dudmuck 0:27aa8733f85d 199 m_spi.write(data);
dudmuck 0:27aa8733f85d 200
dudmuck 0:27aa8733f85d 201 m_cs = 1; // Deselect the device
dudmuck 0:27aa8733f85d 202 }
dudmuck 0:27aa8733f85d 203
dudmuck 1:7dc60eb4c7ec 204 void SX127x::WriteBuffer( uint8_t addr, uint8_t *buffer, uint8_t size )
dudmuck 1:7dc60eb4c7ec 205 {
dudmuck 1:7dc60eb4c7ec 206 uint8_t i;
dudmuck 1:7dc60eb4c7ec 207
dudmuck 1:7dc60eb4c7ec 208 m_cs = 0; // Select the device by seting chip select low
dudmuck 1:7dc60eb4c7ec 209
dudmuck 1:7dc60eb4c7ec 210 m_spi.write(addr | 0x80); // bit7 is high for writing to radio
dudmuck 1:7dc60eb4c7ec 211 for( i = 0; i < size; i++ )
dudmuck 1:7dc60eb4c7ec 212 {
dudmuck 1:7dc60eb4c7ec 213 m_spi.write(buffer[i]);
dudmuck 1:7dc60eb4c7ec 214 }
dudmuck 1:7dc60eb4c7ec 215
dudmuck 1:7dc60eb4c7ec 216 m_cs = 1; // Deselect the device
dudmuck 1:7dc60eb4c7ec 217 }
dudmuck 1:7dc60eb4c7ec 218
dudmuck 0:27aa8733f85d 219 void SX127x::set_opmode(chip_mode_e mode)
dudmuck 0:27aa8733f85d 220 {
dudmuck 0:27aa8733f85d 221 RegOpMode.bits.Mode = mode;
dudmuck 7:927a05f84ede 222
dudmuck 7:927a05f84ede 223 // callback to control antenna switch and PaSelect (PABOOST/RFO) for TX
dudmuck 30:da4ea47f552a 224 if (rf_switch)
dudmuck 30:da4ea47f552a 225 rf_switch.call();
dudmuck 7:927a05f84ede 226
dudmuck 0:27aa8733f85d 227 write_reg(REG_OPMODE, RegOpMode.octet);
dudmuck 0:27aa8733f85d 228 }
dudmuck 0:27aa8733f85d 229
dudmuck 0:27aa8733f85d 230 void SX127x::set_frf_MHz( float MHz )
dudmuck 0:27aa8733f85d 231 {
dudmuck 0:27aa8733f85d 232 uint32_t frf;
dudmuck 0:27aa8733f85d 233
dudmuck 27:da6341d9d5b1 234 frf = MHz / (float)FREQ_STEP_MHZ;
dudmuck 4:d987ac2836bf 235 write_u24(REG_FRFMSB, frf);
dudmuck 0:27aa8733f85d 236
dudmuck 0:27aa8733f85d 237 if (MHz < 525)
dudmuck 0:27aa8733f85d 238 HF = false;
dudmuck 0:27aa8733f85d 239 else
dudmuck 0:27aa8733f85d 240 HF = true;
dudmuck 0:27aa8733f85d 241 }
dudmuck 0:27aa8733f85d 242
dudmuck 0:27aa8733f85d 243 float SX127x::get_frf_MHz(void)
dudmuck 0:27aa8733f85d 244 {
dudmuck 0:27aa8733f85d 245 uint32_t frf;
dudmuck 0:27aa8733f85d 246 uint8_t lsb, mid, msb;
dudmuck 0:27aa8733f85d 247 float MHz;
dudmuck 0:27aa8733f85d 248
dudmuck 0:27aa8733f85d 249 msb = read_reg(REG_FRFMSB);
dudmuck 0:27aa8733f85d 250 mid = read_reg(REG_FRFMID);
dudmuck 0:27aa8733f85d 251 lsb = read_reg(REG_FRFLSB);
dudmuck 0:27aa8733f85d 252 frf = msb;
dudmuck 0:27aa8733f85d 253 frf <<= 8;
dudmuck 0:27aa8733f85d 254 frf += mid;
dudmuck 0:27aa8733f85d 255 frf <<= 8;
dudmuck 0:27aa8733f85d 256 frf += lsb;
dudmuck 0:27aa8733f85d 257
dudmuck 0:27aa8733f85d 258 MHz = frf * FREQ_STEP_MHZ;
dudmuck 0:27aa8733f85d 259
dudmuck 0:27aa8733f85d 260 if (MHz < 525)
dudmuck 0:27aa8733f85d 261 HF = false;
dudmuck 0:27aa8733f85d 262 else
dudmuck 0:27aa8733f85d 263 HF = true;
dudmuck 0:27aa8733f85d 264
dudmuck 0:27aa8733f85d 265 return MHz;
dudmuck 0:27aa8733f85d 266 }
dudmuck 0:27aa8733f85d 267
dudmuck 0:27aa8733f85d 268 void SX127x::hw_reset()
dudmuck 0:27aa8733f85d 269 {
dudmuck 27:da6341d9d5b1 270 int in = reset_pin.read();
dudmuck 0:27aa8733f85d 271 reset_pin.output();
dudmuck 0:27aa8733f85d 272 reset_pin.write(1);
Wayne Roberts 36:af9b41b1e285 273 #if (MBED_MAJOR_VERSION < 6)
Wayne Roberts 36:af9b41b1e285 274 ThisThread::sleep_for(50);
dudmuck 27:da6341d9d5b1 275 if (in == 1) { /* pin is pulled up somewhere? */
dudmuck 27:da6341d9d5b1 276 reset_pin.write(0);
Wayne Roberts 36:af9b41b1e285 277 ThisThread::sleep_for(5);
dudmuck 27:da6341d9d5b1 278 }
dudmuck 0:27aa8733f85d 279 reset_pin.input();
Wayne Roberts 36:af9b41b1e285 280 ThisThread::sleep_for(5);
Wayne Roberts 36:af9b41b1e285 281 #else
Wayne Roberts 36:af9b41b1e285 282 ThisThread::sleep_for(50ms);
Wayne Roberts 36:af9b41b1e285 283 if (in == 1) { /* pin is pulled up somewhere? */
Wayne Roberts 36:af9b41b1e285 284 reset_pin.write(0);
Wayne Roberts 36:af9b41b1e285 285 ThisThread::sleep_for(5ms);
Wayne Roberts 36:af9b41b1e285 286 }
Wayne Roberts 36:af9b41b1e285 287 reset_pin.input();
Wayne Roberts 36:af9b41b1e285 288 ThisThread::sleep_for(5ms);
Wayne Roberts 36:af9b41b1e285 289 #endif
dudmuck 0:27aa8733f85d 290 }
dudmuck 0:27aa8733f85d 291