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:
Fri Feb 27 22:50:18 2015 +0000
Revision:
10:7382c260c4b1
Parent:
7:927a05f84ede
Child:
24:cad6e7ce6928
added get_symbol_duration() to determine if LowDataRateOptimize should be used

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 0:27aa8733f85d 1 #include "sx127x.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 7:927a05f84ede 19 SX127x::SX127x(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName rst, PinName dio_0, PinName dio_1) :
dudmuck 7:927a05f84ede 20 m_spi(mosi, miso, sclk), m_cs(cs), reset_pin(rst), dio0(dio_0), dio1(dio_1)
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 RegLna.octet = read_reg(REG_LNA);
dudmuck 0:27aa8733f85d 42 RegDioMapping1.octet = read_reg(REG_DIOMAPPING1);
dudmuck 0:27aa8733f85d 43 RegDioMapping2.octet = read_reg(REG_DIOMAPPING2);
dudmuck 0:27aa8733f85d 44
dudmuck 0:27aa8733f85d 45 get_type();
dudmuck 0:27aa8733f85d 46
dudmuck 4:d987ac2836bf 47 if (type == SX1272) {
dudmuck 4:d987ac2836bf 48 // turn on PA BOOST, eval boards are wired for this connection
dudmuck 4:d987ac2836bf 49 RegPaConfig.bits.PaSelect = 1;
dudmuck 4:d987ac2836bf 50 write_reg(REG_PACONFIG, RegPaConfig.octet);
dudmuck 4:d987ac2836bf 51 }
dudmuck 0:27aa8733f85d 52 }
dudmuck 0:27aa8733f85d 53
dudmuck 0:27aa8733f85d 54 void SX127x::get_type()
dudmuck 0:27aa8733f85d 55 {
dudmuck 0:27aa8733f85d 56 RegOpMode.octet = read_reg(REG_OPMODE);
dudmuck 10:7382c260c4b1 57
dudmuck 10:7382c260c4b1 58 /* SX1272 starts in FSK mode on powerup, RegOpMode bit3 will be set for BT1.0 in FSK */
dudmuck 10:7382c260c4b1 59 if (!RegOpMode.bits.LongRangeMode) {
dudmuck 10:7382c260c4b1 60 set_opmode(RF_OPMODE_SLEEP);
dudmuck 10:7382c260c4b1 61 wait(0.01);
dudmuck 10:7382c260c4b1 62 RegOpMode.bits.LongRangeMode = 1;
dudmuck 10:7382c260c4b1 63 write_reg(REG_OPMODE, RegOpMode.octet);
dudmuck 10:7382c260c4b1 64 wait(0.01);
dudmuck 10:7382c260c4b1 65 RegOpMode.octet = read_reg(REG_OPMODE);
dudmuck 10:7382c260c4b1 66 }
dudmuck 10:7382c260c4b1 67
dudmuck 0:27aa8733f85d 68 if (RegOpMode.sx1276LORAbits.LowFrequencyModeOn)
dudmuck 0:27aa8733f85d 69 type = SX1276;
dudmuck 0:27aa8733f85d 70 else {
dudmuck 0:27aa8733f85d 71 RegOpMode.sx1276LORAbits.LowFrequencyModeOn = 1;
dudmuck 0:27aa8733f85d 72 write_reg(REG_OPMODE, RegOpMode.octet);
dudmuck 0:27aa8733f85d 73 RegOpMode.octet = read_reg(REG_OPMODE);
dudmuck 0:27aa8733f85d 74 if (RegOpMode.sx1276LORAbits.LowFrequencyModeOn)
dudmuck 0:27aa8733f85d 75 type = SX1276;
dudmuck 0:27aa8733f85d 76 else
dudmuck 0:27aa8733f85d 77 type = SX1272;
dudmuck 0:27aa8733f85d 78 }
dudmuck 0:27aa8733f85d 79 }
dudmuck 1:7dc60eb4c7ec 80
dudmuck 1:7dc60eb4c7ec 81 void
dudmuck 1:7dc60eb4c7ec 82 SX127x::ReadBuffer( uint8_t addr, uint8_t *buffer, uint8_t size )
dudmuck 1:7dc60eb4c7ec 83 {
dudmuck 1:7dc60eb4c7ec 84 uint8_t i;
dudmuck 1:7dc60eb4c7ec 85
dudmuck 1:7dc60eb4c7ec 86 m_cs = 0;
dudmuck 1:7dc60eb4c7ec 87
dudmuck 1:7dc60eb4c7ec 88 m_spi.write(addr); // bit7 is low for reading from radio
dudmuck 1:7dc60eb4c7ec 89
dudmuck 1:7dc60eb4c7ec 90 for( i = 0; i < size; i++ )
dudmuck 1:7dc60eb4c7ec 91 {
dudmuck 1:7dc60eb4c7ec 92 buffer[i] = m_spi.write(0x00);
dudmuck 1:7dc60eb4c7ec 93 }
dudmuck 1:7dc60eb4c7ec 94
dudmuck 1:7dc60eb4c7ec 95 m_cs = 1;
dudmuck 1:7dc60eb4c7ec 96 }
dudmuck 1:7dc60eb4c7ec 97
dudmuck 0:27aa8733f85d 98 uint8_t SX127x::read_reg(uint8_t addr)
dudmuck 0:27aa8733f85d 99 {
dudmuck 0:27aa8733f85d 100 uint8_t ret;
dudmuck 0:27aa8733f85d 101 // Select the device by seting chip select low
dudmuck 0:27aa8733f85d 102 m_cs = 0;
dudmuck 0:27aa8733f85d 103
dudmuck 0:27aa8733f85d 104 m_spi.write(addr); // bit7 is low for reading from radio
dudmuck 0:27aa8733f85d 105
dudmuck 0:27aa8733f85d 106 // Send a dummy byte to receive the contents of register
dudmuck 0:27aa8733f85d 107 ret = m_spi.write(0x00);
dudmuck 0:27aa8733f85d 108
dudmuck 0:27aa8733f85d 109 // Deselect the device
dudmuck 0:27aa8733f85d 110 m_cs = 1;
dudmuck 0:27aa8733f85d 111
dudmuck 0:27aa8733f85d 112 return ret;
dudmuck 0:27aa8733f85d 113 }
dudmuck 0:27aa8733f85d 114
dudmuck 2:fdae76e1215e 115 int16_t SX127x::read_s16(uint8_t addr)
dudmuck 2:fdae76e1215e 116 {
dudmuck 2:fdae76e1215e 117 int16_t ret;
dudmuck 2:fdae76e1215e 118 // Select the device by seting chip select low
dudmuck 2:fdae76e1215e 119 m_cs = 0;
dudmuck 2:fdae76e1215e 120
dudmuck 2:fdae76e1215e 121 m_spi.write(addr); // bit7 is low for reading from radio
dudmuck 2:fdae76e1215e 122
dudmuck 2:fdae76e1215e 123 // Send a dummy byte to receive the contents of register
dudmuck 2:fdae76e1215e 124 ret = m_spi.write(0x00);
dudmuck 2:fdae76e1215e 125 ret <<= 8;
dudmuck 2:fdae76e1215e 126 ret += m_spi.write(0x00);
dudmuck 2:fdae76e1215e 127
dudmuck 2:fdae76e1215e 128 // Deselect the device
dudmuck 2:fdae76e1215e 129 m_cs = 1;
dudmuck 2:fdae76e1215e 130
dudmuck 2:fdae76e1215e 131 return ret;
dudmuck 2:fdae76e1215e 132 }
dudmuck 2:fdae76e1215e 133
dudmuck 0:27aa8733f85d 134 uint16_t SX127x::read_u16(uint8_t addr)
dudmuck 0:27aa8733f85d 135 {
dudmuck 0:27aa8733f85d 136 uint16_t ret;
dudmuck 0:27aa8733f85d 137 // Select the device by seting chip select low
dudmuck 0:27aa8733f85d 138 m_cs = 0;
dudmuck 0:27aa8733f85d 139
dudmuck 0:27aa8733f85d 140 m_spi.write(addr); // bit7 is low for reading from radio
dudmuck 0:27aa8733f85d 141
dudmuck 0:27aa8733f85d 142 // Send a dummy byte to receive the contents of register
dudmuck 0:27aa8733f85d 143 ret = m_spi.write(0x00);
dudmuck 0:27aa8733f85d 144 ret <<= 8;
dudmuck 0:27aa8733f85d 145 ret += m_spi.write(0x00);
dudmuck 0:27aa8733f85d 146
dudmuck 0:27aa8733f85d 147 // Deselect the device
dudmuck 0:27aa8733f85d 148 m_cs = 1;
dudmuck 0:27aa8733f85d 149
dudmuck 0:27aa8733f85d 150 return ret;
dudmuck 0:27aa8733f85d 151 }
dudmuck 0:27aa8733f85d 152
dudmuck 4:d987ac2836bf 153 void SX127x::write_u16(uint8_t addr, uint16_t data)
dudmuck 4:d987ac2836bf 154 {
dudmuck 4:d987ac2836bf 155 m_cs = 0; // Select the device by seting chip select low
dudmuck 4:d987ac2836bf 156
dudmuck 4:d987ac2836bf 157 m_spi.write(addr | 0x80); // bit7 is high for writing to radio
dudmuck 4:d987ac2836bf 158 m_spi.write((data >> 8) & 0xff);
dudmuck 4:d987ac2836bf 159 m_spi.write(data & 0xff);
dudmuck 4:d987ac2836bf 160
dudmuck 4:d987ac2836bf 161 m_cs = 1; // Deselect the device
dudmuck 4:d987ac2836bf 162 }
dudmuck 4:d987ac2836bf 163
dudmuck 4:d987ac2836bf 164 void SX127x::write_u24(uint8_t addr, uint32_t data)
dudmuck 0:27aa8733f85d 165 {
dudmuck 0:27aa8733f85d 166 m_cs = 0; // Select the device by seting chip select low
dudmuck 0:27aa8733f85d 167
dudmuck 0:27aa8733f85d 168 m_spi.write(addr | 0x80); // bit7 is high for writing to radio
dudmuck 0:27aa8733f85d 169 m_spi.write((data >> 16) & 0xff);
dudmuck 0:27aa8733f85d 170 m_spi.write((data >> 8) & 0xff);
dudmuck 0:27aa8733f85d 171 m_spi.write(data & 0xff);
dudmuck 0:27aa8733f85d 172
dudmuck 0:27aa8733f85d 173 m_cs = 1; // Deselect the device
dudmuck 0:27aa8733f85d 174
dudmuck 0:27aa8733f85d 175 if (addr == REG_FRFMSB) {
dudmuck 0:27aa8733f85d 176 if (data < 0x8340000) // < 525MHz
dudmuck 0:27aa8733f85d 177 HF = false;
dudmuck 0:27aa8733f85d 178 else
dudmuck 0:27aa8733f85d 179 HF = true;
dudmuck 0:27aa8733f85d 180 }
dudmuck 0:27aa8733f85d 181 }
dudmuck 0:27aa8733f85d 182
dudmuck 0:27aa8733f85d 183 void SX127x::write_reg(uint8_t addr, uint8_t data)
dudmuck 0:27aa8733f85d 184 {
dudmuck 0:27aa8733f85d 185 m_cs = 0; // Select the device by seting chip select low
dudmuck 0:27aa8733f85d 186
dudmuck 0:27aa8733f85d 187 m_spi.write(addr | 0x80); // bit7 is high for writing to radio
dudmuck 0:27aa8733f85d 188 m_spi.write(data);
dudmuck 0:27aa8733f85d 189
dudmuck 0:27aa8733f85d 190 m_cs = 1; // Deselect the device
dudmuck 0:27aa8733f85d 191 }
dudmuck 0:27aa8733f85d 192
dudmuck 1:7dc60eb4c7ec 193 void SX127x::WriteBuffer( uint8_t addr, uint8_t *buffer, uint8_t size )
dudmuck 1:7dc60eb4c7ec 194 {
dudmuck 1:7dc60eb4c7ec 195 uint8_t i;
dudmuck 1:7dc60eb4c7ec 196
dudmuck 1:7dc60eb4c7ec 197 m_cs = 0; // Select the device by seting chip select low
dudmuck 1:7dc60eb4c7ec 198
dudmuck 1:7dc60eb4c7ec 199 m_spi.write(addr | 0x80); // bit7 is high for writing to radio
dudmuck 1:7dc60eb4c7ec 200 for( i = 0; i < size; i++ )
dudmuck 1:7dc60eb4c7ec 201 {
dudmuck 1:7dc60eb4c7ec 202 m_spi.write(buffer[i]);
dudmuck 1:7dc60eb4c7ec 203 }
dudmuck 1:7dc60eb4c7ec 204
dudmuck 1:7dc60eb4c7ec 205 m_cs = 1; // Deselect the device
dudmuck 1:7dc60eb4c7ec 206 }
dudmuck 1:7dc60eb4c7ec 207
dudmuck 0:27aa8733f85d 208 void SX127x::set_opmode(chip_mode_e mode)
dudmuck 0:27aa8733f85d 209 {
dudmuck 0:27aa8733f85d 210 RegOpMode.bits.Mode = mode;
dudmuck 7:927a05f84ede 211
dudmuck 7:927a05f84ede 212 // callback to control antenna switch and PaSelect (PABOOST/RFO) for TX
dudmuck 7:927a05f84ede 213 rf_switch.call();
dudmuck 7:927a05f84ede 214
dudmuck 0:27aa8733f85d 215 write_reg(REG_OPMODE, RegOpMode.octet);
dudmuck 0:27aa8733f85d 216 }
dudmuck 0:27aa8733f85d 217
dudmuck 0:27aa8733f85d 218 void SX127x::set_frf_MHz( float MHz )
dudmuck 0:27aa8733f85d 219 {
dudmuck 0:27aa8733f85d 220 uint32_t frf;
dudmuck 0:27aa8733f85d 221
dudmuck 0:27aa8733f85d 222 frf = MHz / FREQ_STEP_MHZ;
dudmuck 4:d987ac2836bf 223 write_u24(REG_FRFMSB, frf);
dudmuck 0:27aa8733f85d 224
dudmuck 0:27aa8733f85d 225 if (MHz < 525)
dudmuck 0:27aa8733f85d 226 HF = false;
dudmuck 0:27aa8733f85d 227 else
dudmuck 0:27aa8733f85d 228 HF = true;
dudmuck 0:27aa8733f85d 229 }
dudmuck 0:27aa8733f85d 230
dudmuck 0:27aa8733f85d 231 float SX127x::get_frf_MHz(void)
dudmuck 0:27aa8733f85d 232 {
dudmuck 0:27aa8733f85d 233 uint32_t frf;
dudmuck 0:27aa8733f85d 234 uint8_t lsb, mid, msb;
dudmuck 0:27aa8733f85d 235 float MHz;
dudmuck 0:27aa8733f85d 236
dudmuck 0:27aa8733f85d 237 msb = read_reg(REG_FRFMSB);
dudmuck 0:27aa8733f85d 238 mid = read_reg(REG_FRFMID);
dudmuck 0:27aa8733f85d 239 lsb = read_reg(REG_FRFLSB);
dudmuck 0:27aa8733f85d 240 frf = msb;
dudmuck 0:27aa8733f85d 241 frf <<= 8;
dudmuck 0:27aa8733f85d 242 frf += mid;
dudmuck 0:27aa8733f85d 243 frf <<= 8;
dudmuck 0:27aa8733f85d 244 frf += lsb;
dudmuck 0:27aa8733f85d 245
dudmuck 0:27aa8733f85d 246 MHz = frf * FREQ_STEP_MHZ;
dudmuck 0:27aa8733f85d 247
dudmuck 0:27aa8733f85d 248 if (MHz < 525)
dudmuck 0:27aa8733f85d 249 HF = false;
dudmuck 0:27aa8733f85d 250 else
dudmuck 0:27aa8733f85d 251 HF = true;
dudmuck 0:27aa8733f85d 252
dudmuck 0:27aa8733f85d 253 return MHz;
dudmuck 0:27aa8733f85d 254 }
dudmuck 0:27aa8733f85d 255
dudmuck 0:27aa8733f85d 256 void SX127x::hw_reset()
dudmuck 0:27aa8733f85d 257 {
dudmuck 0:27aa8733f85d 258 /* only a french-swiss design would have hi-Z deassert */
dudmuck 0:27aa8733f85d 259 reset_pin.output();
dudmuck 0:27aa8733f85d 260 reset_pin.write(1);
dudmuck 0:27aa8733f85d 261 wait(0.05);
dudmuck 0:27aa8733f85d 262 reset_pin.input();
dudmuck 0:27aa8733f85d 263 wait(0.05);
dudmuck 0:27aa8733f85d 264 }
dudmuck 0:27aa8733f85d 265