driver for sx1280
Dependents: alarm_slave_extended_SX1280 alarm_master_extended_Vance_SX1280
sx1280.cpp
- Committer:
- Wayne Roberts
- Date:
- 2018-07-16
- Revision:
- 3:54612373bec6
- Parent:
- 2:8a442c3511ae
- Child:
- 4:ac55132283cb
File content as of revision 3:54612373bec6:
#include "sx12xx.h" Callback<void()> SX128x::diox_topHalf; // low latency ISR context const float SX128x::timeOutStep[] = { 0.015625, 0.0625, 1, 4 }; void SX128x::dioxisr() { if (diox_topHalf) diox_topHalf.call(); } SX128x::SX128x(SPI& _spi, PinName _nss, PinName _busy, PinName _diox, PinName _nrst) : spi(_spi), nss(_nss), busy(_busy), diox(_diox), nrst(_nrst) { unsigned busyCnt = 0; nss = 1; while (busy) { if (++busyCnt > 0x80000) { hw_reset(); } } periodBase = 3; diox.rise(dioxisr); } uint8_t SX128x::xfer(uint8_t opcode, uint8_t wlen, uint8_t rlen, uint8_t* ptr) { const uint8_t* stopPtr; const uint8_t* wstop; const uint8_t* rstop; uint8_t nop = 0; uint8_t ret; if (opcode != OPCODE_GET_STATUS) { if (sleeping) { nss = 0; while (busy) ; sleeping = false; } else { while (busy) ; nss = 0; } } else nss = 0; ret = spi.write(opcode); wstop = ptr + wlen; rstop = ptr + rlen; if (rlen > wlen) stopPtr = rstop; else stopPtr = wstop; for (; ptr < stopPtr; ptr++) { if (ptr < wstop && ptr < rstop) *ptr = spi.write(*ptr); else if (ptr < wstop) spi.write(*ptr); else *ptr = spi.write(nop); // n >= write length: send NOP } nss = 1; if (opcode == OPCODE_SET_SLEEP) sleeping = true; return ret; } uint32_t SX128x::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, 2, 3+len, buf); for (i = 0; i < len; i++) { ret <<= 8; ret |= buf[i+3]; } return ret; } void SX128x::start_tx(uint8_t pktLen, float timeout_ms) { IrqFlags_t irqEnable; uint8_t buf[8]; irqEnable.word = 0; irqEnable.bits.TxDone = 1; irqEnable.bits.RxTxTimeout = 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, 0, buf); { 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] = periodBase; if (timeout_ms > 0) { unsigned t_o = timeout_ms / timeOutStep[periodBase]; buf[1] = t_o >> 8; buf[2] = t_o; } else { /* no timeout */ buf[1] = 0; buf[2] = 0; } xfer(OPCODE_SET_TX, 3, 0, buf); chipMode = CHIPMODE_TX; if (chipModeChange) chipModeChange.call(); } void SX128x::hw_reset() { nrst.output(); nrst = 0; wait_us(100); nrst = 1; nrst.mode(PullUp); nrst.input(); while (busy) ; } uint64_t SX128x::getSyncAddr(uint8_t num) { uint64_t ret; unsigned regAdr = REG_ADDR_PKT_SYNC_ADRS_1 + ((num-1) * 5); ret = readReg(regAdr, 1); ret <<= 32; ret |= readReg(regAdr+1, 4); return ret; } void SX128x::setSyncAddr(uint8_t num, uint64_t sa) { unsigned regAdr = REG_ADDR_PKT_SYNC_ADRS_1 + ((num-1) * 5); writeReg(regAdr+1, sa & 0xffffffff, 4); sa >>= 32; writeReg(regAdr, sa & 0xff, 1); } void SX128x::set_tx_dbm(int8_t dbm) { uint8_t buf[2]; buf[0] = dbm; buf[1] = RADIO_RAMP_20_US; xfer(OPCODE_SET_TX_PARAMS, 2, 0, buf); } void SX128x::setMHz(float MHz) { unsigned frf = MHz / PLL_STEP_MHZ; uint8_t buf[3]; buf[0] = frf >> 16; buf[1] = frf >> 8; buf[2] = frf; xfer(OPCODE_SET_RF_FREQUENCY, 3, 0, buf); } float SX128x::getMHz() { uint32_t frf = readReg(REG_ADDR_RFFREQ, 3); return frf * PLL_STEP_MHZ; } void SX128x::setStandby(stby_t stby) { uint8_t octet = stby; xfer(OPCODE_SET_STANDBY, 1, 0, &octet); chipMode = CHIPMODE_NONE; if (chipModeChange) chipModeChange.call(); } void SX128x::setFS() { xfer(OPCODE_SET_FS, 0, 0, NULL); chipMode = CHIPMODE_NONE; if (chipModeChange) chipModeChange.call(); } void SX128x::setSleep(bool warm) { sleepConfig_t sc; if (warm) { xfer(OPCODE_SAVE_CONTEXT, 0, 0, NULL); } chipMode = CHIPMODE_NONE; if (chipModeChange) chipModeChange.call(); sc.octet = 0; sc.retentionBits.dataRAM = warm; sc.retentionBits.dataBuffer = warm; sc.retentionBits.instructionRAM = warm; xfer(OPCODE_SET_SLEEP, 1, 0, &sc.octet); } uint8_t SX128x::getPacketType() { uint8_t buf[2]; xfer(OPCODE_GET_PACKET_TYPE, 0, 2, buf); pktType = buf[1]; return buf[1]; } void SX128x::setPacketType(uint8_t type) { xfer(OPCODE_SET_PACKET_TYPE, 1, 0, &type); pktType = type; } void SX128x::setBufferBase(uint8_t txAddr, uint8_t rxAddr) { uint8_t buf[2]; buf[0] = txAddr; // TX base address buf[1] = rxAddr; // RX base address xfer(OPCODE_SET_BUFFER_BASE_ADDR, 2, 0, buf); } void SX128x::setRegulator(uint8_t rmp) { xfer(OPCODE_SET_REGULATOR_MODE, 1, 0, &rmp); } void SX128x::start_rx(float timeout_ms) { IrqFlags_t irqEnable; uint8_t buf[8]; unsigned t_o; irqEnable.word = 0; irqEnable.bits.RxDone = 1; irqEnable.bits.RxTxTimeout = 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, 0, buf); buf[0] = periodBase; if (timeout_ms > 0) { t_o = timeout_ms / timeOutStep[periodBase]; buf[1] = t_o >> 8; buf[2] = t_o; } else { /* receive packets forever */ buf[1] = 0xff; buf[2] = 0xff; } xfer(OPCODE_SET_RX, 3, 0, buf); chipMode = CHIPMODE_RX; if (chipModeChange) { chipModeChange.call(); } } void SX128x::service() { IrqFlags_t irqFlags, clearIrqFlags; uint8_t buf[6]; pktStatus_t pktStatus; //status_t st; if (busy) { return; } while (diox) { xfer(OPCODE_GET_IRQ_STATUS, 0, 3, buf); /*st.octet = buf[0]; */ irqFlags.word = buf[1] << 8; irqFlags.word |= buf[2]; clearIrqFlags.word = 0; if (irqFlags.bits.TxDone) { chipMode = CHIPMODE_NONE; if (chipModeChange) chipModeChange.call(); if (txDone) txDone.call(); // might change to Rx clearIrqFlags.bits.TxDone = 1; } if (irqFlags.bits.RxDone) { if (rxDone) { uint8_t len, slen; xfer(OPCODE_GET_RX_BUFFER_STATUS, 0, 3, buf); /*st.octet = buf[0]; */ if (buf[1] == 0) len = readReg(REG_ADDR_LORA_TX_PAYLOAD_LENGTH, 1); // lora implicit else len = buf[1]; ReadBuffer(len, buf[2]); if (pktType == PACKET_TYPE_LORA || pktType == PACKET_TYPE_RANGING) slen = 3; else slen = 6; xfer(OPCODE_GET_PACKET_STATUS, 0, slen, pktStatus.buf); rxDone(len, &pktStatus); } clearIrqFlags.bits.RxDone = 1; } if (irqFlags.bits.RxTxTimeout) { if (chipMode != CHIPMODE_NONE) { if (timeout) timeout(chipMode == CHIPMODE_TX); } chipMode = CHIPMODE_NONE; if (chipModeChange) chipModeChange.call(); clearIrqFlags.bits.RxTxTimeout = 1; } if (clearIrqFlags.word != 0) { buf[0] = clearIrqFlags.word >> 8; buf[1] = (uint8_t)clearIrqFlags.word; xfer(OPCODE_CLEAR_IRQ_STATUS, 2, 0, buf); } } // ...while (diox) } // ..service() void SX128x::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--) { buf[n+1] = (uint8_t)data; data >>= 8; } xfer(OPCODE_WRITE_REGISTER, 2+len, 2+len, buf); } void SX128x::ReadBuffer(uint8_t size, uint8_t offset) { //status_t st; unsigned i; while (busy) ; nss = 0; /*st.octet =*/ spi.write(OPCODE_READ_BUFFER); /*st.octet =*/ spi.write(offset); /*st.octet =*/ spi.write(0); // NOP i = 0; for (i = 0; i < size; i++) { rx_buf[i] = spi.write(0); } nss = 1; }