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:
Wed Apr 30 22:49:43 2014 +0000
Revision:
2:fdae76e1215e
Parent:
1:7dc60eb4c7ec
Child:
4:d987ac2836bf
separated LoRa code from FSK code from common code

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