Skip to content

Commit

Permalink
Merge pull request #2504 from particle-iot/fix/sc-107555-interrupts-4.x
Browse files Browse the repository at this point in the history
[4.x] [gen3] fixes interrupts() API, should not clear pending interrupts
  • Loading branch information
technobly authored Aug 12, 2022
2 parents d853b5e + f6ace38 commit f4011f5
Show file tree
Hide file tree
Showing 2 changed files with 269 additions and 1 deletion.
1 change: 0 additions & 1 deletion hal/src/nRF52840/interrupts_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ int HAL_Interrupts_Detach_Ext(uint16_t pin, uint8_t keepHandler, void* reserved)
}

void HAL_Interrupts_Enable_All(void) {
sd_nvic_ClearPendingIRQ(GPIOTE_IRQn);
sd_nvic_EnableIRQ(GPIOTE_IRQn);
}

Expand Down
269 changes: 269 additions & 0 deletions user/tests/app/interrupts/interrupts.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
#include "Particle.h"
SYSTEM_MODE(SEMI_AUTOMATIC);
SerialLogHandler logHandler(LOG_LEVEL_ALL);
int count = 0;
int error = 0;
int test_errors = 0;
int state = 1;
int COUNT_MULTIPLIER = 1;
system_tick_t lastState = 0;
const system_tick_t TIME_FOR_5_PULSES = (20 * 5);
InterruptMode intType = RISING;
//
// We will set most pins to INPUT_x modes, but only test the first 7
// since PM_INT takes up one of the 8, and after that RISING and CHANGE pending interrupt tests will fail.
//
#if (PLATFORM_ID == PLATFORM_ARGON) || (PLATFORM_ID == PLATFORM_BORON)
const int PIN_MAX = A0; // TEST: D0 ~ D6
#elif (PLATFORM_ID == PLATFORM_B5SOM)
const int PIN_MAX = D23;// TEST: D0 ~ D6
#elif (PLATFORM_ID == PLATFORM_BSOM)
const int PIN_MAX = A6; // TEST: D0 ~ D6 (SDA, SCL, RTS, CTS, PWM0, PWM1, PWM2)
#elif (PLATFORM_ID == PLATFORM_ESOMX)
const int PIN_MAX = D9; // TEST: D0, D1, D2, D5, D8, D9
#elif (PLATFORM_ID == PLATFORM_TRACKER)
const int PIN_MAX = D9; // TEST: D0 ~ D3 (D4,D6 will error like shared PORT event interrupts do)
#else
#error "Platform not supported!"
#endif

// required for B SoM / B5SoM
#if defined(HAL_PLATFORM_POWER_MANAGEMENT_OPTIONAL) && HAL_PLATFORM_POWER_MANAGEMENT_OPTIONAL
// Disable runtime PMIC / FuelGauge detection so we can test D0/D1 (SDA/SCL)
STARTUP(System.disable(SYSTEM_FLAG_PM_DETECTION));
#endif // defined(HAL_PLATFORM_POWER_MANAGEMENT_OPTIONAL) && HAL_PLATFORM_POWER_MANAGEMENT_OPTIONAL

pin_t PULSE_PIN = A5; // A randomly higher up pin that's available on all platforms (and won't be in the test as an interrupt pin)

static void attach_interrupt_handler() {
count++;
}

void gimmeFivePulses() {
for (int x = 0; x < 5; x++) {
digitalWrite(PULSE_PIN, HIGH);
delay(10);
digitalWrite(PULSE_PIN, LOW);
delay(10);
}
}

void teardownTest() {
for (int i = 0; i <= PIN_MAX; i++) {
if (i == PULSE_PIN) continue;
if (i >= D7) continue;
#if (PLATFORM_ID == PLATFORM_BSOM)
// if (i == SCL || i == SDA) continue; // exclude SCL & SDA
#elif (PLATFORM_ID == PLATFORM_ESOMX && SYSTEM_VERSION <= SYSTEM_VERSION_BETA(4,0,0,1))
if (i == D3 || i == D3 || i == D6 || i == D7 || i == D22 || i == D23) continue; // these don't exist
#endif
detachInterrupt(i);
}
}

void setupTest(InterruptMode type) {
Log.info("TEST (%s) START", type==RISING?"RISING":type==FALLING?"FALLING":"CHANGE");
for (int i = 0; i <= PIN_MAX; i++) {
if (i == PULSE_PIN) continue;
if (type == RISING) {
pinMode(i, INPUT_PULLDOWN);
} else if (type == FALLING) {
pinMode(i, INPUT_PULLUP);
} else {
pinMode(i, INPUT_PULLUP); // change
}
}
for (int i = 0; i <= PIN_MAX; i++) {
if (i == PULSE_PIN) continue;
if (i >= D7) continue;
#if (PLATFORM_ID == PLATFORM_BSOM)
// if (i == SCL || i == SDA) continue; // exclude SCL & SDA
#elif (PLATFORM_ID == PLATFORM_ESOMX && SYSTEM_VERSION <= SYSTEM_VERSION_BETA(4,0,0,1))
if (i == D3 || i == D3 || i == D6 || i == D7 || i == D22 || i == D23) continue; // these don't exist
#endif
attachInterrupt(i, attach_interrupt_handler, type);
}
delay(10);
error = 0;
state = 1;
COUNT_MULTIPLIER = 1;
count = 0;
gimmeFivePulses();
if (type == CHANGE || type == FALLING) {
if (type == CHANGE) {
COUNT_MULTIPLIER = 2; // double counts if testing CHANGE edge interrupts
}
}
lastState = millis();
}

void runTest(InterruptMode type) {
switch (state) {
case 0:
default: {
break;
}
case 1: {
if (count == 5 * COUNT_MULTIPLIER) {
Log.info("Interrupts are functioning correctly, count: %d", count);
state++;
noInterrupts(); // Single disable
lastState = millis();
} else if (millis() - lastState >= TIME_FOR_5_PULSES) {
Log.error("Interrupts are not functioning correctly, count: %d", count);
noInterrupts(); // Single disable
error++;
count = 5 * COUNT_MULTIPLIER;
gimmeFivePulses();
lastState = millis();
state++;
}
break;
}
case 2: {
if (millis() - lastState >= TIME_FOR_5_PULSES) {
if (count == 5 * COUNT_MULTIPLIER) {
Log.info("Interrupts were disabled, count still: %d", count);
} else {
Log.error("Interrupts were not disabled, count now: %d", count);
error++;
}
count = 5 * COUNT_MULTIPLIER;
gimmeFivePulses();
lastState = millis();
interrupts(); // Single enable
state++;
}
break;
}
case 3: {
if (millis() - lastState >= TIME_FOR_5_PULSES) {
if (count > 5 * COUNT_MULTIPLIER) {
Log.info("Pending interrupts not cleared before enabling interrupts, count now: %d", count);
} else {
Log.error("Pending interrupts were cleared before enabling interrupts, count still: %d", count);
error++;
}
lastState = millis();
count = 5 * COUNT_MULTIPLIER;
gimmeFivePulses();
state++;
}
break;
}
case 4: {
if (count == 10 * COUNT_MULTIPLIER) {
Log.info("Interrupts are functioning correctly, count: %d", count);
lastState = millis();
noInterrupts(); // Double disable
noInterrupts();
state++;
gimmeFivePulses();
} else if (millis() - lastState >= TIME_FOR_5_PULSES) {
Log.error("Interrupts are not functioning correctly, count: %d", count);
error++;
lastState = millis();
noInterrupts(); // Double disable
noInterrupts();
state++;
count = 10 * COUNT_MULTIPLIER;
gimmeFivePulses();
}
break;
}
case 5: {
if (millis() - lastState >= TIME_FOR_5_PULSES) {
if (count == 10 * COUNT_MULTIPLIER) {
Log.info("Interrupts were disabled, count still: %d", count);
} else {
Log.error("Interrupts were not disabled, count now: %d", count);
error++;
}
interrupts(); // Double enable
interrupts();
count = 10 * COUNT_MULTIPLIER;
gimmeFivePulses();
lastState = millis();
state++;
}
break;
}
case 6: {
if (millis() - lastState >= TIME_FOR_5_PULSES) {
if (count > 10 * COUNT_MULTIPLIER) {
Log.info("Pending interrupts not cleared before enabling interrupts, count now: %d", count);
} else {
Log.error("Pending interrupts were cleared before enabling interrupts, count still: %d", count);
error++;
}
lastState = millis();
count = 10 * COUNT_MULTIPLIER;
gimmeFivePulses();
state++;
}
break;
}
case 7: {
if (count == 15 * COUNT_MULTIPLIER) {
// disablePulses();
Log.info("Interrupts are functioning correctly, count: %d", count);
state++;
} else if (millis() - lastState >= TIME_FOR_5_PULSES) {
// disablePulses();
Log.error("Interrupts are not functioning correctly, count: %d", count);
error++;
state++;
}
break;
}
case 8: {
interrupts();
if (error > 0) {
Log.info("TEST (%s) FAILED, Error Count: %d", type==RISING?"RISING":type==FALLING?"FALLING":"CHANGE", error);
RGB.color(255,0,0); // RED
test_errors++;
} else {
Log.info("TEST (%s) PASSED", type==RISING?"RISING":type==FALLING?"FALLING":"CHANGE");
RGB.color(0,255,0); // GREEN
}
delay(500);
RGB.color(0,0,0); // NONE
state = 0;
}
} // switch
}

void setup() {
waitFor(Serial.isConnected, 10000);
delay(200);
Log.info("TESTS START");
Log.info("Connect PULSE_PIN(A5) to any other pin (e.g. D0 ~ D6) and reset the device to start the test");
Log.info("TRIES EACH INTERRUPT TYPE FOR ALL PINS AUTOMATICALLY (RISING, FALLING, CHANGE)");
RGB.control(true);
pinMode(PULSE_PIN, OUTPUT);
digitalWrite(PULSE_PIN, LOW);
setupTest(intType);
}

void loop() {
if (state == 0) {
if (intType == RISING) {
intType = FALLING;
} else if (intType == FALLING) {
intType = CHANGE;
} else {
if (test_errors > 0) {
Log.info("TESTS FAILED: %d/3", test_errors);
RGB.color(255,0,0); // RED
} else {
Log.info("TESTS PASSED: 3/3");
RGB.color(0,255,0); // GREEN
}
Log.info("ALL TESTS COMPLETE!!!");
while(1) Particle.process();
}
teardownTest();
setupTest(intType);
}
runTest(intType);
}

0 comments on commit f4011f5

Please sign in to comment.