[SX127x] Added generalized IRQ handling via PHY

This commit is contained in:
jgromes 2024-08-20 20:37:12 +02:00
parent fcdc1d782e
commit 7067c67304
2 changed files with 108 additions and 43 deletions

View file

@ -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);

View file

@ -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
/*!