sx1261/2 driver
Dependents: alarm_slave iq_sx126x sx126x_simple_TX_shield_2020a sx126x_simple_RX_shield_2020a ... more
Driver for SX1261 or SX1262
sx126x.cpp
- Committer:
- Wayne Roberts
- Date:
- 2018-05-16
- Revision:
- 0:c79a1f70c110
- Child:
- 1:497af0bd9e53
File content as of revision 0:c79a1f70c110:
#include "sx126x.h" Callback<void()> SX126x::dio1_topHalf; // low latency ISR context void SX126x::dio1isr() { if (dio1_topHalf) dio1_topHalf.call(); } SX126x::SX126x(SPI& _spi, PinName _nss, PinName _busy, PinName _dio1) : spi(_spi), nss(_nss), busy(_busy), dio1(_dio1) { uint8_t buf[8]; IrqFlags_t irqEnable; irqEnable.word = 0; irqEnable.bits.TxDone = 1; irqEnable.bits.RxDone = 1; irqEnable.bits.Timeout = 1; buf[0] = irqEnable.word >> 8; // enable bits buf[1] = irqEnable.word; // enable bits buf[2] = irqEnable.word >> 8; // dio1 buf[3] = irqEnable.word; // dio1 buf[4] = 0; // dio2 buf[5] = 0; // dio2 buf[6] = 0; // dio3 buf[7] = 0; // dio3 xfer(OPCODE_SET_DIO_IRQ_PARAMS, 8, buf); dio1.rise(dio1isr); } void SX126x::PrintChipStatus(status_t status) { printf("%02x cmdStatus:", status.octet); switch (status.bits.cmdStatus) { case 0: printf("Reserved"); break; case 1: printf("RFU"); break; case 2: printf("dataAvail"); break; case 3: printf("cmdTimeout"); break; case 4: printf("cmdError"); break; case 5: printf("execFail"); break; case 6: printf("cmdTxDone"); break; } printf(" chipMode:"); switch (status.bits.chipMode) { case 0: printf("Unused"); break; case 1: printf("RFU"); break; case 2: printf("STBY_RC"); break; case 3: printf("STBY_XOSC"); break; case 4: printf("FS"); break; case 5: printf("RX"); break; case 6: printf("TX"); break; } printf("\r\n"); } void SX126x::service() { IrqFlags_t irqFlags, clearIrqFlags; uint8_t buf[4]; if (busy) return; while (dio1) { xfer(OPCODE_GET_IRQ_STATUS, 3, buf); irqFlags.word = buf[1] << 8; irqFlags.word |= buf[2]; clearIrqFlags.word = 0; if (irqFlags.bits.TxDone) { if (txDone) txDone.call(); clearIrqFlags.bits.TxDone = 1; txing = false; } if (irqFlags.bits.RxDone) { if (rxDone) { uint8_t len; float snr, rssi; int8_t s; xfer(OPCODE_GET_RX_BUFFER_STATUS, 3, buf); len = buf[1]; ReadBuffer(len); xfer(OPCODE_GET_PACKET_STATUS, 4, buf); rssi = -buf[1] / 2.0; // TODO FSK s = buf[2]; snr = s / 4.0; rxDone(len, rssi, snr); } clearIrqFlags.bits.RxDone = 1; } if (irqFlags.bits.Timeout) { if (timeout) timeout(txing); txing = false; clearIrqFlags.bits.Timeout = 1; } if (clearIrqFlags.word != 0) { buf[0] = clearIrqFlags.word >> 8; buf[1] = (uint8_t)clearIrqFlags.word; xfer(OPCODE_CLEAR_IRQ_STATUS, 2, buf); } } // ...while (dio1) } // ..service() void SX126x::xfer(uint8_t opcode, uint8_t len, uint8_t* ptr) { if (sleeping) { nss = 0; while (busy) ; sleeping = false; } else { while (busy) ; nss = 0; } spi.write(opcode); while (len > 0) { *ptr = spi.write(*ptr); len--; ptr++; } nss = 1; if (opcode == OPCODE_SET_SLEEP) sleeping = true; } void SX126x::start_tx(uint8_t pktLen) { uint8_t buf[8]; { uint8_t i; while (busy) ; nss = 0; spi.write(OPCODE_WRITE_BUFFER); spi.write(0); // offset i = 0; for (i = 0; i < pktLen; i++) { spi.write(tx_buf[i]); } nss = 1; } buf[0] = 0x40; buf[1] = 0x00; buf[2] = 0x00; xfer(OPCODE_SET_TX, 3, buf); txing = true; } void SX126x::start_rx(unsigned timeout) { uint8_t buf[8]; buf[0] = timeout >> 16; buf[1] = timeout >> 8; buf[2] = timeout; xfer(OPCODE_SET_RX, 3, buf); } #define MHZ_TO_FRF 1048576 // = (1<<25) / Fxtal_MHz uint8_t SX126x::setMHz(float MHz) { unsigned frf = MHz * MHZ_TO_FRF; uint8_t buf[4]; buf[0] = frf >> 24; buf[1] = frf >> 16; buf[2] = frf >> 8; buf[3] = frf; xfer(OPCODE_SET_RF_FREQUENCY, 4, buf); return buf[3]; } void SX126x::setPacketType(uint8_t type) { xfer(OPCODE_SET_PACKET_TYPE, 1, &type); } void SX126x::SetDIO2AsRfSwitchCtrl(uint8_t en) { xfer(OPCODE_SET_DIO2_AS_RFSWITCH, 1, &en); } void SX126x::ReadBuffer(uint8_t size) { unsigned i; while (busy) ; nss = 0; spi.write(OPCODE_READ_BUFFER); spi.write(0); // offset spi.write(0); // NOP i = 0; for (i = 0; i < size; i++) { rx_buf[i] = spi.write(0); } nss = 1; } void SX126x::set_tx_dbm(bool is1262, int8_t dbm) { uint8_t buf[4]; // use OCP default printf("set_tx_dbm(%d) ", dbm); buf[3] = 1; if (is1262) { printf("sx1262 "); buf[0] = 4; buf[1] = 7; buf[2] = 0; if (dbm > 22) dbm = 22; else if (dbm < -3) dbm = -3; } else { printf("sx1261 "); if (dbm == 15) buf[0] = 6; else buf[0] = 4; buf[1] = 0; buf[2] = 1; if (dbm > 14) dbm = 14; else if (dbm < -3) dbm = -3; } xfer(OPCODE_SET_PA_CONFIG, 4, buf); if (is1262 && dbm > 18) { /* OCP is set by chip whenever SetPaConfig() is called */ writeReg(REG_ADDR_OCP, 0x38, 1); } // SetTxParams buf[0] = dbm; //if (opt == 0) txco buf[1] = SET_RAMP_200U; xfer(OPCODE_SET_TX_PARAMS, 2, buf); } void SX126x::writeReg(uint16_t addr, uint32_t data, uint8_t len) { uint8_t buf[6]; uint8_t n; buf[0] = addr >> 8; buf[1] = (uint8_t)addr; for (n = len; n > 0; n--) { //printf("data:%02x to buf[%u]\r\n", (uint8_t)data, n+1); buf[n+1] = (uint8_t)data; data >>= 8; } //printf("write reg %04x: %02x %02x %02x %02x\r\n", addr, buf[0], buf[1], buf[2], buf[3]); xfer(OPCODE_WRITE_REGISTER, 2+len, buf); //printf("write status %02x %02x %02x %02x\r\n", buf[0], buf[1], buf[2], buf[3]); } void SX126x::setStandby(stby_t stby) { uint8_t octet = stby; xfer(OPCODE_SET_STANDBY, 1, &octet); } void SX126x::setSleep(bool warmStart, bool rtcWakeup) { sleepConfig_t sc; sc.octet = 0; sc.bits.rtcWakeup = rtcWakeup; sc.bits.warmStart = warmStart; xfer(OPCODE_SET_SLEEP, 1, &sc.octet); } void SX126x::hw_reset(PinName pin) { DigitalInOut nrst(pin); nrst.output(); nrst = 0; wait_us(100); nrst = 1; nrst.mode(PullUp); nrst.input(); while (busy) ; } uint32_t SX126x::readReg(uint16_t addr, uint8_t len) { uint32_t ret = 0; unsigned i; uint8_t buf[7]; buf[0] = addr >> 8; buf[1] = (uint8_t)addr; xfer(OPCODE_READ_REGISTER, 3+len, buf); for (i = 0; i < len; i++) { ret <<= 8; ret |= buf[i+3]; } return ret; }