Forum Rule: Always post complete source code & details to reproduce any issue!
Page 3 of 5 FirstFirst 1 2 3 4 5 LastLast
Results 51 to 75 of 114

Thread: Arduino Events

  1. #51
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    536
    Hi all. I just downloaded KurtE's fork of the core libs to give the Serial changes a try and noticed that eventResponder was included. So I figured I would give it a shot and test the example that Paul posted. As expected it worked no issue. So I started to looking at what's its doing and of modifying the code. So if I can ask a few questions:
    1. In the loop the call to myevent.triggerEvent(); is starting the event process, turning it on?
    2. The "doSomething" function has a call to mytimer.begin(550, mytimerevent);, not 100% sure what that does - sets the trigger for every 550 ms or starts it after 550ms?
    3. The mytimer2.beginRepeating(750, mytimerevent2) sets the trigger to go off every 750 ms?


    Ok so with that said if I change the example to add another repeating timer (think I did this right):
    Code:
    #include <EventResponder.h>
    
    EventResponder myevent;
    EventResponder mytimerevent;
    EventResponder mytimerevent2;
    EventResponder mytimerevent3;
    MillisTimer mytimer;
    MillisTimer mytimer3;
    MillisTimer mytimer2;
    
    void setup() {
      while (!Serial) ;
      Serial.println("EventResponder test");
      myevent.attach(dosomething);
      mytimerevent.attach(dotimer);
      mytimerevent2.attach(dotimer2);
      mytimerevent3.attach(dotimer3);
      mytimer2.beginRepeating(750, mytimerevent2);
      mytimer3.beginRepeating(250, mytimerevent3);
    }
    
    void loop() {
      Serial.println("loop trigger dosomething");
      myevent.triggerEvent();
      delay(2000);
    }
    
    void dosomething(EventResponderRef event)
    {
      Serial.println("dosomething event");
      mytimer.begin(550, mytimerevent);
    }
    
    void dotimer(EventResponderRef event)
    {
      Serial.println("oneshot timer event");
    }
    
    void dotimer2(EventResponderRef event)
    {
      Serial.println("  repeating timer event");
    }
    
    void dotimer3(EventResponderRef event)
    {
      Serial.println("    what a wonderful world");
    }
    It never executes dotimer2. It appears that the earlier trigger resets all timers to zero, I never see "repeating timer event":
    Code:
    loop trigger dosomething
    dosomething event
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
    loop trigger dosomething
    dosomething event
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
    Also if I noticed if I remove the delay from the loop everything hangs and I have to reset to get the ide/sm working again. Know I have to be missing something. Help.

    thanks
    Mike
    Last edited by mjs513; 08-13-2017 at 10:58 PM.

  2. #52
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    5,178
    my guess: Without that delay the loop is running 10's or 100's of thousands of times per second. The serial.print's are overwhelming the serial output speed and the triggerEvent is acting the same.

    Look into elapsedMillis() and only do those things when some time has elapsed - it doesn't do delay() - just doe it to check and reset the elapsedMillis value to limit entry.

  3. #53
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    536
    Got it. Also beginning to understand a little more did a quick test with out the one shot and just used the repeating. So if I have two separate repeating events only the one with the earliest time gets triggered but not the later one. So you can then only have one repeating event.

  4. #54
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    5,178
    Not sure about "It never executes dotimer2." - KurtE's copy may not be the latest release with it working? Check the Github PJRC source or try again when it comes out in the 1.38b3 if answers don't show up. I scanned the prior posts - that is based on a Paul posted sample - there may be something about overlapping events and priority?

  5. #55
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    536
    Thanks defragster. Think you are right about that. Think I will wait for beta#3 before starting to play with this one.

  6. #56
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    Hi defragster and mjs513 - I believe my code (in this branch) is now only slightly out of date. That is I have not picked up Frank's change Paul merged in a couple of days ago and these had to do with Interval timer... My master branch is in sync... May try to remember how to rebase my change on github, such that the branch only has those changes...

    But back to issue. I do think it might be beneficial to figure out your hang. As my SPI update which added the spi transfer buffer SPI.transfer(buf, retbuf, cnt) also added a version in with Events...
    SPI.transfer(buf, retbuf, cnt, eventResponder) which has been pulled in for the next beta and with it I was running into a hang as well, that was solved by adding in a call to yield();
    At first I thought it was timing, as delay(1) solved it, but then delayMicroseconds(1000) did not...

    Edit: just did a rebase operation on that branch... hopefully worked correctly - Also should point out that still not sure if these changes will actually make it in to the main line or not... And if so if the allocation of added buffer space for reads and/or writes will be done by separate methods like I have it or if, it gets added to the begin method.
    Last edited by KurtE; 08-14-2017 at 02:38 PM.

  7. #57
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    536
    I downloaded Paul's updates to the eventresponder (.h, .cpp and elapsedMillis) and also added a couple of yields. When it first starts it looks like it is doing the right thing:
    Code:
    EventResponder test
    loop trigger dosomething
    dosomething event
    oneshot timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
    loop trigger dosomething
    dosomething event
        what a wonderful world
    oneshot timer event
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
    loop trigger dosomething
    dosomething event
        what a wonderful world
    oneshot timer event
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
    loop trigger dosomething
    dosomething event
        what a wonderful world
    oneshot timer event
        what a wonderful world
        what a wonderful world
        what a wonderful world
        what a wonderful world
    Then it losses the longer duration timer event. Here is the code if you want to give it a try:
    Code:
    #include <EventResponder.h>
    
    EventResponder myevent;
    EventResponder mytimerevent;
    EventResponder mytimerevent2;
    EventResponder mytimerevent3;
    MillisTimer mytimer;
    MillisTimer mytimer3;
    MillisTimer mytimer2;
    
    void setup() {
      while (!Serial) ;
      Serial.println("EventResponder test");
      myevent.attach(dosomething);
      mytimerevent.attach(dotimer);
      mytimerevent2.attach(dotimer2);
      mytimerevent3.attach(dotimer3);
      mytimer2.beginRepeating(750, mytimerevent2);
      mytimer3.beginRepeating(550, mytimerevent3);
    }
    
    void loop() {
      Serial.println("loop trigger dosomething");
      myevent.triggerEvent();
      delay(8000);
    }
    
    void dosomething(EventResponderRef event)
    {
      Serial.println("dosomething event");
      mytimer.begin(550, mytimerevent);
    }
    
    void dotimer(EventResponderRef event)
    {
      Serial.println("oneshot timer event");
    }
    
    void dotimer2(EventResponderRef event)
    {
      Serial.println("  repeating timer event");
      yield();
    }
    
    void dotimer3(EventResponderRef event)
    {
      Serial.println("    what a wonderful world");
      yield();
    }

  8. #58
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    @paul, @mjs513 @defragster - I believe I know the first issue, which I will show in current millisTimer code:
    Code:
    void MillisTimer::beginRepeating(unsigned long milliseconds, EventResponderRef event)
    {
    	if (_state != TimerOff) end();
    	if (!milliseconds) return;
    	_event = &event;
    	_ms = milliseconds;
    	_reload = milliseconds;
    	addToWaitingList();
    }
    
    void MillisTimer::addToWaitingList()
    {
    	_prev = nullptr;
    	bool irq = disableTimerInterrupt();
    	_next = listWaiting;
    	listWaiting = this; // TODO: use STREX to avoid interrupt disable
    	enableTimerInterrupt(irq);
    }
    
    void MillisTimer::addToActiveList() // only called by runFromTimer()
    {
    	if (listActive == nullptr) {
    		// list is empty, easy case
    ...
    The problem is that when you call the beginRepeating twice, the code both times just puts the timer object into a static member listWaiting, so last one wins...
    This is assuming that the timer interrupt is not triggered in between the two calls. There may be other issues like this, still looking...

    Edit: Looks like the runFromTimer will run into similar issue as both will want to trigger and again add them self back in using addToWaitingList

    EDIT2: wrong on adding to list as using next pointer as a queue...
    Last edited by KurtE; 08-14-2017 at 03:46 PM.

  9. #59
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    Actually the more I look at the runFromTimer code, I think it may need some tweaking to properly handle multiple objects.
    Code:
    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;
    	}
    }
    That is the first while(timer) loop when you have two objects with in this example _ms will have 750 in it, the first item the value >0 so you decrement it, but do nothing with 2nd item.

    I think the 2nd part has to do with adding items to the list... And I was wrong on the first part as you are using the next pointer to hold the added items in a queue... So probably again issue with only first item being decremented...

    Edit+1 Actually looks like the code already decremented others in the list based off of the item before it in the list... Still checking...

    Edit ++++
    I understand more... (I think) - More of issues with the function:
    Code:
    void MillisTimer::addToActiveList() // only called by runFromTimer()
    {
    	if (listActive == nullptr) {
    		// list is empty, easy case
    		_next = nullptr;
    		_prev = nullptr;
    		listActive = this;
    	} else if (_ms < listActive->_ms) {
    		// this timer triggers before any on the list
    		_next = listActive;
    		_prev = nullptr;
    		listActive->_prev = this;
    		listActive = this;
    	} else {
    		// add this timer somewhere after the first already on the list
    		MillisTimer *timer = listActive;
    		while (timer->_next) {
    			_ms -= timer->_ms;
    			timer = timer->_next;
    			if (_ms < timer->_ms) {
    				// found the right place in the middle of list
    				_next = timer;
    				_prev = timer->_prev;
    				timer->_prev = this;
    				_prev->_next = this;
    				_state = TimerActive;
    				return;
    			}
    		}
    		// add this time at the end of the list
    		_ms -= timer->_ms;
    		_next = nullptr;
    		_prev = timer;
    		timer->_next = this;
    	}
    	_state = TimerActive;
    }
    That is the code is trying to setup something like: Suppose you had two timer values one at 500 and another at 750, What you want is the list like:
    listActive -> T1(500) -> T2(250) -> nullptr....
    So you count t1 down and then it is removed and the T2 counts down so it counts 500+250=750...
    This works if you first add the 500 handled by (listActive == nullptr) test and then add the 750 as it will not have timer->next so will add to end and will decrement it's count by the 500...

    However suppose you add it in the 750 one first followed by 500. The 750 is added by null ptr, now you call with 500, it is caught by the case:
    (_ms < listActive->_ms) which adds the new 500 item to start of the list, but it does not decrement the 750 item so it is still in at 750...

    Also same case if you have more than 2 items and the item is added in middle, it does not decrement the items after it by it remaining time.

    Got to run, will look into fixing later today if someone does not beat me to it.
    Last edited by KurtE; 08-14-2017 at 04:34 PM.

  10. #60
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    Hopefully I fixed the problem on my unified-serial branch of my fork.
    The fix went in with the commit: https://github.com/KurtE/cores/commi...aaef97eba8c1ce

    The issue was, when a repeating event is triggered, it adds the item back onto the active list. It properly finds the correct spot to place it. Suppose right after things were setup, you had the list like:
    MT3(250)->MT(300)->MT2(200)

    So for the next 250 tics nothing happens, but then it triggers... It then resets to 250 Calls the add again with MT(300)->MT2(200)
    It finds that it wants to add the item to start of the list and ends up again like: MT3(250)->MT(300)->MT2(200)

    So the ones after it get starved. What it needed to do was to decrement the next items time by it's remaining time, so the list should be: at this next time:
    MT3(250)->MT(50)->MT2(200)

    Same problem with the next add where MT3(250) it needed to all the add again with MT(50)->MT2(200)
    So it needed to update to have MT(50) -> MT3(200) -> mt2(0) (Actually in this case it will probably end up with MT3 at end with 0 and MT2(200), but ....

    @mjs513 - maybe see if it works for you .

    @paul - I can create a new branch for this if you would like and issue it as it's own Pull Request or can grab from the commit

  11. #61
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    536
    @KurtE, @paul, @defragster

    Looks like you broke the code, all timer events are firing with the example sketch above less the yields. Here is a sample output:
    Code:
    EventResponder test
    loop trigger dosomething
    dosomething event
    oneshot timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
    loop trigger dosomething
    dosomething event
      repeating timer event
        what a wonderful world
    oneshot timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
    loop trigger dosomething
    dosomething event
      repeating timer event
        what a wonderful world
    oneshot timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
    loop trigger dosomething
    dosomething event
      repeating timer event
        what a wonderful world
    oneshot timer event
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
        what a wonderful world
      repeating timer event
        what a wonderful world
    loop trigger dosomething
    dosomething event
      repeating timer event
        what a wonderful world
    ....
    Changing and reversing the trigger
    Code:
    mytimer2.beginRepeating(750, mytimerevent2);
      mytimer3.beginRepeating(950, mytimerevent3);
    I'm not sure is triggering properly - would have thought the "what a wonderful world" would show first then repeating event timer, but that may be me getting confused - OUTPUT:
    Code:
    EventResponder test
    loop trigger dosomething
    dosomething event
    oneshot timer event
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
        what a wonderful world
      repeating timer event
      repeating timer event
        what a wonderful world
    for the heck of it I add a fourth timer, the devil that I am, and it works:
    Code:
    EventResponder test
    loop trigger dosomething
    dosomething event
    oneshot timer event
        Teensy 3.5 rocks!
      repeating timer event
        what a wonderful world
        Teensy 3.5 rocks!
      repeating timer event
        what a wonderful world
        Teensy 3.5 rocks!
      repeating timer event
        Teensy 3.5 rocks!
        what a wonderful world
      repeating timer event
        Teensy 3.5 rocks!
        what a wonderful world
      repeating timer event
        Teensy 3.5 rocks!
      repeating timer event
        what a wonderful world
        Teensy 3.5 rocks!
      repeating timer event
        Teensy 3.5 rocks!
        what a wonderful world
        Teensy 3.5 rocks!
      repeating timer event
        what a wonderful world
        Teensy 3.5 rocks!
      repeating timer event
    loop trigger dosomething
    Heres is that code:
    Code:
    #include <EventResponder.h>
    
    EventResponder myevent;
    EventResponder mytimerevent;
    EventResponder mytimerevent2;
    EventResponder mytimerevent3;
    EventResponder mytimerevent4;
    MillisTimer mytimer;
    MillisTimer mytimer3;
    MillisTimer mytimer2;
    MillisTimer mytimer4;
    
    void setup() {
      while (!Serial) ;
      Serial.println("EventResponder test");
      myevent.attach(dosomething);
      mytimerevent.attach(dotimer);
      mytimerevent2.attach(dotimer2);
      mytimerevent3.attach(dotimer3);
      mytimerevent4.attach(dotimer4);
      mytimer2.beginRepeating(850, mytimerevent2);
      mytimer3.beginRepeating(1050, mytimerevent3);
      mytimer4.beginRepeating(750, mytimerevent4);
    
    }
    
    void loop() {
      Serial.println("loop trigger dosomething");
      myevent.triggerEvent();
      delay(8000);
    }
    
    void dosomething(EventResponderRef event)
    {
      Serial.println("dosomething event");
      mytimer.begin(550, mytimerevent);
    }
    
    void dotimer(EventResponderRef event)
    {
      Serial.println("oneshot timer event");
    }
    
    void dotimer2(EventResponderRef event)
    {
      Serial.println("  repeating timer event");
    }
    
    void dotimer3(EventResponderRef event)
    {
      Serial.println("    what a wonderful world");
    }
    
    void dotimer4(EventResponderRef event)
    {
      Serial.println("    Teensy 3.5 rocks!");
      yield();
    }
    Thanks
    Mike

  12. #62
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    536
    I know that this is early in the process but I decided to see what would happen if I combined the above example with the TeensyThread library test example. It would not compile with the following error:
    Code:
    C:\Users\CYBERP~1\AppData\Local\Temp\arduino_build_56842/core\core.a(EventResponder.cpp.o): In function `systick_isr':
    
    C:\Local Programs\arduino-1.8.3-KE\hardware\teensy\avr\cores\teensy3/EventResponder.cpp:324: multiple definition of `systick_isr'
    
    C:\Users\CYBERP~1\AppData\Local\Temp\arduino_build_56842\libraries\TeensyThreads\TeensyThreads.cpp.o:C:\Users\CyberPalin\Documents\Arduino\libraries\TeensyThreads/TeensyThreads.cpp:196: first defined here
    
    c:/local programs/arduino-1.8.3-ke/hardware/tools/arm/bin/../lib/gcc/arm-none-eabi/5.4.1/../../../../arm-none-eabi/bin/ld.exe: Disabling relaxation: it will not work with multiple definitions
    
    collect2.exe: error: ld returned 1 exit status
    
    Error compiling for board Teensy 3.5.
    This may be a problem if you use eventresponded in one of the other system libraries like SPI and try using SPI from within a thread. I know @tonton81 uses spi with teensythreads in his applications.

    Thanks
    Mike

  13. #63
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    Hi Mike,

    Not sure what exactly is going on in your example. Would probably have to map out all of the timings. Also as about calling yield(). My guess is it is not a good idea as you are in an interrupt handler at the time...

    To debug some of this earlier my version (not the one I uploaded) I added a member: dumpTimerList() which dumped the address of each item in the list plus timer value...

    Actually to test this more I would maybe have a tendency to instrument your code more, like maybe something like:
    Code:
    #define EVENT2_TIME 850
    ulong32_t event2_expected_time;
    ...
    mytimer2.beginRepeating( EVENT2_TIME, mytimerevent2);
    t event2_expected_time = millis() +  EVENT2_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;
    }
    This is typed on the fly so probably issues, but instead of random strings, print out time, which timer and how far it is off from what we expected...

    I may do something like this if no one beats me to it,

    As for using this with Thread library, does not surprise me as both are needing to get to the low level timer. As for SPI, currently unless you use the new API with event object, all SPI interfaces are Synchronous and wait until the operation is done before completing... Obviously it might be nice for other threads to be able to do stuff as this code is waiting for things like N bytes being fully transferred, but that is independent of this. However as for the new Async version, probably lots to test especially for threads and the like.

  14. #64
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    536
    Hi Kurt.

    Adding the timings was on my todo list for tomorrow. Had too many other things to do today and getting tired now .

    As for the teensythread library, SPI and events was just a guess on my part that there may be other conflicts when this gets implemented. Might say early warning - something to think about.

    Thanks for taking the time on this Kurt.
    Mike

    EDIT: Need to take my own advice. Eyes are closing when I did this so take with grain of salt. One thing I noticed is that when I got rid of the serial.println things started behaving nicer heres the output:
    Code:
    EventResponder test
    loop trigger dosomething
    dosomething event
    4117 - T0(2)
    4317 - T4(2)
    4417 - T2(2)
    4617 - T3(2)
    5067 - T4(2)
    5267 - T2(2)
    5667 - T3(2)
    5817 - T4(2)
    6117 - T2(2)
    6567 - T4(2)
    6717 - T3(2)
    6967 - T2(2)
    7317 - T4(2)
    7767 - T3(2)
    7817 - T2(2)
    8067 - T4(2)
    8667 - T2(2)
    8817 - T3(2)
    8817 - T4(2)
    9517 - T2(2)
    9567 - T4(2)
    9867 - T3(2)
    10317 - T4(2)
    10367 - T2(2)
    10917 - T3(2)
    11067 - T4(2)
    11217 - T2(2)
    loop trigger dosomething
    dosomething event
    11817 - T4(2)
    11967 - T3(2)
    12067 - T2(2)
    12117 - T0(7452)
    12567 - T4(2)
    12917 - T2(2)
    13017 - T3(2)
    13317 - T4(2)
    13767 - T2(2)
    14067 - T3(2)
    14067 - T4(2)
    14617 - T2(2)
    14817 - T4(2)
    15117 - T3(2)
    15467 - T2(2)
    15567 - T4(2)
    16167 - T3(2)
    16317 - T2(2)
    16317 - T4(2)
    17067 - T4(2)
    17167 - T2(2)
    17217 - T3(2)
    17817 - T4(2)
    18017 - T2(2)
    18267 - T3(2)
    18567 - T4(2)
    18867 - T2(2)
    19317 - T3(2)
    19317 - T4(2)
    Heres the code - give a try:
    Code:
    #include <EventResponder.h>
    
    #define EVENT2_TIME 850
    #define EVENT3_TIME 1050
    #define EVENT4_TIME 750
    #define EVENT0_TIME 550
    
    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;
    
    
    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;
    
    }
    
    void loop() {
      Serial.println("loop trigger dosomething");
      myevent.triggerEvent();
      delay(8000);
    }
    
    void dosomething(EventResponderRef event)
    {
      Serial.println("dosomething event");
      mytimer.begin(EVENT0_TIME, mytimerevent);
    }
    
    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;
    }
    Last edited by mjs513; 08-15-2017 at 04:06 AM.

  15. #65
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    Looks good!

    The T0 time is probably not set up correctly which is why you see a value like: 12117 - T0(7452)

    Since it is a do once type of timer, you probably need to change:
    Code:
    void dosomething(EventResponderRef event)
    {
      Serial.println("dosomething event");
      mytimer.begin(EVENT0_TIME, mytimerevent);
      event0_expected_time = millis() +  EVENT0_TIME;
    }
    As the expected time depends on when we call the begin method.

    I created a Pull request: https://github.com/PaulStoffregen/cores/pull/252

    I think it did solve most of the issues, that I saw,
    Last edited by KurtE; 08-15-2017 at 05:08 AM.

  16. #66
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    536
    Fixed the start timer0 as you showed worked fine. Ran a couple more variations including making two timers trigger at the same time and it worked fine no problem. Did try out seeing when the sketch would hang by changing the delay. With no delay it hangs, with a 1 ms delay sketch runs but nothing gets trigger, well actually something gets trigger but the numbers totally crazy, but wasn't really expecting to see anything trigger.

    Thanks
    Mike

  17. #67
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    Thanks Mike,

    @mjs513 - @Paul - Does the explanations like the below help... Or would you prefer to either debug yourself and/or a simple I think I fixed it, try it again...

    Now for the other issues with no delay and 1ms delay....

    I think they are more a robustness/verification issue, with a couple of different issues. First probably swamping USB Serial port. As the code reduces without thinking about events to something like:
    Code:
    void loop() {
      Serial.println("loop trigger dosomething");
      Serial.println("dosomething event");
    }
    ----------------

    Now if we are thinking about events, we have the issue of the link lists integrity: Again if we boil the code down and have now delays, we end up with something like:
    Code:
      mytimer.begin(550, mytimerevent);
      mytimer.begin(550, mytimerevent);
    ...
    The problem here is after the first call: We have the waiting queue: listWaiting -> mytimer -> nullptr
    Then we call the 2nd time: our begin function tries to detect this:
    Code:
    void MillisTimer::begin(unsigned long milliseconds, EventResponderRef event)
    {
    	if (_state != TimerOff) end();
    	if (!milliseconds) return;
    	_event = &event;
    	_ms = milliseconds;
    	_reload = 0;
    	addToWaitingList();
    }
    With the first test... Problem was the addToWaitingList did not update the state so we end up with circular loop: listWaiting -> mytimer -> mytimer ->...

    Hopefully easy fix: Set the state in addToWaitingList like:
    Code:
    void MillisTimer::addToWaitingList()
    {
    	_prev = nullptr;
    	bool irq = disableTimerInterrupt();
    	_next = listWaiting;
    	listWaiting = this; // TODO: use STREX to avoid interrupt disable
    	_state = TimerWaiting;
    	enableTimerInterrupt(irq);
    }
    -----

    Next issue: With short delay... My guess anything less than about 550...

    So again the first call works like before: and you have listwaiting -> myTimer -> nullptr .

    So with the delay the millis timer happens and the item is removed from the waiting list and put on the active list. Now if you have your other events that we added with values like T2=850, T3=1050 and T4=750... And for this conversation assume no timers have elapsed, you would have something like:
    listActive -> mytimer(550) -> T4(200) -> T2(100) -> T3(200)

    So in state != TimerOff so it calls end(), which removes it from the Active list:
    Code:
    void MillisTimer::end()
    {
    	bool irq = disableTimerInterrupt();
    	TimerStateType s = _state;
    	if (s == TimerActive) {
    		if (_next) {
    			_next->_prev = _prev;
    		}
    		if (_prev) {
    			_prev->_next = _next;
    		} else {
    			listActive = _next;
    		}
    		_state = TimerOff;
    	} else if (s == TimerWaiting) {
    		if (listWaiting == this) {
    			listWaiting = _next;
    		} else {
    			MillisTimer *timer = listWaiting;
    			while (timer) {
    				if (timer->_next == this) {
    					timer->_next = _next;
    					break;
    				}
    				timer = timer->_next;
    			}
    		}
    		_state = TimerOff;
    	}
    	enableTimerInterrupt(irq);
    }
    So I think it properly can remove the item from the list, BUT timings are screwed up:
    We have something like: listActive -> T4(200) -> T2(100) -> T3(200)
    So it will fire too early. As our 550 (minus how many tics happened) was not taken into account. So above code should probably be updated like:
    Code:
    void MillisTimer::end()
    {
    	bool irq = disableTimerInterrupt();
    	TimerStateType s = _state;
    	if (s == TimerActive) {
    		if (_next) {
    			_next->_prev = _prev;
                            _next->_ms += _ms;   // add in the rest of our timing to next entry...
    		}
    		if (_prev) {
    			_prev->_next = _next;
    		} else {
    			listActive = _next;
    		}
    		_state = TimerOff;
    	} else if (s == TimerWaiting) {
    ...
    I will try these changes out locally and if it does not look like it completely screwed things up, will upload to the patch branch I created.

  18. #68
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    Update: made the above changes and I believe they are working. So update Pull request: https://github.com/PaulStoffregen/cores/pull/252

    I tried with no wait and with delay 250... No wait hung as expected due to Serial messages, so I commented them out and it appears to work:
    Code:
    #include <EventResponder.h>
    
    #define EVENT2_TIME 850
    #define EVENT3_TIME 1050
    #define EVENT4_TIME 750
    #define EVENT0_TIME 550
    
    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;
    
    
    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;
    
    }
    
    void loop() {
    //  Serial.println("loop trigger dosomething");
      myevent.triggerEvent();
    //  delay(250);
    }
    
    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;
    }

    Edit: Side question... Wondering about timings...

    If you do code like:
    Code:
      mytimer.begin(EVENT0_TIME, mytimerevent);
      event0_expected_time = millis() +  EVENT0_TIME;
    And then during the event you compare the millis() with the expected time and we are appear to be always off by 2...

    As you can see by some of the output from above program:
    Code:
    785687 - T4(2)
    785837 - T3(2)
    785837 - T2(2)
    786437 - T4(2)
    786687 - T2(2)
    786887 - T3(2)
    787187 - T4(2)
    787537 - T2(2)
    787937 - T3(2)
    787937 - T4(2)
    Why? We wait for the next systick timer interrupt to move it from waiting to active (so here is +1) and then the runFromTimer only runs when _ms == 0 else decrements... So if we called to wait 1 ms. It would get the next systick after added to queue, decrement, wait for next systick and then run... So another +1
    Wonder if it maters.
    Last edited by KurtE; 08-15-2017 at 03:12 PM.

  19. #69
    Senior Member
    Join Date
    Jul 2014
    Location
    New York
    Posts
    536
    @KurtE - just tried your changes myself and looks like you got it. Like you said the Serial.prints kill the timing and it hangs. Was wondering about the delta of 2 all the time. Figured it was overhead, so I never mentioned it.

  20. #70
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    Put in quick update(hack) to handle the off by 2...

    Changed the begin and beginRepeating to decrement by 2 wait time > 2 else set to 0... Left the repeat time alone as the issue was on the first firing of the timer after started...
    Updated PR...

  21. #71
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    884
    Just to chime in: Some time ago I wrote an implementation of the observer pattern called signals: https://github.com/crteensy/Signals

    You can create a signal object that others can connect to. Both functions and methods can be connected. There has been some discussion, but I'm not sure if the examples given there still compile: https://forum.pjrc.com/threads/25460...d-slot-classes

  22. #72
    Senior Member manitou's Avatar
    Join Date
    Jan 2013
    Posts
    1,265
    Just as a cross reference, here is a thread discussing EventResponder interplay with overriding "weak" yield()
    https://forum.pjrc.com/threads/46442...h-void-yield()

  23. #73
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    4,347
    Isn't it possible to use that extended sysick only when the Event Responder is in use ?
    With redirecting the interrupt - only if an app uses the Event Responder - for example.

  24. #74
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    4,347
    Quote Originally Posted by Frank B View Post
    Isn't it possible to use that extended sysick only when the Event Responder is in use ?
    With redirecting the interrupt - only if an app uses the Event Responder - for example.
    I'd love to make patch and a pullrequest, tomorrow - if wanted. Are there any worries?

  25. #75
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,229
    I was going to suggest (and or do), maybe add the event responder code only after the first millis object is used...

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •