Achieving low-latency UART communication on Torizoncore RT kernel

Dear comunity/support

We encountered some issues when using torizoncore image based on RT kernel. For our application we need to have an UART communication with the external MCU each millisecond. If there is no load on the kernel, these timing requirements are met, but when kernel is busy, a noticeable delay is observed, which is not acceptable.
Upon searching and reading the web, we found that this is a known issue and we are not the first ones to encounter it. It is related to the tty being pushed to the worker thread, thus loosing the realtime priority. Some earlier versions of kernel had the low_latency flag, but this was removed, more info here.
So, in essence to solve this issue, kernel needs to be modified in such a way that a dedicated workqueue is created for tty which in turn allows us to give it real-time priority without affecting the entire worker thread. So far so good, but since we are relying on the torizoncore image, rebuilding the entire kernel is out of the question. The only approach we can take is modifying the existing kernel source files, compiling and linking with imx.c file and then using that as a loadable kernel module.
This is where the problems arise, mostly because it is not easy to pry off the tty source files and compile them independently. There are a lot of dependencies that go into the deeper levels of kernel. Torizoncore builder is very user friendly, with tcbuild.yaml file entry “source-dir:” which points to the module source dir, but when build command is called, I’m not entirely sure what goes on under the hood. For example, does torizoncore rebuild the modified core files and links them with the driver, or does it have them already compiled and just links against them. In our case, tty_io.c, tty.h and tty_buffer.c need to be modified.
When using only imx.c source as a module, it builds successfully, but when adding and compiling the files from CONFIG_TTY linker typically complains about symbols being exported twice. This is why I suspect that these files are already compiled somewhere.
So, my question is how to override this and get the UART module to build successfully with modified source files? If you have a better solution or suggestion for a different approach, that is also appreciated.

We are using kernel: 5.15.77-rt53-6.3.0 on Verdin iMX8M Plus.

Best regards,

Marin

1 Like

Hi @Marin ,

On TorizonCore 6.3.0 for the Verdin iMX8M Plus CONFIG_TTY appears to be built into the kernel image (option y):

torizon@verdin-imx8mp-14777535:~$ uname -r
5.15.77-6.3.0+git.ddc6ca4d76ea
torizon@verdin-imx8mp-14777535:~$ zcat /proc/config.gz | grep -i CONFIG_TTY
CONFIG_TTY=y
# CONFIG_TTY_PRINTK is not set

I’m not really sure if it is possible to override the existing built-in component and use your modified files loaded as a module. I don’t know how the kernel will behave with two components with presumably the same name.

While you can try using TorizonCore Builder to load the modified driver, we don’t recommend it for this specific purpose as it wasn’t created with this use-case in mind.

I would say that rebuilding the kernel seems to be the safest alternative, although that will require building TorizonCore from source with Yocto, given that TorizonCore Builder can’t modify the kernel itself. You can check this article for more details about it:

Best regards,
Lucas Akira

1 Like

Hi @lucas_a.tx,

thanks so much for your answer. We are avoiding Yocto and sticking to the official release of TorizonCore, although for some of the customizations needed, Yocto would certainly make life easier. Main reason being the stability of TorizonCore official releases.
There is one more option I’m investigating, and that is building the module in Yocto with a static flag, so that it doesn’t require any runtime dependencies, and than copying it and loading it on TorizonCore system. Let me know what do you think about this idea.

Best regards,

Marin

Hi @Marin ,

You can try doing the static build to avoid the dependency problems, although there is still the potential name conflict issues that you might have with the built-in driver.

If you want to try loading your modified version of the components as a module (built with Yocto or TorizonCore Builder), I have a suggestion: You can also use a different name for your module to avoid conflicts with the built-in version, but this would also require changing the corresponding compatible fields in your device tree to refer to the new name.

Keep in mind that I didn’t test this suggestion, so I’m not even sure if it will work. Please take it with a grain of salt.

Though I understand your reason to avoid building a custom version of TorizonCore with Yocto, I’d still recommend going this route when modifying anything built into the kernel.

Hope this helps.

Best regards,
Lucas Akira

Thanks @lucas_a.tx , we’ll still need to decide what is the best way to focus our efforts, but I can mark this as a solution, because the options are very clear now.

Best regards,

Marin