From 7067c673046bb7720d6574987f52ae908d7470fe Mon Sep 17 00:00:00 2001 From: jgromes Date: Tue, 20 Aug 2024 20:37:12 +0200 Subject: [PATCH] [SX127x] Added generalized IRQ handling via PHY --- src/modules/SX127x/SX127x.cpp | 129 ++++++++++++++++++++++++---------- src/modules/SX127x/SX127x.h | 22 ++++-- 2 files changed, 108 insertions(+), 43 deletions(-) diff --git a/src/modules/SX127x/SX127x.cpp b/src/modules/SX127x/SX127x.cpp index 7cc33c9f..60b81ed7 100644 --- a/src/modules/SX127x/SX127x.cpp +++ b/src/modules/SX127x/SX127x.cpp @@ -12,6 +12,18 @@ int16_t SX127x::begin(uint8_t* chipVersions, uint8_t numVersions, uint8_t syncWo this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + // set IRQ mapping - it is different for LoRa and FSK mode + this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE; + this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE; + this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER; + this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR; + this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE; + this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED; + this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT; + // try to find the SX127x chip if(!SX127x::findChip(chipVersions, numVersions)) { RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); @@ -63,6 +75,18 @@ int16_t SX127x::beginFSK(uint8_t* chipVersions, uint8_t numVersions, float freqD this->mod->hal->pinMode(this->mod->getIrq(), this->mod->hal->GpioModeInput); this->mod->hal->pinMode(this->mod->getGpio(), this->mod->hal->GpioModeInput); + // set IRQ mapping - it is different for LoRa and FSK mode + this->irqMap[RADIOLIB_IRQ_TX_DONE] = RADIOLIB_SX127X_FLAG_PACKET_SENT << 8; + this->irqMap[RADIOLIB_IRQ_RX_DONE] = RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8; + this->irqMap[RADIOLIB_IRQ_PREAMBLE_DETECTED] = RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0; + this->irqMap[RADIOLIB_IRQ_SYNC_WORD_VALID] = RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0; + this->irqMap[RADIOLIB_IRQ_HEADER_VALID] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_HEADER_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_CRC_ERR] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_CAD_DONE] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_CAD_DETECTED] = RADIOLIB_IRQ_NOT_SUPPORTED; + this->irqMap[RADIOLIB_IRQ_TIMEOUT] = RADIOLIB_SX127X_FLAG_TIMEOUT << 0; + // try to find the SX127x chip if(!SX127x::findChip(chipVersions, numVersions)) { RADIOLIB_DEBUG_BASIC_PRINTLN("No SX127x found!"); @@ -211,13 +235,13 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { if(this->mod->getGpio() == RADIOLIB_NC) { // no GPIO pin provided, use software timeout if(this->mod->hal->millis() - start > timeout) { - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); return(RADIOLIB_ERR_RX_TIMEOUT); } } else { // GPIO provided, use that if(this->mod->hal->digitalRead(this->mod->getGpio())) { - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -237,7 +261,7 @@ int16_t SX127x::receive(uint8_t* data, size_t len) { while(!this->mod->hal->digitalRead(this->mod->getIrq())) { this->mod->hal->yield(); if(this->mod->hal->millis() - start > timeout) { - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); return(RADIOLIB_ERR_RX_TIMEOUT); } } @@ -389,7 +413,7 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { RADIOLIB_ERRATA_SX127X(true); // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set FIFO pointers state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_FIFO_RX_BASE_ADDR, RADIOLIB_SX127X_FIFO_RX_BASE_ADDR_MAX); @@ -402,7 +426,7 @@ int16_t SX127x::startReceive(uint8_t len, uint8_t mode) { RADIOLIB_ASSERT(state); // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // FSK modem does not distinguish between Rx single and continuous if(mode == RADIOLIB_SX127X_RXCONTINUOUS) { @@ -571,7 +595,7 @@ int16_t SX127x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { RADIOLIB_ERRATA_SX127X(false); // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set packet length state |= this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_PAYLOAD_LENGTH, len); @@ -582,7 +606,7 @@ int16_t SX127x::startTransmit(const uint8_t* data, size_t len, uint8_t addr) { } else if(modem == RADIOLIB_SX127X_FSK_OOK) { // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set DIO mapping if(len > RADIOLIB_SX127X_MAX_PACKET_LENGTH_FSK) { @@ -628,7 +652,7 @@ int16_t SX127x::finishTransmit() { mod->hal->delayMicroseconds(1000000/1200); // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set mode to standby to disable transmitter/RF switch return(standby()); @@ -686,7 +710,7 @@ int16_t SX127x::readData(uint8_t* data, size_t len) { this->packetLengthQueried = false; // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); return(state); } @@ -702,7 +726,7 @@ int16_t SX127x::startChannelScan() { RADIOLIB_ASSERT(state); // clear interrupt flags - clearIRQFlags(); + clearIrqFlags(RADIOLIB_SX127X_FLAGS_ALL); // set DIO pin mapping state = this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE | RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 7, 4); @@ -1302,29 +1326,66 @@ int16_t SX127x::irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) { return(RADIOLIB_ERR_NONE); } -int16_t SX127x::checkIrq(uint8_t irq) { - uint16_t flags = getIRQFlags(); - switch(irq) { - case RADIOLIB_IRQ_TX_DONE: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE); - case RADIOLIB_IRQ_RX_DONE: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE); - case RADIOLIB_IRQ_HEADER_VALID: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER); - case RADIOLIB_IRQ_CRC_ERR: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR); - case RADIOLIB_IRQ_CAD_DONE: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE); - case RADIOLIB_IRQ_CAD_DETECTED: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED); - case RADIOLIB_IRQ_TIMEOUT: - return(flags & RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT); - default: - return(RADIOLIB_ERR_UNSUPPORTED); +uint32_t SX127x::getIrqFlags() { + return((uint32_t)this->getIRQFlags()); +} + +int16_t SX127x::setIrqFlags(uint32_t irq) { + // this is a bit convoluted, but unfortunately SX127x IRQ flags are not used to enable/disable that IRQ ... + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + switch(irq) { + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_TX_DONE): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_DONE): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_RX_DONE, 7, 6)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_VALID_HEADER): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_LORA_VALID_HEADER, 1, 0)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_PAYLOAD_CRC_ERROR): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO3_LORA_PAYLOAD_CRC_ERROR, 1, 0)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DONE): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_LORA_CAD_DONE, 7, 6)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_CAD_DETECTED): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_CAD_DETECTED, 5, 4)); + case(RADIOLIB_SX127X_CLEAR_IRQ_FLAG_RX_TIMEOUT): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO1_LORA_RX_TIMEOUT, 5, 4)); + } + return(RADIOLIB_ERR_UNSUPPORTED); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + switch(irq) { + case(RADIOLIB_SX127X_FLAG_PACKET_SENT << 8): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PACKET_SENT, 7, 6)); + case(RADIOLIB_SX127X_FLAG_PAYLOAD_READY << 8): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO0_PACK_PAYLOAD_READY, 7, 6)); + case(RADIOLIB_SX127X_FLAG_PREAMBLE_DETECT << 0): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_2, RADIOLIB_SX127X_DIO4_PACK_RSSI_PREAMBLE_DETECT, 7, 6)); + case(RADIOLIB_SX127X_FLAG_SYNC_ADDRESS_MATCH << 0): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO2_PACK_SYNC_ADDRESS, 3, 2)); + case(RADIOLIB_SX127X_FLAG_TIMEOUT << 0): + return(this->mod->SPIsetRegValue(RADIOLIB_SX127X_REG_DIO_MAPPING_1, RADIOLIB_SX127X_DIO2_PACK_TIMEOUT, 3, 2)); + } + return(RADIOLIB_ERR_UNSUPPORTED); } + return(RADIOLIB_ERR_UNSUPPORTED); } +int16_t SX127x::clearIrqFlags(uint32_t irq) { + int16_t modem = getActiveModem(); + if(modem == RADIOLIB_SX127X_LORA) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, (uint8_t)irq); + return(RADIOLIB_ERR_NONE); + + } else if(modem == RADIOLIB_SX127X_FSK_OOK) { + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, (uint8_t)irq); + this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, (uint8_t)(irq >> 8)); + return(RADIOLIB_ERR_NONE); + } + + return(RADIOLIB_ERR_UNKNOWN); +} + int16_t SX127x::setCrcFiltering(bool enable) { this->crcOn = enable; @@ -1619,16 +1680,6 @@ int16_t SX127x::setActiveModem(uint8_t modem) { return(state); } -void SX127x::clearIRQFlags() { - int16_t modem = getActiveModem(); - if(modem == RADIOLIB_SX127X_LORA) { - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS, 0b11111111); - } else if(modem == RADIOLIB_SX127X_FSK_OOK) { - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_1, 0b11111111); - this->mod->SPIwriteRegister(RADIOLIB_SX127X_REG_IRQ_FLAGS_2, 0b11111111); - } -} - void SX127x::clearFIFO(size_t count) { while(count) { this->mod->SPIreadRegister(RADIOLIB_SX127X_REG_FIFO); diff --git a/src/modules/SX127x/SX127x.h b/src/modules/SX127x/SX127x.h index c00cd42f..b24d2051 100644 --- a/src/modules/SX127x/SX127x.h +++ b/src/modules/SX127x/SX127x.h @@ -500,6 +500,7 @@ #define RADIOLIB_SX127X_FLAG_PAYLOAD_READY 0b00000100 // 2 2 packet was successfully received #define RADIOLIB_SX127X_FLAG_CRC_OK 0b00000010 // 1 1 CRC check passed #define RADIOLIB_SX127X_FLAG_LOW_BAT 0b00000001 // 0 0 battery voltage dropped below threshold +#define RADIOLIB_SX127X_FLAGS_ALL 0xFFFF // RADIOLIB_SX127X_REG_DIO_MAPPING_1 #define RADIOLIB_SX127X_DIO0_LORA_RX_DONE 0b00000000 // 7 6 @@ -1073,10 +1074,24 @@ class SX127x: public PhysicalLayer { int16_t irqRxDoneRxTimeout(uint32_t &irqFlags, uint32_t &irqMask) override; /*! - \brief Check whether a specific IRQ bit is set (e.g. RxTimeout, CadDone). - \returns Whether requested IRQ is set. + \brief Read currently active IRQ flags. + \returns IRQ flags. */ - int16_t checkIrq(uint8_t irq) override; + uint32_t getIrqFlags(); + + /*! + \brief Set interrupt on DIO1 to be sent on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes + */ + int16_t setIrqFlags(uint32_t irq); + + /*! + \brief Clear interrupt on a specific IRQ bit (e.g. RxTimeout, CadDone). + \param irq Module-specific IRQ flags. + \returns \ref status_codes + */ + int16_t clearIrqFlags(uint32_t irq); /*! \brief Enable CRC filtering and generation. @@ -1257,7 +1272,6 @@ class SX127x: public PhysicalLayer { bool findChip(const uint8_t* vers, uint8_t num); int16_t setMode(uint8_t mode); int16_t setActiveModem(uint8_t modem); - void clearIRQFlags(); void clearFIFO(size_t count); // used mostly to clear remaining bytes in FIFO after a packet read /*!