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 May 02 23:35:30 2014 +0000
Revision:
4:d987ac2836bf
Parent:
2:fdae76e1215e
Child:
6:5d94ee847016
Child:
7:927a05f84ede
fixed FSK AFC

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