Using PCINT0 instead of INT0 for LoRA Radiohead (RH_RF95) driver

I am developing simple LoRA board (sx1276) with Atmega328PB but I ended up wiring DIO0 pin on lora module to pin D8. I’m using watteroot bootloader on Arduino framework. According to Arduino documentation (PcInt, PinChangeInt) I should be able to use PCINT interrupt instead of external interrupt INT0 and INT1.

As far as I can see I could do this in couple of ways.

  1. Attach interrupt to pin 8 with method attachInterrupt(interruptPinNumber, isr_funct, RISING) and monitor for RISING signal. Then in loop() make a call when send()/recv() returnstrue/false .

  2. Detach interrupt from pin 2 (PD2) and attach interrupt to pin 8. But how do I pass interrupt pin to rf95 object instance:

RH_RF5 rf = rf(CS_PIN, INTERRUPT_PIN);

The only way I see doing (2) would be to modify RadioHead RH_RF95.cpp code posted below to handle other interrupts other than external ones.

init()

_deviceForInterrupt[_myInterruptIndex] = this;
    if (_myInterruptIndex == 0)
    attachInterrupt(interruptNumber, isr0, RISING);
    else if (_myInterruptIndex == 1)
    attachInterrupt(interruptNumber, isr1, RISING);
    else if (_myInterruptIndex == 2)
    attachInterrupt(interruptNumber, isr2, RISING);
    else
    return false; // Too many devices,not enough interrupt vectors

isr0()

void RH_INTERRUPT_ATTR RH_RF95::isr0()
{
    if (_deviceForInterrupt[0])
    _deviceForInterrupt[0]->handleInterrupt();
}
void RH_INTERRUPT_ATTR RH_RF95::isr1()
{
    if (_deviceForInterrupt[1])
    _deviceForInterrupt[1]->handleInterrupt();
}
void RH_INTERRUPT_ATTR RH_RF95::isr2()
{
    if (_deviceForInterrupt[2])
    _deviceForInterrupt[2]->handleInterrupt();
}

handleInterrupt()

void RH_RF95::handleInterrupt()
{
    // Read the interrupt register
    uint8_t irq_flags = spiRead(RH_RF95_REG_12_IRQ_FLAGS);
    // Read the RegHopChannel register to check if CRC presence is signalled
    // in the header. If not it might be a stray (noise) packet.*
    uint8_t crc_present = spiRead(RH_RF95_REG_1C_HOP_CHANNEL);
    if (_mode == RHModeRx
    && ((irq_flags & (RH_RF95_RX_TIMEOUT | RH_RF95_PAYLOAD_CRC_ERROR))
        | !(crc_present & RH_RF95_RX_PAYLOAD_CRC_IS_ON)))
//    if (_mode == RHModeRx && irq_flags & (RH_RF95_RX_TIMEOUT | RH_RF95_PAYLOAD_CRC_ERROR))
    {
    _rxBad++;
    }
    else if (_mode == RHModeRx && irq_flags & RH_RF95_RX_DONE)
    {
    // Have received a packet
    uint8_t len = spiRead(RH_RF95_REG_13_RX_NB_BYTES);


    // Reset the fifo read ptr to the beginning of the packet
    spiWrite(RH_RF95_REG_0D_FIFO_ADDR_PTR, spiRead(RH_RF95_REG_10_FIFO_RX_CURRENT_ADDR));
    spiBurstRead(RH_RF95_REG_00_FIFO, _buf, len);
    _bufLen = len;
    spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags


    // Remember the last signal to noise ratio, LORA mode
    // Per page 111, SX1276/77/78/79 datasheet
    _lastSNR = (int8_t)spiRead(RH_RF95_REG_19_PKT_SNR_VALUE) / 4;


    // Remember the RSSI of this packet, LORA mode
    // this is according to the doc, but is it really correct?
    // weakest receiveable signals are reported RSSI at about -66
    _lastRssi = spiRead(RH_RF95_REG_1A_PKT_RSSI_VALUE);
    // Adjust the RSSI, datasheet page 87
    if (_lastSNR < 0)
        _lastRssi = _lastRssi + _lastSNR;
    else
        _lastRssi = (int)_lastRssi * 16 / 15;
    if (_usingHFport)
        _lastRssi -= 157;
    else
        _lastRssi -= 164;
       
    // We have received a message.
    validateRxBuf();
    if (_rxBufValid)
        setModeIdle(); // Got one
    }
    else if (_mode == RHModeTx && irq_flags & RH_RF95_TX_DONE)
    {
    _txGood++;
    setModeIdle();
    }
    else if (_mode == RHModeCad && irq_flags & RH_RF95_CAD_DONE)
    {
        _cad = irq_flags & RH_RF95_CAD_DETECTED;
        setModeIdle();
    }
    // Sigh: on some processors, for some unknown reason, doing this only once does not actually
    // clear the radio's interrupt flag. So we do it twice. Why?
    spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags
    spiWrite(RH_RF95_REG_12_IRQ_FLAGS, 0xff); // Clear all IRQ flags
}

According to Arduino documentation (PcInt, PinChangeInt) I should be able to use PCINT interrupt instead of external interrupt INT0 and INT1.

You can use it in many places where you used an external hardware interrupt but not in all.

  1. Attach interrupt to pin 8 with method attachInterrupt(interruptPinNumber, isr_funct, RISING) and monitor for RISING signal. Then in loop() make a call when send()/recv() returnstrue/false .

Wrong, you cannot use attachInterrupt for PCInt pins, that works only for external hardware interrupts.

The only way I see doing (2) would be to modify RadioHead RH_RF95.cpp code posted below to handle other interrupts other than external ones.

Correct. You have to modify the code to use the pin change interrupt instead of the external interrupt and check in every interrupt if the correct pin was changed and if the correct edge was detected. As you can see the pin change interrupt is not a full fledged replacement for the external hardware interrupt.