Make a precise Timer with 1ms

Hi,
I’m looking to execute some commands very timing accurate for my next project (RasPi command line app).
I startet with the Timer object first and recognized that this is not precise.
The timer should “fire” every 10ms but with a accuracy of 1ms.
So I went to request in a while(true) the microseconds like this:

[code]var millis, millis_syncStart as Double

millis = System.Microseconds / 1000
millis_syncStart = millis

while (true)
millis = System.Microseconds / 1000
if millis > millis_syncStart + 10 then
millis_syncStart = millis
// 10ms is over NOW
//DO ACTION
end if
app.DoEvents(1)
wend[/code]
The problem now is, that it’s very CPU consuming … is there any better solution to do a timer within a while loop with less CPU consumption?
Or maybe any totally other solution?
Thank you very much, Markus.

I think MBS plugins may help

https://www.monkeybreadsoftware.net/global-delaymbs.shtml
Your best bet would be to use it in a ConsoleApplication in the run event you make a loop that calls this

Try adding ‘#PRAGMA DisableBackgroundTasks’ at the beginning of your code. That might help a little.

Bear in mind that the Raspbian OS is not intended for real-time operations.
For close to real-time you would be better off using an Arduino - if accuracy is really critical.
Of course the language and IDE is very different and a somewhat steeper learning curve :slight_smile:

This article may help you get into the nitty-gritty of more accurate timing using a Raspberry Pi: https://www.studica.com/blog/raspberry-pi-timer-embedded-environments

[quote=481211:@Robin Lauryssen-Mitchell]Try adding ‘#PRAGMA DisableBackgroundTasks’ at the beginning of your code. That might help a little.

Bear in mind that the Raspbian OS is not intended for real-time operations.
For close to real-time you would be better off using an Arduino - if accuracy is really critical.
Of course the language and IDE is very different and a somewhat steeper learning curve :slight_smile:

This article may help you get into the nitty-gritty of more accurate timing using a Raspberry Pi: https://www.studica.com/blog/raspberry-pi-timer-embedded-environments[/quote]

This link should work:
https://www.studica.com/blog/raspberry-pi-timer-embedded-environments

you can set the affinity for your process. So that a single core is used for a single xojo (console application) process only. We use that for some advanced stuff. You can configure the Raspberry pi to do so. Then your console app has a full core for itself.
If you need more info about his, and are into advanced rpi stuff let me know.

Thank you for all your replys! I’m currently have a look to all of them.

[quote=481209:@Derk Jochems]I think MBS plugins may help

https://www.monkeybreadsoftware.net/global-delaymbs.shtml
Your best bet would be to use it in a ConsoleApplication in the run event you make a loop that calls this[/quote]
Looks interesting, the thing is - I really would like to understand what a Timer is doing instead of my while loop.
Is there a difference between a timer and such a while solution with doevents?
It’s just for my understanding that I can better know what the CPU is really doing :slight_smile:

[quote=481211:@Robin Lauryssen-Mitchell]Try adding ‘#PRAGMA DisableBackgroundTasks’ at the beginning of your code. That might help a little.

Bear in mind that the Raspbian OS is not intended for real-time operations.
For close to real-time you would be better off using an Arduino - if accuracy is really critical.
Of course the language and IDE is very different and a somewhat steeper learning curve :slight_smile:

This article may help you get into the nitty-gritty of more accurate timing using a Raspberry Pi: https://www.studica.com/blog/raspberry-pi-timer-embedded-environments[/quote]
I’m working a lot with Arduino, too - But here it is too complex to use it. I’m going to build a show lighting control and so I need much more power than the Arduino can provide.

[quote=481215:@Derk Jochems]you can set the affinity for your process. So that a single core is used for a single xojo (console application) process only. We use that for some advanced stuff. You can configure the Raspberry pi to do so. Then your console app has a full core for itself.
If you need more info about his, and are into advanced rpi stuff let me know.[/quote]
That’s a nice way - Do you have something I can read about how to achieve this?

Good to know you are finding solutions to the problem Markus.
Derk does good things with Raspberry Pi’s :slight_smile:

1 Like

I’ll lookup the stuff for your requirements. You’d need to change the /boot/cmdline.txt to define what cores to be used by the raspbian installation (or any other for that matter). And basicly call a shell command (from within Xojo) to set the affinity (what core you want your process to be in).

I’ll update this topic once i have a set of information.

(NOTE cmdline.txt shoud be a SINGLE line, so without linebreaks.)
So basicly you have to change the /boot/cmdline.txt and add this to it using (“sudo nano /boot/cmdline.txt” for example):

so if the default /boot/cmdline.txt would be:

your new /boot/cmdline.txt would be:

This isolates cpu core index 3 (it begins with 0 up to 3, as it’s 0-based)

Information can be found here: Raspberry Pi: Isolating Cores in linux kernel (yosh.ke.mu)

Then in your application you use this method to set the cpu affinity (or process to a specific core):

Private Sub SetCPUCoreAffinity(CoreIndex As Integer = 0)
  Var sh As New Shell
  sh.ExecuteMode = Shell.ExecuteModes.Synchronous
  sh.Execute("pidof "+App.ExecutableFile.Name)
  
  If sh.ExitCode = 0 Then
    
    Var pid As String = sh.Result
    
    If pid = "" Then 
      
      System.Log(System.LogLevelCritical, "PID of process name "+App.ExecutableFile.Name+ " was not found." )
      Return
      
    End If
    
    Select Case CoreIndex 
    Case 0,1,2,3
      sh.Execute("sudo taskset -pc "+CoreIndex.ToString+" "+pid) 
      // this sets the cpu defined as an number to have only the process with pid as it's processid
    Else
      System.Log(System.LogLevelCritical, "Setting CPU Affinity for Core "+CoreIndex.ToString+" Failed, invalid CoreIndex given.")
    End Select
    
    If Sh.ExitCode = 0 Then
      
      Var res As String = sh.Result
      System.Log(System.LogLevelCritical, "Setting CPU Affinity for Core "+CoreIndex.ToString+" Success.")
      Return
      
    Else
      // Taskset exitcode failed.
      System.Log(System.LogLevelCritical, "2) Setting CPU Affinity for Core "+CoreIndex.ToString+" Failed.")
    End If
    
  Else
    // pidof exit code failed
    System.Log(System.LogLevelCritical, "1) Setting CPU Affinity for Core "+CoreIndex.ToString+" Failed.")
  End If
  
End Sub

In your App.Open (or App.Run) on the top you call:

SetCPUCoreAffinity(3) // Add this process to core index 3. 
//(the method will isolate the executable that calls this method to the given core index)

Now the (console) application has much better precision. It’s best to have a loop doing only what it should be doing. It will come VERY close the the Arduino timing results. The best way to have it have as low as possible CPU is -as always- the MBS plugins.

https://www.monkeybreadsoftware.net/global-delaymbs.shtml

Function Run(args() as String) Handles Run as Integer
  // You should somehow set KeepRunning = False somewhere, maybe use a Mutex to control this.
  Var KeepRunning As Boolean = True
  
  #Pragma BackgroundTasks False
  While KeepRunning
    
    // Check something here:
    If KeepRunning = False Then
      Print("how did we get here?!?") //<-- should never happen
    End If
    
    // Delay this process for 0.1 second
    DelayMBS(0.1) //<-- should keep the cpu pretty low.
    // There is also a DelayMBS function with a mode that yields.
    
    // If you use classes and events then uncomment the following:
    // App.DoEvents(0) // Note this may create delay and loss of precision
  Wend
  #Pragma BackgroundTasks True
  
  Return 0 // <-- program finished
End Function

More information about taskset:
https://linux.die.net/man/1/taskset

[quote=481226:@Derk Jochems]More information about taskset:
https://linux.die.net/man/1/taskset[/quote]
Whooow thx Derk for your time on sunday for giving me such a great explanation!

No thanks, it will help others too. And since we all need something to do these days…

Did you try TimerMBS class?

The problem with classes (async) is that you need App.DoEvents(0)* in console applications, which in terms give a HIGH CPU %
The average of an idle Xojo process is 5-7% which may be alot for pi-based solutions. At least i did not test this, as it’s async. For say high precision pi is not the best, but having a specific core for a (xojo console application) process comes very close to an arduino in terms of precision.

  • App.DoEvents(0) will give high cpu and App.DoEvents(10) for example gives loss of precision.

can’t you separate the work : let the arduino do the time rigid tasks, and let the raspberry do the rest ?
I suppose the 1ms timer is to synchronize with the mains frequency ?
so you could make a small arduino that handles the mains synchronisation, and the Pi just send a value 0-255 to the arduino
and the arduino lights up the required value to the corresponding lamp, doing the precise timing by itself ?

In one of my apps I have different modes.
So when we are idle, we use 10 ms wait time.
When there may be work coming, we set to 1ms and if we are working, we use 0ms.

Works fine here and keeps the app using low CPU usage when doing nothing, but speed up, when data is processing.