Add SX1280 driver and split driver in three parts

This commit is contained in:
jacob.eva 2024-02-09 20:46:39 +00:00
parent 252b11ab90
commit 78a02c5ae4
No known key found for this signature in database
GPG Key ID: 0B92E083BBCCAA1E
11 changed files with 2867 additions and 1611 deletions

View File

@ -315,8 +315,9 @@
#define HAS_NP false
#define HAS_SD false
#define HAS_TCXO true
#define HAS_RXEN_BUSY true
#define MODEM SX1262
#define HAS_RF_SWITCH_RX_TX true
#define HAS_BUSY true
#define MODEM SX1280
#define CONFIG_UART_BUFFER_SIZE 6144
#define CONFIG_QUEUE_SIZE 6144
@ -325,14 +326,14 @@
#define EEPROM_OFFSET EEPROM_SIZE+0xED000-EEPROM_RESERVED
// following pins are for the sx1262
const int pin_rxen = 37;
/*const int pin_rxen = 37;
const int pin_reset = 38;
const int pin_cs = 42;
const int pin_sclk = 43;
const int pin_mosi = 44;
const int pin_miso = 45;
const int pin_busy = 46;
const int pin_dio = 47;
const int pin_dio = 47;*/
const int pin_led_rx = LED_BLUE;
const int pin_led_tx = LED_GREEN;
const int pin_tcxo_enable = -1;
@ -351,12 +352,16 @@
#define eeprom_addr(a) (a+EEPROM_OFFSET)
#ifndef HAS_RXEN_BUSY
#ifndef HAS_RF_SWITCH_RX_TX
const int pin_rxen = -1;
const int pin_txen = -1;
#endif
#ifndef HAS_BUSY
const int pin_busy = -1;
#endif
#if MODEM == SX1262 && defined(NRF52840_XXAA)
#if (MODEM == SX1262 || MODEM == SX1280) && defined(NRF52840_XXAA)
SPIClass spiModem(NRF_SPIM2, pin_miso, pin_sclk, pin_mosi);
#endif

1505
LoRa.cpp

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,4 @@
#define SX1276 0x01
#define SX1278 0x02
#define SX1262 0x03
#define SX1280 0x04

View File

@ -93,16 +93,22 @@ void setup() {
// Set chip select, reset and interrupt
// pins for the LoRa module
LoRa.setPins(pin_cs, pin_reset, pin_dio, pin_rxen, pin_busy);
#if MODEM == SX1276 || MODEM == SX1278
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy);
#elif MODEM == SX1262
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy, pin_rxen);
#elif MODEM == SX1280
LoRa->setPins(pin_cs, pin_reset, pin_dio, pin_busy, pin_rxen, pin_txen);
#endif
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
init_channel_stats();
// Check installed transceiver chip and
// probe boot parameters.
if (LoRa.preInit()) {
if (LoRa->preInit()) {
modem_installed = true;
uint32_t lfr = LoRa.getFrequency();
uint32_t lfr = LoRa->getFrequency();
if (lfr == 0) {
// Normal boot
} else if (lfr == M_FRQ_R) {
@ -115,7 +121,7 @@ void setup() {
} else {
// Unknown boot
}
LoRa.setFrequency(M_FRQ_S);
LoRa->setFrequency(M_FRQ_S);
} else {
modem_installed = false;
}
@ -158,14 +164,14 @@ void setup() {
// Validate board health, EEPROM and config
validate_status();
if (op_mode != MODE_TNC) LoRa.setFrequency(0);
if (op_mode != MODE_TNC) LoRa->setFrequency(0);
}
void lora_receive() {
if (!implicit) {
LoRa.receive();
LoRa->receive();
} else {
LoRa.receive(implicit_l);
LoRa->receive(implicit_l);
}
}
@ -187,7 +193,7 @@ inline void kiss_write_packet() {
inline void getPacketData(uint16_t len) {
while (len-- && read_len < MTU) {
pbuf[read_len++] = LoRa.read();
pbuf[read_len++] = LoRa->read();
}
}
@ -198,7 +204,7 @@ void ISR_VECT receive_callback(int packet_size) {
// by combining two raw LoRa packets.
// We read the 1-byte header and extract
// packet sequence number and split flags
uint8_t header = LoRa.read(); packet_size--;
uint8_t header = LoRa->read(); packet_size--;
uint8_t sequence = packetSequence(header);
bool ready = false;
@ -210,8 +216,8 @@ void ISR_VECT receive_callback(int packet_size) {
seq = sequence;
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
#endif
getPacketData(packet_size);
@ -223,8 +229,8 @@ void ISR_VECT receive_callback(int packet_size) {
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = (last_rssi+LoRa.packetRssi())/2;
last_snr_raw = (last_snr_raw+LoRa.packetSnrRaw())/2;
last_rssi = (last_rssi+LoRa->packetRssi())/2;
last_snr_raw = (last_snr_raw+LoRa->packetSnrRaw())/2;
#endif
getPacketData(packet_size);
@ -241,8 +247,8 @@ void ISR_VECT receive_callback(int packet_size) {
seq = sequence;
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
#endif
getPacketData(packet_size);
@ -260,8 +266,8 @@ void ISR_VECT receive_callback(int packet_size) {
}
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
#endif
getPacketData(packet_size);
@ -287,8 +293,8 @@ void ISR_VECT receive_callback(int packet_size) {
read_len = 0;
#if MCU_VARIANT != MCU_ESP32 && MCU_VARIANT != MCU_NRF52
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
getPacketData(packet_size);
// We first signal the RSSI of the
@ -310,7 +316,7 @@ bool startRadio() {
update_radio_lock();
if (!radio_online && !console_active) {
if (!radio_locked && hw_ready) {
if (!LoRa.begin(lora_freq)) {
if (!LoRa->begin(lora_freq)) {
// The radio could not be started.
// Indicate this failure over both the
// serial port and with the onboard LEDs
@ -329,9 +335,9 @@ bool startRadio() {
setCodingRate();
getFrequency();
LoRa.enableCrc();
LoRa->enableCrc();
LoRa.onReceive(receive_callback);
LoRa->onReceive(receive_callback);
lora_receive();
@ -360,7 +366,7 @@ bool startRadio() {
}
void stopRadio() {
LoRa.end();
LoRa->end();
radio_online = false;
}
@ -469,23 +475,23 @@ void transmit(uint16_t size) {
header = header | FLAG_SPLIT;
}
LoRa.beginPacket();
LoRa.write(header); written++;
LoRa->beginPacket();
LoRa->write(header); written++;
for (uint16_t i=0; i < size; i++) {
LoRa.write(tbuf[i]);
LoRa->write(tbuf[i]);
written++;
if (written == 255) {
LoRa.endPacket(); add_airtime(written);
LoRa.beginPacket();
LoRa.write(header);
LoRa->endPacket(); add_airtime(written);
LoRa->beginPacket();
LoRa->write(header);
written = 1;
}
}
LoRa.endPacket(); add_airtime(written);
LoRa->endPacket(); add_airtime(written);
} else {
// In promiscuous mode, we only send out
// plain raw LoRa packets with a maximum
@ -501,17 +507,17 @@ void transmit(uint16_t size) {
// If implicit header mode has been set,
// set packet length to payload data length
if (!implicit) {
LoRa.beginPacket();
LoRa->beginPacket();
} else {
LoRa.beginPacket(size);
LoRa->beginPacket(size);
}
for (uint16_t i=0; i < size; i++) {
LoRa.write(tbuf[i]);
LoRa->write(tbuf[i]);
written++;
}
LoRa.endPacket(); add_airtime(written);
LoRa->endPacket(); add_airtime(written);
}
} else {
kiss_indicate_error(ERROR_TXFAILED);
@ -631,7 +637,7 @@ void serialCallback(uint8_t sbyte) {
kiss_indicate_spreadingfactor();
} else {
int sf = sbyte;
if (sf < 6) sf = 6;
if (sf < 5) sf = 5;
if (sf > 12) sf = 12;
lora_sf = sf;
@ -938,8 +944,8 @@ void updateModemStatus() {
portENTER_CRITICAL();
#endif
uint8_t status = LoRa.modemStatus();
current_rssi = LoRa.currentRssi();
uint8_t status = LoRa->modemStatus();
current_rssi = LoRa->currentRssi();
last_status_update = millis();
#if MCU_VARIANT == MCU_ESP32
@ -1158,8 +1164,8 @@ void loop() {
#if MCU_VARIANT == MCU_ESP32
if (packet_ready) {
portENTER_CRITICAL(&update_lock);
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
portEXIT_CRITICAL(&update_lock);
kiss_indicate_stat_rssi();
kiss_indicate_stat_snr();
@ -1173,8 +1179,8 @@ void loop() {
#elif MCU_VARIANT == MCU_NRF52
if (packet_ready) {
portENTER_CRITICAL();
last_rssi = LoRa.packetRssi();
last_snr_raw = LoRa.packetSnrRaw();
last_rssi = LoRa->packetRssi();
last_snr_raw = LoRa->packetSnrRaw();
portEXIT_CRITICAL();
kiss_indicate_stat_rssi();
kiss_indicate_stat_snr();
@ -1199,7 +1205,7 @@ void loop() {
}
if (!dcd) {
uint8_t csma_r = (uint8_t)random(256);
uint8_t csma_r = (uint8_t)random(20); // updated to increase bitrate: todo check
if (csma_p >= csma_r) {
flushQueue();
} else {

View File

@ -22,7 +22,18 @@
int written_bytes = 0;
#endif
#include <stddef.h>
#include "LoRa.h"
#if MODEM == SX1262
#include "sx126x.h"
sx126x *LoRa = &sx126x_modem;
#elif MODEM == SX1276 || MODEM == SX1278
#include "sx127x.h"
sx127x *LoRa = &sx127x_modem;
#elif MODEM == SX1280
#include "sx128x.h"
sx128x *LoRa = &sx128x_modem;
#endif
#include "ROM.h"
#include "Framing.h"
#include "MD5.h"
@ -657,11 +668,7 @@ void kiss_indicate_stat_tx() {
}
void kiss_indicate_stat_rssi() {
#if MODEM == SX1276 || MODEM == SX1278
uint8_t packet_rssi_val = (uint8_t)(last_rssi+rssi_offset);
#elif MODEM == SX1262
int8_t packet_rssi_val = (int8_t)(last_rssi+rssi_offset);
#endif
uint8_t packet_rssi_val = (uint8_t)(last_rssi+rssi_offset);
serial_write(FEND);
serial_write(CMD_STAT_RSSI);
escaped_serial_write(packet_rssi_val);
@ -975,7 +982,7 @@ inline uint8_t packetSequence(uint8_t header) {
}
void setPreamble() {
if (radio_online) LoRa.setPreambleLength(lora_preamble_symbols);
if (radio_online) LoRa->setPreambleLength(lora_preamble_symbols);
kiss_indicate_phy_stats();
}
@ -1002,12 +1009,12 @@ void updateBitrate() {
}
void setSpreadingFactor() {
if (radio_online) LoRa.setSpreadingFactor(lora_sf);
if (radio_online) LoRa->setSpreadingFactor(lora_sf);
updateBitrate();
}
void setCodingRate() {
if (radio_online) LoRa.setCodingRate4(lora_cr);
if (radio_online) LoRa->setCodingRate4(lora_cr);
updateBitrate();
}
@ -1021,66 +1028,66 @@ void set_implicit_length(uint8_t len) {
}
int getTxPower() {
uint8_t txp = LoRa.getTxPower();
uint8_t txp = LoRa->getTxPower();
return (int)txp;
}
void setTXPower() {
if (radio_online) {
if (model == MODEL_A2) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A3) LoRa.setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A4) LoRa.setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A7) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A8) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A9) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A2) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A3) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A4) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A7) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B3) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B4) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B8) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B9) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C4) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C9) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E4) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E9) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FE) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FF) LoRa.setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_FE) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FF) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
}
}
void getBandwidth() {
if (radio_online) {
lora_bw = LoRa.getSignalBandwidth();
lora_bw = LoRa->getSignalBandwidth();
}
updateBitrate();
}
void setBandwidth() {
if (radio_online) {
LoRa.setSignalBandwidth(lora_bw);
LoRa->setSignalBandwidth(lora_bw);
getBandwidth();
}
}
void getFrequency() {
if (radio_online) {
lora_freq = LoRa.getFrequency();
lora_freq = LoRa->getFrequency();
}
}
void setFrequency() {
if (radio_online) {
LoRa.setFrequency(lora_freq);
LoRa->setFrequency(lora_freq);
getFrequency();
}
}
uint8_t getRandom() {
if (radio_online) {
return LoRa.random();
return LoRa->random();
} else {
return 0x00;
}

911
sx126x.cpp Normal file
View File

@ -0,0 +1,911 @@
// Copyright (c) Sandeep Mistry. All rights reserved.
// Licensed under the MIT license.
// Modifications and additions copyright 2023 by Mark Qvist
// Obviously still under the MIT license.
#include "sx126x.h"
#define MCU_1284P 0x91
#define MCU_2560 0x92
#define MCU_ESP32 0x81
#define MCU_NRF52 0x71
#if defined(__AVR_ATmega1284P__)
#define PLATFORM PLATFORM_AVR
#define MCU_VARIANT MCU_1284P
#elif defined(__AVR_ATmega2560__)
#define PLATFORM PLATFORM_AVR
#define MCU_VARIANT MCU_2560
#elif defined(ESP32)
#define PLATFORM PLATFORM_ESP32
#define MCU_VARIANT MCU_ESP32
#elif defined(NRF52840_XXAA)
#define PLATFORM PLATFORM_NRF52
#define MCU_VARIANT MCU_NRF52
#endif
#ifndef MCU_VARIANT
#error No MCU variant defined, cannot compile
#endif
#if MCU_VARIANT == MCU_ESP32
#include "soc/rtc_wdt.h"
#define ISR_VECT IRAM_ATTR
#else
#define ISR_VECT
#endif
#define OP_RF_FREQ_6X 0x86
#define OP_SLEEP_6X 0x84
#define OP_STANDBY_6X 0x80
#define OP_TX_6X 0x83
#define OP_RX_6X 0x82
#define OP_PA_CONFIG_6X 0x95
#define OP_SET_IRQ_FLAGS_6X 0x08 // also provides info such as
// preamble detection, etc for
// knowing when it's safe to switch
// antenna modes
#define OP_CLEAR_IRQ_STATUS_6X 0x02
#define OP_GET_IRQ_STATUS_6X 0x12
#define OP_RX_BUFFER_STATUS_6X 0x13
#define OP_PACKET_STATUS_6X 0x14 // get snr & rssi of last packet
#define OP_CURRENT_RSSI_6X 0x15
#define OP_MODULATION_PARAMS_6X 0x8B // bw, sf, cr, etc.
#define OP_PACKET_PARAMS_6X 0x8C // crc, preamble, payload length, etc.
#define OP_STATUS_6X 0xC0
#define OP_TX_PARAMS_6X 0x8E // set dbm, etc
#define OP_PACKET_TYPE_6X 0x8A
#define OP_BUFFER_BASE_ADDR_6X 0x8F
#define OP_READ_REGISTER_6X 0x1D
#define OP_WRITE_REGISTER_6X 0x0D
#define OP_DIO3_TCXO_CTRL_6X 0x97
#define OP_DIO2_RF_CTRL_6X 0x9D
#define OP_CALIBRATE_6X 0x89
#define IRQ_TX_DONE_MASK_6X 0x01
#define IRQ_RX_DONE_MASK_6X 0x02
#define IRQ_HEADER_DET_MASK_6X 0x10
#define IRQ_PAYLOAD_CRC_ERROR_MASK_6X 0x40
#define MODE_LONG_RANGE_MODE_6X 0x01
#define OP_FIFO_WRITE_6X 0x0E
#define OP_FIFO_READ_6X 0x1E
#define REG_OCP_6X 0x08E7
#define REG_LNA_6X 0x08AC // no agc in sx1262
#define REG_SYNC_WORD_MSB_6X 0x0740
#define REG_SYNC_WORD_LSB_6X 0x0741
#define REG_PAYLOAD_LENGTH_6X 0x0702 // https://github.com/beegee-tokyo/SX126x-Arduino/blob/master/src/radio/sx126x/sx126x.h#L98
#define REG_RANDOM_GEN_6X 0x0819
#define MODE_TCXO_3_3V_6X 0x07
#define IRQ_PREAMBLE_DET_MASK_6X 0x04
#define XTAL_FREQ_6X (double)32000000
#define FREQ_DIV_6X (double)pow(2.0, 25.0)
#define FREQ_STEP_6X (double)(XTAL_FREQ_6X / FREQ_DIV_6X)
extern SPIClass spiModem;
#define SPI spiModem
extern SPIClass SPI;
#define MAX_PKT_LENGTH 255
sx126x::sx126x() :
_spiSettings(8E6, MSBFIRST, SPI_MODE0),
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _busy(LORA_DEFAULT_BUSY_PIN), _rxen(LORA_DEFAULT_RXEN_PIN),
_frequency(0),
_txp(0),
_sf(0x07),
_bw(0x04),
_cr(0x01),
_ldro(0x00),
_packetIndex(0),
_preambleLength(18),
_implicitHeaderMode(0),
_payloadLength(255),
_crcMode(1),
_fifo_tx_addr_ptr(0),
_fifo_rx_addr_ptr(0),
_packet({0}),
_preinit_done(false),
_onReceive(NULL)
{
// overide Stream timeout value
setTimeout(0);
}
bool sx126x::preInit() {
// setup pins
pinMode(_ss, OUTPUT);
// set SS high
digitalWrite(_ss, HIGH);
SPI.begin();
// check version (retry for up to 2 seconds)
long start = millis();
uint8_t syncmsb;
uint8_t synclsb;
while (((millis() - start) < 2000) && (millis() >= start)) {
syncmsb = readRegister(REG_SYNC_WORD_MSB_6X);
synclsb = readRegister(REG_SYNC_WORD_LSB_6X);
if ( uint16_t(syncmsb << 8 | synclsb) == 0x1424 || uint16_t(syncmsb << 8 | synclsb) == 0x4434) {
break;
}
delay(100);
}
if ( uint16_t(syncmsb << 8 | synclsb) != 0x1424 && uint16_t(syncmsb << 8 | synclsb) != 0x4434) {
return false;
}
_preinit_done = true;
return true;
}
uint8_t ISR_VECT sx126x::readRegister(uint16_t address)
{
return singleTransfer(OP_READ_REGISTER_6X, address, 0x00);
}
void sx126x::writeRegister(uint16_t address, uint8_t value)
{
singleTransfer(OP_WRITE_REGISTER_6X, address, value);
}
uint8_t ISR_VECT sx126x::singleTransfer(uint8_t opcode, uint16_t address, uint8_t value)
{
waitOnBusy();
uint8_t response;
digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings);
SPI.transfer(opcode);
SPI.transfer((address & 0xFF00) >> 8);
SPI.transfer(address & 0x00FF);
if (opcode == OP_READ_REGISTER_6X) {
SPI.transfer(0x00);
}
response = SPI.transfer(value);
SPI.endTransaction();
digitalWrite(_ss, HIGH);
return response;
}
void sx126x::rxAntEnable()
{
uint8_t byte = 0x01;
// enable dio2 rf switch
executeOpcode(OP_DIO2_RF_CTRL_6X, &byte, 1);
digitalWrite(_rxen, HIGH);
}
void sx126x::loraMode() {
// enable lora mode on the SX1262 chip
uint8_t mode = MODE_LONG_RANGE_MODE_6X;
executeOpcode(OP_PACKET_TYPE_6X, &mode, 1);
}
void sx126x::waitOnBusy() {
if (_busy != -1) {
while (digitalRead(_busy) == HIGH)
{
// do nothing
}
}
}
void sx126x::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size)
{
waitOnBusy();
digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings);
SPI.transfer(opcode);
for (int i = 0; i < size; i++)
{
SPI.transfer(buffer[i]);
}
SPI.endTransaction();
digitalWrite(_ss, HIGH);
}
void sx126x::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size)
{
waitOnBusy();
digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings);
SPI.transfer(opcode);
SPI.transfer(0x00);
for (int i = 0; i < size; i++)
{
buffer[i] = SPI.transfer(0x00);
}
SPI.endTransaction();
digitalWrite(_ss, HIGH);
}
void sx126x::writeBuffer(const uint8_t* buffer, size_t size)
{
waitOnBusy();
digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings);
SPI.transfer(OP_FIFO_WRITE_6X);
SPI.transfer(_fifo_tx_addr_ptr);
for (int i = 0; i < size; i++)
{
SPI.transfer(buffer[i]);
_fifo_tx_addr_ptr++;
}
SPI.endTransaction();
digitalWrite(_ss, HIGH);
}
void sx126x::readBuffer(uint8_t* buffer, size_t size)
{
waitOnBusy();
digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings);
SPI.transfer(OP_FIFO_READ_6X);
SPI.transfer(_fifo_rx_addr_ptr);
SPI.transfer(0x00);
for (int i = 0; i < size; i++)
{
buffer[i] = SPI.transfer(0x00);
}
SPI.endTransaction();
digitalWrite(_ss, HIGH);
}
void sx126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) {
// because there is no access to these registers on the sx1262, we have
// to set all these parameters at once or not at all.
uint8_t buf[8];
buf[0] = sf;
buf[1] = bw;
buf[2] = cr;
// low data rate toggle
buf[3] = ldro;
// unused params in LoRa mode
buf[4] = 0x00;
buf[5] = 0x00;
buf[6] = 0x00;
buf[7] = 0x00;
executeOpcode(OP_MODULATION_PARAMS_6X, buf, 8);
}
void sx126x::setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
// because there is no access to these registers on the sx1262, we have
// to set all these parameters at once or not at all.
uint8_t buf[9];
buf[0] = uint8_t((preamble & 0xFF00) >> 8);
buf[1] = uint8_t((preamble & 0x00FF));
buf[2] = headermode;
buf[3] = length;
buf[4] = crc;
// standard IQ setting (no inversion)
buf[5] = 0x00;
// unused params
buf[6] = 0x00;
buf[7] = 0x00;
buf[8] = 0x00;
executeOpcode(OP_PACKET_PARAMS_6X, buf, 9);
}
int sx126x::begin(long frequency)
{
if (_reset != -1) {
pinMode(_reset, OUTPUT);
// perform reset
digitalWrite(_reset, LOW);
delay(10);
digitalWrite(_reset, HIGH);
delay(10);
}
if (_busy != -1) {
pinMode(_busy, INPUT);
}
if (!_preinit_done) {
if (!preInit()) {
return false;
}
}
//#if HAS_TCXO
// turn TCXO on
enableTCXO();
//#endif
loraMode();
idle();
// cannot access registers in sleep mode on sx1262, set to idle instead
if (_rxen != -1) {
pinMode(_rxen, OUTPUT);
rxAntEnable();
}
// calibrate RC64k, RC13M, PLL, ADC and image
uint8_t calibrate = 0x7F;
executeOpcode(OP_CALIBRATE_6X, &calibrate, 1);
setFrequency(frequency);
// set output power to 2 dBm
setTxPower(2);
// set LNA boost
writeRegister(REG_LNA_6X, 0x96);
// set base addresses
uint8_t basebuf[2] = {0};
executeOpcode(OP_BUFFER_BASE_ADDR_6X, basebuf, 2);
setModulationParams(_sf, _bw, _cr, _ldro);
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
return 1;
}
void sx126x::end()
{
// put in sleep mode
sleep();
// stop SPI
SPI.end();
_preinit_done = false;
}
int sx126x::beginPacket(int implicitHeader)
{
// put in standby mode
idle();
if (implicitHeader) {
implicitHeaderMode();
} else {
explicitHeaderMode();
}
_payloadLength = 0;
_fifo_tx_addr_ptr = 0;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
return 1;
}
int sx126x::endPacket()
{
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
// put in single TX mode
uint8_t timeout[3] = {0};
executeOpcode(OP_TX_6X, timeout, 3);
uint8_t buf[2];
buf[0] = 0x00;
buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
// wait for TX done
while ((buf[1] & IRQ_TX_DONE_MASK_6X) == 0) {
buf[0] = 0x00;
buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
yield();
}
// clear IRQ's
uint8_t mask[2];
mask[0] = 0x00;
mask[1] = IRQ_TX_DONE_MASK_6X;
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, mask, 2);
return 1;
}
uint8_t sx126x::modemStatus() {
// imitate the register status from the sx1276 / 78
uint8_t buf[2] = {0};
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
uint8_t clearbuf[2] = {0};
uint8_t byte = 0x00;
if (buf[1] & IRQ_PREAMBLE_DET_MASK_6X != 0) {
byte = byte | 0x01 | 0x04;
// clear register after reading
clearbuf[1] = IRQ_PREAMBLE_DET_MASK_6X;
}
if (buf[1] & IRQ_HEADER_DET_MASK_6X != 0) {
byte = byte | 0x02 | 0x04;
// clear register after reading
clearbuf[1] = clearbuf[1] | IRQ_HEADER_DET_MASK_6X;
}
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, clearbuf, 2);
return byte;
}
uint8_t sx126x::currentRssiRaw() {
uint8_t byte = 0;
executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1);
return byte;
}
int ISR_VECT sx126x::currentRssi() {
uint8_t byte = 0;
executeOpcodeRead(OP_CURRENT_RSSI_6X, &byte, 1);
int rssi = -(int(byte)) / 2;
return rssi - RSSI_OFFSET;
}
uint8_t sx126x::packetRssiRaw() {
uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
return buf[2];
}
int ISR_VECT sx126x::packetRssi() {
// may need more calculations here
uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
int pkt_rssi = -buf[0] / 2;
return pkt_rssi - RSSI_OFFSET;
}
uint8_t ISR_VECT sx126x::packetSnrRaw() {
uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
return buf[1];
}
float ISR_VECT sx126x::packetSnr() {
uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS_6X, buf, 3);
return float(buf[1]) * 0.25;
}
long sx126x::packetFrequencyError()
{
// todo: implement this, no idea how to check it on the sx1262
const float fError = 0.0;
return static_cast<long>(fError);
}
size_t sx126x::write(uint8_t byte)
{
return write(&byte, sizeof(byte));
}
size_t sx126x::write(const uint8_t *buffer, size_t size)
{
if ((_payloadLength + size) > MAX_PKT_LENGTH) {
size = MAX_PKT_LENGTH - _payloadLength;
}
// write data
writeBuffer(buffer, size);
_payloadLength = _payloadLength + size;
return size;
}
int ISR_VECT sx126x::available()
{
uint8_t buf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, buf, 2);
return buf[0] - _packetIndex;
}
int ISR_VECT sx126x::read()
{
if (!available()) {
return -1;
}
// if received new packet
if (_packetIndex == 0) {
uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
int size = rxbuf[0];
_fifo_rx_addr_ptr = rxbuf[1];
readBuffer(_packet, size);
}
uint8_t byte = _packet[_packetIndex];
_packetIndex++;
return byte;
}
int sx126x::peek()
{
if (!available()) {
return -1;
}
// if received new packet
if (_packetIndex == 0) {
uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
int size = rxbuf[0];
_fifo_rx_addr_ptr = rxbuf[1];
readBuffer(_packet, size);
}
uint8_t b = _packet[_packetIndex];
return b;
}
void sx126x::flush()
{
}
void sx126x::onReceive(void(*callback)(int))
{
_onReceive = callback;
if (callback) {
pinMode(_dio0, INPUT);
// set preamble and header detection irqs, plus dio0 mask
uint8_t buf[8];
// set irq masks, enable all
buf[0] = 0xFF;
buf[1] = 0xFF;
// set dio0 masks
buf[2] = 0x00;
buf[3] = IRQ_RX_DONE_MASK_6X;
// set dio1 masks
buf[4] = 0x00;
buf[5] = 0x00;
// set dio2 masks
buf[6] = 0x00;
buf[7] = 0x00;
executeOpcode(OP_SET_IRQ_FLAGS_6X, buf, 8);
#ifdef SPI_HAS_NOTUSINGINTERRUPT
SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
#endif
attachInterrupt(digitalPinToInterrupt(_dio0), sx126x::onDio0Rise, RISING);
} else {
detachInterrupt(digitalPinToInterrupt(_dio0));
#ifdef SPI_HAS_NOTUSINGINTERRUPT
SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0));
#endif
}
}
void sx126x::receive(int size)
{
if (size > 0) {
implicitHeaderMode();
// tell radio payload length
_payloadLength = size;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
} else {
explicitHeaderMode();
}
if (_rxen != -1) {
rxAntEnable();
}
uint8_t mode[3] = {0xFF, 0xFF, 0xFF}; // continuous mode
executeOpcode(OP_RX_6X, mode, 3);
}
void sx126x::idle()
{
//#if HAS_TCXO
// STDBY_XOSC
uint8_t byte = 0x01;
//#else
// // STDBY_RC
// uint8_t byte = 0x00;
//#endif
executeOpcode(OP_STANDBY_6X, &byte, 1);
}
void sx126x::sleep()
{
uint8_t byte = 0x00;
executeOpcode(OP_SLEEP_6X, &byte, 1);
}
void sx126x::enableTCXO() {
// only tested for RAK4630, voltage may be different on other platforms
uint8_t buf[4] = {MODE_TCXO_3_3V_6X, 0x00, 0x00, 0xFF};
executeOpcode(OP_DIO3_TCXO_CTRL_6X, buf, 4);
}
void sx126x::disableTCXO() {
// currently cannot disable on SX1262?
}
void sx126x::setTxPower(int level, int outputPin) {
// currently no low power mode for SX1262 implemented, assuming PA boost
// WORKAROUND - Better Resistance of the SX1262 Tx to Antenna Mismatch, see DS_SX1261-2_V1.2 datasheet chapter 15.2
// RegTxClampConfig = @address 0x08D8
writeRegister(0x08D8, readRegister(0x08D8) | (0x0F << 1));
uint8_t pa_buf[4];
pa_buf[0] = 0x04;
pa_buf[1] = 0x07;
pa_buf[2] = 0x00;
pa_buf[3] = 0x01;
executeOpcode(OP_PA_CONFIG_6X, pa_buf, 4); // set pa_config for high power
if (level > 22) {
level = 22;
}
else if (level < -9) {
level = -9;
}
writeRegister(REG_OCP_6X, 0x38); // 160mA limit, overcurrent protection
uint8_t tx_buf[2];
tx_buf[0] = level;
tx_buf[1] = 0x02; // ramping time - 40 microseconds
executeOpcode(OP_TX_PARAMS_6X, tx_buf, 2);
_txp = level;
}
uint8_t sx126x::getTxPower() {
return _txp;
}
void sx126x::setFrequency(long frequency) {
_frequency = frequency;
uint8_t buf[4];
uint32_t freq = (uint32_t)((double)frequency / (double)FREQ_STEP_6X);
buf[0] = ((freq >> 24) & 0xFF);
buf[1] = ((freq >> 16) & 0xFF);
buf[2] = ((freq >> 8) & 0xFF);
buf[3] = (freq & 0xFF);
executeOpcode(OP_RF_FREQ_6X, buf, 4);
}
uint32_t sx126x::getFrequency() {
// we can't read the frequency on the sx1262 / 80
uint32_t frequency = _frequency;
return frequency;
}
void sx126x::setSpreadingFactor(int sf)
{
if (sf < 5) {
sf = 5;
} else if (sf > 12) {
sf = 12;
}
_sf = sf;
setModulationParams(sf, _bw, _cr, _ldro);
handleLowDataRate();
}
long sx126x::getSignalBandwidth()
{
int bw = _bw;
switch (bw) {
case 0x00: return 7.8E3;
case 0x01: return 15.6E3;
case 0x02: return 31.25E3;
case 0x03: return 62.5E3;
case 0x04: return 125E3;
case 0x05: return 250E3;
case 0x06: return 500E3;
case 0x08: return 10.4E3;
case 0x09: return 20.8E3;
case 0x0A: return 41.7E3;
}
return 0;
}
void sx126x::handleLowDataRate(){
_ldro = 1;
setModulationParams(_sf, _bw, _cr, _ldro);
}
void sx126x::optimizeModemSensitivity(){
// todo: check if there's anything the sx1262 can do here
}
void sx126x::setSignalBandwidth(long sbw)
{
if (sbw <= 7.8E3) {
_bw = 0x00;
} else if (sbw <= 10.4E3) {
_bw = 0x08;
} else if (sbw <= 15.6E3) {
_bw = 0x01;
} else if (sbw <= 20.8E3) {
_bw = 0x09;
} else if (sbw <= 31.25E3) {
_bw = 0x02;
} else if (sbw <= 41.7E3) {
_bw = 0x0A;
} else if (sbw <= 62.5E3) {
_bw = 0x03;
} else if (sbw <= 125E3) {
_bw = 0x04;
} else if (sbw <= 250E3) {
_bw = 0x05;
} else /*if (sbw <= 250E3)*/ {
_bw = 0x06;
}
setModulationParams(_sf, _bw, _cr, _ldro);
handleLowDataRate();
optimizeModemSensitivity();
}
void sx126x::setCodingRate4(int denominator)
{
if (denominator < 5) {
denominator = 5;
} else if (denominator > 8) {
denominator = 8;
}
int cr = denominator - 4;
_cr = cr;
setModulationParams(_sf, _bw, cr, _ldro);
}
void sx126x::setPreambleLength(long length)
{
setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode);
}
void sx126x::setSyncWord(int sw)
{
writeRegister(REG_SYNC_WORD_MSB_6X, sw & 0xFF00);
writeRegister(REG_SYNC_WORD_LSB_6X, sw & 0x00FF);
}
void sx126x::enableCrc()
{
_crcMode = 1;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
}
void sx126x::disableCrc()
{
_crcMode = 0;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
}
byte sx126x::random()
{
return readRegister(REG_RANDOM_GEN_6X);
}
void sx126x::setPins(int ss, int reset, int dio0, int busy, int rxen)
{
_ss = ss;
_reset = reset;
_dio0 = dio0;
_busy = busy;
_rxen = rxen;
}
void sx126x::setSPIFrequency(uint32_t frequency)
{
_spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0);
}
void sx126x::dumpRegisters(Stream& out)
{
for (int i = 0; i < 128; i++) {
out.print("0x");
out.print(i, HEX);
out.print(": 0x");
out.println(readRegister(i), HEX);
}
}
void sx126x::explicitHeaderMode()
{
_implicitHeaderMode = 0;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
}
void sx126x::implicitHeaderMode()
{
_implicitHeaderMode = 1;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
}
void ISR_VECT sx126x::handleDio0Rise()
{
uint8_t buf[2];
buf[0] = 0x00;
buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS_6X, buf, 2);
executeOpcode(OP_CLEAR_IRQ_STATUS_6X, buf, 2);
if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK_6X) == 0) {
// received a packet
_packetIndex = 0;
// read packet length
uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS_6X, rxbuf, 2);
int packetLength = rxbuf[0];
if (_onReceive) {
_onReceive(packetLength);
}
}
}
void ISR_VECT sx126x::onDio0Rise()
{
sx126x_modem.handleDio0Rise();
}
sx126x sx126x_modem;

View File

@ -4,8 +4,8 @@
// Modifications and additions copyright 2023 by Mark Qvist
// Obviously still under the MIT license.
#ifndef LORA_H
#define LORA_H
#ifndef SX126X_H
#define SX126X_H
#include <Arduino.h>
#include <SPI.h>
@ -15,6 +15,7 @@
#define LORA_DEFAULT_RESET_PIN 9
#define LORA_DEFAULT_DIO0_PIN 2
#define LORA_DEFAULT_RXEN_PIN -1
#define LORA_DEFAULT_TXEN_PIN -1
#define LORA_DEFAULT_BUSY_PIN -1
#define PA_OUTPUT_RFO_PIN 0
@ -22,9 +23,9 @@
#define RSSI_OFFSET 157
class LoRaClass : public Stream {
class sx126x : public Stream {
public:
LoRaClass();
sx126x();
int begin(long frequency);
void end();
@ -74,18 +75,16 @@ public:
void enableTCXO();
void disableTCXO();
#if MODEM == SX1262
void enableAntenna();
void disableAntenna();
void loraMode();
void waitOnBusy();
void executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size);
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
void writeBuffer(const uint8_t* buffer, size_t size);
void readBuffer(uint8_t* buffer, size_t size);
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro);
void setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc);
#endif
void rxAntEnable();
void loraMode();
void waitOnBusy();
void executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size);
void executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size);
void writeBuffer(const uint8_t* buffer, size_t size);
void readBuffer(uint8_t* buffer, size_t size);
void setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc);
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro);
// deprecated
void crc() { enableCrc(); }
@ -93,7 +92,7 @@ public:
byte random();
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN, int rxen = LORA_DEFAULT_RXEN_PIN, int busy = LORA_DEFAULT_BUSY_PIN);
void setPins(int ss = LORA_DEFAULT_SS_PIN, int reset = LORA_DEFAULT_RESET_PIN, int dio0 = LORA_DEFAULT_DIO0_PIN, int busy = LORA_DEFAULT_BUSY_PIN, int rxen = LORA_DEFAULT_RXEN_PIN);
void setSPIFrequency(uint32_t frequency);
void dumpRegisters(Stream& out);
@ -104,15 +103,9 @@ private:
void handleDio0Rise();
#if MODEM == SX1276 || MODEM == SX1278