James Sullivan
Hi,

I have a simple project that transfers the state at input %IX1.5 to output %QX1.1. The main goal is to achieve a minimum delay between the positive edge of the input signal and the positive edge of the output signal (Fig.1).
I set the cyclic interval to 10 milliseconds and gave a signal of 10Hz (Fig.2), 15 Hz (Fig.3), 20Hz (Fig.4) and other frequencies (9Hz, 11Hz, 25Hz, 50Hz). It is seen that signal transfers uncorrect. I tried to set cyclic interval to 50, 20, 10, 5, 2, 1 milliseconds and 500, 200, 100 microseconds. But it didn't work.

What could you recommend? Maybe need to change some settings of Linux?

Project was working on the Raspberry Pi 3B+. Linux realtimepi 4.19.66-v7+. Raspbian GNU/Linux 9.11 (stretch).

0.png  1.png  2.png  3.png
Quote 0 0
thiagoralves
It is hard to have a good real-time behavior on Linux without proper configurations. I would suggest for you to have it running on a vanilla raspbian lite installation (without anything else installed). This usually will give you better results. Also, you can have a more deterministic response if you change the boot arguments to isolate one core (check https://www.linuxtopia.org/online_books/linux_kernel/kernel_configuration/re46.html 😉 and then change main.cpp config file to run the main OpenPLC task on the isolated core. Something like this on the REAL-TIME INITIALIZATION section should do the job:
//Set process affinity to core 1
  cpu_set_t mask;
  CPU_ZERO(&mask);
  CPU_SET(1, &mask);
  if (sched_setaffinity(0, sizeof(mask), &mask) < 0)
  {
    printf("WARNING: Error setting affinity of main thread\n");
  }
  if (pthread_setaffinity_np(pthread_self(), sizeof(mask), &mask) < 0)
  {
    printf("WARNING: Error setting thread affinity of main thread\n");
  }

This sample code makes OpenPLC main task run on core 1. If you had isolated a different core on the bootloader, please change the code accordingly, otherwise it will have no effect in improving your real-time behavior.

With those changes in place, I had pretty good results on a Raspberry Pi. A 10ms scan time should be easily achieved, with almost no deviations.
Quote 0 0
James Sullivan
Hi,

I tried what you recommend (by the way, instead of change main.cpp you can use `taskset` to set numbers of cpu for process).

Now I have question: how I can receive minimal delay between signal on the input GPIO and signal, which generation Raspberry when input signal was received, on the output GPIO?

Current results: at 1 ms and 10ms cyclic time project works incorrect. When I establish 10 Hz signal, projects repeats signal form (Fig. 2 at first item message), but on other frequencies it can't repeat signal properly (for exampe, 15 Hz and 20 Hz - Fig. 3-4 at first item message). Same situation on less frequencies 5-10 Hz.
Quote 0 0
James Sullivan
Maybe here "interrupt" mode needs? Then could Beremiz be better for this task?
Quote 0 0
thiagoralves
Interrupt definitely is the best way to have fast response from a signal. However, interrupt mode is not supported on OpenPLC. Beremiz's runtime is based on Python, and is pretty generic (i.e. not focusing on any platform in particular). This means that you'll probably have to write your own code on top of their runtime to control GPIO on the Raspberry, and that it won't work with interrupts either, at least not as a hardware interrupt. In fact, I don't think you will be able to have hardware interrupts on Linux at all, unless you modify the kernel.

That being said, I believe that there might be changes you can make to improve your response time. First, avoid setting the task cycle to anything less than 1ms. I believe something like 5ms would be ideal. Second, you can try to investigate if WiringPi (the library behind GPIO control on the Raspberry Pi driver for OpenPLC) has some faster methods to access GPIO, or even replacing WiringPi altogether with a faster approach (if there is one). Third, make sure your input signal is following the Nyquist rule based on your task cycle time, otherwise your output will be totally off.
Quote 0 0