Showing results for 
Search instead for 
Did you mean: 

Using a call library function node to access cpu register?

I am trying to implement watchdog timer functionality into my LabVIEW program. I'd like to read the watchdog timer register, which has an I/O address E85h (0xE85) from my LabVIEW program using a call library function node.


I am running RHEL 8.0 (Linux) and LabVIEW 2019 on a single board computer.


My computer's manual, specifying the watchdog register address and setup is on page 64 here:


I wrote the following C code to read the register (not 100% sure if this is correct):



#include "watchdog.h"

#include <stdio.h>


#define watchdog_addr 0xE8B


int readWD() {

int c;

c = (*(volitile int *) watchdog_addr);





extern int readWD();


I created a .so file using the C code above and wrote a simple VI that uses a call library function node to display the variable c.


LabVIEW crashes when I try to run it.


I have experience with call library function nodes and general C code, but not with read/writing registers from C or LabVIEW.


Any help would be appreciated.



0 Kudos
Message 1 of 9

"Any help would be appreciated."


I am not going to be of much help since I have not developed code for Linux since it was called Unix.


Wild guess is all I can offer.


Accessing hardware may (most likely) require you be in Kernal mode (if that is what they call it in Linux) which requires privledges (of course). Additionally the "call Library" defaults to the User Interface thread so maybe try "run in any thread".


Driver development wizard may also be worth looking at.



Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 2 of 9

Applications are running in ring 3 of the x86 CPU architecture which is user space. In this level access to many things are restricted or simply forbidden. That includes certain CPU instructions as well as any access to physical addresses, be it memory or IO addresses.

Only code running in ring 0 has the privilege to execute such operations. On Linux (and Windows) the kernel is running in Ring 0 and only code that runs in the context of the kernel has therefore the right to do this. This means that in order to access your physical address you have to have some form of kernel device driver that is loaded and initialized by the kernel itself. There are probably ways to install a generic IO device driver that could be configured to open up certain addresses to a user space but this is not such a good idea as such a generic IO device driver could be abused by other software for less than bonafide purposes. It is almost like shooting a big hole into the security provisions of the separation of the system into kernel and user space. Any software that is aware of this driver can then use it to do just about anything it may wish, from accessing the disk IO controller to wipe your drive to reprogramming the power regulations for your CPU power to fry your CPU beyond repair. Or do much more stealthy things that nobody would want to have on his system.

The only proper way nowadays is to write a real kernel driver that is accessing the specific addresses for your hardware and install it. This kernel driver can be then accessed from user space as a device through standard file IO and depending on the implementation it could provide a stream based interface that can be accessed through read() and write() calls, or it can use ioctl() calls that are specific to your driver.


Basically to access hardware from LabVIEW (or any other application level software, except possibly a simple C program that calls directly the device IO functions) you have in any modern OS to have a device driver that can run in the kernel,  and a user space shared library that provides a meaningful API to your driver in the form of functions and in those functions calls into your device driver through device IO calls. This is principially the same for Windows and Linux although the actual device IO calls to use are of course very different (and the implementation of a device driver is totally different for them).


In your approach you try to access the virtual memory address 0xEB8, because virtual addresses is all a user space software can acces. Such a low virtual address is often not mapped to any valid memory as such low addresses are indications that a software tries to access bad memory and by not mapping them into a process they will simply generate an access violation interrupt in the CPU. The virtual memory is mapped to physical memory through the memory management unit, which sets up address translation for this based on the OSes request when a process requests new memory. The physical memory address is however only accessible from the kernel, but you don't want to access physical memory but rather physical IO space and that is through special CPU opcodes that are protected to only be executable from ring 0 software too.


The times when you could do an INS opcode from your application software are long gone. That worked for DOS  and Windows 3.1 software and to some extend even Windows 9x, but with the introduction of Windows NT that was definitely something from the past. Linux being based on a fully protected mode model too, had basically from start a separation into the kernel mode and user space mode.

You may possibly come across this possibility in some legacy realtime kernels too, but most modern software including realtime OSes nowadays use a software model that clearly separates the system into a kernel that runs in a higher priviledge mode and a user space that has many restrictions in what it may do. And that is on a subsantially lower level than any user right management with admin/root and normal users as it is directly implemented in the CPU hardware itself.

Rolf Kalbermatter
DEMO, TU Delft
My Blog
Message 3 of 9

LabVIEW Real-Time includes a Watchdog Timer, described here.   Depending on your needs and the rest of your code, you could also implement it as a parallel asynchronous loop with your own code.


Bob Schor

0 Kudos
Message 4 of 9

Thanks for the updated insight Rolf!


Nice to know that studying VMS internals and Data Structures 30 years ago is still paying off.


An updated version of a joke about what if Airlines were like Operating Systems found here.


I stepped away from the low level stuff when VMS and Unix were the thing.


I bring up the OS joke since the deal with Linux was it was possible to modify the OS. While this is not a LINUX support board, I would tend to believe a brave soul could spin-off a version of Linux that did offer the required services to expose reading a register as you described.


So it is not a LabVIEW question but more a Linux question.



Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 5 of 9

There is certainly a possibility to write a generic IO kernel driver. There are of course various complications as you are not supposed to capture any IO space that has been captured by other kernel drivers already, or might need to be captured by drivers that load after yours, etc. etc. or very strange things can happen. Given this it is actually quite complicated to write a useful generic IO driver. Also you would not want this driver to allow access to everything so there would need to be some configuration needed which needs to be protected too. There have been several attempts in the past on something like this, also for Linux. In Windows 32-bit there is a depreciated kernel API that can be accessed by a kernel driver. The CVI device driver at the basis of the old LabVIEW Memory and IO VIs used that kernel API. Windows 64-bit has axed that kernel API so the porting of this functionality to LabVIEW for 64-bit was basically complicated and would have required a completely new device driver. As this functionality is nowadays anyways considered a pretty unsafe and hence bad idea, this effort was never attempted. The Linux kernel drivers that attempted this were also hampered by efforts in the kernel to let such drivers not request full control of everything. It basically requires a patch in the kernel to add an according API. While patching your own Linux kernel is certainly possible for a developer, it is not something that the average Linux distribution user could and should attempt. Also every time your Ubuntu (or whatever distribution) updates the kernel you have to go back in and apply that patch again, which is of course a maintenance nightmare.


The basic security is that only root/admin can install a kernel driver in a system, same as with Windows. So you better pray that the person holding these rights is knowledgeable enough to use these rights safely :-).

Rolf Kalbermatter
DEMO, TU Delft
My Blog
Message 6 of 9

Thank you Rolf!


So for a one-off or limited number of instances, it is possible.


But as the basis of a product that will be duplicated many times there is a lot of work involved in the support.



Retired Senior Automation Systems Architect with Data Science Automation LabVIEW Champion Knight of NI and Prepper LinkedIn Profile YouTube Channel
0 Kudos
Message 7 of 9

Thank you for all the responses. I will contact the single board computer manufacturer to see if they have any drivers that I can use.

0 Kudos
Message 8 of 9

@JHugh wrote:

Thank you for all the responses. I will contact the single board computer manufacturer to see if they have any drivers that I can use.

Not sure if the aDIO driver is the right thing to access your IO ports. But they have here the source code package for this. The latest 3.02.00 version seems to be the same for all modern boards of this manufacturer independent of the chipset used.

Rolf Kalbermatter
DEMO, TU Delft
My Blog
0 Kudos
Message 9 of 9