i2c-bcm2711 driver example
This example uses the implementation of the RPi4 I2C driver i2c-bcm2711, available in the RPi4 BSP download package, com.qnx.qnx800.bsp.hw.raspberrypi_bcm2711_rpi4, under src/hardware/i2c/bcm2711.
Driver implementation
The driver implements required functions as described below and static-links against the i2c-master library. The library provides the main executable entry point, which calls i2c_master_getfuncs() to connect to implementation and starts the resource manager to handle the client communication.
The following table maps the i2c-bcm2711 driver implementations to their related documentation:
| Related section | Implementation source file | Implementation name | Notes |
|---|---|---|---|
| Define a structure | proto.h | bcm2711_dev_t | |
| Driver initialization | init.c | bcm2711_init() | |
| Set the slave address | slave_addr.c | bcm2711_set_slave_addr() | |
| Send data | send.c wait.c |
bcm2711_send() bcm2711_wait_complete() |
Instead of wait_for_completion(), i2c-bcm2711 uses bcm2711_wait_complete(). |
| Receive data | recv.c wait.c |
bcm2711_recv() bcm2711_wait_complete() |
Instead of wait_for_completion(), i2c-bcm2711 uses bcm2711_wait_complete(). |
| Clean up the driver | fini.c | bcm2711_fini() | |
| Integrate the implementations | lib.c | i2c_master_getfuncs() | Called by the i2c-master library to initialize driver and manager communication. |
int bcm2711_set_bus_speed(void *hdl, unsigned int speed, unsigned int *ospeed)-
- Implements the set_bus_speed() function in the i2c_master_funcs_t structure.
- Specifies the bus speed. If an invalid bus speed is requested, this function should return failure and leave the bus speed unchanged.
- Arguments:
- hdl — Handle returned from init().
- speed — Bus speed. Units are implementation-defined.
- ospeed — If not
NULL, actual bus speed.
- Returns:
0— Success.-1— Failure.
int bcm2711_version_info(i2c_libversion_t *version)-
- Implements the version_info() function in the i2c_master_funcs_t structure.
- Writes the library version information into passed version structure.
- Argument:
- version — A pointer to the
i2c_libversion_t structure to
populate with version
information:
typedef struct { unsigned char major; unsigned char minor; unsigned char revision; } i2c_libversion_t;
- version — A pointer to the
i2c_libversion_t structure to
populate with version
information:
- Returns:
0— Success.-1— Failure.
int bcm2711_driver_info(void *hdl, i2c_driver_info_t *info)-
- Implements the driver_info() function in the i2c_master_funcs_t structure.
- Requests information about the driver.
- Arguments:
- hdl — Handle returned from init().
- info — A pointer to the
i2c_driver_info_t structure to
populate with version
information:
typedef struct { _Uint32t speed_mode; /* supported speeds: I2C_SPEED_* */ _Uint32t addr_mode; /* supported address fmts: I2C_ADDRFMT_* */ _Uint32t verbosity; /* Driver verbosity level */ _Uint32t reserved; } i2c_driver_info_t;
- Returns:
0— Success.-1— Failure.
int bus_reset(void *hdl)-
- Resets the I2C bus module.
- Returns:
0— Success.-1— Failure.
Client samples
Refer to the following I2C client samples:
-
Generic I2C client API, implemented as shared library, for interacting with the I2C driver.
-
SN3218A RGB LED Driver for QNX, which uses the above library. The specification of SN3218A is as follows:
-
I2C Address:
0x54 -
Register Map:
-
0x00: Shutdown register (0= shutdown,1= normal operation) -
0x01-0x12: PWM brightness registers (18 registers, one per channel) -
0x13-0x15: LED enable registers (3 registers, each controlling 6 channels) -
0x16: Update register (write any value to apply brightness changes) -
0x17: Reset register (write0xFFto reset the chip)
-
-
With the above device specification, you can control the device by writing values to it. For example, to reset the chip and get the device out of shutdown mode, you can use the function smbus_write_byte_data():
// 1) Reset the chip
rc = sn3218_reset();
if (rc != I2C_SUCCESS) {
fprintf(stderr, "Error resetting SN3218.\n");
return rc;
}
// 2) Exit shutdown (write 0x01 to REG_SHUTDOWN)
rc = sn3218_write_byte(REG_SHUTDOWN, 0x01);
if (rc != I2C_SUCCESS) {
fprintf(stderr, "Error enabling SN3218 output.\n");
return rc;
}
255):// 3) Enable all 18 channels.
// Each LED control register (0x13, 0x14, 0x15) controls 6 channels (bits D5:D0).
// To enable each channel, write 0x3F (binary 00111111) to each register.
int rc;
// Enable all channels (registers 0x13, 0x14, 0x15)
for (int i = 0; i < 3; i++) {
rc = smbus_write_byte_data(1, 0x54, 0x13 + i, 0x3F);
if (rc != I2C_SUCCESS) {
fprintf(stderr, "Error enabling SN3218 channels");
return rc;
}
usleep(1000); // 1 ms delay between writes
}
// 4) Set all channels to maximum brightness (255)
uint8_t g_brightness[18]; // 18 channels
for (int i = 0; i < 18; i++) {
g_brightness[i] = 255;
}
// Write brightness values to all 18 PWM registers (0x01-0x12)
for (int i = 0; i < 18; i++) {
rc = smbus_write_byte_data(1, 0x54, 0x01 + i, g_brightness[i]);
if (rc != I2C_SUCCESS) {
fprintf(stderr, "Error writing brightness for channel %d.\n", i);
return rc;
}
usleep(1000); // 1 ms delay between writes
}
// 5) Latch changes by writing to REG_UPDATE (0x16).
rc = smbus_write_byte_data(1, 0x54, 0x16, 0x00);
if (rc != I2C_SUCCESS) {
fprintf(stderr, "Error updating SN3218.\n");
return rc;
}
For a more detailed implementation, which includes testing functions, refer to sn3218a-rgb-led.c: https://gitlab.com/qnx/projects/hardware-component-samples/-/blob/main/sn3218a-rgb-led/c/src/sn3218a-rgb-led.c?ref_type=heads.
