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 01:18:59 2014 +0000
Revision:
3:3bf2515b1eed
Parent:
2:fdae76e1215e
Child:
9:ae1a71ccd730
brought fsk to functioning

Who changed what in which revision?

UserRevisionLine numberNew contents of line
dudmuck 2:fdae76e1215e 1 #include "sx127x.h"
dudmuck 2:fdae76e1215e 2
dudmuck 2:fdae76e1215e 3 // LoRa registers
dudmuck 2:fdae76e1215e 4 #define REG_LR_FIFOADDRPTR 0x0d
dudmuck 2:fdae76e1215e 5 #define REG_LR_FIFOTXBASEADDR 0x0e
dudmuck 2:fdae76e1215e 6 #define REG_LR_FIFORXBASEADDR 0x0f
dudmuck 2:fdae76e1215e 7 #define REG_LR_FIFORXCURRENTADDR /*REG_LR_RXDATAADDR*/ 0x10
dudmuck 2:fdae76e1215e 8 #define REG_LR_IRQFLAGSMASK 0x11
dudmuck 2:fdae76e1215e 9 #define REG_LR_IRQFLAGS 0x12
dudmuck 2:fdae76e1215e 10 #define REG_LR_RXNBBYTES 0x13
dudmuck 2:fdae76e1215e 11 #define REG_LR_RXHEADERCNTVALUE_MSB 0x14
dudmuck 2:fdae76e1215e 12 #define REG_LR_RXHEADERCNTVALUE_LSB 0x15
dudmuck 2:fdae76e1215e 13 #define REG_LR_RXPACKETCNTVALUE_MSB 0x16
dudmuck 2:fdae76e1215e 14 #define REG_LR_RXPACKETCNTVALUE_LSB 0x17
dudmuck 2:fdae76e1215e 15 #define REG_LR_MODEMSTAT 0x18
dudmuck 2:fdae76e1215e 16 #define REG_LR_PKTSNRVALUE 0x19
dudmuck 2:fdae76e1215e 17 #define REG_LR_PKTRSSIVALUE 0x1a
dudmuck 2:fdae76e1215e 18 #define REG_LR_RSSIVALUE 0x1b
dudmuck 2:fdae76e1215e 19 #define REG_LR_HOPCHANNEL 0x1c
dudmuck 2:fdae76e1215e 20 #define REG_LR_MODEMCONFIG 0x1d
dudmuck 2:fdae76e1215e 21 #define REG_LR_MODEMCONFIG2 0x1e
dudmuck 2:fdae76e1215e 22 #define REG_LR_SYMBTIMEOUTLSB 0x1f
dudmuck 2:fdae76e1215e 23 #define REG_LR_PREAMBLEMSB 0x20
dudmuck 2:fdae76e1215e 24 #define REG_LR_PREAMBLELSB 0x21
dudmuck 2:fdae76e1215e 25 #define REG_LR_PAYLOADLENGTH 0x22 // and RX length for implicit
dudmuck 2:fdae76e1215e 26 #define REG_LR_RX_MAX_PAYLOADLENGTH 0x23 // length limit for explicit mode
dudmuck 2:fdae76e1215e 27 #define REG_LR_HOPPERIOD 0x24
dudmuck 2:fdae76e1215e 28 #define REG_LR_RXBYTEADDR /*REG_LR_RXDATAADDR*/ 0x25
dudmuck 2:fdae76e1215e 29 #define REG_LR_MODEMCONFIG3 0x26 // sx1272 REG_LR_PPM_CORRECTION_MSB
dudmuck 2:fdae76e1215e 30 #define REG_LR_PPM_CORRECTION_LSB 0x27
dudmuck 2:fdae76e1215e 31 #define REG_LR_TEST28 0x28 // est_freq_error
dudmuck 2:fdae76e1215e 32 #define REG_LR_TEST29 0x29 // est_freq_error
dudmuck 2:fdae76e1215e 33 #define REG_LR_TEST2A 0x2a // est_freq_error
dudmuck 2:fdae76e1215e 34 #define REG_LR_TEST2B 0x2b //
dudmuck 2:fdae76e1215e 35 #define REG_LR_WIDEBAND_RSSI 0x2c
dudmuck 2:fdae76e1215e 36 #define REG_LR_AGCH_TH 0x2d // agc_upper_th
dudmuck 2:fdae76e1215e 37 #define REG_LR_AGCL_TH 0x2e // agc_lower_th
dudmuck 2:fdae76e1215e 38 #define REG_LR_IFFRQH 0x2f // if_freq(12:8)
dudmuck 2:fdae76e1215e 39 #define REG_LR_IFFRQL 0x30 // if_freq(7:0)
dudmuck 2:fdae76e1215e 40 #define REG_LR_TEST31 0x31 // if_freq_auto, ...
dudmuck 2:fdae76e1215e 41 #define REG_LR_TEST32 0x32 //
dudmuck 2:fdae76e1215e 42 #define REG_LR_TEST33 0x33
dudmuck 2:fdae76e1215e 43 #define REG_LR_DETECTION_THRESHOLD 0x37
dudmuck 2:fdae76e1215e 44
dudmuck 2:fdae76e1215e 45 typedef union {
dudmuck 2:fdae76e1215e 46 struct { // sx127x register 0x12
dudmuck 2:fdae76e1215e 47 uint8_t CadDetected : 1; // 0
dudmuck 2:fdae76e1215e 48 uint8_t FhssChangeChannel : 1; // 1
dudmuck 2:fdae76e1215e 49 uint8_t CadDone : 1; // 2
dudmuck 2:fdae76e1215e 50 uint8_t TxDone : 1; // 3
dudmuck 2:fdae76e1215e 51 uint8_t ValidHeader : 1; // 4
dudmuck 2:fdae76e1215e 52 uint8_t PayloadCrcError : 1; // 5
dudmuck 2:fdae76e1215e 53 uint8_t RxDone : 1; // 6
dudmuck 2:fdae76e1215e 54 uint8_t RxTimeout : 1; // 7
dudmuck 2:fdae76e1215e 55 } bits;
dudmuck 2:fdae76e1215e 56 uint8_t octet;
dudmuck 2:fdae76e1215e 57 } RegIrqFlags_t;
dudmuck 2:fdae76e1215e 58
dudmuck 2:fdae76e1215e 59 typedef union {
dudmuck 2:fdae76e1215e 60 struct { // sx127x register 0x18
dudmuck 2:fdae76e1215e 61 uint8_t detect : 1; // 0
dudmuck 2:fdae76e1215e 62 uint8_t sync : 1; // 1
dudmuck 2:fdae76e1215e 63 uint8_t rx_ongoing : 1; // 2
dudmuck 2:fdae76e1215e 64 uint8_t header_valid : 1; // 3
dudmuck 2:fdae76e1215e 65 uint8_t clear : 1; // 4
dudmuck 2:fdae76e1215e 66 uint8_t RxCodingRate : 3; // 5,6,7
dudmuck 2:fdae76e1215e 67 } bits;
dudmuck 2:fdae76e1215e 68 uint8_t octet;
dudmuck 2:fdae76e1215e 69 } RegModemStatus_t;
dudmuck 2:fdae76e1215e 70
dudmuck 2:fdae76e1215e 71 typedef union {
dudmuck 2:fdae76e1215e 72 struct { // sx127x register 0x1c
dudmuck 2:fdae76e1215e 73 uint8_t FhssPresentChannel : 6; // 0,1,2,3,4,5
dudmuck 2:fdae76e1215e 74 uint8_t RxPayloadCrcOn : 1; // 6
dudmuck 2:fdae76e1215e 75 uint8_t PllTimeout : 1; // 7
dudmuck 2:fdae76e1215e 76 } bits;
dudmuck 2:fdae76e1215e 77 uint8_t octet;
dudmuck 2:fdae76e1215e 78 } RegHopChannel_t;
dudmuck 2:fdae76e1215e 79
dudmuck 2:fdae76e1215e 80 typedef union {
dudmuck 2:fdae76e1215e 81 struct { // sx1276 register 0x1d
dudmuck 2:fdae76e1215e 82 uint8_t ImplicitHeaderModeOn : 1; // 0
dudmuck 2:fdae76e1215e 83 uint8_t CodingRate : 3; // 1,2,3
dudmuck 2:fdae76e1215e 84 uint8_t Bw : 4; // 4,5,6,7
dudmuck 2:fdae76e1215e 85 } sx1276bits;
dudmuck 2:fdae76e1215e 86 struct { // sx1272 register 0x1d
dudmuck 2:fdae76e1215e 87 uint8_t LowDataRateOptimize : 1; // 0 ppm_offset: number of cyclic shifts possible to encode to symbol
dudmuck 2:fdae76e1215e 88 uint8_t RxPayloadCrcOn : 1; // 1
dudmuck 2:fdae76e1215e 89 uint8_t ImplicitHeaderModeOn : 1; // 2
dudmuck 2:fdae76e1215e 90 uint8_t CodingRate : 3; // 3,4,5
dudmuck 2:fdae76e1215e 91 uint8_t Bw : 2; // 6,7
dudmuck 2:fdae76e1215e 92 } sx1272bits;
dudmuck 2:fdae76e1215e 93 uint8_t octet;
dudmuck 2:fdae76e1215e 94 } RegModemConfig_t;
dudmuck 2:fdae76e1215e 95
dudmuck 2:fdae76e1215e 96 typedef union {
dudmuck 2:fdae76e1215e 97 struct { // sx1276 register 0x1e
dudmuck 2:fdae76e1215e 98 uint8_t SymbTimeoutMsb : 2; // 0,1
dudmuck 2:fdae76e1215e 99 uint8_t RxPayloadCrcOn : 1; // 2
dudmuck 2:fdae76e1215e 100 uint8_t TxContinuousMode : 1; // 3
dudmuck 2:fdae76e1215e 101 uint8_t SpreadingFactor : 4; // 4,5,6,7
dudmuck 2:fdae76e1215e 102 } sx1276bits;
dudmuck 2:fdae76e1215e 103 struct { // sx1272 register 0x1e
dudmuck 2:fdae76e1215e 104 uint8_t SymbTimeoutMsb : 2; // 0,1
dudmuck 2:fdae76e1215e 105 uint8_t AgcAutoOn : 1; // 2
dudmuck 2:fdae76e1215e 106 uint8_t TxContinuousMode : 1; // 3
dudmuck 2:fdae76e1215e 107 uint8_t SpreadingFactor : 4; // 4,5,6,7
dudmuck 2:fdae76e1215e 108 } sx1272bits;
dudmuck 2:fdae76e1215e 109 uint8_t octet;
dudmuck 2:fdae76e1215e 110 } RegModemConfig2_t;
dudmuck 2:fdae76e1215e 111
dudmuck 2:fdae76e1215e 112 typedef union {
dudmuck 2:fdae76e1215e 113 struct { // sx127x register 0x26
dudmuck 2:fdae76e1215e 114 uint8_t reserved : 2; // 0,1
dudmuck 2:fdae76e1215e 115 uint8_t AgcAutoOn : 1; // 2
dudmuck 2:fdae76e1215e 116 uint8_t LowDataRateOptimize : 1; // 3 ppm_offset
dudmuck 2:fdae76e1215e 117 uint8_t unused : 4; // 4,5,6,7
dudmuck 2:fdae76e1215e 118 } sx1276bits;
dudmuck 2:fdae76e1215e 119 uint8_t octet;
dudmuck 2:fdae76e1215e 120 uint8_t sx1272_ppm_correction_msb;
dudmuck 2:fdae76e1215e 121 } RegModemConfig3_t;
dudmuck 2:fdae76e1215e 122
dudmuck 2:fdae76e1215e 123
dudmuck 2:fdae76e1215e 124 typedef union {
dudmuck 2:fdae76e1215e 125 struct { // sx127x register 0x31
dudmuck 2:fdae76e1215e 126 uint8_t detect_trig_same_peaks_nb : 3; // 0,1,2
dudmuck 2:fdae76e1215e 127 uint8_t disable_pll_timeout : 1; // 3
dudmuck 2:fdae76e1215e 128 uint8_t tracking_intergral : 2; // 4,5
dudmuck 2:fdae76e1215e 129 uint8_t frame_sync_gain : 1; // 6
dudmuck 2:fdae76e1215e 130 uint8_t if_freq_auto : 1; // 7
dudmuck 2:fdae76e1215e 131 } bits;
dudmuck 2:fdae76e1215e 132 uint8_t octet;
dudmuck 2:fdae76e1215e 133 } RegTest31_t;
dudmuck 2:fdae76e1215e 134
dudmuck 2:fdae76e1215e 135 //class SX127x_lora : public SX127x
dudmuck 2:fdae76e1215e 136 class SX127x_lora {
dudmuck 2:fdae76e1215e 137 public:
dudmuck 2:fdae76e1215e 138 //SX127x_lora(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName rst, PinName dio_0, PinName dio_1, PinName fem_ctx, PinName fem_cps);
dudmuck 3:3bf2515b1eed 139 SX127x_lora(SX127x& r);
dudmuck 2:fdae76e1215e 140
dudmuck 2:fdae76e1215e 141 ~SX127x_lora();
dudmuck 2:fdae76e1215e 142
dudmuck 2:fdae76e1215e 143 /** changes from FSK mode to LoRa mdoe */
dudmuck 2:fdae76e1215e 144 void enable(void);
dudmuck 2:fdae76e1215e 145
dudmuck 2:fdae76e1215e 146 /** fills radio FIFO with payload contents, prior to transmission
dudmuck 2:fdae76e1215e 147 * @param len count of bytes to put into FIFO
dudmuck 2:fdae76e1215e 148 * @note tx_buf[] should contain desired payload (to send) prior to calling
dudmuck 2:fdae76e1215e 149 */
dudmuck 2:fdae76e1215e 150 void write_fifo(uint8_t len);
dudmuck 2:fdae76e1215e 151
dudmuck 2:fdae76e1215e 152 /** transmit a packet
dudmuck 2:fdae76e1215e 153 * @param len size of packet
dudmuck 2:fdae76e1215e 154 * @note Limited to (lora fifo size 256)
dudmuck 2:fdae76e1215e 155 */
dudmuck 2:fdae76e1215e 156 void start_tx(uint8_t len);
dudmuck 2:fdae76e1215e 157
dudmuck 2:fdae76e1215e 158 /** start receive mode
dudmuck 2:fdae76e1215e 159 * @note the variable service_action needs to be monitored to indicate read_fifo() needs to be called to pull packet from FIFO.
dudmuck 2:fdae76e1215e 160 */
dudmuck 2:fdae76e1215e 161 void start_rx(void);
dudmuck 2:fdae76e1215e 162
dudmuck 2:fdae76e1215e 163 /** Called by main program when indicated by service_action variable, to pull recevied packet from radio FIFO.
dudmuck 2:fdae76e1215e 164 * @returns count of bytes received
dudmuck 2:fdae76e1215e 165 * @note received packet in rx_buf[]
dudmuck 2:fdae76e1215e 166 */
dudmuck 2:fdae76e1215e 167 void read_fifo(uint8_t len);
dudmuck 2:fdae76e1215e 168
dudmuck 2:fdae76e1215e 169 /** CodingRate: how much FEC to encoding onto packet */
dudmuck 2:fdae76e1215e 170 uint8_t getCodingRate(bool from_rx); // false:transmitted, true:last recevied packet
dudmuck 2:fdae76e1215e 171 void setCodingRate(uint8_t cr);
dudmuck 2:fdae76e1215e 172
dudmuck 2:fdae76e1215e 173 /** HeaderMode: explicit mode sents CodingRate and payload length, implicit mode requires assumption by receiver */
dudmuck 2:fdae76e1215e 174 bool getHeaderMode(void);
dudmuck 2:fdae76e1215e 175 void setHeaderMode(bool hm);
dudmuck 2:fdae76e1215e 176
dudmuck 2:fdae76e1215e 177 /** bandwidth: SX1272 has three bandwidths. SX1276 adds more narrower bandwidths. */
dudmuck 2:fdae76e1215e 178 uint8_t getBw(void);
dudmuck 2:fdae76e1215e 179 void setBw(uint8_t bw);
dudmuck 2:fdae76e1215e 180
dudmuck 2:fdae76e1215e 181 /** spreading factor: trade-off between data rate and processing gain (link budget) */
dudmuck 2:fdae76e1215e 182 uint8_t getSf(void);
dudmuck 2:fdae76e1215e 183 void setSf(uint8_t sf);
dudmuck 2:fdae76e1215e 184
dudmuck 2:fdae76e1215e 185 /** enable CRC in transmitted packet */
dudmuck 2:fdae76e1215e 186 bool getRxPayloadCrcOn(void);
dudmuck 2:fdae76e1215e 187 void setRxPayloadCrcOn(bool);
dudmuck 2:fdae76e1215e 188
dudmuck 2:fdae76e1215e 189 bool getAgcAutoOn(void);
dudmuck 2:fdae76e1215e 190 void setAgcAutoOn(bool);
dudmuck 2:fdae76e1215e 191
dudmuck 2:fdae76e1215e 192 float get_pkt_rssi(void);
dudmuck 2:fdae76e1215e 193
dudmuck 2:fdae76e1215e 194 service_action_e service(void); // (SLIH) ISR bottom half
dudmuck 2:fdae76e1215e 195
dudmuck 2:fdae76e1215e 196 bool poll_vh;
dudmuck 2:fdae76e1215e 197
dudmuck 2:fdae76e1215e 198 RegIrqFlags_t RegIrqFlags; // 0x12
dudmuck 2:fdae76e1215e 199 uint8_t RegRxNbBytes; // 0x13
dudmuck 2:fdae76e1215e 200 RegModemStatus_t RegModemStatus; // 0x18
dudmuck 2:fdae76e1215e 201 int8_t RegPktSnrValue; // 0x19 signed, s/n can be negative
dudmuck 2:fdae76e1215e 202 uint8_t RegPktRssiValue; // 0x1a
dudmuck 2:fdae76e1215e 203 RegHopChannel_t RegHopChannel; // 0x1c
dudmuck 2:fdae76e1215e 204 RegModemConfig_t RegModemConfig; // 0x1d
dudmuck 2:fdae76e1215e 205 RegModemConfig2_t RegModemConfig2; // 0x1e
dudmuck 2:fdae76e1215e 206 uint16_t RegPreamble; // 0x20->0x21
dudmuck 2:fdae76e1215e 207 uint8_t RegPayloadLength; // 0x22
dudmuck 2:fdae76e1215e 208 uint8_t RegRxMaxPayloadLength; // 0x23
dudmuck 2:fdae76e1215e 209 uint8_t RegHopPeriod; // 0x24
dudmuck 2:fdae76e1215e 210 RegModemConfig3_t RegModemConfig3; // 0x26
dudmuck 2:fdae76e1215e 211 RegTest31_t RegTest31; // 0x31
dudmuck 2:fdae76e1215e 212
dudmuck 2:fdae76e1215e 213 private:
dudmuck 3:3bf2515b1eed 214 SX127x& m_xcvr;
dudmuck 2:fdae76e1215e 215 void set_nb_trig_peaks(int);
dudmuck 2:fdae76e1215e 216 };