Skip to content

Commit

Permalink
Merge pull request #949 from TristanWebber/sx126x
Browse files Browse the repository at this point in the history
Add driver for SX126x modems
  • Loading branch information
terrillmoore authored Oct 1, 2024
2 parents 4ceb2b0 + fa08713 commit e9e7bae
Show file tree
Hide file tree
Showing 11 changed files with 1,725 additions and 6 deletions.
5 changes: 4 additions & 1 deletion project_config/lmic_project_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@
//#define CFG_kr920 1
//#define CFG_in866 1
#define CFG_sx1276_radio 1
//#define LMIC_USE_INTERRUPTS
//#define CFG_sx1261_radio 1
//#define CFG_sx1262_radio 1
//#define ARDUINO_heltec_wifi_lora_32_V3
//#define LMIC_USE_INTERRUPTS
2 changes: 2 additions & 0 deletions src/arduino_lmic_hal_boards.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ const HalPinmap_t *GetPinmap_Catena4802();
const HalPinmap_t* GetPinmap_ttgo_lora32_v1();
const HalPinmap_t *GetPinmap_ttgo_lora32_v21();
const HalPinmap_t* GetPinmap_heltec_lora32();
const HalPinmap_t* GetPinmap_heltec_lora32_v3();
const HalPinmap_t* GetPinmap_Disco_L072cz_Lrwan1();
const HalPinmap_t* GetPinmap_ttgo_tbeam_s3();

const HalPinmap_t *GetPinmap_ThisBoard();

Expand Down
4 changes: 4 additions & 0 deletions src/arduino_lmic_hal_configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,11 @@ class HalConfiguration_t

virtual void begin(void) {}
virtual void end(void) {}
virtual uint8_t queryBusyPin(void) { return HalPinmap_t::LMIC_UNUSED_PIN; }
virtual bool queryUsingTcxo(void) { return false; }
virtual bool queryUsingDcdc(void) { return false; }
virtual bool queryUsingDIO2AsRfSwitch(void) { return false; }
virtual bool queryUsingDIO3AsTCXOSwitch(void) { return false; }

// compute desired transmit power policy. HopeRF needs
// (and previous versions of this library always chose)
Expand Down
76 changes: 76 additions & 0 deletions src/hal/getpinmap_heltec_lora32_v3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/*
Module: getpinmap_heltec_lora32_v3.cpp
Function:
Arduino-LMIC C++ HAL pinmap for Heltec Wireless Stick Lite V3 and Wifi Lora32 V3
Copyright & License:
See accompanying LICENSE file.
Author:
Tristan Webber, Shrunk Innovation Labs July 2023
*/

#if defined(ARDUINO_heltec_wifi_lora_32_V3)

#include <arduino_lmic_hal_boards.h>
#include <Arduino.h>

#include "../lmic/oslmic.h"

namespace Arduino_LMIC
{

class HalConfiguration_heltec_lora32_v3 : public HalConfiguration_t
{
public:
enum DIGITAL_PINS : uint8_t
{
PIN_SX1262_NSS = SS,
PIN_SX1262_NRESET = RST_LoRa,
PIN_SX1262_BUSY = BUSY_LoRa,
PIN_SX1262_DIO1 = DIO0,
PIN_SX1262_DIO2 = HalPinmap_t::UNUSED_PIN,
PIN_SX1262_DIO3 = HalPinmap_t::UNUSED_PIN,
PIN_SX1262_ANT_SWITCH_RX = HalPinmap_t::UNUSED_PIN,
PIN_SX1262_ANT_SWITCH_TX_BOOST = HalPinmap_t::UNUSED_PIN,
PIN_SX1262_ANT_SWITCH_TX_RFO = HalPinmap_t::UNUSED_PIN,
PIN_VDD_BOOST_ENABLE = HalPinmap_t::UNUSED_PIN,
};

virtual u1_t queryBusyPin(void) override { return HalConfiguration_heltec_lora32_v3::PIN_SX1262_BUSY; };

virtual bool queryUsingDcdc(void) override { return true; };

virtual bool queryUsingDIO2AsRfSwitch(void) override { return true; };

virtual bool queryUsingDIO3AsTCXOSwitch(void) override { return true; };
};

static HalConfiguration_heltec_lora32_v3 myConfig;

static const HalPinmap_t myPinmap =
{
.nss = HalConfiguration_heltec_lora32_v3::PIN_SX1262_NSS,
.rxtx = HalConfiguration_heltec_lora32_v3::PIN_SX1262_ANT_SWITCH_RX,
.rst = HalConfiguration_heltec_lora32_v3::PIN_SX1262_NRESET,
.dio = {
HalConfiguration_heltec_lora32_v3::PIN_SX1262_DIO1,
HalConfiguration_heltec_lora32_v3::PIN_SX1262_DIO2,
HalConfiguration_heltec_lora32_v3::PIN_SX1262_DIO3,
},
.rxtx_rx_active = 0,
.rssi_cal = 10,
.spi_freq = 8000000, /* 8MHz */
.pConfig = &myConfig};

const HalPinmap_t *GetPinmap_heltec_lora32_v3(void)
{
return &myPinmap;
}

}; // namespace Arduino_LMIC

#endif // defined(ARDUINO_heltec_wifi_lora_32_V3)
4 changes: 4 additions & 0 deletions src/hal/getpinmap_thisboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ const HalPinmap_t *GetPinmap_ThisBoard(void)
return GetPinmap_ttgo_lora32_v21();
#elif defined(ARDUINO_HELTEC_WIFI_LORA_32) || defined(ARDUINO_HELTEC_WIFI_LORA_32_V2) || defined(ARDUINO_HELTEC_WIRELESS_STICK)
return GetPinmap_heltec_lora32();
#elif defined(ARDUINO_heltec_wifi_lora_32_V3)
return GetPinmap_heltec_lora32_v3();
#elif defined(ARDUINO_TTGO_T_BEAM_S3)
return GetPinmap_ttgo_tbeam_s3();
#else
#pragma message("Board not supported -- use an explicit pinmap")
return nullptr;
Expand Down
70 changes: 70 additions & 0 deletions src/hal/getpinmap_ttgo_tbeam_s3.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
Module: getpinmap_ttgo_tbeam_s3.cpp.cpp
Function:
Arduino-LMIC C++ HAL pinmap for T-Beam S3 Core and T-Beam Supreme
Copyright & License:
See accompanying LICENSE file.
*/

#if defined(ARDUINO_TTGO_T_BEAM_S3)

#include <arduino_lmic_hal_boards.h>
#include <Arduino.h>

#include "../lmic/oslmic.h"

namespace Arduino_LMIC {

class HalConfiguration_ttgo_tbeam_s3 : public HalConfiguration_t {
public:
enum DIGITAL_PINS : uint8_t {
PIN_SX1262_NSS = 10,
PIN_SX1262_NRESET = 5,
PIN_SX1262_BUSY = 4,
PIN_SX1262_DIO1 = 1,
PIN_SX1262_DIO2 = HalPinmap_t::UNUSED_PIN,
PIN_SX1262_DIO3 = HalPinmap_t::UNUSED_PIN,
PIN_SX1262_ANT_SWITCH_RX = HalPinmap_t::UNUSED_PIN,
PIN_SX1262_ANT_SWITCH_TX_BOOST = HalPinmap_t::UNUSED_PIN,
PIN_SX1262_ANT_SWITCH_TX_RFO = HalPinmap_t::UNUSED_PIN,
PIN_VDD_BOOST_ENABLE = HalPinmap_t::UNUSED_PIN,
};

virtual u1_t queryBusyPin(void) override { return HalConfiguration_ttgo_tbeam_s3::PIN_SX1262_BUSY; };

virtual bool queryUsingDcdc(void) override { return true; };

virtual bool queryUsingDIO2AsRfSwitch(void) override { return true; };

virtual bool queryUsingDIO3AsTCXOSwitch(void) override { return true; };
};

static HalConfiguration_ttgo_tbeam_s3 myConfig;

static const HalPinmap_t myPinmap =
{
.nss = HalConfiguration_ttgo_tbeam_s3::PIN_SX1262_NSS,
.rxtx = HalConfiguration_ttgo_tbeam_s3::PIN_SX1262_ANT_SWITCH_RX,
.rst = HalConfiguration_ttgo_tbeam_s3::PIN_SX1262_NRESET,
.dio = {
HalConfiguration_ttgo_tbeam_s3::PIN_SX1262_DIO1,
HalConfiguration_ttgo_tbeam_s3::PIN_SX1262_DIO2,
HalConfiguration_ttgo_tbeam_s3::PIN_SX1262_DIO3,
},
.rxtx_rx_active = 0,
.rssi_cal = 8,
.spi_freq = 8000000, /* 8MHz */
.pConfig = &myConfig
};

const HalPinmap_t* GetPinmap_ttgo_tbeam_s3(void) {
return &myPinmap;
}

}; // namespace Arduino_LMIC

#endif // defined(ARDUINO_TTGO_T_BEAM_S3)
66 changes: 66 additions & 0 deletions src/hal/hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,10 @@ static void hal_io_init () {
// NSS and DIO0 are required, DIO1 is required for LoRa, DIO2 for FSK
ASSERT(plmic_pins->nss != LMIC_UNUSED_PIN);
ASSERT(plmic_pins->dio[0] != LMIC_UNUSED_PIN);
// SX126x family can operate with a single DIO
#if (defined(CFG_sx1276_radio) || defined(CFG_sx1272_radio))
ASSERT(plmic_pins->dio[1] != LMIC_UNUSED_PIN || plmic_pins->dio[2] != LMIC_UNUSED_PIN);
#endif

// Serial.print("nss: "); Serial.println(plmic_pins->nss);
// Serial.print("rst: "); Serial.println(plmic_pins->rst);
Expand All @@ -55,6 +58,10 @@ static void hal_io_init () {
pinMode(plmic_pins->rst, INPUT);
}

if (pHalConfig->queryBusyPin() != LMIC_UNUSED_PIN) {
pinMode(pHalConfig->queryBusyPin(), INPUT);
}

hal_interrupt_init();
}

Expand Down Expand Up @@ -184,6 +191,13 @@ static void hal_spi_init () {
SPI.begin();
}

#if (defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio))
bit_t is_busy() {
// SX126x uses BUSY pin
return digitalRead(pHalConfig->queryBusyPin()) ? true : false;
}
#endif

static void hal_spi_trx(u1_t cmd, u1_t* buf, size_t len, bit_t is_read) {
uint32_t spi_freq;
u1_t nss = plmic_pins->nss;
Expand All @@ -195,6 +209,11 @@ static void hal_spi_trx(u1_t cmd, u1_t* buf, size_t len, bit_t is_read) {
SPI.beginTransaction(settings);
digitalWrite(nss, 0);

// SX126x modems use BUSY pin. Only interact with SPI when BUSY goes LOW
#if (defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio))
while (is_busy());
#endif

SPI.transfer(cmd);

for (; len > 0; --len, ++buf) {
Expand All @@ -216,6 +235,41 @@ void hal_spi_read(u1_t cmd, u1_t* buf, size_t len) {
hal_spi_trx(cmd, buf, len, 1);
}

// SX126x modems behave slightly differently to SX127x. They will often need to transfer multiple bytes before reading
#if (defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio))
void hal_spi_read_sx126x(u1_t cmd, u1_t* addr, size_t addr_len, u1_t* buf, size_t buf_len) {
uint32_t spi_freq;
u1_t nss = plmic_pins->nss;

if ((spi_freq = plmic_pins->spi_freq) == 0)
spi_freq = LMIC_SPI_FREQ;

SPISettings settings(spi_freq, MSBFIRST, SPI_MODE0);
SPI.beginTransaction(settings);
digitalWrite(nss, 0);

while (is_busy());

SPI.transfer(cmd);

// Transfer address and NOP bits
for (; addr_len > 0; --addr_len, ++addr) {
u1_t addr_byte = *addr;
SPI.transfer(addr_byte);
}

// Read buf_len bytes to buf
for (; buf_len > 0; --buf_len, ++buf) {
u1_t data = 0x00;
data = SPI.transfer(data);
*buf = data;
}

digitalWrite(nss, 1);
SPI.endTransaction();
}
#endif

// -----------------------------------------------------------------------------
// TIME

Expand Down Expand Up @@ -499,6 +553,18 @@ bit_t hal_queryUsingTcxo(void) {
return pHalConfig->queryUsingTcxo();
}

bit_t hal_queryUsingDcdc(void) {
return pHalConfig->queryUsingDcdc();
}

bit_t hal_queryUsingDIO2AsRfSwitch(void) {
return pHalConfig->queryUsingDIO2AsRfSwitch();
}

bit_t hal_queryUsingDIO3AsTCXOSwitch(void) {
return pHalConfig->queryUsingDIO3AsTCXOSwitch();
}

uint8_t hal_getTxPowerPolicy(
u1_t inputPolicy,
s1_t requestedPower,
Expand Down
10 changes: 7 additions & 3 deletions src/lmic/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,15 @@
//#define CFG_sx1276_radio 1

// ensure that a radio is defined.
#if ! (defined(CFG_sx1272_radio) || defined(CFG_sx1276_radio))
#if !(defined(CFG_sx1272_radio) || defined(CFG_sx1276_radio) || defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio))
# warning Target radio not defined, assuming CFG_sx1276_radio
#define CFG_sx1276_radio 1
#elif defined(CFG_sx1272_radio) && defined(CFG_sx1276_radio)
# error You can define at most one of CFG_sx1272_radio and CF_sx1276_radio
#elif defined(CFG_sx1272_radio) && (defined(CFG_sx1276_radio) || defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio))
# error You can define at most one target radio
#elif defined(CFG_sx1276_radio) && (defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio))
# error You can define at most one target radio
#elif defined(CFG_sx1261_radio) && (defined(CFG_sx1261_radio))
# error You can define at most one target radio
#endif

// LMIC requires ticks to be 15.5μs - 100 μs long
Expand Down
23 changes: 22 additions & 1 deletion src/lmic/hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,17 @@ void hal_spi_write(u1_t cmd, const u1_t* buf, size_t len);
*/
void hal_spi_read(u1_t cmd, u1_t* buf, size_t len);

/*
* Perform SPI read transaction with SX126x series radio chip
* - write the command byte 'cmd'
* - write the 'addr_len' register address bytes 'addr'
* - write the 'NOP' byte 0x00
* - read 'buf_len' bytes into 'buf'
*/
#if (defined(CFG_sx1261_radio) || defined(CFG_sx1262_radio))
void hal_spi_read_sx126x(u1_t cmd, u1_t* addr, size_t addr_len, u1_t* buf, size_t buf_len);
#endif

/*
* disable all CPU interrupts.
* - might be invoked nested
Expand Down Expand Up @@ -148,9 +159,18 @@ s1_t hal_getRssiCal (void);
*/
ostime_t hal_setModuleActive (bit_t val);

/* find out if we're using Tcxo */
/* find out if we're using Tcxo controlled by a host pin */
bit_t hal_queryUsingTcxo(void);

/* SX126x function: find out if the board is configured for DC-DC regulator control */
bit_t hal_queryUsingDcdc(void);

/* SX126x function: find out if the board is configured to control the RF switch with modem DIO2 */
bit_t hal_queryUsingDIO2AsRfSwitch(void);

/* SX126x function: find out if the board is configured to control a TCXO with modem DIO3 */
bit_t hal_queryUsingDIO3AsTCXOSwitch(void);

/* represent the various radio TX power policy */
enum {
LMICHAL_radio_tx_power_policy_rfo = 0,
Expand All @@ -171,6 +191,7 @@ uint8_t hal_getTxPowerPolicy(

void hal_pollPendingIRQs_helper();
void hal_processPendingIRQs(void);
bit_t is_busy();

/// \brief check for any pending interrupts: stub if interrupts are enabled.
static inline void hal_pollPendingIRQs(void)
Expand Down
Loading

0 comments on commit e9e7bae

Please sign in to comment.