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 Oct 22 01:27:18 2015 +0000
Revision:
25:fa867fb9d2f6
Parent:
24:cad6e7ce6928
Child:
27:da6341d9d5b1
fixed typo

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