13

I have to time the time difference between high -> low and low -> high signal edge on GPIO pins. I have written simple program that does this. After running it for some time I was quite happy with the result (0,01 s variations). But from time to time there was like 0,5 s error. I was thinking that this may be due to some other system process running at that time. So my question is:

Can I reserve one processor core just for my program and let other 3 cores for the system?

I'm using Raspbian Jessie Lite, so I think that 3 cores will be enough to run it.

NonStandardModel
  • 286
  • 2
  • 12
  • 5
    I assume you are polling in a loop for the status of the GPIO pin. This is highly susceptible to how the operating system decides to execute your program, that will spend most of its time keeping the CPU busy while doing nothing actually useful. You might want to look at a way to set up an interrupt on a given GPIO pin, which you can use to let your program sleep between signal edges on GPIO pins. – Florian Castellane Feb 14 '17 at 16:10
  • 5
    Unsure what your project it, but sometimes a Microcontroller is a better fit, especially when you need more a more realtime-like system. Arduino offers a lot of options, and you can write your program in C/C++. – SnakeDoc Feb 14 '17 at 17:15
  • @Florian There is an function in RPi.GPIO that is similar to interrupt. It will block the program until the edge is detected (source:https://sourceforge.net/p/raspberry-gpio-python/wiki/Inputs/). – NonStandardModel Feb 14 '17 at 18:31
  • @SnakeDoc I know that microcontroler is better. I was hoping to avoid it, because I do not need microsecond precision. 1/100 of a second is more than enough. Also I need just the time diff, so if there is a delay I was hoping that will be same for start and stop. If this doesn't work I have to go with microcontroler connected to RPi to store the data. – NonStandardModel Feb 14 '17 at 18:31
  • 2
    Or get a Realtime OS running on the PI. The problem with your setup, is it depends on a "best effort" by the OS. Depending what else is going on at the same time your program requests privileged access to the GPIO's, it may get queued up behind other tasks the OS is performing at that instant. You're userland program will get a lower priority than system tasks. There's also preemption, which means during your program's runtime it may be "paused and "set aside" by the OS for another process to run, meaning your timing observations might be skewed. – SnakeDoc Feb 14 '17 at 18:47
  • Most programs don't need that fine-grained control of timing, etc.. making general-purpose OS' just fine in most cases. There are also single-board systems that include a microcontroller as well as a full os on the same board (that can communicate together somehow), such as Udoo: http://www.udoo.org/udoo-dual-and-quad/ – SnakeDoc Feb 14 '17 at 18:50
  • Usually you do not need any additional tuning to avoid sub-0.01s delays. How does you program work? Maybe some blocking activity (like file i/o) in the same thread? Which language do you use? How do you manage GPIO pins? – edo1 Feb 14 '17 at 22:48
  • Not easily if you are using Rasbian. What language are you writing your program in? Real time as in microsecond accuracy is hard to do in a non-specialised OS. Within 10 milliseconds should be possible with most kernels although you do start to need special libraries for C. – TafT Feb 15 '17 at 08:54
  • First test was done with program writen in Python. I have made few corrections to this program but I have to test it. I started to work on a program in C, but right now I have to help to a coworker to finish his project so this is on hold. I do not need microsecond accuracy, 1/100 of a second is OK. – NonStandardModel Feb 15 '17 at 10:33
  • You don't tell us about the application other than ±10 milliseconds is OK, and ±500 milliseconds is not. Sometimes is is possible to use pretty inaccurate data to choose between several known-possible values. And sometimes you can discard events that you know had bad timing. Of course, if the length of the signal is an analog value you need to capture without dropping any values, that is more difficult. – Chad Farmer Feb 21 '17 at 00:11

4 Answers4

14

Dedicating a core is probably overkill.

I suggest you try my pigpio library. By default it will time GPIO level changes to within 10µs.

As a quick test I suggest you look at this Python example, which will print any GPIO level transition and the time in microseconds since the last transition on that GPIO.

pigpio is not installed by default in Jessie Lite. Either install the latest from the linked site or install the older version in the repositories.

sudo apt-get install pigpio python-pigpio python3-pigpio

pigpio - Library for Raspberry Pi GPIO control
python-pigpio - Python module which talks to the pigpio daemon (Python 2)
python3-pigpio - Python module which talks to the pigpio daemon (Python 3)
joan
  • 71,024
  • 5
  • 73
  • 106
  • I will try your pigpio library. Right now I have to finish another project, but I will go back to this. I will report back in few weeks. Thank you! – NonStandardModel Feb 14 '17 at 19:52
5

You can lock your program to one core using schedutils as described in this Cyberciti article:

sudo apt-get install schedutils
sudo taskset -c 3 -p 13545  # Lock PID 13545 to core 3

Other processes can still be scheduled on the same core, though. So the second thing to do is to make sure your command runs with the highest priority using the nice command (this will tell the Linux kernel that other processes should be pre-empted if necessary). Start your program in this way:

nice -n -20 your-program

There are some other possible reasons for your timing issues. These are not as easy to do anything about:

  • If you are programming in Python there is a garbage collector that sometimes pauses your program to free up unused memory.
  • Interrupts makes the CPU handle something else than you want. For example, network packets or other input/output.
  • If your program is sleeping a lot there might be other processes that fill up the CPU caches (L1/L2 cache). This forces you to wait for RAM access.
    • Even worse if your RAM is full so that your process gets swapped out to disk because SD cards are sloooow.

There are ways to make your process realtime, which means that it will run with certain timing guarantees. The problem with this is that everything else might be slower, and it is a complex topic. If you want to go down this rabbit hole I suggest you start reading up on real time processes in Linux.

  • 3
    Rather than nice it would be better to give the process real-time priority which would ensure it runs in preference to non-real-time processes. – joan Feb 14 '17 at 10:53
  • Good point, I'll add in a note about that. – Emil Vikström Feb 14 '17 at 11:18
  • 2
    "gc.disable()" what happens if you disable the garbage collector? – Keine Feb 14 '17 at 12:43
  • @Keine You can get a memory leak. Say that you have an object A that have a variable that points to B. Python will track this reference as a number, it knows that B have 1 object pointing towards it. Remove A when you don't need it anymore. The reference count for B will decrease, and if it hits 0 Python can free B too. This is called reference counting. But now say that B have a reference back to A. Now you have a cluster of objects pointing to each other. None of them will hit 0 and be freed. GC can find such clusters and remove them when the main program don't point "into" the cluster. – Emil Vikström Feb 14 '17 at 14:21
  • 1
    I will add the suggestions you made to my project. But I am hoping to avoid too complex topics. In that case I suppose it is better to make a microcontroler interrupt detection and connect it to RPi just for saving data. Thank you! – NonStandardModel Feb 14 '17 at 19:57
3

Since you are having timing requirements Raspberry Pi is no longer the appropriate platform for this. It is not a real time platform and timing can be thrown off by a lot of different sources of interference.

Instead you should use a microcontroller to measure this time, preferably using interrupts, and pass the information to the Pi later.

Maxthon Chan
  • 1,051
  • 7
  • 14
  • 2
    Isn't it possible to get interrupts on GPIO pins on a Raspberry Pi though? – Florian Castellane Feb 14 '17 at 16:11
  • Surely this depends on if there is any other part of the design requirements that makes a linux machine more appropriate than an MCU. RPi is able to handle this task fine, as is a MCU clocked at 10 MHz. – Sean Houlihane Feb 14 '17 at 17:13
2

As per you requirement I don't think you need to use a single core processor. What you need is to make sure your program runs all the time. To achieve that, you can set the priority of your program very high, so that it does not get disturbed by any other process.

As far as I know the OS (General Purpose OS), that we use are not designed to be used in real time systems, so if you want to run your process in real time so that no other process disturbs it, you need to go for a Real Time OS (RTOS). Maybe they will come up with core selection. :)

Bex
  • 2,929
  • 3
  • 25
  • 34
  • 2
    Are there good free RTOS out there? – Keine Feb 14 '17 at 12:51
  • RTLinux and Vxworks are examples of RTOS and they are good as well. But you need to study about OS(what was the focus for its creation) before installing, so that it can satisfy your needs. – Vishwajeet Vishu Feb 15 '17 at 09:00