From 7e97360e853d4e29ae7797f110418f0402e5b349 Mon Sep 17 00:00:00 2001 From: Brendan <2bndy5@gmail.com> Date: Sun, 10 Mar 2024 21:26:11 -0700 Subject: [PATCH] separate ISR handling from IRQ processing (#956) --- .../InterruptConfigure/InterruptConfigure.ino | 52 +++++++++++-------- examples_linux/interruptConfigure.cpp | 28 +++++----- examples_pico/interruptConfigure.cpp | 24 +++++++-- 3 files changed, 65 insertions(+), 39 deletions(-) diff --git a/examples/InterruptConfigure/InterruptConfigure.ino b/examples/InterruptConfigure/InterruptConfigure.ino index bae6dff8c..19ef9c504 100644 --- a/examples/InterruptConfigure/InterruptConfigure.ino +++ b/examples/InterruptConfigure/InterruptConfigure.ino @@ -19,6 +19,7 @@ // We will be using the nRF24L01's IRQ pin for this example #define IRQ_PIN 2 // this needs to be a digital input capable pin +volatile bool got_interrupt = false; // used to signal processing of interrupt volatile bool wait_for_event = false; // used to wait for an IRQ event to trigger #define CE_PIN 7 @@ -136,9 +137,11 @@ void setup() { } void loop() { - if (role && !wait_for_event) { + if (got_interrupt) { + assessInterruptEvent(); + } - // delay(1); // wait for IRQ pin to fully RISE + if (role && !wait_for_event) { // This device is a TX node. This if block is only triggered when // NOT waiting for an IRQ event to happen @@ -218,25 +221,22 @@ void loop() { pl_iterator++; // proceed from step 3 to last step (stop at step 4 for readability) } - } else if (!role) { - // This device is a RX node - - if (radio.rxFifoFull()) { - // wait until RX FIFO is full then stop listening + } else if (!role && radio.rxFifoFull()) { + // This device is a RX node: + // wait until RX FIFO is full then stop listening - delay(100); // let ACK payload finish transmitting - radio.stopListening(); // also discards unused ACK payloads - printRxFifo(); // flush the RX FIFO + delay(100); // let ACK payload finish transmitting + radio.stopListening(); // also discards unused ACK payloads + printRxFifo(); // flush the RX FIFO - // Fill the TX FIFO with 3 ACK payloads for the first 3 received - // transmissions on pipe 1. - radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); - radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); - radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); + // Fill the TX FIFO with 3 ACK payloads for the first 3 received + // transmissions on pipe 1. + radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); + radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); - delay(100); // let TX node finish its role - radio.startListening(); // We're ready to start over. Begin listening. - } + delay(100); // let TX node finish its role + radio.startListening(); // We're ready to start over. Begin listening. } // role @@ -271,6 +271,7 @@ void loop() { // Fill the TX FIFO with 3 ACK payloads for the first 3 received // transmissions on pipe 1 radio.flush_tx(); // make sure there is room for 3 new ACK payloads + radio.flush_rx(); // make sure there is room for 3 incoming payloads radio.writeAckPayload(1, &ack_payloads[0], ack_pl_size); radio.writeAckPayload(1, &ack_payloads[1], ack_pl_size); radio.writeAckPayload(1, &ack_payloads[2], ack_pl_size); @@ -281,9 +282,18 @@ void loop() { /** - * when the IRQ pin goes active LOW, call this fuction print out why + * when the IRQ pin goes active LOW. + * Here we just tell the main loop() to call `assessInterruptEve4nt()`. */ void interruptHandler() { + got_interrupt = true; // forward event handling back to main loop() +} + +/** + * Called when an event has been triggered. + * Here, we want to verify the expected IRQ flag has been asserted. + */ +void assessInterruptEvent() { // print IRQ status and all masking flags' states Serial.println(F("\tIRQ pin is actively LOW")); // show that this function was called @@ -316,9 +326,9 @@ void interruptHandler() { Serial.print(F(" 'Data Fail' event test ")); Serial.println(tx_df ? F("passed") : F("failed")); } + got_interrupt = false; // reset this flag to prevent calling this function from loop() wait_for_event = false; // ready to continue with loop() operations -} // interruptHandler - +} /** * Print the entire RX FIFO with one buffer. This will also flush the RX FIFO. diff --git a/examples_linux/interruptConfigure.cpp b/examples_linux/interruptConfigure.cpp index 22de739d1..99694d5fc 100644 --- a/examples_linux/interruptConfigure.cpp +++ b/examples_linux/interruptConfigure.cpp @@ -25,7 +25,7 @@ using namespace std; #define IRQ_PIN 12 // this needs to be a digital input capable pin // this example is a sequential program. so we need to wait for the event to be handled -volatile bool wait_for_event = false; // used to signify that the event is handled +volatile bool got_interrupt = false; // used to signify that the event started /****************** Linux ***********************/ // Radio CE Pin, CSN Pin, SPI Speed @@ -245,12 +245,12 @@ void slave() */ void ping_n_wait() { + got_interrupt = false; + // use the non-blocking call to write a payload and begin transmission // the "false" argument means we are expecting an ACK packet response radio.startFastWrite(tx_payloads[pl_iterator], tx_pl_size, false); - - wait_for_event = true; - while (wait_for_event) { + while (!got_interrupt) { /* * IRQ pin is LOW when activated. Otherwise it is always HIGH * Wait in this empty loop until IRQ pin is activated. @@ -260,13 +260,6 @@ void ping_n_wait() * default, we don't need a timeout check to prevent an infinite loop. */ } -} - -/** - * when the IRQ pin goes active LOW, call this fuction print out why - */ -void interruptHandler() -{ // print IRQ status and all masking flags' states cout << "\tIRQ pin is actively LOW" << endl; // show that this function was called @@ -292,8 +285,17 @@ void interruptHandler() else if (pl_iterator == 3) cout << " 'Data Fail' event test " << (tx_df ? "passed" : "failed") << endl; - wait_for_event = false; // ready to continue -} // interruptHandler + got_interrupt = false; +} + +/** + * when the IRQ pin goes active LOW. + * Here we just set a flag to unblock ping_n_wait() + */ +void interruptHandler() +{ + got_interrupt = true; // ready to continue +} /** * Print the entire RX FIFO with one buffer. This will also flush the RX FIFO. diff --git a/examples_pico/interruptConfigure.cpp b/examples_pico/interruptConfigure.cpp index 0b59aff6b..27a272696 100644 --- a/examples_pico/interruptConfigure.cpp +++ b/examples_pico/interruptConfigure.cpp @@ -21,6 +21,7 @@ // We will be using the nRF24L01's IRQ pin for this example volatile bool wait_for_event = false; // used to wait for an IRQ event to trigger +volatile bool got_interrupt = false; // used to signal when an IRQ event has been triggered // instantiate an object for the nRF24L01 transceiver RF24 radio(CE_PIN, CSN_PIN); @@ -40,6 +41,7 @@ char ack_payloads[][ack_pl_size + 1] = {"Yak ", "Back", " ACK"}; void interruptHandler(uint gpio, uint32_t events); // prototype to handle IRQ events void printRxFifo(); // prototype to print RX FIFO with 1 buffer +void assessInterruptEvent(); // prototype to assess IRQ flags triggered bool setup() { @@ -121,7 +123,6 @@ bool setup() } // For debugging info - // printf_begin(); // needed only once for printing details // radio.printDetails(); // (smaller) function that prints raw register values // radio.printPrettyDetails(); // (larger) function that prints human readable data @@ -231,6 +232,10 @@ void loop() } // role + if (got_interrupt) { + assessInterruptEvent(); + } + char input = getchar_timeout_us(0); // get char from buffer for user input if (input != PICO_ERROR_TIMEOUT) { // change the role via the serial terminal @@ -239,7 +244,7 @@ void loop() // Become the TX node if (!role) printf("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK\n"); - else if (role && wait_for_event) // don't interrupt on ongoing test + else if (role && wait_for_event) // don't interrupt an ongoing test return; // exit now; start next loop() else printf("*** RESTARTING IRQ PIN TEST ***\n"); @@ -277,16 +282,24 @@ void loop() } // loop /** - * when the IRQ pin goes active LOW, call this fuction print out why + * when the IRQ pin goes active LOW. + * Here we just tell the main loop() to call `assessInterruptEve4nt()`. */ void interruptHandler(uint gpio, uint32_t events) { - if (gpio != IRQ_PIN && !(events | GPIO_IRQ_EDGE_FALL)) { // the gpio pin and event does not match the configuration we specified return; } + got_interrupt = true; // forward event handling back to main loop() +} +/** + * Called when an event has been triggered. + * Here, we want to verify the expected IRQ flag has been asserted. + */ +void assessInterruptEvent() +{ // print IRQ status and all masking flags' states printf("\tIRQ pin is actively LOW\n"); // show that this function was called bool tx_ds, tx_df, rx_dr; // declare variables for IRQ masks @@ -315,8 +328,9 @@ void interruptHandler(uint gpio, uint32_t events) else if (pl_iterator == 4) { printf(" 'Data Fail' event test %s\n", tx_df ? "passed" : "failed"); } + got_interrupt = false; // reset this flag to prevent calling this function from loop() wait_for_event = false; // ready to continue with loop() operations -} // interruptHandler +} /** * Print the entire RX FIFO with one buffer. This will also flush the RX FIFO.