Driver library for SX1272/SX1276 transceivers

Dependents:   LORA_RX LORA_TX WindConcentrator hid_test ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers sx127x_lora.cpp Source File

sx127x_lora.cpp

00001 #include "sx127x_lora.h"
00002 
00003 /* SX127x driver
00004  * Copyright (c) 2013 Semtech
00005  *
00006  * Licensed under the Apache License, Version 2.0 (the "License");
00007  * you may not use this file except in compliance with the License.
00008  * You may obtain a copy of the License at
00009  *
00010  *     http://www.apache.org/licenses/LICENSE-2.0
00011  *
00012  * Unless required by applicable law or agreed to in writing, software
00013  * distributed under the License is distributed on an "AS IS" BASIS,
00014  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00015  * See the License for the specific language governing permissions and
00016  * limitations under the License.
00017  */
00018 
00019 SX127x_lora::SX127x_lora(SX127x& r) : m_xcvr(r)
00020 {
00021     if (!m_xcvr.RegOpMode.bits.LongRangeMode)
00022         enable();
00023         
00024     RegModemConfig.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG);
00025     RegModemConfig2.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG2);
00026     RegTest33.octet = m_xcvr.read_reg(REG_LR_TEST33);     // invert_i_q
00027     RegDriftInvert.octet = m_xcvr.read_reg(REG_LR_DRIFT_INVERT);
00028     RegGainDrift.octet = m_xcvr.read_reg(REG_LR_GAIN_DRIFT);
00029     
00030     if (m_xcvr.type == SX1276) {
00031         RegAutoDrift.octet = m_xcvr.read_reg(REG_LR_SX1276_AUTO_DRIFT);
00032     }
00033     
00034 
00035 }
00036 
00037 SX127x_lora::~SX127x_lora()
00038 {
00039 }
00040     
00041 void SX127x_lora::write_fifo(uint8_t len)
00042 {
00043     int i;
00044     
00045     m_xcvr.m_cs = 0;
00046     m_xcvr.m_spi.write(REG_FIFO | 0x80); // bit7 is high for writing to radio
00047     
00048     for (i = 0; i < len; i++) {
00049         m_xcvr.m_spi.write(m_xcvr.tx_buf[i]);
00050     }
00051     m_xcvr.m_cs = 1;
00052 }
00053 
00054 void SX127x_lora::read_fifo(uint8_t len)
00055 {
00056     int i;
00057      
00058     m_xcvr.m_cs = 0;
00059     m_xcvr.m_spi.write(REG_FIFO); // bit7 is low for reading from radio
00060     for (i = 0; i < len; i++) {
00061         m_xcvr.rx_buf[i] = m_xcvr.m_spi.write(0);
00062     }
00063     m_xcvr.m_cs = 1;
00064 }
00065 
00066 void SX127x_lora::enable()
00067 {
00068     m_xcvr.set_opmode(RF_OPMODE_SLEEP);
00069     
00070     m_xcvr.RegOpMode.bits.LongRangeMode = 1;
00071     m_xcvr.write_reg(REG_OPMODE, m_xcvr.RegOpMode.octet);
00072     
00073     m_xcvr.RegDioMapping1.bits.Dio0Mapping = 0;    // DIO0 to RxDone
00074     m_xcvr.RegDioMapping1.bits.Dio1Mapping = 0;
00075     m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
00076     
00077     RegTest31.octet = m_xcvr.read_reg(REG_LR_TEST31);    
00078     RegTest31.bits.if_freq_auto = 0;    // improved RX spurious rejection
00079     m_xcvr.write_reg(REG_LR_TEST31, RegTest31.octet);    
00080         
00081     m_xcvr.set_opmode(RF_OPMODE_STANDBY);            
00082 }
00083 
00084 uint8_t SX127x_lora::getCodingRate(bool from_rx)
00085 {
00086     if (from_rx) {
00087         // expected RegModemStatus was read on RxDone interrupt
00088         return RegModemStatus.bits.RxCodingRate;    
00089     } else {    // transmitted coding rate...
00090         if (m_xcvr.type == SX1276)
00091             return RegModemConfig.sx1276bits.CodingRate;
00092         else if (m_xcvr.type == SX1272)
00093             return RegModemConfig.sx1272bits.CodingRate;
00094         else
00095             return 0;
00096     }
00097 }
00098 
00099 
00100 
00101 void SX127x_lora::setCodingRate(uint8_t cr)
00102 {
00103     if (!m_xcvr.RegOpMode.bits.LongRangeMode)
00104         return;
00105         
00106     if (m_xcvr.type == SX1276)
00107         RegModemConfig.sx1276bits.CodingRate = cr;
00108     else if (m_xcvr.type == SX1272)
00109         RegModemConfig.sx1272bits.CodingRate = cr;
00110     else
00111         return;
00112         
00113     m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
00114 }
00115 
00116 
00117 
00118 bool SX127x_lora::getHeaderMode(void)
00119 {
00120     if (m_xcvr.type == SX1276) {
00121         RegModemConfig.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG);
00122         return RegModemConfig.sx1276bits.ImplicitHeaderModeOn;
00123     } else if (m_xcvr.type == SX1272) {
00124         RegModemConfig.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG);
00125         return RegModemConfig.sx1272bits.ImplicitHeaderModeOn;
00126     } else
00127         return false;
00128 }
00129 
00130 void SX127x_lora::setHeaderMode(bool hm)
00131 {
00132     if (m_xcvr.type == SX1276)
00133         RegModemConfig.sx1276bits.ImplicitHeaderModeOn = hm;
00134     else if (m_xcvr.type == SX1272)
00135         RegModemConfig.sx1272bits.ImplicitHeaderModeOn = hm;
00136     else
00137         return;
00138         
00139     m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
00140 }
00141 
00142 
00143 uint8_t SX127x_lora::getBw(void)
00144 {
00145     if (m_xcvr.type == SX1276)
00146         return RegModemConfig.sx1276bits.Bw;
00147     else if (m_xcvr.type == SX1272)
00148         return RegModemConfig.sx1272bits.Bw;
00149     else
00150         return 0;
00151 }
00152 
00153 int SX127x_lora::get_freq_error_Hz()
00154 {
00155     int freq_error;
00156     float f, khz = 0;
00157     freq_error = m_xcvr.read_reg(REG_LR_TEST28);
00158     freq_error <<= 8;
00159     freq_error += m_xcvr.read_reg(REG_LR_TEST29);
00160     freq_error <<= 8;
00161     freq_error += m_xcvr.read_reg(REG_LR_TEST2A);
00162     if (freq_error & 0x80000) {  // 20bit value is negative
00163         //signed 20bit to 32bit
00164         freq_error |= 0xfff00000;
00165     }   
00166     f = freq_error / (float)XTAL_FREQ;
00167     f *= (float)0x1000000; // 2^24
00168     if (m_xcvr.type == SX1272) {
00169         switch (RegModemConfig.sx1272bits.Bw) {
00170             case 0: khz = 125; break;
00171             case 1: khz = 250; break;
00172             case 2: khz = 500; break;                
00173         }
00174     } else if (m_xcvr.type == SX1276) {
00175         switch (RegModemConfig.sx1276bits.Bw) {
00176             case 0: khz = 7.8; break;
00177             case 1: khz = 10.4; break;
00178             case 2: khz = 15.6; break;
00179             case 3: khz = 20.8; break;
00180             case 4: khz = 31.25; break;
00181             case 5: khz = 41.7; break;
00182             case 6: khz = 62.5; break;
00183             case 7: khz = 125; break;
00184             case 8: khz = 250; break;
00185             case 9: khz = 500; break;            
00186         }
00187     }
00188     f *= khz / 500;
00189     return (int)f;
00190 }
00191 
00192 float SX127x_lora::get_symbol_period()
00193 {
00194     float khz = 0;
00195     
00196     if (m_xcvr.type == SX1276) {
00197         switch (RegModemConfig.sx1276bits.Bw) {
00198             case 0: khz = 7.8; break;
00199             case 1: khz = 10.4; break;
00200             case 2: khz = 15.6; break;
00201             case 3: khz = 20.8; break;
00202             case 4: khz = 31.25; break;
00203             case 5: khz = 41.7; break;
00204             case 6: khz = 62.5; break;
00205             case 7: khz = 125; break;
00206             case 8: khz = 250; break;
00207             case 9: khz = 500; break;
00208         }
00209     } else if (m_xcvr.type == SX1272) {
00210         switch (RegModemConfig.sx1272bits.Bw) {
00211             case 0: khz = 125; break;
00212             case 1: khz = 250; break;
00213             case 2: khz = 500; break;            
00214         }
00215     }
00216     
00217     // return symbol duration in milliseconds
00218     return (1 << RegModemConfig2.sx1276bits.SpreadingFactor) / khz; 
00219 }
00220 
00221 void SX127x_lora::setBw_KHz(int khz)
00222 {
00223     uint8_t bw = 0;
00224     
00225     if (m_xcvr.type == SX1276) {
00226         if (khz <= 8) bw = 0;
00227         else if (khz <= 11) bw = 1;
00228         else if (khz <= 16) bw = 2;
00229         else if (khz <= 21) bw = 3;
00230         else if (khz <= 32) bw = 4;
00231         else if (khz <= 42) bw = 5;
00232         else if (khz <= 63) bw = 6;
00233         else if (khz <= 125) bw = 7;
00234         else if (khz <= 250) bw = 8;
00235         else if (khz <= 500) bw = 9;
00236     } else if (m_xcvr.type == SX1272) {
00237         if (khz <= 125) bw = 0;
00238         else if (khz <= 250) bw = 1;
00239         else if (khz <= 500) bw = 2;
00240     }
00241     
00242     setBw(bw);
00243 }
00244 
00245 void SX127x_lora::setBw(uint8_t bw)
00246 {
00247     if (!m_xcvr.RegOpMode.bits.LongRangeMode)
00248         return;
00249         
00250     if (m_xcvr.type == SX1276) {        
00251         RegModemConfig.sx1276bits.Bw = bw;
00252         if (get_symbol_period() > 16)
00253             RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
00254         else
00255             RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
00256         m_xcvr.write_reg(REG_LR_MODEMCONFIG3, RegModemConfig3.octet);        
00257     } else if (m_xcvr.type == SX1272) {
00258         RegModemConfig.sx1272bits.Bw = bw;
00259         if (get_symbol_period() > 16)
00260             RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
00261         else
00262             RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
00263     } else
00264         return;
00265         
00266     m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
00267 }
00268 
00269 
00270 
00271 uint8_t SX127x_lora::getSf(void)
00272 {
00273     // spreading factor same between sx127[26]
00274     return RegModemConfig2.sx1276bits.SpreadingFactor;
00275 }
00276 
00277 void SX127x_lora::set_nb_trig_peaks(int n)
00278 {
00279     /* TODO: different requirements for RX_CONTINUOUS vs RX_SINGLE */
00280     RegTest31.bits.detect_trig_same_peaks_nb = n;
00281     m_xcvr.write_reg(REG_LR_TEST31, RegTest31.octet);
00282 }
00283 
00284 
00285 void SX127x_lora::setSf(uint8_t sf)
00286 {
00287     if (!m_xcvr.RegOpMode.bits.LongRangeMode)
00288         return; 
00289 
00290     // write register at 0x37 with value 0xc if at SF6
00291     if (sf < 7)
00292         m_xcvr.write_reg(REG_LR_DETECTION_THRESHOLD, 0x0c);
00293     else
00294         m_xcvr.write_reg(REG_LR_DETECTION_THRESHOLD, 0x0a);
00295     
00296     RegModemConfig2.sx1276bits.SpreadingFactor = sf; // spreading factor same between sx127[26]
00297     m_xcvr.write_reg(REG_LR_MODEMCONFIG2, RegModemConfig2.octet);
00298     
00299     if (m_xcvr.type == SX1272) {
00300         if (get_symbol_period() > 16)
00301             RegModemConfig.sx1272bits.LowDataRateOptimize = 1;
00302         else
00303             RegModemConfig.sx1272bits.LowDataRateOptimize = 0;
00304         m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
00305     } else if (m_xcvr.type == SX1276) {
00306         if (get_symbol_period() > 16)
00307             RegModemConfig3.sx1276bits.LowDataRateOptimize = 1;
00308         else
00309             RegModemConfig3.sx1276bits.LowDataRateOptimize = 0;
00310         m_xcvr.write_reg(REG_LR_MODEMCONFIG3, RegModemConfig3.octet);
00311     }
00312 }
00313 
00314 
00315         
00316 bool SX127x_lora::getRxPayloadCrcOn(void)
00317 {
00318     /* RxPayloadCrcOn enables CRC generation in transmitter */
00319     /* in implicit mode, this bit also enables CRC in receiver */
00320     if (m_xcvr.type == SX1276) {
00321         RegModemConfig2.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG2);
00322         return RegModemConfig2.sx1276bits.RxPayloadCrcOn;
00323     } else if (m_xcvr.type == SX1272) {
00324         RegModemConfig.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG);
00325         return RegModemConfig.sx1272bits.RxPayloadCrcOn;
00326     } else
00327         return 0;
00328 }
00329 
00330 
00331 void SX127x_lora::setRxPayloadCrcOn(bool on)
00332 {
00333     if (m_xcvr.type == SX1276) {
00334         RegModemConfig2.sx1276bits.RxPayloadCrcOn = on;
00335         m_xcvr.write_reg(REG_LR_MODEMCONFIG2, RegModemConfig2.octet);
00336     } else if (m_xcvr.type == SX1272) {
00337         RegModemConfig.sx1272bits.RxPayloadCrcOn = on;
00338         m_xcvr.write_reg(REG_LR_MODEMCONFIG, RegModemConfig.octet);
00339     }   
00340 }
00341 
00342 
00343 
00344 bool SX127x_lora::getAgcAutoOn(void)
00345 {
00346     if (m_xcvr.type == SX1276) {
00347         RegModemConfig3.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG3);
00348         return RegModemConfig3.sx1276bits.AgcAutoOn;
00349     } else if (m_xcvr.type == SX1272) {
00350         RegModemConfig2.octet = m_xcvr.read_reg(REG_LR_MODEMCONFIG2);
00351         return RegModemConfig2.sx1272bits.AgcAutoOn;
00352     } else
00353         return 0;
00354 }
00355 
00356 void SX127x_lora::setAgcAutoOn(bool on)
00357 {
00358     if (m_xcvr.type == SX1276) {
00359         RegModemConfig3.sx1276bits.AgcAutoOn = on;
00360         m_xcvr.write_reg(REG_LR_MODEMCONFIG3, RegModemConfig3.octet);
00361     } else if (m_xcvr.type == SX1272) {
00362         RegModemConfig2.sx1272bits.AgcAutoOn = on;
00363         m_xcvr.write_reg(REG_LR_MODEMCONFIG2, RegModemConfig2.octet);
00364     }
00365     
00366 }
00367 
00368 void SX127x_lora::invert_tx(bool inv)
00369 {
00370     RegTest33.bits.chirp_invert_tx = !inv;
00371     m_xcvr.write_reg(REG_LR_TEST33, RegTest33.octet);    
00372 }
00373 
00374 void SX127x_lora::invert_rx(bool inv)
00375 {
00376     RegTest33.bits.invert_i_q = inv;
00377     m_xcvr.write_reg(REG_LR_TEST33, RegTest33.octet);
00378     /**/
00379     RegDriftInvert.bits.invert_timing_error_per_symbol = !RegTest33.bits.invert_i_q;    
00380     m_xcvr.write_reg(REG_LR_DRIFT_INVERT, RegDriftInvert.octet);
00381 }
00382 
00383 void SX127x_lora::start_tx(uint8_t len)
00384 {                   
00385     // DIO0 to TxDone
00386     if (m_xcvr.RegDioMapping1.bits.Dio0Mapping != 1) {
00387         m_xcvr.RegDioMapping1.bits.Dio0Mapping = 1;
00388         m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
00389     }
00390     
00391     // set FifoPtrAddr to FifoTxPtrBase
00392     m_xcvr.write_reg(REG_LR_FIFOADDRPTR, m_xcvr.read_reg(REG_LR_FIFOTXBASEADDR));
00393     
00394     // write PayloadLength bytes to fifo
00395     write_fifo(len);
00396        
00397     m_xcvr.set_opmode(RF_OPMODE_TRANSMITTER);
00398 }
00399 
00400 void SX127x_lora::start_rx(chip_mode_e mode)
00401 {
00402     if (!m_xcvr.RegOpMode.bits.LongRangeMode)
00403         return; // fsk mode
00404     if (m_xcvr.RegOpMode.sx1276LORAbits.AccessSharedReg)
00405         return; // fsk page
00406         
00407     if (m_xcvr.type == SX1276) {
00408         if (RegModemConfig.sx1276bits.Bw == 9) {  // if 500KHz bw: improved tolerance of reference frequency error
00409             if (RegAutoDrift.bits.freq_to_time_drift_auto) {
00410                 RegAutoDrift.bits.freq_to_time_drift_auto = 0;
00411                 m_xcvr.write_reg(REG_LR_SX1276_AUTO_DRIFT, RegAutoDrift.octet);
00412             }
00413             if (m_xcvr.HF) {
00414                 // > 525MHz
00415                 if (RegGainDrift.bits.freq_to_time_drift != 0x24) {
00416                     RegGainDrift.bits.freq_to_time_drift = 0x24;
00417                     m_xcvr.write_reg(REG_LR_GAIN_DRIFT, RegGainDrift.octet);                    
00418                 }
00419             } else {
00420                 // < 525MHz
00421                 if (RegGainDrift.bits.freq_to_time_drift != 0x3f) {
00422                     RegGainDrift.bits.freq_to_time_drift = 0x3f;
00423                     m_xcvr.write_reg(REG_LR_GAIN_DRIFT, RegGainDrift.octet); 
00424                 }
00425             }
00426 
00427         } else {
00428             if (!RegAutoDrift.bits.freq_to_time_drift_auto) {
00429                 RegAutoDrift.bits.freq_to_time_drift_auto = 1;
00430                 m_xcvr.write_reg(REG_LR_SX1276_AUTO_DRIFT, RegAutoDrift.octet);
00431             }
00432         }
00433     } // ... if (m_xcvr.type == SX1276)  
00434     
00435     // RX_CONTINUOUS: false detections vs missed detections tradeoff
00436     switch (RegModemConfig2.sx1276bits.SpreadingFactor) {
00437         case 6:
00438             set_nb_trig_peaks(3);
00439             break;
00440         case 7:
00441             set_nb_trig_peaks(4);
00442             break;
00443         default:
00444             set_nb_trig_peaks(5);
00445             break;
00446     }   
00447         
00448     m_xcvr.set_opmode(mode);
00449 
00450     if (m_xcvr.RegDioMapping1.bits.Dio0Mapping != 0) {
00451         m_xcvr.RegDioMapping1.bits.Dio0Mapping = 0;    // DIO0 to RxDone
00452         m_xcvr.write_reg(REG_DIOMAPPING1, m_xcvr.RegDioMapping1.octet);
00453     }
00454     
00455     m_xcvr.write_reg(REG_LR_FIFOADDRPTR, m_xcvr.read_reg(REG_LR_FIFORXBASEADDR));
00456 }
00457 
00458 int SX127x_lora::get_pkt_rssi()
00459 {
00460     if (m_xcvr.type == SX1276) {
00461         if (m_xcvr.HF)
00462             return RegPktRssiValue - 157;
00463         else
00464             return RegPktRssiValue - 164;
00465     } else
00466         return RegPktRssiValue - 139;
00467 }
00468 
00469 int SX127x_lora::get_current_rssi()
00470 {
00471     uint8_t v = m_xcvr.read_reg(REG_LR_RSSIVALUE);
00472     if (m_xcvr.type == SX1276) {
00473         if (m_xcvr.HF)
00474             return v - 157;
00475         else
00476             return v - 164;
00477     } else
00478         return v - 139;
00479 }
00480 
00481 service_action_e SX127x_lora::service()
00482 {
00483     if (m_xcvr.RegOpMode.bits.Mode == RF_OPMODE_RECEIVER) {
00484         if (poll_vh) {
00485             RegIrqFlags.octet = m_xcvr.read_reg(REG_LR_IRQFLAGS);
00486             if (RegIrqFlags.bits.ValidHeader) {
00487                 RegIrqFlags.octet = 0;
00488                 RegIrqFlags.bits.ValidHeader = 1;
00489                 m_xcvr.write_reg(REG_LR_IRQFLAGS, RegIrqFlags.octet);
00490                 printf("VH\r\n");
00491             }
00492         }
00493     }
00494        
00495     if (m_xcvr.dio0 == 0)
00496         return SERVICE_NONE;
00497         
00498     switch (m_xcvr.RegDioMapping1.bits.Dio0Mapping) {
00499         case 0: // RxDone
00500             /* user checks for CRC error in IrqFlags */
00501             RegIrqFlags.octet = m_xcvr.read_reg(REG_LR_IRQFLAGS);  // save flags
00502             RegHopChannel.octet = m_xcvr.read_reg(REG_LR_HOPCHANNEL);
00503             //printf("[%02x]", RegIrqFlags.octet);
00504             m_xcvr.write_reg(REG_LR_IRQFLAGS, RegIrqFlags.octet); // clear flags in radio
00505             
00506             /* any register of interest on received packet is read(saved) here */        
00507             RegModemStatus.octet = m_xcvr.read_reg(REG_LR_MODEMSTAT);          
00508             RegPktSnrValue = m_xcvr.read_reg(REG_LR_PKTSNRVALUE);
00509             RegPktRssiValue = m_xcvr.read_reg(REG_LR_PKTRSSIVALUE);
00510             RegRxNbBytes = m_xcvr.read_reg(REG_LR_RXNBBYTES);
00511     
00512             m_xcvr.write_reg(REG_LR_FIFOADDRPTR, m_xcvr.read_reg(REG_LR_FIFORXCURRENTADDR));
00513             read_fifo(RegRxNbBytes);
00514             return SERVICE_READ_FIFO;
00515         case 1: // TxDone
00516             RegIrqFlags.octet = 0;
00517             RegIrqFlags.bits.TxDone = 1;
00518             m_xcvr.write_reg(REG_LR_IRQFLAGS, RegIrqFlags.octet);                  
00519             return SERVICE_TX_DONE;        
00520     } // ...switch (RegDioMapping1.bits.Dio0Mapping)
00521     
00522     return SERVICE_ERROR;    
00523 }
00524