From 35a4b6ff4e2e4d2733f215e6d061890792f3d1ca Mon Sep 17 00:00:00 2001 From: Mark Qvist Date: Fri, 3 Jan 2025 21:23:23 +0100 Subject: [PATCH] Added support for T3S3 SX1280 --- sx128x.cpp | 450 +++++++++++++++++++++++++++++------------------------ sx128x.h | 1 + 2 files changed, 244 insertions(+), 207 deletions(-) diff --git a/sx128x.cpp b/sx128x.cpp index eceee81..c59752d 100644 --- a/sx128x.cpp +++ b/sx128x.cpp @@ -38,6 +38,7 @@ #define ISR_VECT #endif +// SX128x registers #define OP_RF_FREQ_8X 0x86 #define OP_SLEEP_8X 0x84 #define OP_STANDBY_8X 0x80 @@ -111,34 +112,52 @@ sx128x::sx128x() : setTimeout(0); } -void ISR_VECT sx128x::onDio0Rise() { sx128x_modem.handleDio0Rise(); } -void sx128x::handleDio0Rise() { +bool ISR_VECT sx128x::getPacketValidity() { uint8_t buf[2]; buf[0] = 0x00; buf[1] = 0x00; executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2); + executeOpcode(OP_CLEAR_IRQ_STATUS_8X, buf, 2); + if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_8X) == 0) { - // received a packet - _packetIndex = 0; + return true; + } else { + return false; + } +} - uint8_t rxbuf[2] = {0}; - executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2); +void ISR_VECT sx128x::onDio0Rise() { + BaseType_t int_status = taskENTER_CRITICAL_FROM_ISR(); + if (sx128x_modem.getPacketValidity()) { sx128x_modem.handleDio0Rise(); } + // On the SX1280, there is a bug which can cause the busy line + // to remain high if a high amount of packets are received when + // in continuous RX mode. This is documented as Errata 16.1 in + // the SX1280 datasheet v3.2 (page 149) + // Therefore, the modem is set into receive mode each time a packet is received. + sx128x_modem.receive(); + taskEXIT_CRITICAL_FROM_ISR(int_status); +} - _rxPacketLength = rxbuf[0]; - _fifo_rx_addr_ptr = rxbuf[1]; - readBuffer(_packet, _rxPacketLength); +void sx128x::handleDio0Rise() { + // received a packet + _packetIndex = 0; - // On the SX1280, there is a bug which can cause the busy line - // to remain high if a high amount of packets are received when - // in continuous RX mode. This is documented as Errata 16.1 in - // the SX1280 datasheet v3.2 (page 149) - // Therefore, the modem is set into receive mode each time a packet is received. - receive(0); + uint8_t rxbuf[2] = {0}; + executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2); + + // If implicit header mode is enabled, read packet length as payload length instead. + // See SX1280 datasheet v3.2, page 92 + if (_implicitHeaderMode == 0x80) { + _rxPacketLength = _payloadLength; + } else { + _rxPacketLength = rxbuf[0]; + } - if (_onReceive) { _onReceive(_rxPacketLength); } + if (_onReceive) { + _onReceive(_rxPacketLength); } } @@ -209,14 +228,24 @@ uint8_t ISR_VECT sx128x::singleTransfer(uint8_t opcode, uint16_t address, uint8_ return response; } -void sx128x::rxAntEnable() { - if (_txen != -1) { digitalWrite(_txen, LOW); } - if (_rxen != -1) { digitalWrite(_rxen, HIGH); } +void sx128x::rxAntEnable() +{ + if (_txen != -1) { + digitalWrite(_txen, LOW); + } + if (_rxen != -1) { + digitalWrite(_rxen, HIGH); + } } -void sx128x::txAntEnable() { - if (_txen != -1) { digitalWrite(_txen, HIGH); } - if (_rxen != -1) { digitalWrite(_rxen, LOW); } +void sx128x::txAntEnable() +{ + if (_txen != -1) { + digitalWrite(_txen, HIGH); + } + if (_rxen != -1) { + digitalWrite(_rxen, LOW); + } } void sx128x::loraMode() { @@ -341,29 +370,23 @@ void sx128x::setPacketParams(uint32_t preamble, uint8_t headermode, uint8_t leng // because there is no access to these registers on the sx1280, we have // to set all these parameters at once or not at all. uint8_t buf[7]; - // calculate exponent and mantissa values for modem - // uint8_t e = 1; - // uint8_t m = 1; - // uint32_t preamblelen; - - // while (e <= 15) { - // while (m <= 15) { - // preamblelen = m * (pow(2,e)); - // if (preamblelen >= preamble) break; - // m++; - // } - // if (preamblelen >= preamble) break; - // m = 0; - // e++; - // } - - // Serial.printf("Calculated preamble: %d\r\n", preamblelen); - // Serial.printf("Reg value: %d\r\n", (e << 4) | m); - - // TODO: Remove / clean - //buf[0] = (e << 4) | m; - buf[0] = 0x1C; + uint8_t e = 1; + uint8_t m = 1; + uint32_t preamblelen; + + while (e <= 15) { + while (m <= 15) { + preamblelen = m * (pow(2,e)); + if (preamblelen >= preamble) break; + m++; + } + if (preamblelen >= preamble) break; + m = 0; + e++; + } + + buf[0] = (e << 4) | m; buf[1] = headermode; buf[2] = length; buf[3] = crc; @@ -402,7 +425,9 @@ int sx128x::begin(unsigned long frequency) loraMode(); rxAntEnable(); - setFrequency(_frequency); + Serial.printf("Setting freq to %d\r\n", _frequency); + Serial.printf("Should be %d\r\n", frequency); + setFrequency(frequency); // set LNA boost // todo: implement this @@ -537,14 +562,6 @@ uint8_t sx128x::packetRssiRaw() { return buf[0]; } -int ISR_VECT sx128x::packetRssi() { - // may need more calculations here - uint8_t buf[5] = {0}; - executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5); - int pkt_rssi = -buf[0] / 2; - return pkt_rssi; -} - int ISR_VECT sx128x::packetRssi(uint8_t pkt_snr_raw) { // may need more calculations here uint8_t buf[5] = {0}; @@ -561,7 +578,7 @@ uint8_t ISR_VECT sx128x::packetSnrRaw() { float ISR_VECT sx128x::packetSnr() { uint8_t buf[5] = {0}; - executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 3); + executeOpcodeRead(OP_PACKET_STATUS_8X, buf, 5); return float(buf[1]) * 0.25; } @@ -590,17 +607,41 @@ size_t sx128x::write(const uint8_t *buffer, size_t size) return size; } -int ISR_VECT sx128x::available() { return _rxPacketLength - _packetIndex; } +int ISR_VECT sx128x::available() +{ + return _rxPacketLength - _packetIndex; +} int ISR_VECT sx128x::read() { - if (!available()) { - return -1; - } + if (!available()) { + return -1; + } + + // if received new packet + if (_packetIndex == 0) { + uint8_t rxbuf[2] = {0}; + executeOpcodeRead(OP_RX_BUFFER_STATUS_8X, rxbuf, 2); + int size; + // If implicit header mode is enabled, read packet length as payload length instead. + // See SX1280 datasheet v3.2, page 92 + if (_implicitHeaderMode == 0x80) { + size = _payloadLength; + } else { + size = rxbuf[0]; + } + _fifo_rx_addr_ptr = rxbuf[1]; - uint8_t byte = _packet[_packetIndex]; - _packetIndex++; - return byte; + if (size > 255) { + size = 255; + } + + readBuffer(_packet, size); + } + + uint8_t byte = _packet[_packetIndex]; + _packetIndex++; + return byte; } int sx128x::peek() @@ -650,10 +691,9 @@ void sx128x::onReceive(void(*callback)(int)) { executeOpcode(OP_SET_IRQ_FLAGS_8X, buf, 8); #ifdef SPI_HAS_NOTUSINGINTERRUPT - _spiModem->usingInterrupt(digitalPinToInterrupt(_dio0)); + SPI.usingInterrupt(digitalPinToInterrupt(_dio0)); #endif - // extern void onDio0Rise(); attachInterrupt(digitalPinToInterrupt(_dio0), onDio0Rise, RISING); } else { @@ -679,13 +719,13 @@ void sx128x::receive(int size) rxAntEnable(); - // On the SX1280, there is a bug which can cause the busy line - // to remain high if a high amount of packets are received when - // in continuous RX mode. This is documented as Errata 16.1 in - // the SX1280 datasheet v3.2 (page 149) - // Therefore, the modem is set to single RX mode below instead. - uint8_t mode[3] = {0}; // single RX mode - executeOpcode(OP_RX_8X, mode, 3); + // On the SX1280, there is a bug which can cause the busy line + // to remain high if a high amount of packets are received when + // in continuous RX mode. This is documented as Errata 16.1 in + // the SX1280 datasheet v3.2 (page 149) + // Therefore, the modem is set to single RX mode below instead. + uint8_t mode[3] = {0}; // single RX mode + executeOpcode(OP_RX_8X, mode, 3); } void sx128x::standby() @@ -726,7 +766,7 @@ void sx128x::setPins(int ss, int reset, int dio0, int busy, int rxen, int txen) void sx128x::setTxPower(int level, int outputPin) { uint8_t tx_buf[2]; - #if BOARD_VARIANT == MODEL_13 + #if BOARD_VARIANT == MODEL_13 || BOARD_VARIANT == MODEL_21 // RAK4631 with WisBlock SX1280 module (LIBSYS002) if (level > 27) { level = 27; @@ -743,73 +783,73 @@ void sx128x::setTxPower(int level, int outputPin) { reg_value = -18; break; case 1: - reg_value = -17; + reg_value = -16; break; case 2: - reg_value = -16; + reg_value = -15; break; case 3: - reg_value = -15; + reg_value = -14; break; case 4: - reg_value = -14; + reg_value = -13; break; case 5: - reg_value = -13; + reg_value = -12; break; case 6: - reg_value = -12; + reg_value = -11; break; case 7: - reg_value = -10; + reg_value = -9; break; case 8: - reg_value = -9; + reg_value = -8; break; case 9: - reg_value = -8; + reg_value = -7; break; case 10: - reg_value = -7; + reg_value = -6; break; case 11: - reg_value = -6; + reg_value = -5; break; case 12: - reg_value = -5; + reg_value = -4; break; case 13: - reg_value = -4; + reg_value = -3; break; case 14: - reg_value = -3; + reg_value = -2; break; case 15: - reg_value = -2; + reg_value = -1; break; case 16: - reg_value = -1; + reg_value = 0; break; case 17: - reg_value = 0; + reg_value = 1; break; case 18: - reg_value = 1; + reg_value = 2; break; case 19: - reg_value = 2; + reg_value = 3; break; case 20: - reg_value = 3; + reg_value = 4; break; case 21: - reg_value = 4; + reg_value = 5; break; case 22: - reg_value = 5; + reg_value = 6; break; case 23: - reg_value = 6; + reg_value = 7; break; case 24: reg_value = 8; @@ -828,103 +868,103 @@ void sx128x::setTxPower(int level, int outputPin) { break; } - tx_buf[0] = reg_value; + tx_buf[0] = reg_value + 18; tx_buf[1] = 0xE0; // ramping time - 20 microseconds executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); - + + #elif BOARD_VARIANT == MODEL_AC // T3S3 SX1280 PA - #elif BOARD_VARIANT == MODEL_AB - if (level > 20) { level = 20; } - else if (level < 0) { level = 0; } - - _txp = level; - int reg_value; - - switch (level) { - /*case 0: - reg_value = -18; - break; - case 1: - reg_value = -17; - break; - case 2: - reg_value = -16; - break; - case 3: - reg_value = -15; - break; - case 4: - reg_value = -14; - break; - case 5: - reg_value = -13; - break; - case 6: - reg_value = -12; - break; - case 7: - reg_value = -10; - break; - case 8: - reg_value = -9; - break; - case 9: - reg_value = -8; - break; - case 10: - reg_value = -7; - break; - case 11: - reg_value = -6; - break; - case 12: - reg_value = -5; - break; - case 13: - reg_value = -4; - break; - case 14: - reg_value = -3; - break; - case 15: - reg_value = -2; - break; - case 16: - reg_value = -1; - break; - case 17: - reg_value = 0; - break; - case 18: - reg_value = 1; - break; - case 19: - reg_value = 2; - break;*/ - case 20: - reg_value = 3; - break; - default: - reg_value = 0; - break; - } + if (level > 20) { level = 20; } + else if (level < 0) { level = 0; } + + _txp = level; + + int reg_value; + + switch (level) { + /*case 0: + reg_value = -18; + break; + case 1: + reg_value = -17; + break; + case 2: + reg_value = -16; + break; + case 3: + reg_value = -15; + break; + case 4: + reg_value = -14; + break; + case 5: + reg_value = -13; + break; + case 6: + reg_value = -12; + break; + case 7: + reg_value = -10; + break; + case 8: + reg_value = -9; + break; + case 9: + reg_value = -8; + break; + case 10: + reg_value = -7; + break; + case 11: + reg_value = -6; + break; + case 12: + reg_value = -5; + break; + case 13: + reg_value = -4; + break; + case 14: + reg_value = -3; + break; + case 15: + reg_value = -2; + break; + case 16: + reg_value = -1; + break; + case 17: + reg_value = 0; + break; + case 18: + reg_value = 1; + break; + case 19: + reg_value = 2; + break;*/ + case 20: + reg_value = 3; + break; + default: + reg_value = 0; + break; + } - tx_buf[0] = reg_value; - tx_buf[1] = 0xE0; // ramping time - 20 microseconds - - // For SX1280 boards with no specific PA requirements + tx_buf[0] = reg_value; + tx_buf[1] = 0xE0; // ramping time - 20 microseconds #else - if (level > 13) { - level = 13; - } else if (level < -18) { - level = -18; - } + // For SX1280 boards with no specific PA requirements + if (level > 13) { + level = 13; + } else if (level < -18) { + level = -18; + } - _txp = level; + _txp = level; - tx_buf[0] = level; - tx_buf[1] = 0xE0; // ramping time - 20 microseconds + tx_buf[0] = level + 18; + tx_buf[1] = 0xE0; // ramping time - 20 microseconds #endif executeOpcode(OP_TX_PARAMS_8X, tx_buf, 2); } @@ -977,13 +1017,16 @@ uint32_t sx128x::getSignalBandwidth() { return 0; } -// todo: do i need this?? -void sx128x::handleLowDataRate() { } +void sx128x::handleLowDataRate(){ + // todo: do i need this?? +} -// todo: check if there's anything the sx1280 can do here -void sx128x::optimizeModemSensitivity() { } +void sx128x::optimizeModemSensitivity(){ + // todo: check if there's anything the sx1280 can do here +} -void sx128x::setSignalBandwidth(uint32_t sbw) { +void sx128x::setSignalBandwidth(uint32_t sbw) +{ if (sbw <= 203.125E3) { _bw = 0x34; } else if (sbw <= 406.25E3) { @@ -1018,9 +1061,13 @@ void sx128x::setCodingRate4(int denominator) setModulationParams(_sf, _bw, _cr); } -uint8_t sx128x::getCodingRate4() { return _cr + 4; } +uint8_t sx128x::getCodingRate4() +{ + return _cr + 4; +} -void sx128x::setPreambleLength(long length) { +void sx128x::setPreambleLength(long length) +{ _preambleLength = length; setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode); } @@ -1030,21 +1077,21 @@ void sx128x::setSyncWord(int sw) // not implemented } -void sx128x::enableCrc() -{ +void sx128x::enableCrc() { _crcMode = 0x20; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); } -void sx128x::disableCrc() -{ +void sx128x::disableCrc() { _crcMode = 0; setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); } -byte sx128x::random() -{ +uint8_t sx128x::random() { // todo: implement + return 0x4; //chosen by fair die roll + //guarenteed to be random + //https://xkcd.com/221/ } void sx128x::setSPIFrequency(uint32_t frequency) @@ -1075,15 +1122,4 @@ void sx128x::implicitHeaderMode() setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode); } -void sx128x::clearIRQStatus() { - uint8_t buf[2]; - - buf[0] = 0x00; - buf[1] = 0x00; - - executeOpcodeRead(OP_GET_IRQ_STATUS_8X, buf, 2); - - executeOpcode(OP_CLEAR_IRQ_STATUS_8X, buf, 2); -} - sx128x sx128x_modem; \ No newline at end of file diff --git a/sx128x.h b/sx128x.h index 93f287f..0652c91 100644 --- a/sx128x.h +++ b/sx128x.h @@ -106,6 +106,7 @@ private: void explicitHeaderMode(); void implicitHeaderMode(); + bool getPacketValidity(); void handleDio0Rise(); uint8_t readRegister(uint16_t address);