GPIO and Python on QNX
Much of the Python GPIO API is the same on QNX. Small changes may be needed to existing scripts or libraries; notably, the module for GPIO is named rpi_gpio
and can be imported with import rpi_gpio as GPIO
. Refer to the QNX rpi_gpio
APIs page for the differences between Python's GPIO API and QNX's.
Here are some basic API usages to get started:
- Pin numbering
Two modes are available for pin numbering:
- Setting up channels
Configure a channel as input or output:
- Output to a channel
Set the output of a channel to high or low:
GPIO.output(channel, GPIO.HIGH) GPIO.output(channel, GPIO.LOW)
- Read from a channel
Read the input of a channel:
value = GPIO.input(channel)
- Clean up
Close the file descriptor of the QNX resource manager:
GPIO.cleanup()
- Event detection
Enable event detection for a GPIO input. When an event is detected, you must use a callback function to perform an action.
GPIO.add_event_detect(channel, GPIO.BOTH, callback = myfunction) # Use GPIO,BOTH to detect both rising and falling edge events
Here are a few sample applications to help further your understanding:
Note how the basics of managing the GPIO are the same as with Pi OS.
Is the rpi_gpio
module missing some functionality you're expecting? Please let us know by opening an issue!
GPIO processes
There are several key processes that help manage the GPIO. If you experience any trouble, first make sure these are running:
rpi_gpio
- The GPIO resource manageri2c-bcm2711
- The I2C communication resource managerspi-bcm2711
- The SPI communication resource manager
qnxuser@qnxpi:~$ su root
...
root@qnxpi:~# pidin -p "rpi_gpio" ar
pid Arguments
821234 rpi_gpio
root@qnxpi:~# pidin -p "i2c-bcm2711" ar
pid Arguments
801234 i2c-bcm2711 -p0xfe804000
root@qnxpi:~# pidin -p "spi-bcm2711" ar
pid Arguments
860189 spi-bcm2711 -c /system/etc/config/spi/spi.conf
PWM
PWM (Pulse Width Modulation) allows you to simulate analog voltage levels by rapidly switching a digital pin HIGH and LOW. By adjusting the ratio of HIGH time to LOW time (the duty cycle), you can control the amount of power delivered to a device like an LED or a motor.
The following GPIO pins support hardware PWM:
- GPIO 12 and GPIO 18 share PWM channel 1.
- GPIO 13 and GPIO 19 share PWM channel 2.
If both GPIO 13 and 19 are configured for hardware PWM, then they will have the same period and duty cycle.
The QNX rpi_gpio
module supports the following PWM modes:
- MS mode
Each PWM period starts with the signal HIGH for the duty time, then LOW for the rest of the period. So, if you set a duty cycle of 25%, the signal is HIGH for 25% of the cycle, then LOW for 75%.
- PWM mode
The HIGH and LOW phases are spread out across the period. For the same 25% duty cycle as the previous MS mode example, the HIGH/LOW state toggles multiple times per period, but still results in being HIGH for 25% of the time.
PWM APIs
To create a PWM instance:
p = GPIO.PWM(channel, frequency) # Use channel 12, 18, 13, and 19 for hardware PWM
You can optionally set the PWM mode:
p = GPIO.PWM(channel, frequency, mode) # GPIO.PWM.MODE_PWM or GPIO.PWM.MODE_MS
If you don't specify mode, it defaults to GPIO.PWM.MODE_MS
.
To start PWM:
p.start(dc) # where dc is the duty cycle (0.0 <= dc <= 100.0)
To change the frequency:
p.ChangeFrequency(freq) # where freq is the new frequency in Hz
To change the duty cycle:
p.ChangeDutyCycle(dc) # where 0.0 <= dc <= 100.0
To change the duty cycle using an absolute value:
p.ChangeDutyCycleAbs(dc) # where 0 <= dc <= 1024
To stop PWM:
p.stop()
Sample application
SPI
SPI (Serial Peripheral Interface) is a serial communication protocol that enables full-duplex data exchange between a master device and its peripherals through communication wires. These wires are named MISO, MOSI, SCLK, and CS.
While the RPI4 has multiple SPI buses, only SPI0 is exposed by default. The following GPIO pins support the SPI0 bus:
- GPIO 7 is the CE1 pin.
- GPIO 8 is the CE0 pin.
- GPIO 9 is the MISO pin.
- GPIO 10 is the MOSI pin.
- GPIO 11 is the SCLK pin.
SPI APIs
These APIs interact only with the SPI0 bus.
- Initialize the SPI interface
GPIO.init_spi(clkdiv)
Where:
clkdiv
: The divisor to apply to the system clock to produce the SPI bus clock. By default, the reference clock is at 500MHz. So, for example, to get a SPI bus clock of 10MHz, you should specify a value of 50 forclkdiv
.
Note:This API must be called before using the other SPI APIs.
- Write data to a device
GPIO.write_spi([data1, data2, ..., dataN])
Where:
[data1, data2, ..., dataN]
: An array of integers to write to a device. Each integer can be in the range [0,255]. You can write up to 256 bytes in a single call.
Note:This API only writes to the device connected to the CE0 pin.
- Write and Read data to/from a device
response = GPIO.write_read_spi(ce, [inData1, inData2, ..., inDataN], [outData1, outData2, ..., outDataM])
Where:
ce
: The Chip Enable (CE) line to enable. Set to 0 to enable CE0. Set to 1 to enable CE1.[inData1, inData2, ..., inDataN]
: An array of integers to write to a device. Each integer can be in the range [0,255]. You can write up to 256 bytes in a single call.[outData1, outData2, ..., outDataM]
: An array that will be populated with bytes read from the device. The amount of data read is equal to the length of the array. The array can have a length of at most 256.
Note:The length of the
outData
array must be equal to or less than the length of theinData
array. In other words,M
<=N
must be true.
Sample application
Not available.
I2C
I2C (Inter-Integrated Circuit) is a serial communication protocol that allows multiple devices to communicate with a Raspberry Pi using two wires; SDA (data) and SCL (clock).
The following GPIO pins support I2C:
- GPIO 2 is the SDA pin.
- GPIO 3 is the SCL pin.
I2C APIs
You must execute the following I2C APIs as root.
Before using the the I2C APIs, import the SMBus module using import smbus
.
Create a connection to the I2C resource manager:
bus = smbus.SMBus()
bus.open(1)
The number 1 in the open() argument matches the I2C bus number, as assigned by the resource manager (i.e., /dev/i2c1).
Optionally, you can also create a connection to the resource manager during smbus
initialization:
bus = smbus.SMBus(1)
Closes the connection to the I2C resource manager:
bus.close()
Reads a single byte from a device without specifying a register:
value = bus.read_byte(addr)
Writes a single byte to a device without specifying a register:
bus.write_byte(addr, data)
Reads a byte from a specific register of the device:
value = bus.read_byte_data(addr, reg)
Writes a byte to a specific register of the device:
bus.write_byte_data(addr, reg, data)
Writes multiple bytes starting at a specific register:
bus.write_block_data(addr, reg, [data1, data2, data3, data4])