Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

Timers not working right, more or less at the speed of light

netmf timers timing

  • Please log in to reply
10 replies to this topic

#1 Emilio x64

Emilio x64

    Advanced Member

  • Members
  • PipPipPip
  • 40 posts

Posted 08 August 2013 - 11:01 PM

In my NETMF application I make use of two types of Timers from System.Threading (is there a better one?).

 

One timer actually times the period of time a button is depressed, if it is less than 2 seconds X happens but if it is pressed for more than 2 seconds then Y happens. This is common in embedded devices.The timer is started when the NETMF application detects that the GPIO pin has gone low (active low) and it also detects when the button is released when the GPIO pin goes high. I am using I/O interrupts on both edges to detect the press/release.

 

The other timer is a loop processing timer which is used to periodically do the processing of signals and state transitions of my state machine. When a button is pressed for example a Pressed signal is put into the queue and at the next processing loop the signal is picked up from the queue and processed according to the state.

 

Now, I also found out that in NETMF Timers aren't what we are used to in the standard framework, namely that you can't start/stop them the usual way, they start as soon as they are created (unless a delay is specified) and they keep on running forever. The only way to stop it is by Disposing the timer instance and setting it to null so that it is garbage collected. I use 2000 (milliseconds) for the button press/release and originally used 200 ms for the loop processing.

 

Now, I am testing my "virtual device" and see that even if I click quickly on the button (much less than 2 seconds) the timeout signal is raised as if I had pressed the button for more than 2 seconds!!!

 

Am I missing something here? is there perhaps some NETMF setting that controls the time base of the timers? it appears to me that they are running at the speed of light and therefore what is supposed to be 2 seconds turns out to be more like 100 milliseconds!



#2 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 09 August 2013 - 03:06 AM

Hi degt, Can you simplify this a bit, as ten lines of code or less, and share it here? Then we can help you analyze the code and figure out what's going on with you. Chris

#3 Nevyn

Nevyn

    Advanced Member

  • Members
  • PipPipPip
  • 1072 posts
  • LocationNorth Yorkshire, UK

Posted 09 August 2013 - 06:18 AM

Doesn't one of the arguments in the button event/interrupt give you the time an even occurred?

 

You are right about Timers running forever.  I found that out earlier this year and ended up writing a post about it.

 

Regards,

Mark


To be or not to be = 0xFF

 

Blogging about Netduino, .NET, STM8S and STM32 and generally waffling on about life

Follow @nevynuk on Twitter


#4 Emilio x64

Emilio x64

    Advanced Member

  • Members
  • PipPipPip
  • 40 posts

Posted 09 August 2013 - 03:34 PM

Doesn't one of the arguments in the button event/interrupt give you the time an even occurred?

 

You are right about Timers running forever.  I found that out earlier this year and ended up writing a post about it.

 

Regards,

Mark

 

Perhaps it does in the emulator application but that information is AFAIK not available on the NETMF application because it doesn't receive a button event.



#5 nakchak

nakchak

    Advanced Member

  • Members
  • PipPipPip
  • 404 posts
  • LocationBristol, UK

Posted 09 August 2013 - 03:55 PM

Pretty sure you get a timestamp with the Interrupt port handler, cant remember if the value is ever initialised though, if memory serves me correctly the time is from power on of the board.  The Advanced Button App in the projects section of the site certainly has the third argument of the handler as a DateTime.

 

Nak.



#6 Emilio x64

Emilio x64

    Advanced Member

  • Members
  • PipPipPip
  • 40 posts

Posted 09 August 2013 - 04:24 PM

Chris, here are some code snippets relevant to the problem at hand...

class AnyController {private mTimerTransfer;private mTransferTimedOut = false;private void StopTimer(TimerID id){    switch (id)    {        case TimerID.TransferTimer:            if (this.mTimerTransfer != null) {                mTimerTransfer.Dispose();                mTimerTransfer = null;           }           break;              :    }}private void StartTimer(TimerID id, int msDelay, int msPeriod){    switch (id) {       case TimerID.TransferTimer:           mTimerTransfer = new Timer(new TimerCallback(ActionTimers_Tick), TimerID.TransferTimer, msDelay, msPeriod);           mTransferTimedOut = false;           break;            :    }}} // class

Then my Timer event handler on the above class looks like this. It handles several timers but they have the same mechanism so I show only one for brevity.

private void ActionTimers_Tick(object sender){    StopTimer((TimerID)sender);    Signals timeoutSignal = Signals.NoOp;    // an enumeration of all signals in the S.M.    switch ((TimerID)sender) {       case TimerID.TransferTimer:          timeoutSignal = Signals.TimeoutTransfer;          mTransferTimedOut = true;    // used to discard the signal if necessary          break;           :    }    if (timeoutSignal != Signals.NoOp) {        mSignalQueue.Enqueue(timeoutSignal);    // of type Queue    }}

Now the Program.cs class in my NETMF I have rigged it so that the TRANSFER button generates a GPIO interrupt on the leading (going low, pressed) and trailing (going high, released) edge. That works well. So there when the interrupt occurs on the leading edge I call the TransferPressed() method on the above class, and TransferReleased() when it is released. These methods are implemented like this in the above class:

class AnyController {  :  public void TransferPressed() {     lock (this.mLock) {         mSignalQueue.Enqueue(Signals.TransferPressed);     }  }  public void TransferReleased() {      lock (this.mLock) {           StopTimer(TimerID.TransferTimer);  // asap           if (!this.mTransferTimedOut)               mSignalQueue.Enqueue(Signals.TransferReleased);           else               this.mTransferTimedOut = false;   // signal is discarded      }  }

And here is the processing of the main timer loop (not seen in the definitions) which executed every 200ms (even tried 75ms) and is in charge of processing the events and state transitions, a state machine... Here shown to the bare minimum for the purpose of clarity showing the mechanism I am using.

private void ControllerTimer_Tick(object sender){     Signals rxsignal = Signals.NoOp;     if (mSignalQueue.Count > 0)         rxsignal = (Signals)mSignalQueue.Dequeue();     switch (this.mState)     {         case States.SomeStateA:              if (rxsignal == Signals.TransferPressed) {                   StartTimer(TimerID.TransferTimer, 0, 2000);  // no delay, 2000ms period              }              else if (rxsignal == Signals.TransferReleased) {                   StopTimer(TimerID.TransferTimer);                   Swap();   // does action related to pressing less than 2 secs              }              else if (rxsignal == Signals.TimeoutReleased) {                   mState = States.OtherState;              }              break;     } // switch state}

That may deserve some extra explanation. The Program NETMF class rigged the GPIO to cauase an interrupt on the leading (going low, pressed) and trailing (going high, released) edges of the GPIO and that is detected properly. When that detects a button pressed associated to that GPIO (The TRANSFER button) it invokes the TransferPressed() public method in the AnyController class. That in turn ALWAYS queues the TransferPressed signal into the signal queue.

 

Now, as I indicated in the OP, if the button is pressed less than 2 seconds it does the standard action, in this case Swap() and remains on the same state. If on the other hand the button is pressed more than 2 seconds the ActionTimers_Tick() event handler would STOP the one shot timer that times the button press AND raises the timeout by putting the TimeoutTransfer signal on the signal queue. It also flags that it has timed out on the mTimedoutTransfer.

 

So, why is that you may ask? well, when the button is pressed more than two seconds the TransferTimeout signal is on the queue, since the button was pressed for more than 2 seconds, the next time in the main processing loop (ControllerTimer_Tick()) it will initiate a state transition. That means that in that particular case the release of the Transfer button would happen AFTER the timeout, and I don't want that release event (related to the timeout) to be passed to the signal queue because it would cause the new state to pop back to the original state (not show) because it also processes the Transfer button. So, what I do in AnyController.TransferReleased() is that IF the mTimedoutTransfer boolean is set then the signal is discarded (note, there might be another press/release pair on the new state), if it is not set (not timed out) then the TransferRelased signal is put on the queue.

 

So, that is the scheme but the problem as I mentioned is that these timers seem to  be working at a frequency of Terahertz or something like that because even if I set the timer to expire at a period of 2000 ms (2,000 ms == 2 secs) and have a time between press/release of MUCH LESS than 2 seconds (not even close, even less than a second) the timer times out first than the release and TransferTimeout signal is processed.



#7 Emilio x64

Emilio x64

    Advanced Member

  • Members
  • PipPipPip
  • 40 posts

Posted 09 August 2013 - 04:54 PM

BTW I added a few Debug.Print() statements to the timer code, first with the standard date format and got that the Start, Stop AND Timeout occurred on the same second (34). 

 

Then I went on to be more accurate and instead print the Milliseconds property of DateTime.Now and this is what I got:

ID_PORT_XFR pressed> TransferPressedXFER TMR Start 663XFER TMR Stop 665XFER TMR TimedOut 665> TimeoutTransfer

The ID_PORT_XFR pressed output was produced by the Program class on its GPIO Interrupt method. The > TransferPressed/TimeoutTransfer output was produced by the main processing loop (ControllerTimer_Tick()) when it gets the signal from the queue.

 

So that confirms that the base frequency of the timer is running at the speed of light where a millisecond is much much much shorter. Where do I set those base timing things as applicable to the Netduino Plus 2 board?



#8 Chris Walker

Chris Walker

    Secret Labs Staff

  • Moderators
  • 7767 posts
  • LocationNew York, NY

Posted 09 August 2013 - 05:08 PM

Hi degt, Wow, that's a lot of info :) I can see that you've put quite a bit of work into this app. If you can boil that down to a ten line program (or a few more lines if absolutely necessary to exhibit the issue), we'll be happy to take a look at it. There are a lot of different moving parts in your larger snippets (including thread synchronization) which could be interacting in odd ways...so making a simple repro for the issue will help figure out what's going on. Chris

#9 Emilio x64

Emilio x64

    Advanced Member

  • Members
  • PipPipPip
  • 40 posts

Posted 09 August 2013 - 07:50 PM

I am convinced it has to do with the base timer time cycle. As you can see from the debug output that while the timer has been programmed for a time period of 2,000 ms (2 secs) it is expiring (timed out) in three (3) milliseconds, that is quite a difference.

ID_PORT_XFR pressed 582TransferPressed 586> TransferPressedXFER TMR Start 591XFER TMR Stop 593XFER TMR TimedOut 593> TimeoutTransfer 596

From this latest timing, we have the following with the time given in milliseconds:

 

@ 582ms the Program class receives a GPIO Interrupt signaling the TRANSFER button was pressed

@ 586ms the Controller class' TransferPressed() method is called, it puts TransferPressed signal into the queue

@ 591ms the Controller class' main loop (state machine) receives the TransferPressed signal and starts the timer for 2,000 milliseconds

@ 593ms the Controller class' ActionTimers_Tick() handler receives the timeout and stops the 2,000 ms timer and the

                TransferTimeout signal is put out on the queue

@ 596ms the Controller class' main loop (state machine) receives the TransferTimeout signal and processes it.



#10 Emilio x64

Emilio x64

    Advanced Member

  • Members
  • PipPipPip
  • 40 posts

Posted 09 August 2013 - 08:47 PM

Also tried by adding this in my emulator.config of the custom emulator project (the code shown above is all in the .NET MF project, not the emulator).

<Emulator>  <Types>    <TimingServices>Microsoft.SPOT.Emulator.Time.TimingServices</TimingServices>  </Types>  <EmulatorComponents>     <TimingServices id="NetduinoPlus2_TimingSvcs">        <SystemClockFrequency>168000000</SystemClockFrequency>     </TimingServices>  </EmulatorComponents></Emulator>

did that in hope that the emulator that runs my project would adjust its timing to 168MHz (Netduino Plus 2) but the result is the same...

 

I can follow what NakChak suggests, using the timestamp (in ticks since powerup) provided on the interrupt callback and pass that down the chain and then compare the initial timestamp with the last (release) timestamp to check if it was more than 2000 ms but that would simply be a workaround, the underlying System.Timer should provide realistic, reliable timing services.

 

Though I could not measure very accurately it appears to me (using a chronometer) that a press/release period of about 2 seconds translates to a NETMF "millisecond" difference of 331 against the expected 2,000.



#11 Emilio x64

Emilio x64

    Advanced Member

  • Members
  • PipPipPip
  • 40 posts

Posted 10 August 2013 - 07:18 PM

Changing my SystemClockFrequency to 1.000.000 resulted in the timestamps (passed in the interrupt) to be more realistic though with it a 3./ second push is seen as 2 seconds but the Timer keeps on expiring right away...







Also tagged with one or more of these keywords: netmf, timers, timing

0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.