cervin sx1265 operating with transceiver firmware

Dependents:   lr1110_wifi_geolocation_device lr1110_wifi_geolocation_gateway

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lr1110.cpp Source File

lr1110.cpp

00001 #include "sx12xx.h"
00002 
00003 Callback<void()> SX1265::dio9_topHalf;    // low latency ISR context
00004 
00005 void SX1265::dio9isr()
00006 {
00007     if (dio9_topHalf)
00008         dio9_topHalf.call();
00009 }
00010 
00011 SX1265::SX1265(SPI& _spi, PinName _nss, PinName _busy, PinName _dio9, PinName _nrst, uint32_t di, unsigned tto, uint8_t tv)
00012     : spi(_spi), nss(_nss), busy(_busy), dio9(_dio9), nrst(_nrst), default_irqs(di), tcxoStartDelay(tto), tcxoVolts(tv)
00013 {
00014     nss = 1;
00015     dio9.mode(PullDown);    // dio9 floats if no interrupts enabled
00016 
00017     t.start();
00018 
00019     if (busy) {
00020         hw_reset();
00021     }
00022 
00023     dio9.rise(dio9isr);
00024     txTimeout = 0;    // default tx-timeout off
00025 }
00026 
00027 
00028 void SX1265::hw_reset(void)
00029 {
00030     nrst.output();
00031     nrst.write(0);
00032     ThisThread::sleep_for(2);
00033     nrst.write(1);
00034     nrst.input();
00035     /* measured 211ms to startup (busy-hi during chip startup) */
00036     ThisThread::sleep_for(200);
00037     while (busy)
00038         ThisThread::sleep_for(2);
00039 
00040     enable_default_irqs_();
00041 }
00042 
00043 const char *SX1265::cmdStatus_toString(uint8_t s)
00044 {
00045     switch (s) {
00046         case CMD_FAIL: return "CMD_FAIL";
00047         case CMD_PERR: return "CMD_PERR";
00048         case CMD_OK: return "CMD_OK";
00049         case CMD_DAT: return "CMD_DAT";
00050         default: return NULL;
00051     }
00052 }
00053 
00054 uint32_t SX1265::service(void)
00055 {
00056     uint32_t ret = 0;
00057     uint8_t buf[4];
00058     uint8_t irqbuf[4];
00059 
00060     inService = true;
00061     if (dio9) {
00062         bool try_rx = false;
00063         irq_t irq;
00064         stat_t stat;
00065         stat.word = xfer(OPCODE_GET_STATUS, 4, 4, irqbuf);
00066         if (stat.bits.rfu) {
00067             inService = false;
00068             return -1;
00069         }
00070         irq.dword = from_big_endian32(irqbuf);
00071         ret = irq.dword;
00072         if (stat.bits.rfu) {
00073             ret = -1;
00074             goto done;
00075         }
00076         if (irq.bits.TxDone) {
00077             chipMode = CHIPMODE_NONE;
00078             if (chipModeChange)
00079                 chipModeChange.call();  // might change to Rx
00080             if (txDone)
00081                 txDone.call();
00082         }
00083         if (irq.bits.RxDone) {
00084             uint8_t len, offset;
00085             float rssi, snr;
00086             int8_t s;
00087 
00088             stat.word = xfer(OPCODE_GET_RX_BUFFER_STATUS, 0, 0, NULL);
00089             stat.word = xfer(0x0000, 0, 2, buf);
00090             rx_buf_offset = buf[1];
00091             len = buf[0];
00092             offset = buf[1];
00093             
00094             buf[0] = offset;
00095             buf[1] = len;
00096             stat.word = xfer(OPCODE_READ_BUFFER8, 2, 0, buf);
00097             stat.word = xfer(0x0000, 0, len, rx_buf);
00098             stat.word = xfer(OPCODE_GET_PKT_STATUS, 0, 0, NULL);
00099             stat.word = xfer(0x0000, 0, 3, buf);
00100             rssi = buf[0] / -2.0;
00101             s = buf[1];
00102             snr = s / 4.0;
00103 
00104             rxDone(len, rssi, snr);
00105             stat.word = xfer(OPCODE_CLEAR_RX_BUFFER, 0, 0, NULL); // yyy
00106         }
00107         if (irq.bits.CadDone) {
00108             if (cadDone)
00109                 cadDone(irq.bits.CadDetected);
00110         }
00111         if (irq.bits.CmdErr) {
00112             err_opcode = prev_opcode; // culprit opcode
00113         }
00114         if (irq.bits.Error) {
00115             stat.word = xfer(OPCODE_GET_ERRORS, 0, 0, NULL);
00116             stat.word = xfer(0x0000, 0, 2, buf);
00117             if (stat.bits.cmdStatus == CMD_DAT) {
00118                 errorStat.word = buf[0];
00119                 errorStat.word <<= 8;
00120                 errorStat.word |= buf[1];
00121                 if (errorStat.bits.hf_xosc_start_) {
00122                     buf[0] = tcxoVolts;
00123                     to_big_endian32(tcxoStartDelay, buf+1);
00124                     xfer(OPCODE_SET_TCXO_MODE, 5, 0, buf);
00125                     buf[0] = 0;
00126                     xfer(OPCODE_CALIBRATE, 1, 0, buf);
00127 
00128                     if (chipMode == CHIPMODE_RX) {
00129                         /* RX start failed due to HF xosc being a tcxo */
00130                         try_rx = true;
00131                     }
00132                 }
00133                 /* ? OPCODE_CLEAR_ERRORS ? */
00134             }
00135         }
00136         if (irq.bits.Timeout) {
00137             if (chipMode != CHIPMODE_NONE) {
00138                 if (timeout)
00139                     timeout(chipMode == CHIPMODE_TX);
00140             }
00141             chipMode = CHIPMODE_NONE;
00142             if (chipModeChange)
00143                 chipModeChange.call();
00144         }
00145 
00146         stat.word = xfer(OPCODE_CLEAR_IRQ, 4, 0, irqbuf);
00147 
00148         if (try_rx) {
00149             /* RX wasnt started because xosc wasnt started */
00150             xfer(OPCODE_SET_RX, 3, 0, rxArgs);
00151         }
00152     } // ..if (dio9)
00153 
00154 done:
00155     inService = false;
00156     return ret;
00157 }
00158 
00159 uint16_t SX1265::xfer(uint16_t opcode, uint16_t wlen, uint16_t rlen, uint8_t* ptr)
00160 {
00161     const uint8_t* stopPtr;
00162     const uint8_t* wstop;
00163     const uint8_t* rstop;
00164     const uint8_t nop = 0;
00165     uint16_t oc;
00166     stat_t ret;
00167     unsigned f;
00168 
00169     if (opcode == OPCODE_SET_RX) {
00170         const uint8_t* _ptr = ptr;
00171         rxArgs[0] = *_ptr++;
00172         rxArgs[1] = *_ptr++;
00173         rxArgs[2] = *_ptr++;
00174     }
00175 
00176     if (sleeping) {
00177         nss = 0;
00178         while (busy)
00179             ;
00180         sleeping = false;
00181     } else {
00182         if (busy) {
00183             int startAt = t.read_ms();
00184             while (busy) {
00185                 if (t.read_ms() - startAt > 50) {
00186                     ret.bits.rfu = 15;
00187                     return ret.word;
00188                 }
00189             }
00190         }
00191         nss = 0;
00192     }
00193 
00194     prev_opcode = this_opcode;
00195     this_opcode = opcode;
00196 
00197     oc = opcode;
00198     f = oc >> 8;
00199     ret.word = spi.write(f);
00200     ret.word <<= 8;
00201     if (opcode != 0) {
00202         /* two byte command sent */
00203         ret.word |= spi.write(oc & 0xff);
00204     } /* else: response */
00205     else
00206         ret.word |= 0xff;   // put impossible value for stat2, indicating only stat1 returned
00207 
00208     wstop = ptr + wlen;
00209     rstop = ptr + rlen;
00210     if (rlen > wlen)
00211         stopPtr = rstop;
00212     else
00213         stopPtr = wstop;
00214 
00215     for (; ptr < stopPtr; ptr++) {
00216         if (ptr < wstop && ptr < rstop)
00217             *ptr = spi.write(*ptr);
00218         else if (ptr < wstop)
00219             spi.write(*ptr);
00220         else
00221             *ptr = spi.write(nop);    // n >= write length: send NOP
00222     }
00223 
00224     nss = 1;
00225 
00226     if (opcode == OPCODE_SET_SLEEP ||
00227         opcode == OPCODE_SET_TX ||
00228         opcode == OPCODE_SET_RX ||
00229         opcode == OPCODE_SET_STANDBY ||
00230         opcode == OPCODE_SET_FS)
00231     {
00232         if (opcode == OPCODE_SET_TX)
00233             chipMode = CHIPMODE_TX;
00234         else if (opcode == OPCODE_SET_RX)
00235             chipMode = CHIPMODE_RX;
00236         else if (opcode == OPCODE_SET_SLEEP || opcode == OPCODE_SET_STANDBY || opcode == OPCODE_SET_FS) {
00237             if (opcode == OPCODE_SET_SLEEP)
00238                 sleeping = true;
00239             chipMode = CHIPMODE_NONE;
00240         }
00241 
00242         if (chipModeChange)
00243             chipModeChange.call();
00244     }
00245 
00246     if (!inService && ret.bits.intActive)
00247         service();
00248 
00249     return ret.word;
00250 }
00251 
00252 uint32_t SX1265::from_big_endian32(const uint8_t *in)
00253 {
00254     uint32_t ret;
00255     ret = *in++;
00256     ret <<= 8;
00257     ret |= *in++;
00258     ret <<= 8;
00259     ret |= *in++;
00260     ret <<= 8;
00261     ret |= *in;
00262     return ret;
00263 }
00264 
00265 void SX1265::to_big_endian16(uint16_t in, uint8_t *out)
00266 {
00267     out[1] = in & 0xff;
00268     in >>= 8;
00269     out[0] = in & 0xff;
00270 }
00271 
00272 void SX1265::to_big_endian24(uint32_t in, uint8_t *out)
00273 {
00274     out[2] = in & 0xff;
00275     in >>= 8;
00276     out[1] = in & 0xff;
00277     in >>= 8;
00278     out[0] = in & 0xff;
00279 }
00280 
00281 void SX1265::to_big_endian32(uint32_t in, uint8_t *out)
00282 {
00283     out[3] = in & 0xff;
00284     in >>= 8;
00285     out[2] = in & 0xff;
00286     in >>= 8;
00287     out[1] = in & 0xff;
00288     in >>= 8;
00289     out[0] = in & 0xff;
00290 }
00291 
00292 int SX1265::memRegRead(uint32_t addr, uint16_t len_dwords, uint32_t *dest)
00293 {
00294     uint8_t buf[5];
00295     stat_t stat;
00296     while (len_dwords > 0) {
00297         unsigned this_len_dwords = len_dwords;
00298         if (this_len_dwords > 64)
00299             this_len_dwords = 64;
00300         buf[4] = this_len_dwords;
00301         to_big_endian32(addr, buf);
00302         stat.word = xfer(OPCODE_READREGMEM32, 5, 5, buf);
00303         if (stat.bits.rfu) {
00304             hw_reset();
00305             return -1;
00306         }
00307         unsigned n, len_bytes = this_len_dwords * 4;
00308         stat.word = xfer(0x0000, 0, len_bytes, (uint8_t*)dest);
00309         if (stat.bits.rfu) {
00310             hw_reset();
00311             return -1;
00312         } else {
00313             if (stat.bits.cmdStatus != CMD_DAT) {
00314                 return -1;
00315             }
00316             for (n = 0; n < this_len_dwords; n++) {
00317                 *dest = from_big_endian32((uint8_t*)dest);
00318                 dest++;
00319             }
00320         }
00321 
00322         addr += len_bytes;
00323         len_dwords -= this_len_dwords;
00324     } // ..while (len_dwords > 0)
00325 
00326     return 0;
00327 } // ..memRegRead()
00328 
00329 void SX1265::enable_default_irqs_()
00330 {
00331     /* DIO9 is hi-z when no irqs enabled (floats high) */
00332     uint8_t buf[4];
00333     to_big_endian32(default_irqs, buf);
00334     xfer(OPCODE_SET_DIOIRQPARAMS, 4, 4, buf);
00335 }
00336 
00337 float SX1265::getMHz()
00338 {
00339     uint32_t frf;
00340     memRegRead(REG_ADDR_RFFREQ, 1, &frf);
00341     return frf / 1048576.0;
00342 }
00343 
00344 uint8_t SX1265::setMHz(float MHz)
00345 {
00346     uint8_t buf[4];
00347     to_big_endian32(MHz * 1000000, buf);
00348     xfer(OPCODE_SET_RF_FREQ_HZ, 4, 0, buf);
00349     return 0;
00350 }
00351 
00352 void SX1265::setPacketType(uint8_t pt)
00353 {
00354     xfer(OPCODE_SET_PACKET_TYPE, 1, 0, &pt);
00355 }
00356 
00357 uint8_t SX1265::getPacketType()
00358 {
00359     uint8_t buf;
00360     stat_t stat;
00361     xfer(OPCODE_GET_PACKET_TYPE, 0, 0, NULL);
00362     stat.word = xfer(0x0000, 0, 1, &buf);
00363     if (stat.bits.cmdStatus == CMD_DAT)
00364         return buf;
00365     else
00366         return 0;
00367 }
00368 
00369 void SX1265::start_tx(uint8_t pktLen)
00370 {
00371     uint8_t buf[3];
00372     xfer(OPCODE_WRITE_BUFFER8, pktLen, 0, tx_buf);
00373     to_big_endian24(txTimeout, buf);
00374     xfer(OPCODE_SET_TX, 3, 0, buf);
00375 }
00376 
00377 void SX1265::GetPaConfig(uint8_t *out)
00378 {
00379     txParamsA_t tpa;
00380     txParamsB_t tpb;
00381     /* PaSel also in 0x00f30088 */
00382     memRegRead(REG_ADDR_TX_PARAMS_A, 1, &tpa.dword);
00383     memRegRead(REG_ADDR_TX_PARAMS_B, 1, &tpb.dword);
00384     out[0] = tpb.bits.PaSel;
00385     out[1] = tpa.bits.RegPASupply;
00386     out[2] = tpb.bits.PaDutyCycle;
00387     out[3] = tpb.bits.PaHPSel;
00388 }
00389 
00390 void SX1265::GetLoRaModulationParameters(uint8_t *out)
00391 {
00392     loraConfig0_t cfg0;
00393     memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
00394 
00395     out[0] = cfg0.bits.modem_sf;
00396     out[1] = cfg0.bits.modem_bw;
00397     out[2] = cfg0.bits.coding_rate;
00398     out[3] = cfg0.bits.ppm_offset;
00399 }
00400 
00401 void SX1265::GetGfskModulationParameters(uint8_t *out)
00402 {
00403     uint32_t u32;
00404     gfskBW_t bw_reg;
00405     gfskConfig0_t cfg0;
00406     uint8_t bwf;
00407     unsigned hz;
00408 
00409     memRegRead(REG_ADDR_GFSK_BITRATE, 1, &u32);
00410     hz = GFSK_BITRATE_NUMERATOR / u32;
00411     to_big_endian32(hz, out);
00412 
00413     memRegRead(REG_ADDR_GFSK_CFG0, 1, &cfg0.dword);
00414     switch (cfg0.bits.bt) {
00415         case 0: /* off */ out[4] = GFSK_BT_OFF; break;
00416         case 1: /* 0.3 */ out[4] = GFSK_BT_0_3; break;
00417         case 2: /* 0.5 */ out[4] = GFSK_BT_0_5; break;
00418         case 3: /* 0.7 */ out[4] = GFSK_BT_0_7; break;
00419         case 4: /* 1.0 */ out[4] = GFSK_BT_1_0; break;
00420     }
00421 
00422     memRegRead(REG_ADDR_GFSK_BWF, 1, &bw_reg.dword);
00423     bwf = bw_reg.bits.bwf_hi;
00424     bwf <<= 3;
00425     bwf |= bw_reg.bits.bwf_lo;
00426     out[5] = bwf;
00427 
00428     memRegRead(REG_ADDR_GFSK_FDEV, 1, &u32);
00429     hz = (unsigned) ((u32 * FREQ_STEP) - 0.5);
00430     to_big_endian32(hz, out+6);
00431 }
00432 
00433 void SX1265::GetLoRaPacketParameters(uint8_t *out)
00434 {
00435     loraConfig0_t cfg0;
00436     loraConfigA_t cfgA;
00437     loraConfigC_t cfgc;
00438     unsigned pl;
00439 
00440     memRegRead(REG_ADDR_LORA_CONFIGC, 1, &cfgc.dword);
00441     pl = cfgc.bits.preamble_length;
00442     out[1] = pl & 0xff;
00443     pl >>= 8;
00444     out[0] = pl;
00445 
00446     memRegRead(REG_ADDR_LORA_CONFIG0, 1, &cfg0.dword);
00447     out[2] = cfg0.bits.implicit_header;
00448     out[3] = cfg0.bits.payload_length;
00449     out[4] = cfg0.bits.crc_on;
00450 
00451     memRegRead(REG_ADDR_LORA_CONFIGA, 1, &cfgA.dword);
00452     out[5] = cfgA.bits.invertIQ;
00453 }
00454 
00455 void SX1265::GetGfskPacketParameters(uint8_t *out)
00456 {
00457     gfskConfig1_t cfg1;
00458     gfskConfig2_t cfg2;
00459     gfskConfig3_t cfg3;
00460     gfskConfig4_t cfg4;
00461     gfskConfig5_t cfg5;
00462     uint32_t u32;
00463 
00464     memRegRead(REG_ADDR_GFSK_CFG1, 1, &cfg1.dword);
00465 
00466     u32 = cfg1.bits.preamble_length;
00467     out[1] = u32;
00468     u32 >>= 8;
00469     out[0] = u32;
00470 
00471     memRegRead(REG_ADDR_GFSK_CFG1, 1, &cfg1.dword);
00472     if (cfg1.bits.preamble_det_enable)
00473         out[2] = cfg1.bits.preamble_det_len;
00474     else
00475         out[2] = 0;
00476 
00477     memRegRead(REG_ADDR_GFSK_CFG2, 1, &cfg2.dword);
00478     out[3] = cfg2.bits.sync_word_length;
00479 
00480     memRegRead(REG_ADDR_GFSK_PAYLOAD_LENGTH_B, 1, &cfg4.dword);
00481     out[4] = cfg4.bits.addr_comp;
00482 
00483     memRegRead(REG_ADDR_GFSK_CFG3, 1, &cfg3.dword);
00484     out[5] = cfg3.bits.variable_length;
00485 
00486     memRegRead(REG_ADDR_GFSK_PAYLOAD_LENGTH_A, 1, &u32);
00487     out[6] = u32 & 0xff;
00488 
00489     memRegRead(REG_ADDR_GFSK_CFG5, 1, &cfg5.dword);
00490 
00491     if (cfg5.bits.crc_off)
00492         out[7] |= 1;
00493     else
00494         out[7] &= ~1;
00495 
00496     if (cfg5.bits.crc_size)
00497         out[7] |= 2;
00498     else
00499         out[7] &= ~2;
00500 
00501     if (cfg5.bits.crc_invert)
00502         out[7] |= 4;
00503     else
00504         out[7] &= ~4;
00505 
00506     out[8] = cfg5.bits.whitening_enable;
00507 }
00508