static void (*previous_systick_isr)();
static void my_systick_isr() {
(*previous_systick_isr)();
/* do my own thing */
}
void MyClass::begin()
{
previous_systick_isr = _VectorsRam[15];
_VectorsRam[15] = my_systick_isr;
}
I suggested to add some c++ code to the core that handles this chaning and makes it easy to use - maybe for every interrupt ?
One could add a function like "addToIntChain(intnum, function);"
class interruptChain {
public:
interruptChain() {
prevInterruptPtr = NULL;
intNum = 0;
}
void chainInterrupt(int intNumber, void (*interruptPtr)(void)) {
if (intNumber > 0 && intNumber <= NVIC_NUM_INTERRUPTS + 16) {
intNum = intNumber;
prevInterruptPtr = _VectorsRam[intNum];
_VectorsRam[intNum] = interruptPtr;
}
}
inline void callNext(void) {
prevInterruptPtr();
}
void unChainInterrupt(void) {
if (intNum) {
_VectorsRam[intNum] = prevInterruptPtr;
};
prevInterruptPtr = NULL;
intNum = 0;
}
protected:
uint8_t intNum;
void (*prevInterruptPtr)(void);
};
[B]//Test this :[/B]
[B]interruptChain myAdditionalSystick;[/B]
volatile int counter = 0;
[B]void mySystick(void) {
counter++;
myAdditionalSystick.callNext();
}
[/B]
void setup() {
while (!Serial);
[B] myAdditionalSystick.chainInterrupt(15, mySystick);[/B]
}
void loop() {
static unsigned long t = millis();
static int c = 0;
unsigned long m = millis();
if ( m - t > 500) {
Serial.print(m);
Serial.print(" ");
Serial.println(counter);
t = m;
c++;
if (c > 10) {
[B]myAdditionalSystick.unChainInterrupt();[/B]
}
}
}
This class can be used to chain the MillisTimer.MillisTimer is intended to fill this role, at least for access to SysTick.
Note, this one calls the new Interrupt before the others. Take it just as an example, not more. I spend a few minutes with it, and I'm sure it can be done better.
Perhaps we should write a class which can do both - insert befor all others or insert as last element.
It works with two or more int-functions, too. All needed is a interruptChain variable.
And, for example, you can add it to the SerialX interrupt and know when it's worth to call the event without polling available() (?!)
This class can be used to chain the MillisTimer.
Edit: Maybe, it's useful for the NMIs, too..
typedef void (*IsrFunc)();
class isr_list {
std::list<IsrFunc> isr;
void run() {
for (IsrFunc fx : isr) {
(*fx)()
}
}
void add(IsrFunc f) { isr->push_back(f); }
void remove(IsrFunc f) { isr->remove(f); };
etc.
}
void systick_isr() {
systick_list->run();
}
class interruptChain {
public:
void chainInterrupt(int intNumber, void (*interruptPtr)(void)) {
prevInterruptPtr = _VectorsRam[intNumber];
_VectorsRam[intNumber] = interruptPtr
}
inline void callNext(void) {
prevInterruptPtr();
}
protected:
void (*prevInterruptPtr)(void);
};
Just because you can doesn't mean you should....
I'm trying to keep an open mind about this, but that pretty much sums up my feelings so far on interrupt chaining. Convince me why we need this for something other than SysTick, or if for SysTick why MillisTimer isn't enough. Convince me this is actually a good idea. Convince me this isn't going to be seen as an ugly kludge and (in hindsight) a mistake that probably never should have been published, but can't be removed since it'll break some programs or libs using it?
void MillisTimer::runFromTimer()
{
MillisTimer *timer = listActive;
while (timer) {
if (timer->_ms > 0) {
timer->_ms--;
break;
} else {
MillisTimer *next = timer->_next;
if (next) next->_prev = nullptr;
listActive = next;
timer->_state = TimerOff;
EventResponderRef event = *(timer->_event);
event.triggerEvent(0, timer);
if (timer->_reload) {
timer->_ms = timer->_reload;
timer->addToActiveList();
}
timer = listActive;
}
}
bool irq = disableTimerInterrupt();
MillisTimer *waiting = listWaiting;
listWaiting = nullptr; // TODO: use STREX to avoid interrupt disable
enableTimerInterrupt(irq);
while (waiting) {
MillisTimer *next = waiting->_next;
waiting->addToActiveList();
waiting = next;
}
}
extern "C" volatile uint32_t systick_millis_count;
void systick_isr(void)
{
systick_millis_count++;
if (MillisTimer::haveTimers() {
MillisTimer::runFromTimer();
}
}
I am assuming haveTimers would be inline... So just a simple test...
Then, why you asked "how" ?Just because you can doesn't mean you should....
Your rhetorical trick led me think you were really interested.How would that work?
#include <EventResponder.h>
#define EVENT2_TIME 850
#define EVENT3_TIME 1050
#define EVENT4_TIME 250
#define EVENT0_TIME 750
uint32_t event0_expected_time;
uint32_t event2_expected_time;
uint32_t event3_expected_time;
uint32_t event4_expected_time;
EventResponder myevent;
EventResponder mytimerevent;
EventResponder mytimerevent2;
EventResponder mytimerevent3;
EventResponder mytimerevent4;
MillisTimer mytimer;
MillisTimer mytimer3;
MillisTimer mytimer2;
MillisTimer mytimer4;
#include <Arduino.h>
#include "TeensyThreads.h"
const int LED = 13;
volatile int blinkcode = 0;
void blinkthread() {
while(1) {
if (blinkcode) {
for (int i=0; i<blinkcode; i++) {
digitalWrite(LED, HIGH);
threads.delay(150);
digitalWrite(LED, LOW);
threads.delay(150);
}
blinkcode = 0;
}
threads.yield();
}
}
void setup() {
while (!Serial) ;
Serial.println("EventResponder test");
myevent.attach(dosomething);
mytimerevent.attach(dotimer);
mytimerevent2.attach(dotimer2);
mytimerevent3.attach(dotimer3);
mytimerevent4.attach(dotimer4);
event0_expected_time = millis() + EVENT0_TIME;
mytimer2.beginRepeating( EVENT2_TIME, mytimerevent2);
event2_expected_time = millis() + EVENT2_TIME;
mytimer3.beginRepeating(EVENT3_TIME, mytimerevent3);
event3_expected_time = millis() + EVENT3_TIME;
mytimer4.beginRepeating(EVENT4_TIME, mytimerevent4);
event4_expected_time = millis() + EVENT4_TIME;
pinMode(LED, OUTPUT);
threads.addThread(blinkthread);
}
int count = 0;
void loop() {
blinkcode = 2;
Serial.println("loop trigger dosomething");
myevent.triggerEvent();
delay(249);
}
void dosomething(EventResponderRef event)
{
Serial.println("dosomething event");
mytimer.begin(EVENT0_TIME, mytimerevent);
event0_expected_time = millis() + EVENT0_TIME;
}
void dotimer(EventResponderRef event)
{
uint32_t t = millis();
Serial.printf("%u - T0(%d)\n", t, (t >= event0_expected_time)? t - event0_expected_time : event0_expected_time - t);
event0_expected_time += EVENT0_TIME;}
void dotimer3(EventResponderRef event)
{
uint32_t t = millis();
Serial.printf("%u - T3(%d)\n", t, (t >= event3_expected_time)? t - event3_expected_time : event3_expected_time - t);
event3_expected_time += EVENT3_TIME;
}
void dotimer4(EventResponderRef event)
{
uint32_t t = millis();
Serial.printf("%u - T4(%d)\n", t, (t >= event4_expected_time)? t - event4_expected_time : event4_expected_time - t);
event4_expected_time += EVENT4_TIME;
}
void dotimer2(EventResponderRef event)
{
uint32_t t = millis();
Serial.printf("%u - T2(%d)\n", t, (t >= event2_expected_time)? t - event2_expected_time : event2_expected_time - t);
event2_expected_time += EVENT2_TIME;
}
EventResponder test
loop trigger dosomething
dosomething event
loop trigger dosomething
dosomething event
loop trigger dosomething
dosomething event
EventResponder test
loop trigger dosomething
dosomething event
loop trigger dosomething
dosomething event
3468 - T4(0)
loop trigger dosomething
dosomething event
3718 - T4(0)
loop trigger dosomething
dosomething event
3968 - T4(0)
4068 - T2(0)
loop trigger dosomething
dosomething event
4218 - T4(0)
4268 - T3(0)
loop trigger dosomething
dosomething event
4468 - T4(0)
loop trigger dosomething
dosomething event
4718 - T4(0)
4918 - T2(0)
loop trigger dosomething
dosomething event
4968 - T4(0)
loop trigger dosomething
dosomething event
5218 - T4(0)
5318 - T3(0)
loop trigger dosomething
dosomething event
5468 - T4(0)
loop trigger dosomething
dosomething event
5718 - T4(0)
5768 - T2(0)
loop trigger dosomething
dosomething event
5968 - T4(0)
loop trigger dosomething
dosomething event
6218 - T4(0)
6368 - T3(0)
loop trigger dosomething
dosomething event
6468 - T4(0)
6618 - T2(0)
loop trigger dosomething
dosomething event
6718 - T4(0)
loop trigger dosomething
dosomething event
6968 - T4(0)
loop trigger dosomething
dosomething event
7218 - T4(0)
7418 - T3(0)
loop trigger dosomething
dosomething event
7468 - T2(0)
7468 - T4(0)
@Frank B. Thanks for the explanation. Beginning to understand the issues here.
Thanks
Mike
EventResponder test
loop trigger dosomething
dosomething event
@fritas. Man that was a quick update. Just gave the updated library a try with my test code above. Don't think it is working. It hangs after the first event response and no-blinking occurs.