11

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.

  • 4
    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
  • 4
    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: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
  • 1
    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
13

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)
  • 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
4

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.

  • 2
    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
  • 1
    "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
2

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.

  • 1
    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
1

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. :)

  • 1
    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 9:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.