Add sx127x component

This commit is contained in:
Jonathan Swoboda 2024-09-23 21:54:19 -04:00
parent 4ece4a389e
commit 89d6df58c5
3 changed files with 438 additions and 0 deletions

View file

@ -0,0 +1,125 @@
from esphome import pins
import esphome.codegen as cg
from esphome.components import spi
import esphome.config_validation as cv
from esphome.const import CONF_FREQUENCY, CONF_ID
CODEOWNERS = ["@swoboda1337"]
DEPENDENCIES = ["spi"]
CONF_PA_POWER = "pa_power"
CONF_PA_PIN = "pa_pin"
CONF_NSS_PIN = "nss_pin"
CONF_RST_PIN = "rst_pin"
CONF_MODULATION = "modulation"
CONF_RX_FLOOR = "rx_floor"
CONF_RX_START = "rx_start"
CONF_RX_BANDWIDTH = "rx_bandwidth"
CONF_FSK_FDEV = "fsk_fdev"
CONF_FSK_RAMP = "fsk_ramp"
CONF_FSK_SHAPING = "fsk_shaping"
sx127x_ns = cg.esphome_ns.namespace("sx127x")
SX127x = sx127x_ns.class_("SX127x", cg.Component, spi.SPIDevice)
SX127xOpMode = sx127x_ns.enum("SX127xOpMode")
SX127xRxBw = sx127x_ns.enum("SX127xRxBw")
SX127xPaConfig = sx127x_ns.enum("SX127xPaConfig")
SX127xPaRamp = sx127x_ns.enum("SX127xPaRamp")
PA_PIN = {
"RFO": SX127xPaConfig.PA_PIN_RFO,
"BOOST": SX127xPaConfig.PA_PIN_BOOST,
}
SHAPING = {
"BT_0_3": SX127xPaRamp.SHAPING_BT_0_3,
"BT_0_5": SX127xPaRamp.SHAPING_BT_0_5,
"BT_1_0": SX127xPaRamp.SHAPING_BT_1_0,
"NONE": SX127xPaRamp.SHAPING_NONE,
}
RAMP = {
"10us": SX127xPaRamp.PA_RAMP_10,
"12us": SX127xPaRamp.PA_RAMP_12,
"15us": SX127xPaRamp.PA_RAMP_15,
"20us": SX127xPaRamp.PA_RAMP_20,
"25us": SX127xPaRamp.PA_RAMP_25,
"31us": SX127xPaRamp.PA_RAMP_31,
"40us": SX127xPaRamp.PA_RAMP_40,
"50us": SX127xPaRamp.PA_RAMP_50,
"62us": SX127xPaRamp.PA_RAMP_62,
"100us": SX127xPaRamp.PA_RAMP_100,
"125us": SX127xPaRamp.PA_RAMP_125,
"250us": SX127xPaRamp.PA_RAMP_250,
"500us": SX127xPaRamp.PA_RAMP_500,
"1000us": SX127xPaRamp.PA_RAMP_1000,
"2000us": SX127xPaRamp.PA_RAMP_2000,
"3400us": SX127xPaRamp.PA_RAMP_3400,
}
MOD = {
"FSK": SX127xOpMode.MOD_FSK,
"OOK": SX127xOpMode.MOD_OOK,
}
RX_BW = {
"2_6kHz": SX127xRxBw.RX_BW_2_6,
"3_1kHz": SX127xRxBw.RX_BW_3_1,
"3_9kHz": SX127xRxBw.RX_BW_3_9,
"5_2kHz": SX127xRxBw.RX_BW_5_2,
"6_3kHz": SX127xRxBw.RX_BW_6_3,
"7_8kHz": SX127xRxBw.RX_BW_7_8,
"10_4kHz": SX127xRxBw.RX_BW_10_4,
"12_5kHz": SX127xRxBw.RX_BW_12_5,
"15_6kHz": SX127xRxBw.RX_BW_15_6,
"20_8kHz": SX127xRxBw.RX_BW_20_8,
"25_0kHz": SX127xRxBw.RX_BW_25_0,
"31_3kHz": SX127xRxBw.RX_BW_31_3,
"41_7kHz": SX127xRxBw.RX_BW_41_7,
"50_0kHz": SX127xRxBw.RX_BW_50_0,
"62_5kHz": SX127xRxBw.RX_BW_62_5,
"83_3kHz": SX127xRxBw.RX_BW_83_3,
"100_0kHz": SX127xRxBw.RX_BW_100_0,
"125_0kHz": SX127xRxBw.RX_BW_125_0,
"166_7kHz": SX127xRxBw.RX_BW_166_7,
"200_0kHz": SX127xRxBw.RX_BW_200_0,
"250_0kHz": SX127xRxBw.RX_BW_250_0,
}
CONFIG_SCHEMA = cv.Schema(
{
cv.GenerateID(): cv.declare_id(SX127x),
cv.Required(CONF_RST_PIN): pins.internal_gpio_output_pin_schema,
cv.Required(CONF_NSS_PIN): pins.internal_gpio_output_pin_schema,
cv.Required(CONF_FREQUENCY): cv.int_range(min=137000000, max=1020000000),
cv.Required(CONF_MODULATION): cv.enum(MOD),
cv.Optional(CONF_FSK_FDEV, default=5000): cv.int_range(min=0, max=100000),
cv.Optional(CONF_FSK_RAMP, default="40us"): cv.enum(RAMP),
cv.Optional(CONF_FSK_SHAPING, default="NONE"): cv.enum(SHAPING),
cv.Optional(CONF_RX_FLOOR, default=-94): cv.float_range(min=-128, max=-1),
cv.Optional(CONF_RX_START, default=True): cv.boolean,
cv.Optional(CONF_RX_BANDWIDTH, default="50_0kHz"): cv.enum(RX_BW),
cv.Optional(CONF_PA_PIN, default="BOOST"): cv.enum(PA_PIN),
cv.Optional(CONF_PA_POWER, default=17): cv.int_range(min=0, max=17),
}
).extend(spi.spi_device_schema(False, 8e6, "mode0"))
async def to_code(config):
var = cg.new_Pvariable(config[CONF_ID])
await cg.register_component(var, config)
await spi.register_spi_device(var, config)
rst_pin = await cg.gpio_pin_expression(config[CONF_RST_PIN])
cg.add(var.set_rst_pin(rst_pin))
nss_pin = await cg.gpio_pin_expression(config[CONF_NSS_PIN])
cg.add(var.set_nss_pin(nss_pin))
cg.add(var.set_frequency(config[CONF_FREQUENCY]))
cg.add(var.set_modulation(config[CONF_MODULATION]))
cg.add(var.set_rx_floor(config[CONF_RX_FLOOR]))
cg.add(var.set_rx_start(config[CONF_RX_START]))
cg.add(var.set_rx_bandwidth(config[CONF_RX_BANDWIDTH]))
cg.add(var.set_pa_pin(config[CONF_PA_PIN]))
cg.add(var.set_pa_power(config[CONF_PA_POWER]))
cg.add(var.set_fsk_fdev(config[CONF_FSK_FDEV]))
cg.add(var.set_fsk_ramp(config[CONF_FSK_RAMP]))
cg.add(var.set_fsk_shaping(config[CONF_FSK_SHAPING]))

View file

@ -0,0 +1,155 @@
#include "sx127x.h"
namespace esphome {
namespace sx127x {
static const char *const TAG = "sx127x";
uint8_t SX127x::read_register_(uint8_t reg) { return this->single_transfer_((uint8_t) reg & 0x7f, 0x00); }
void SX127x::write_register_(uint8_t reg, uint8_t value) { this->single_transfer_((uint8_t) reg | 0x80, value); }
uint8_t SX127x::single_transfer_(uint8_t reg, uint8_t value) {
uint8_t response;
this->delegate_->begin_transaction();
this->nss_pin_->digital_write(false);
this->delegate_->transfer(reg);
response = this->delegate_->transfer(value);
this->nss_pin_->digital_write(true);
this->delegate_->end_transaction();
return response;
}
void SX127x::setup() {
ESP_LOGCONFIG(TAG, "Setting up SX127x...");
// setup nss and set high
this->nss_pin_->setup();
this->nss_pin_->digital_write(true);
// setup reset
this->rst_pin_->setup();
// start spi
this->spi_setup();
// configure rf
this->configure();
}
void SX127x::configure() {
// toggle chip reset
this->rst_pin_->digital_write(false);
delay(1);
this->rst_pin_->digital_write(true);
delay(10);
// check silicon version to make sure hw is ok
if (this->read_register_(REG_VERSION) != 0x12) {
this->mark_failed();
return;
}
// set modulation and make sure transceiver is in sleep mode
this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_SLEEP);
delay(1);
// set freq
uint64_t frf = ((uint64_t) this->frequency_ << 19) / 32000000;
this->write_register_(REG_FRF_MSB, (uint8_t) ((frf >> 16) & 0xFF));
this->write_register_(REG_FRF_MID, (uint8_t) ((frf >> 8) & 0xFF));
this->write_register_(REG_FRF_LSB, (uint8_t) ((frf >> 0) & 0xFF));
// set fdev
uint32_t fdev = std::min(this->fsk_fdev_ / 61, 0x3FFFu);
this->write_register_(REG_FDEV_MSB, (uint8_t) ((fdev >> 8) & 0xFF));
this->write_register_(REG_FDEV_LSB, (uint8_t) ((fdev >> 0) & 0xFF));
// set the channel bw
this->write_register_(REG_RX_BW, this->rx_bandwidth_);
// config pa
if (this->pa_pin_ == PA_PIN_BOOST) {
this->pa_power_ = std::max(this->pa_power_, 2u);
this->pa_power_ = std::min(this->pa_power_, 17u);
this->write_register_(REG_PA_CONFIG, (this->pa_power_ - 2) | this->pa_pin_ | PA_MAX_POWER);
} else {
this->pa_power_ = std::min(this->pa_power_, 14u);
this->write_register_(REG_PA_CONFIG, (this->pa_power_ - 0) | this->pa_pin_ | PA_MAX_POWER);
}
if (this->modulation_ == MOD_FSK) {
this->write_register_(REG_PA_RAMP, this->fsk_ramp_ | this->fsk_shaping_);
} else {
this->write_register_(REG_PA_RAMP, this->fsk_ramp_);
}
// disable packet mode
this->write_register_(REG_PACKET_CONFIG_1, 0x00);
this->write_register_(REG_PACKET_CONFIG_2, 0x00);
// disable bit synchronizer, disable sync generation and setup threshold
this->write_register_(REG_SYNC_CONFIG, 0x00);
this->write_register_(REG_OOK_PEAK, OOK_THRESH_STEP_0_5 | OOK_THRESH_PEAK);
this->write_register_(REG_OOK_AVG, OOK_THRESH_DEC_1_8);
// set ook floor
this->write_register_(REG_OOK_FIX, 256 + int(this->rx_floor_ * 2.0));
// enable standby mode
this->set_mode_standby();
delay(1);
// enable rx mode
if (this->rx_start_) {
this->set_mode_rx();
delay(1);
}
}
void SX127x::set_mode_standby() { this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_STDBY); }
void SX127x::set_mode_rx() {
this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_RX_FS);
delay(1);
this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_RX);
}
void SX127x::set_mode_tx() {
this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_TX_FS);
delay(1);
this->write_register_(REG_OP_MODE, this->modulation_ | MODE_LF_ON | MODE_TX);
}
void SX127x::dump_config() {
static const uint16_t RAMP_LUT[16] = {3400, 2000, 1000, 500, 250, 125, 100, 62, 50, 40, 31, 25, 20, 15, 12, 10};
uint32_t rx_bw_mant = 16 + (this->rx_bandwidth_ >> 3) * 4;
uint32_t rx_bw_exp = this->rx_bandwidth_ & 0x7;
float rx_bw = (float) 32000000 / (rx_bw_mant * (1 << (rx_bw_exp + 2)));
ESP_LOGCONFIG(TAG, "SX127x:");
LOG_PIN(" NSS Pin: ", this->nss_pin_);
LOG_PIN(" RST Pin: ", this->rst_pin_);
ESP_LOGCONFIG(TAG, " PA Pin: %s", this->pa_pin_ == PA_PIN_BOOST ? "BOOST" : "RFO");
ESP_LOGCONFIG(TAG, " PA Power: %d dBm", this->pa_power_);
ESP_LOGCONFIG(TAG, " Frequency: %f MHz", (float) this->frequency_ / 1000000);
ESP_LOGCONFIG(TAG, " Modulation: %s", this->modulation_ == MOD_FSK ? "FSK" : "OOK");
ESP_LOGCONFIG(TAG, " Rx Bandwidth: %.1f kHz", (float) rx_bw / 1000);
ESP_LOGCONFIG(TAG, " Rx Start: %s", this->rx_start_ ? "true" : "false");
ESP_LOGCONFIG(TAG, " Rx Floor: %.1f dBm", this->rx_floor_);
ESP_LOGCONFIG(TAG, " FSK Fdev: %d Hz", this->fsk_fdev_);
ESP_LOGCONFIG(TAG, " FSK Ramp: %d us", RAMP_LUT[this->fsk_ramp_]);
if (this->fsk_shaping_ == SHAPING_BT_1_0) {
ESP_LOGCONFIG(TAG, " FSK Shaping: BT_1_0");
} else if (this->fsk_shaping_ == SHAPING_BT_0_5) {
ESP_LOGCONFIG(TAG, " FSK Shaping: BT_0_5");
} else if (this->fsk_shaping_ == SHAPING_BT_0_3) {
ESP_LOGCONFIG(TAG, " FSK Shaping: BT_0_3");
} else {
ESP_LOGCONFIG(TAG, " FSK Shaping: NONE");
}
if (this->is_failed()) {
ESP_LOGE(TAG, "Configuring SX127x failed");
}
}
} // namespace sx127x
} // namespace esphome

View file

@ -0,0 +1,158 @@
#pragma once
#include "esphome/components/spi/spi.h"
namespace esphome {
namespace sx127x {
enum SX127xReg : uint8_t {
REG_OP_MODE = 0x01,
REG_FDEV_MSB = 0x04,
REG_FDEV_LSB = 0x05,
REG_FRF_MSB = 0x06,
REG_FRF_MID = 0x07,
REG_FRF_LSB = 0x08,
REG_PA_CONFIG = 0x09,
REG_PA_RAMP = 0x0A,
REG_RX_BW = 0x12,
REG_OOK_PEAK = 0x14,
REG_OOK_FIX = 0x15,
REG_OOK_AVG = 0x16,
REG_SYNC_CONFIG = 0x27,
REG_PACKET_CONFIG_1 = 0x30,
REG_PACKET_CONFIG_2 = 0x31,
REG_VERSION = 0x42
};
enum SX127xOpMode : uint8_t {
MOD_FSK = 0x00,
MOD_OOK = 0x20,
MODE_LF_ON = 0x08,
MODE_RX = 0x05,
MODE_RX_FS = 0x04,
MODE_TX = 0x03,
MODE_TX_FS = 0x02,
MODE_STDBY = 0x01,
MODE_SLEEP = 0x00
};
enum SX127xOokPeak : uint8_t {
BIT_SYNC_ON = 0x20,
BIT_SYNC_OFF = 0x00,
OOK_THRESH_AVG = 0x10,
OOK_THRESH_PEAK = 0x08,
OOK_THRESH_FIXED = 0x00,
OOK_THRESH_STEP_6_0 = 0x07,
OOK_THRESH_STEP_5_0 = 0x06,
OOK_THRESH_STEP_4_0 = 0x05,
OOK_THRESH_STEP_3_0 = 0x04,
OOK_THRESH_STEP_2_0 = 0x03,
OOK_THRESH_STEP_1_5 = 0x02,
OOK_THRESH_STEP_1_0 = 0x01,
OOK_THRESH_STEP_0_5 = 0x00
};
enum SX127xOokAvg : uint8_t {
OOK_THRESH_DEC_16 = 0xE0,
OOK_THRESH_DEC_8 = 0xC0,
OOK_THRESH_DEC_4 = 0xA0,
OOK_THRESH_DEC_2 = 0x80,
OOK_THRESH_DEC_1_8 = 0x60,
OOK_THRESH_DEC_1_4 = 0x40,
OOK_THRESH_DEC_1_2 = 0x20,
OOK_THRESH_DEC_1 = 0x00
};
enum SX127xRxBw : uint8_t {
RX_BW_2_6 = 0x17,
RX_BW_3_1 = 0x0F,
RX_BW_3_9 = 0x07,
RX_BW_5_2 = 0x16,
RX_BW_6_3 = 0x0E,
RX_BW_7_8 = 0x06,
RX_BW_10_4 = 0x15,
RX_BW_12_5 = 0x0D,
RX_BW_15_6 = 0x05,
RX_BW_20_8 = 0x14,
RX_BW_25_0 = 0x0C,
RX_BW_31_3 = 0x04,
RX_BW_41_7 = 0x13,
RX_BW_50_0 = 0x0B,
RX_BW_62_5 = 0x03,
RX_BW_83_3 = 0x12,
RX_BW_100_0 = 0x0A,
RX_BW_125_0 = 0x02,
RX_BW_166_7 = 0x11,
RX_BW_200_0 = 0x09,
RX_BW_250_0 = 0x01
};
enum SX127xPaRamp : uint8_t {
SHAPING_BT_0_3 = 0x60,
SHAPING_BT_0_5 = 0x40,
SHAPING_BT_1_0 = 0x20,
SHAPING_NONE = 0x00,
PA_RAMP_10 = 0x0F,
PA_RAMP_12 = 0x0E,
PA_RAMP_15 = 0x0D,
PA_RAMP_20 = 0x0C,
PA_RAMP_25 = 0x0B,
PA_RAMP_31 = 0x0A,
PA_RAMP_40 = 0x09,
PA_RAMP_50 = 0x08,
PA_RAMP_62 = 0x07,
PA_RAMP_100 = 0x06,
PA_RAMP_125 = 0x05,
PA_RAMP_250 = 0x04,
PA_RAMP_500 = 0x03,
PA_RAMP_1000 = 0x02,
PA_RAMP_2000 = 0x01,
PA_RAMP_3400 = 0x00
};
enum SX127xPaConfig : uint8_t { PA_PIN_RFO = 0x00, PA_PIN_BOOST = 0x80, PA_MAX_POWER = 0x70 };
class SX127x : public Component,
public spi::SPIDevice<spi::BIT_ORDER_MSB_FIRST, spi::CLOCK_POLARITY_LOW, spi::CLOCK_PHASE_LEADING,
spi::DATA_RATE_8MHZ> {
public:
float get_setup_priority() const override { return setup_priority::HARDWARE; }
void setup() override;
void dump_config() override;
void set_rst_pin(InternalGPIOPin *rst_pin) { this->rst_pin_ = rst_pin; }
void set_nss_pin(InternalGPIOPin *nss_pin) { this->nss_pin_ = nss_pin; }
void set_frequency(uint32_t frequency) { this->frequency_ = frequency; }
void set_modulation(SX127xOpMode modulation) { this->modulation_ = modulation; }
void set_fsk_shaping(SX127xPaRamp shaping) { this->fsk_shaping_ = shaping; }
void set_fsk_ramp(SX127xPaRamp ramp) { this->fsk_ramp_ = ramp; }
void set_fsk_fdev(uint32_t fdev) { this->fsk_fdev_ = fdev; }
void set_rx_start(bool start) { this->rx_start_ = start; }
void set_rx_floor(float floor) { this->rx_floor_ = floor; }
void set_rx_bandwidth(SX127xRxBw bandwidth) { this->rx_bandwidth_ = bandwidth; }
void set_pa_pin(SX127xPaConfig pin) { this->pa_pin_ = pin; }
void set_pa_power(uint32_t power) { this->pa_power_ = power; }
void set_mode_standby();
void set_mode_tx();
void set_mode_rx();
void configure();
protected:
void write_register_(uint8_t reg, uint8_t value);
uint8_t single_transfer_(uint8_t reg, uint8_t value);
uint8_t read_register_(uint8_t reg);
InternalGPIOPin *rst_pin_{nullptr};
InternalGPIOPin *nss_pin_{nullptr};
SX127xPaConfig pa_pin_;
SX127xRxBw rx_bandwidth_;
SX127xOpMode modulation_;
SX127xPaRamp fsk_shaping_;
SX127xPaRamp fsk_ramp_;
uint32_t fsk_fdev_;
uint32_t frequency_;
uint32_t pa_power_;
float rx_floor_;
bool rx_start_;
};
} // namespace sx127x
} // namespace esphome