Explaining I2C on QNX
I’m assuming you already have a QNX image up and running on your Raspberry Pi 5. I’m also assuming that you know what I2C is and how it works on your usual real-time microcontroller, like an arduino or an STM32 with an RTOS installed.
Interfacing with devices on UNIX-like operating systems
UNIX convention means everything is a file. If you’re used to microcontroller code with no operating system, you would directly read and write to pins on the board or maybe use a library to hide the busy work with communication on the pins.
With an operating system you would prefer to avoid direct pin access and use the file system as an abstraction.
What does it mean to be a resource manager
Resource managers on QNX are similar to drivers. In a microkernel architecture
they receive and send messages as their interface. This all gets abstracted away
into devctl calls, so the standard POSIX methods are still working.
Making sure I2C is enabled
UNIX-like operating systems by convention expose devices with a file descriptor,
found in /dev/. You need to have the I2C driver (called a kernel module on the
other nix) enabled and loaded. By default the Raspberry Pi auto-loads needed
overlays for any device descriptor accessed. Read the /boot/overlays/readme
file for more info about what an overlay is. Loading overlays is a Raspberry Pi
5 concept, implemented by the board designers. The i2c-dwc-rpi5 command just starts the driver.
On the default parameters you wouldn’t need to run or configure anything. If you
run ls /dev/i2c* and see I2C devices present, you should be set. On my machine
I see there’s already file descriptors at /dev/i2c1 and /dev/i2c6. i2c1
corresponds to the top pins on my board
First interactions with an I2C userspace interface
First thing you’ll note is that there’s no i2c-tools available for QNX. Cross-compiling it would need a patch but I haven’t gotten around to doing that just yet. Any interactions with I2C will need you to run the program as root.
QNX has a very extensive GPIO library 1 and one of the solutions
there is a very convenient API 2 to talk on the I2C file
descriptor. It’s still possible to create the structures on your own and pass
pointers around with devctl, but this library is only one header + one source
file and it handles what is essentially standard I2C protocols. The repository
also contains a library for SPI, we’ll be using it for communicating with the
LoRa module.
Suppose you’ve got an ADS1115 connected on the usual Pi I2C
pins, then you could perform I2C operations via
the /dev/i2c1 file descriptor.
Documentation and links
-
https://www.qnx.com/developers/docs/8.0/com.qnx.doc.neutrino.resmgr/topic/overview_I2C_example.html This explains how I2C communication could work as a resource manager.
-
https://gitlab.com/qnx/projects/hardware-component-samples/-/tree/main/common/rpi_i2c?ref_type=heads :: Actual code on how to interact with the I2C driver on the Pi 5.
-
https://gitlab.com/qnx/projects/hardware-component-samples/-/tree/main - General repository of examples on the raspberry pi. ↩︎
-
https://gitlab.com/qnx/projects/hardware-component-samples/-/tree/main/common/rpi_i2c - I2C interface for raspberry pi ↩︎