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
Child:
3:3bf2515b1eed
separated LoRa code from FSK code from common code

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 2:fdae76e1215e 1 #include "sx127x_fsk.h"
dudmuck 2:fdae76e1215e 2
dudmuck 2:fdae76e1215e 3 /* SX127x driver
dudmuck 2:fdae76e1215e 4 * Copyright (c) 2013 Semtech
dudmuck 2:fdae76e1215e 5 *
dudmuck 2:fdae76e1215e 6 * Licensed under the Apache License, Version 2.0 (the "License");
dudmuck 2:fdae76e1215e 7 * you may not use this file except in compliance with the License.
dudmuck 2:fdae76e1215e 8 * You may obtain a copy of the License at
dudmuck 2:fdae76e1215e 9 *
dudmuck 2:fdae76e1215e 10 * http://www.apache.org/licenses/LICENSE-2.0
dudmuck 2:fdae76e1215e 11 *
dudmuck 2:fdae76e1215e 12 * Unless required by applicable law or agreed to in writing, software
dudmuck 2:fdae76e1215e 13 * distributed under the License is distributed on an "AS IS" BASIS,
dudmuck 2:fdae76e1215e 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
dudmuck 2:fdae76e1215e 15 * See the License for the specific language governing permissions and
dudmuck 2:fdae76e1215e 16 * limitations under the License.
dudmuck 2:fdae76e1215e 17 */
dudmuck 2:fdae76e1215e 18
dudmuck 2:fdae76e1215e 19 //SX127x_fsk::SX127x_fsk(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName rst, PinName dio_0, PinName dio_1, PinName fem_ctx, PinName fem_cps) : SX127x(mosi, miso, sclk, cs, rst, dio_0, dio_1, fem_ctx, fem_cps)
dudmuck 2:fdae76e1215e 20 SX127x_fsk::SX127x_fsk(SX127x r) : m_xcvr(r)
dudmuck 2:fdae76e1215e 21 {
dudmuck 2:fdae76e1215e 22 }
dudmuck 2:fdae76e1215e 23
dudmuck 2:fdae76e1215e 24 SX127x_fsk::~SX127x_fsk()
dudmuck 2:fdae76e1215e 25 {
dudmuck 2:fdae76e1215e 26 }
dudmuck 2:fdae76e1215e 27
dudmuck 2:fdae76e1215e 28 void SX127x_fsk::write_fifo(uint8_t len)
dudmuck 2:fdae76e1215e 29 {
dudmuck 2:fdae76e1215e 30 int i;
dudmuck 2:fdae76e1215e 31
dudmuck 2:fdae76e1215e 32 m_xcvr.m_cs = 0;
dudmuck 2:fdae76e1215e 33 m_xcvr.m_spi.write(REG_FIFO | 0x80); // bit7 is high for writing to radio
dudmuck 2:fdae76e1215e 34
dudmuck 2:fdae76e1215e 35 if (!m_xcvr.RegOpMode.bits.LongRangeMode && RegPktConfig1.bits.PacketFormatVariable)
dudmuck 2:fdae76e1215e 36 m_xcvr.m_spi.write(len);
dudmuck 2:fdae76e1215e 37
dudmuck 2:fdae76e1215e 38 for (i = 0; i < len; i++) {
dudmuck 2:fdae76e1215e 39 m_xcvr.m_spi.write(m_xcvr.tx_buf[i]);
dudmuck 2:fdae76e1215e 40 }
dudmuck 2:fdae76e1215e 41 m_xcvr.m_cs = 1;
dudmuck 2:fdae76e1215e 42 }
dudmuck 2:fdae76e1215e 43
dudmuck 2:fdae76e1215e 44 void SX127x_fsk::enable()
dudmuck 2:fdae76e1215e 45 {
dudmuck 2:fdae76e1215e 46 m_xcvr.set_opmode(RF_OPMODE_SLEEP);
dudmuck 2:fdae76e1215e 47
dudmuck 2:fdae76e1215e 48 m_xcvr.RegOpMode.bits.LongRangeMode = 0;
dudmuck 2:fdae76e1215e 49 m_xcvr.write_reg(REG_OPMODE, m_xcvr.RegOpMode.octet);
dudmuck 2:fdae76e1215e 50 wait(0.01);
dudmuck 2:fdae76e1215e 51
dudmuck 2:fdae76e1215e 52 /*RegOpMode.octet = read_reg(REG_OPMODE);
dudmuck 2:fdae76e1215e 53 printf("setloraoff:%02x\r\n", RegOpMode.octet);*/
dudmuck 2:fdae76e1215e 54
dudmuck 2:fdae76e1215e 55 // todo: read FSK regsiters
dudmuck 2:fdae76e1215e 56 //SX1272ReadBuffer( REG_OPMODE, SX1272Regs + 1, 0x70 - 1 );
dudmuck 2:fdae76e1215e 57 RegPktConfig1.octet = m_xcvr.read_reg(REG_FSK_PACKETCONFIG1);
dudmuck 2:fdae76e1215e 58 RegPktConfig2.word = m_xcvr.read_u16(REG_FSK_PACKETCONFIG2);
dudmuck 2:fdae76e1215e 59
dudmuck 2:fdae76e1215e 60 m_xcvr.set_opmode(RF_OPMODE_STANDBY);
dudmuck 2:fdae76e1215e 61 }
dudmuck 2:fdae76e1215e 62
dudmuck 2:fdae76e1215e 63 uint32_t SX127x_fsk::ComputeRxBw( uint8_t mantisse, uint8_t exponent )
dudmuck 2:fdae76e1215e 64 {
dudmuck 2:fdae76e1215e 65 // rxBw
dudmuck 2:fdae76e1215e 66 if (m_xcvr.RegOpMode.bits.ModulationType == 0)
dudmuck 2:fdae76e1215e 67 return XTAL_FREQ / (mantisse * (1 << (exponent+2)));
dudmuck 2:fdae76e1215e 68 else
dudmuck 2:fdae76e1215e 69 return XTAL_FREQ / (mantisse * (1 << (exponent+3)));
dudmuck 2:fdae76e1215e 70 }
dudmuck 2:fdae76e1215e 71
dudmuck 2:fdae76e1215e 72
dudmuck 2:fdae76e1215e 73 void SX127x_fsk::ComputeRxBwMantExp( uint32_t rxBwValue, uint8_t* mantisse, uint8_t* exponent )
dudmuck 2:fdae76e1215e 74 {
dudmuck 2:fdae76e1215e 75 uint8_t tmpExp, tmpMant;
dudmuck 2:fdae76e1215e 76 double tmpRxBw;
dudmuck 2:fdae76e1215e 77 double rxBwMin = 10e6;
dudmuck 2:fdae76e1215e 78
dudmuck 2:fdae76e1215e 79 for( tmpExp = 0; tmpExp < 8; tmpExp++ ) {
dudmuck 2:fdae76e1215e 80 for( tmpMant = 16; tmpMant <= 24; tmpMant += 4 ) {
dudmuck 2:fdae76e1215e 81 tmpRxBw = ComputeRxBw(tmpMant, tmpExp);
dudmuck 2:fdae76e1215e 82 if( fabs( tmpRxBw - rxBwValue ) < rxBwMin ) {
dudmuck 2:fdae76e1215e 83 rxBwMin = fabs( tmpRxBw - rxBwValue );
dudmuck 2:fdae76e1215e 84 *mantisse = tmpMant;
dudmuck 2:fdae76e1215e 85 *exponent = tmpExp;
dudmuck 2:fdae76e1215e 86 }
dudmuck 2:fdae76e1215e 87 }
dudmuck 2:fdae76e1215e 88 }
dudmuck 2:fdae76e1215e 89 }
dudmuck 2:fdae76e1215e 90
dudmuck 2:fdae76e1215e 91
dudmuck 2:fdae76e1215e 92 uint32_t SX127x_fsk::get_rx_bw_hz(uint8_t addr)
dudmuck 2:fdae76e1215e 93 {
dudmuck 2:fdae76e1215e 94 FSKRegRxBw_t reg_bw;
dudmuck 2:fdae76e1215e 95 uint8_t mantissa;
dudmuck 2:fdae76e1215e 96
dudmuck 2:fdae76e1215e 97 if (m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 2:fdae76e1215e 98 return 0;
dudmuck 2:fdae76e1215e 99
dudmuck 2:fdae76e1215e 100 reg_bw.octet = m_xcvr.read_reg(addr);
dudmuck 2:fdae76e1215e 101 switch (reg_bw.bits.Mantissa) {
dudmuck 2:fdae76e1215e 102 case 0: mantissa = 16; break;
dudmuck 2:fdae76e1215e 103 case 1: mantissa = 20; break;
dudmuck 2:fdae76e1215e 104 case 2: mantissa = 24; break;
dudmuck 2:fdae76e1215e 105 default: mantissa = 0; break;
dudmuck 2:fdae76e1215e 106 }
dudmuck 2:fdae76e1215e 107
dudmuck 2:fdae76e1215e 108 if (addr == REG_FSK_RXBW)
dudmuck 2:fdae76e1215e 109 RegRxBw.octet = reg_bw.octet;
dudmuck 2:fdae76e1215e 110 else if (addr == REG_FSK_AFCBW)
dudmuck 2:fdae76e1215e 111 RegAfcBw.octet = reg_bw.octet;
dudmuck 2:fdae76e1215e 112
dudmuck 2:fdae76e1215e 113 return ComputeRxBw(mantissa, reg_bw.bits.Exponent);
dudmuck 2:fdae76e1215e 114 }
dudmuck 2:fdae76e1215e 115
dudmuck 2:fdae76e1215e 116
dudmuck 2:fdae76e1215e 117 void SX127x_fsk::set_rx_dcc_bw_hz(uint32_t bw_hz, char afc)
dudmuck 2:fdae76e1215e 118 {
dudmuck 2:fdae76e1215e 119 uint8_t mantisse = 0;
dudmuck 2:fdae76e1215e 120 uint8_t exponent = 0;
dudmuck 2:fdae76e1215e 121
dudmuck 2:fdae76e1215e 122 if (m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 2:fdae76e1215e 123 return;
dudmuck 2:fdae76e1215e 124
dudmuck 2:fdae76e1215e 125 ComputeRxBwMantExp( bw_hz, &mantisse, &exponent );
dudmuck 2:fdae76e1215e 126 //printf("bw_hz:%d, mantisse:%d, exponent:%d\n", bw_hz, mantisse, exponent );
dudmuck 2:fdae76e1215e 127 switch( mantisse ) {
dudmuck 2:fdae76e1215e 128 case 16:
dudmuck 2:fdae76e1215e 129 RegRxBw.bits.Mantissa = 0;
dudmuck 2:fdae76e1215e 130 break;
dudmuck 2:fdae76e1215e 131 case 20:
dudmuck 2:fdae76e1215e 132 RegRxBw.bits.Mantissa = 1;
dudmuck 2:fdae76e1215e 133 break;
dudmuck 2:fdae76e1215e 134 case 24:
dudmuck 2:fdae76e1215e 135 RegRxBw.bits.Mantissa = 2;
dudmuck 2:fdae76e1215e 136 break;
dudmuck 2:fdae76e1215e 137 default:
dudmuck 2:fdae76e1215e 138 // Something went terribely wrong
dudmuck 2:fdae76e1215e 139 printf("maintisse:%d\n", mantisse);
dudmuck 2:fdae76e1215e 140 break;
dudmuck 2:fdae76e1215e 141 }
dudmuck 2:fdae76e1215e 142 RegRxBw.bits.Exponent = exponent;
dudmuck 2:fdae76e1215e 143
dudmuck 2:fdae76e1215e 144 if (afc)
dudmuck 2:fdae76e1215e 145 m_xcvr.write_reg(REG_FSK_AFCBW, RegRxBw.octet);
dudmuck 2:fdae76e1215e 146 else
dudmuck 2:fdae76e1215e 147 m_xcvr.write_reg(REG_FSK_RXBW, RegRxBw.octet);
dudmuck 2:fdae76e1215e 148 }
dudmuck 2:fdae76e1215e 149
dudmuck 2:fdae76e1215e 150
dudmuck 2:fdae76e1215e 151 void SX127x_fsk::start_tx(uint16_t arg_len)
dudmuck 2:fdae76e1215e 152 {
dudmuck 2:fdae76e1215e 153 uint16_t pkt_buf_len;
dudmuck 2:fdae76e1215e 154 FSKRegIrqFlags2_t RegIrqFlags2;
dudmuck 2:fdae76e1215e 155 int maxlen = FSK_FIFO_SIZE-1;
dudmuck 2:fdae76e1215e 156
dudmuck 2:fdae76e1215e 157 if (m_xcvr.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER) {
dudmuck 2:fdae76e1215e 158 m_xcvr.set_opmode(RF_OPMODE_STANDBY);
dudmuck 2:fdae76e1215e 159 }
dudmuck 2:fdae76e1215e 160
dudmuck 2:fdae76e1215e 161 if (m_xcvr.RegDioMapping1.bits.Dio0Mapping != 0) {
dudmuck 2:fdae76e1215e 162 m_xcvr.RegDioMapping1.bits.Dio0Mapping = 0;
dudmuck 2:fdae76e1215e 163 m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
dudmuck 2:fdae76e1215e 164 }
dudmuck 2:fdae76e1215e 165
dudmuck 2:fdae76e1215e 166 if (RegPktConfig1.bits.PacketFormatVariable) {
dudmuck 2:fdae76e1215e 167 printf("variable-fmt %d\r\n", arg_len);
dudmuck 2:fdae76e1215e 168 pkt_buf_len = arg_len;
dudmuck 2:fdae76e1215e 169 } else {
dudmuck 2:fdae76e1215e 170 pkt_buf_len = RegPktConfig2.bits.PayloadLength;
dudmuck 2:fdae76e1215e 171 printf("fixed-fmt %d\r\n", pkt_buf_len);
dudmuck 2:fdae76e1215e 172 }
dudmuck 2:fdae76e1215e 173
dudmuck 2:fdae76e1215e 174 RegIrqFlags2.octet = m_xcvr.read_reg(REG_FSK_IRQFLAGS2);
dudmuck 2:fdae76e1215e 175 if (RegIrqFlags2.bits.FifoEmpty) {
dudmuck 2:fdae76e1215e 176 if (RegPktConfig1.bits.PacketFormatVariable) {
dudmuck 2:fdae76e1215e 177 --maxlen; // space for length byte
dudmuck 2:fdae76e1215e 178 if (pkt_buf_len > maxlen) {
dudmuck 2:fdae76e1215e 179 /*setup_FifoLevel(FALLING_EDGE);
dudmuck 2:fdae76e1215e 180 radio_write_fifo_(pkt_buf, maxlen, pkt_buf_len);
dudmuck 2:fdae76e1215e 181 remaining_ = pkt_buf_len - maxlen;
dudmuck 2:fdae76e1215e 182 printf("var-oversized %d R=%d\r\n", pkt_buf_len, remaining_);*/
dudmuck 2:fdae76e1215e 183 printf("var-oversized %d\r\n", pkt_buf_len);
dudmuck 2:fdae76e1215e 184 } else {
dudmuck 2:fdae76e1215e 185 //setup_FifoLevel(NO_EDGE); // disable
dudmuck 2:fdae76e1215e 186 printf("var-write-fifo %d\r\n", pkt_buf_len);
dudmuck 2:fdae76e1215e 187 write_fifo(pkt_buf_len);
dudmuck 2:fdae76e1215e 188 //remaining_ = 0; // all was sent
dudmuck 2:fdae76e1215e 189 }
dudmuck 2:fdae76e1215e 190 } else { // fixed-length pkt format...
dudmuck 2:fdae76e1215e 191 pkt_buf_len = RegPktConfig2.bits.PayloadLength;
dudmuck 2:fdae76e1215e 192 if (RegPktConfig2.bits.PayloadLength > maxlen) {
dudmuck 2:fdae76e1215e 193 /*setup_FifoLevel(FALLING_EDGE);
dudmuck 2:fdae76e1215e 194 radio_write_fifo_(pkt_buf, maxlen, -1);
dudmuck 2:fdae76e1215e 195 remaining_ = SX1272FSK->RegPktConfig2.bits.PayloadLength - maxlen;*/
dudmuck 2:fdae76e1215e 196 printf("todo: fsk large packet\r\n");
dudmuck 2:fdae76e1215e 197 } else {
dudmuck 2:fdae76e1215e 198 //setup_FifoLevel(NO_EDGE); // disable
dudmuck 2:fdae76e1215e 199 printf("fixed-write-fifo %d\r\n", RegPktConfig2.bits.PayloadLength);
dudmuck 2:fdae76e1215e 200 write_fifo(RegPktConfig2.bits.PayloadLength);
dudmuck 2:fdae76e1215e 201 }
dudmuck 2:fdae76e1215e 202 }
dudmuck 2:fdae76e1215e 203 } else
dudmuck 2:fdae76e1215e 204 printf("fifo not empty %02x\r\n", RegIrqFlags2.octet);
dudmuck 2:fdae76e1215e 205
dudmuck 2:fdae76e1215e 206 m_xcvr.set_opmode(RF_OPMODE_TRANSMITTER);
dudmuck 2:fdae76e1215e 207
dudmuck 2:fdae76e1215e 208 }
dudmuck 2:fdae76e1215e 209
dudmuck 2:fdae76e1215e 210
dudmuck 2:fdae76e1215e 211 void SX127x_fsk::start_rx()
dudmuck 2:fdae76e1215e 212 {
dudmuck 2:fdae76e1215e 213 if (m_xcvr.RegOpMode.bits.LongRangeMode)
dudmuck 2:fdae76e1215e 214 return;
dudmuck 2:fdae76e1215e 215
dudmuck 2:fdae76e1215e 216 if (m_xcvr.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER) {
dudmuck 2:fdae76e1215e 217 // was already receiving, restart it
dudmuck 2:fdae76e1215e 218 m_xcvr.set_opmode(RF_OPMODE_STANDBY);
dudmuck 2:fdae76e1215e 219 wait(0.01);
dudmuck 2:fdae76e1215e 220 }
dudmuck 2:fdae76e1215e 221 m_xcvr.set_opmode(RF_OPMODE_RECEIVER);
dudmuck 2:fdae76e1215e 222 }
dudmuck 2:fdae76e1215e 223
dudmuck 2:fdae76e1215e 224 service_action_e SX127x_fsk::service()
dudmuck 2:fdae76e1215e 225 {
dudmuck 2:fdae76e1215e 226 int i;
dudmuck 2:fdae76e1215e 227
dudmuck 2:fdae76e1215e 228 if (m_xcvr.RegOpMode.bits.Mode == RF_OPMODE_TRANSMITTER) {
dudmuck 2:fdae76e1215e 229 if (m_xcvr.dio0) {
dudmuck 2:fdae76e1215e 230 m_xcvr.set_opmode(RF_OPMODE_STANDBY);
dudmuck 2:fdae76e1215e 231 return SERVICE_TX_DONE;
dudmuck 2:fdae76e1215e 232 }
dudmuck 2:fdae76e1215e 233 } else if (m_xcvr.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER) {
dudmuck 2:fdae76e1215e 234 uint8_t len;
dudmuck 2:fdae76e1215e 235 if (RegPktConfig1.bits.PacketFormatVariable) {
dudmuck 2:fdae76e1215e 236 len = m_xcvr.read_reg(REG_FIFO);
dudmuck 2:fdae76e1215e 237 } else {
dudmuck 2:fdae76e1215e 238 len = RegPktConfig2.bits.PayloadLength;
dudmuck 2:fdae76e1215e 239 }
dudmuck 2:fdae76e1215e 240
dudmuck 2:fdae76e1215e 241 m_xcvr.m_cs = 0;
dudmuck 2:fdae76e1215e 242 m_xcvr.m_spi.write(REG_FIFO); // bit7 is low for reading from radio
dudmuck 2:fdae76e1215e 243 for (i = 0; i < len; i++) {
dudmuck 2:fdae76e1215e 244 m_xcvr.rx_buf[i] = m_xcvr.m_spi.write(0);
dudmuck 2:fdae76e1215e 245 }
dudmuck 2:fdae76e1215e 246 m_xcvr.m_cs = 1;
dudmuck 2:fdae76e1215e 247 return SERVICE_READ_FIFO;
dudmuck 2:fdae76e1215e 248 }
dudmuck 2:fdae76e1215e 249
dudmuck 2:fdae76e1215e 250 return SERVICE_NONE;
dudmuck 2:fdae76e1215e 251 }