khoih-prog / NRF52_MBED_TimerInterrupt

This library enables you to use Interrupt from Hardware Timers on an NRF52-based board using mbed-RTOS such as Nano-33-BLE. These nRF52 Hardware Timers, using Interrupt, still work even if other functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software timers using millis() or micros(). That's mandatory if you need to measure some data requiring better accuracy. It now supports 16 ISR-based Timers, while consuming only 1 Hardware Timer. Timers' interval is very long (ulong millisecs). The most important feature is they're ISR-based Timers. Therefore, their executions are not blocked by bad-behaving functions or tasks. This important feature is absolutely necessary for mission-critical tasks.
MIT License
15 stars 2 forks source link

Issue w/ AnalogRead in Interrupt #5

Closed daanstevenson closed 3 years ago

daanstevenson commented 3 years ago

Hi Khoi, Thanks for writing and sharing this timer interrupt library. I am trying to implement consistently spaced sampling on a Nano33BLE, but the board seems to crash whenever I have a call to analogRead within the ISR.

Arduino IDE version: 1.8.13 Arduino mbed Nano Core Version 2.4.1 OS: Windows 10

Minimal code is below. I have also tried with an Adafruit nrf52 board and your other version of the library. This seems to work, but only if interrupts are halted before the analogRead call and enabled afterwards.

Working on native Nordic SDK firmware, but it would be great to accelerate prototyping with your library!

// test of timer ADC functionality

include "NRF52_MBED_TimerInterrupt.h"

define MOTOR_PIN P0_27 // 9u, D9

define OPTO_PIN P0_21 // 8u, D8

define FIELD_MILL_PIN P0_5 // 15u, A1

define SAMPLE_INTERVAL 500

define BLE_INTERVAL 10000

NRF52_MBED_Timer sample_timer(NRF_TIMER_4); NRF52_MBED_Timer ble_timer(NRF_TIMER_3);

volatile int idx; volatile unsigned long times[20] = {}; volatile int readings[20] = {}; volatile int fm_output = 0;

unsigned long t_now; // start time for current loop unsigned long t_last_sample = 0; unsigned long sample_delay = 5000; unsigned long t_last_print = 0; unsigned long print_delay = 500E3;

void setup() { // put your setup code here, to run once:

Serial.begin(57600);

analogReadResolution(12);

sample_timer.attachInterruptInterval(SAMPLE_INTERVAL, SampleTimerFunc); ble_timer.attachInterruptInterval(BLE_INTERVAL, BleTimerFunc);

}

void loop() { // put your main code here, to run repeatedly:

t_now = micros(); // if (t_now - t_last_sample > sample_delay) // { // t_last_sample = t_now; // times[idx] = micros(); // readings[idx] = analogRead(FIELD_MILL_PIN); // idx++; // if (idx >= 20) // { // idx = 0; // } // }

// Print debug data if (t_now - t_last_print > print_delay) { t_last_print = t_now; Serial.println(fm_output); for (int i = 0; i < 20; i++) { Serial.print(times[i]); Serial.print("\t"); } Serial.println(); for (int i = 0; i < 20; i++) { Serial.print(readings[i]); Serial.print("\t"); } Serial.println(); } }

void SampleTimerFunc() { times[idx] = micros(); // noInterrupts(); readings[idx] = analogRead(FIELD_MILL_PIN); // interrupts(); // readings[idx] = 200;

idx++; if (idx >= 20) { idx = 0; } }

void BleTimerFunc() { int total = 0; for (int i = 0; i < 20; i++) { total += readings[i]; } fm_output = (int)(76.0 * (double)total / 20.0); }

khoih-prog commented 3 years ago

As a rule, you can't do something too long in ISR, especially using the messy analogRead().

The correct way to do is set a flag inside ISR, then call analogRead() outside ISR using a loop depending on millis().

Also have a look at analogRead #2

Thanks for your interest in the library.

Good Luck,