diff --git a/App/idf_component.yml b/App/idf_component.yml index 87afb64e..18cfbfba 100644 --- a/App/idf_component.yml +++ b/App/idf_component.yml @@ -21,7 +21,7 @@ dependencies: rules: - if: "target == esp32s3" jgromes/radiolib: - version: "7.2.1" + version: "7.3.0" rules: - if: "target in [esp32s3, esp32p4]" diff --git a/Boards/LilygoTLoraPager/Source/LilygoTloraPager.cpp b/Boards/LilygoTLoraPager/Source/LilygoTloraPager.cpp index 8dfc7e79..1a99af42 100644 --- a/Boards/LilygoTLoraPager/Source/LilygoTloraPager.cpp +++ b/Boards/LilygoTLoraPager/Source/LilygoTloraPager.cpp @@ -25,7 +25,7 @@ static DeviceVector createDevices() { auto sx1262 = std::make_shared(Sx1262::Configuration{ .spiHostDevice = SPI2_HOST, - .spiFrequency = 10'000'000, + .spiFrequency = 4'000'000, .csPin = GPIO_NUM_36, .resetPin = GPIO_NUM_47, .busyPin = GPIO_NUM_48, diff --git a/Drivers/RadioLibCompat/Source/LevelInterruptHandler.cpp b/Drivers/RadioLibCompat/Source/LevelInterruptHandler.cpp new file mode 100644 index 00000000..d4b92498 --- /dev/null +++ b/Drivers/RadioLibCompat/Source/LevelInterruptHandler.cpp @@ -0,0 +1,70 @@ +#include "LevelInterruptHandler.h" + +#include + +void IRAM_ATTR LevelInterruptHandler::handlePositiveEdge(void* isr_arg) { + LevelInterruptHandler* self = static_cast(isr_arg); + switch (self->state) { + case State::Low: + gpio_set_intr_type(self->pin, GPIO_INTR_HIGH_LEVEL); + self->state = State::High; + break; + case State::High: + gpio_set_intr_type(self->pin, GPIO_INTR_LOW_LEVEL); + self->isr(self->context); + self->state = State::Low; + break; + } +} + +void IRAM_ATTR LevelInterruptHandler::handleNegativeEdge(void* isr_arg) { + LevelInterruptHandler* self = static_cast(isr_arg); + switch (self->state) { + case State::High: + gpio_set_intr_type(self->pin, GPIO_INTR_LOW_LEVEL); + self->state = State::Low; + break; + case State::Low: + gpio_set_intr_type(self->pin, GPIO_INTR_HIGH_LEVEL); + self->isr(self->context); + self->state = State::High; + break; + } +} + +void IRAM_ATTR LevelInterruptHandler::handleOneshot(void* isr_arg) { + LevelInterruptHandler* self = static_cast(isr_arg); + gpio_intr_disable(self->pin); + self->isr(self->context); +} + +void LevelInterruptHandler::install() { + switch (type) { + case Type::HighOneshot: + gpio_set_intr_type(pin, GPIO_INTR_HIGH_LEVEL); + gpio_isr_handler_add(pin, handleOneshot, this); + break; + case Type::LowOneshot: + gpio_set_intr_type(pin, GPIO_INTR_LOW_LEVEL); + gpio_isr_handler_add(pin, handleOneshot, this); + break; + case Type::PositiveEdge: + gpio_set_intr_type(pin, GPIO_INTR_LOW_LEVEL); + gpio_isr_handler_add(pin, handlePositiveEdge, this); + state = State::Low; + break; + case Type::NegativeEdge: + gpio_set_intr_type(pin, GPIO_INTR_HIGH_LEVEL); + gpio_isr_handler_add(pin, handleNegativeEdge, this); + state = State::High; + break; + } +} + +void LevelInterruptHandler::arm() { + gpio_intr_enable(pin); +} + +void LevelInterruptHandler::disarm() { + gpio_intr_disable(pin); +} diff --git a/Drivers/RadioLibCompat/Source/LevelInterruptHandler.h b/Drivers/RadioLibCompat/Source/LevelInterruptHandler.h new file mode 100644 index 00000000..e31f6fbc --- /dev/null +++ b/Drivers/RadioLibCompat/Source/LevelInterruptHandler.h @@ -0,0 +1,56 @@ +#pragma once + +#include + +/** + * An interrupt handler class which can trigger any given IRAM service routine + * for falling/rising edge level changes and oneshot level detection. + * This class is needed if the erratum 3.11 from ESP32 Series SoC Errata Version v2.9 applies. + * In short, once an edge sensitive interrupt is installed, subsequent interrupts may not work. + * This class uses high/low level interrupts to handle both edge detection and oneshot detection of levels + * which circumvents this problem. + */ +class LevelInterruptHandler { +public: + enum class Type { + HighOneshot, + LowOneshot, + PositiveEdge, + NegativeEdge + }; + + using ServiceRoutine = void(*)(void* ctx); + +private: + enum class State { + Low, + High + }; + + const gpio_num_t pin; + const Type type; + const ServiceRoutine isr; + void* context; + State state; + + static void handlePositiveEdge(void* isr_arg); + static void handleNegativeEdge(void* isr_arg); + static void handleOneshot(void* isr_arg); + +public: + LevelInterruptHandler(const gpio_num_t pin, const Type type, ServiceRoutine isr, void* context) + : pin(pin) + , type(type) + , isr(isr) + , context(context) + {} + + virtual ~LevelInterruptHandler() { + disarm(); + } + + + void install(); + void arm(); + void disarm(); +}; diff --git a/Drivers/RadioLibCompat/Source/RadiolibTactilityHal.cpp b/Drivers/RadioLibCompat/Source/RadiolibTactilityHal.cpp index 36217889..811fb00d 100644 --- a/Drivers/RadioLibCompat/Source/RadiolibTactilityHal.cpp +++ b/Drivers/RadioLibCompat/Source/RadiolibTactilityHal.cpp @@ -1,17 +1,17 @@ #include "RadiolibTactilityHal.h" +#include + #include "hal/gpio_hal.h" #include "esp_timer.h" constexpr const char* TAG = "RadiolibTactilityHal"; void RadiolibTactilityHal::init() { - // we only need to init the SPI here spiBegin(); } void RadiolibTactilityHal::term() { - // we only need to stop the SPI here spiEnd(); } @@ -24,7 +24,7 @@ void RadiolibTactilityHal::pinMode(uint32_t pin, uint32_t mode) { gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); gpio_config_t conf = { - .pin_bit_mask = (1ULL< e) { // overflow - while((uint64_t)esp_timer_get_time() > e); - } - while((uint64_t)esp_timer_get_time() < e); - } + tt::kernel::delayMicros(us); } unsigned long RadiolibTactilityHal::millis() { - return((unsigned long)(esp_timer_get_time() / 1000ULL)); + return (unsigned long)(esp_timer_get_time() / 1000ULL); } unsigned long RadiolibTactilityHal::micros() { - return((unsigned long)(esp_timer_get_time())); + return (unsigned long)(esp_timer_get_time()); } long RadiolibTactilityHal::pulseIn(uint32_t pin, uint32_t state, unsigned long timeout) { @@ -111,52 +84,46 @@ long RadiolibTactilityHal::pulseIn(uint32_t pin, uint32_t state, unsigned long t while(this->digitalRead(pin) == state) { if((this->micros() - curtick) > timeout) { - return(0); + return 0; } } - return(this->micros() - start); + return (this->micros() - start); } void RadiolibTactilityHal::spiBegin() { if (!spiInitialized) { - TT_LOG_I(TAG, "SPI Begin!"); spi_device_interface_config_t devcfg = {}; devcfg.clock_speed_hz = spiFrequency; devcfg.mode = 0; - devcfg.spics_io_num = csPin; + // CS is set to unused, as RadioLib sets it manually + devcfg.spics_io_num = -1; devcfg.queue_size = 1; esp_err_t ret = spi_bus_add_device(spiHostDevice, &devcfg, &spiDeviceHandle); if (ret != ESP_OK) { - TT_LOG_E(TAG, "Failed to add SPI device: %s", esp_err_to_name(ret)); + TT_LOG_E(TAG, "Failed to add SPI device, error %s", esp_err_to_name(ret)); } spiInitialized = true; } } void RadiolibTactilityHal::spiBeginTransaction() { - // This function is used to set up the transaction (speed, bit order, mode, ...). - // With the ESP-IDF HAL this is automatically done, so no code needed. + getLock()->lock(); + spi_device_acquire_bus(spiDeviceHandle, portMAX_DELAY); } void RadiolibTactilityHal::spiTransfer(uint8_t* out, size_t len, uint8_t* in) { spi_transaction_t t; - - auto lock = getLock()->asScopedLock(); - bool locked = lock.lock(portMAX_DELAY); - if (!locked) { - TT_LOG_E(TAG, "Failed to aquire SPI lock"); - } - - memset(&t, 0, sizeof(t)); // Zero out the transaction - t.length = len * 8; // Length is in bits - t.tx_buffer = out; // The data to send - t.rx_buffer = in; // The data to receive + memset(&t, 0, sizeof(t)); + t.length = len * 8; + t.tx_buffer = out; + t.rx_buffer = in; spi_device_polling_transmit(spiDeviceHandle, &t); } void RadiolibTactilityHal::spiEndTransaction() { - // nothing needs to be done here + spi_device_release_bus(spiDeviceHandle); + getLock()->unlock(); } void RadiolibTactilityHal::spiEnd() { diff --git a/Drivers/RadioLibCompat/Source/RadiolibTactilityHal.h b/Drivers/RadioLibCompat/Source/RadiolibTactilityHal.h index d718a8e0..64bcbb78 100644 --- a/Drivers/RadioLibCompat/Source/RadiolibTactilityHal.h +++ b/Drivers/RadioLibCompat/Source/RadiolibTactilityHal.h @@ -17,14 +17,12 @@ class RadiolibTactilityHal : public RadioLibHal { private: spi_host_device_t spiHostDevice; int spiFrequency; - gpio_num_t csPin; spi_device_handle_t spiDeviceHandle; std::shared_ptr lock; bool spiInitialized; - bool isrServiceInitialized; public: - explicit RadiolibTactilityHal(spi_host_device_t spiHostDevice, int spiFrequency, gpio_num_t csPin) + explicit RadiolibTactilityHal(spi_host_device_t spiHostDevice, int spiFrequency) : RadioLibHal( GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, @@ -34,10 +32,8 @@ public: GPIO_INTR_NEGEDGE) , spiHostDevice(spiHostDevice) , spiFrequency(spiFrequency) - , csPin(csPin) , lock(tt::hal::spi::getLock(spiHostDevice)) - , spiInitialized(false) - , isrServiceInitialized(false) {} + , spiInitialized(false) {} void init() override; void term() override; diff --git a/Drivers/SX126x/Source/Sx1262.cpp b/Drivers/SX126x/Source/Sx1262.cpp index da225e2d..552bba7d 100644 --- a/Drivers/SX126x/Source/Sx1262.cpp +++ b/Drivers/SX126x/Source/Sx1262.cpp @@ -32,8 +32,9 @@ static constexpr Sx1262::ParameterStatus checkValuesAndApply(T &target, const fl return Sx1262::ParameterStatus::ValueError; } -void IRAM_ATTR dio1handler(void* context) { - ((Sx1262*)context)->dio1Event(); +void IRAM_ATTR Sx1262::dio1Isr(void* ctx) { + GPIO.out_w1ts = 1 << 9; + static_cast(ctx)->dio1Event(); } Sx1262::ParameterStatus Sx1262::setBaseParameter(const Parameter parameter, const float value) { @@ -291,35 +292,38 @@ tt::hal::radio::Unit Sx1262::getParameterUnit(const Parameter parameter) const { } void Sx1262::registerDio1Isr() { - gpio_hal_context_t gpiohal; - gpiohal.dev = GPIO_LL_GET_HW(GPIO_PORT_0); - gpio_config_t conf = { - .pin_bit_mask = (1ULL<pin[configuration.irqPin].int_type, + .pull_down_en = GPIO_PULLDOWN_DISABLE, + .intr_type = GPIO_INTR_DISABLE, + }; + gpio_config(&conf); + // TODO: Debug Code - Remove + conf = { + .pin_bit_mask = (1ULL< data(rxSize); - uint16_t rc = radio.readData(data.data(), rxSize); + rc = radio.readData(data.data(), rxSize); if (rc != RADIOLIB_ERR_NONE) { TT_LOG_E(TAG, "Error receiving data, RadioLib returned %hi", rc); } else if(rxSize == 0) { @@ -488,6 +491,6 @@ void Sx1262::doReceive() { } // A delay before a new command improves reliability - vTaskDelay(pdMS_TO_TICKS(SX1262_COOLDOWN_MILLIS)); + //vTaskDelay(pdMS_TO_TICKS(SX1262_COOLDOWN_MILLIS)); } diff --git a/Drivers/SX126x/Source/Sx1262.h b/Drivers/SX126x/Source/Sx1262.h index 94058e01..9c562ed8 100644 --- a/Drivers/SX126x/Source/Sx1262.h +++ b/Drivers/SX126x/Source/Sx1262.h @@ -7,6 +7,7 @@ #include #include "RadiolibTactilityHal.h" #include "RadiolibThreadedDevice.h" +#include "LevelInterruptHandler.h" #include @@ -32,17 +33,17 @@ private: static constexpr auto SX1262_INTERRUPT_BIT = BIT0; static constexpr auto SX1262_DIO1_EVENT_BIT = BIT1; static constexpr auto SX1262_QUEUED_TX_BIT = BIT2; + static constexpr auto SX1262_IRQ_FLAGS = (RADIOLIB_IRQ_RX_DEFAULT_FLAGS); - std::string name; const Configuration configuration; - std::shared_ptr lock; + LevelInterruptHandler interrupt; + std::string name; tt::EventFlag events; RadiolibTactilityHal hal; Module radioModule; SX1262 radio; TxItem currentTx; - // Shared parameters which have a common lowest value are set here int8_t power = -9.0; float frequency = 150; float bandwidth = 0.0; @@ -57,6 +58,7 @@ private: void registerDio1Isr(); void unregisterDio1Isr(); + void armDio1Irq(); ParameterStatus setBaseParameter(const Parameter parameter, const float value); ParameterStatus setLoraParameter(const Parameter parameter, const float value); @@ -69,6 +71,8 @@ private: protected: + static void dio1Isr(void* ctx); + virtual void txQueuedSignal() override; virtual void interruptSignal() override; @@ -82,17 +86,18 @@ public: explicit Sx1262(const Configuration& configuration, const std::string& name = SX1262_DEFAULT_NAME) : RadiolibThreadedDevice(name, 4096) - , name(name) , configuration(configuration) - , hal(configuration.spiHostDevice, configuration.spiFrequency, configuration.csPin) - , radioModule(&hal, configuration.csPin, configuration.irqPin, configuration.resetPin, configuration.busyPin) + , interrupt(configuration.irqPin, LevelInterruptHandler::Type::PositiveEdge, dio1Isr, this) + , name(name) + , hal(configuration.spiHostDevice, configuration.spiFrequency) + , radioModule(&hal, configuration.csPin, RADIOLIB_NC, configuration.resetPin, configuration.busyPin) , radio(&radioModule) {} ~Sx1262() override = default; std::string getName() const override { return name; } - std::string getDescription() const override { return "Semtech SX1262 LoRa, FSK and LR-FHSS capable radio"; } + std::string getDescription() const override { return "Semtech SX1262 LoRa and (G)FSK capable radio"; } ParameterStatus setParameter(const Parameter parameter, const float value) override; ParameterStatus getParameter(const Parameter parameter, float &value) const override;