BERGSONNE

I2C

Two wires, many devices. core_i2c is a blocking I2C master — probe for a device, then read and write its registers by 7-bit address. The hal_i2c and ll_i2c layers sit underneath. Use the Core / HAL / LL toggle at the top of the sidebar to switch.

Overview

You pick an I2C instance (I2C1, I2C3, …) and a bus speed — I2C_100K (standard), I2C_400K (fast), or I2C_1M (fast-mode plus). The bus timing for your kernel clock is computed for you. Everything is blocking and 7-bit addressed.

core_i2c is handle-based (Tier 1) with a full register API. A small Tier 2 *_bus surface (byte read/write/probe by config-declared bus id) is what Studio emits.

Probe & scan

probe sends an address and checks for an ACK — the quickest way to confirm a device is alive. scan walks the whole bus:

#include "core.h"

core_i2c_t i2c;
core_i2c_init(&i2c, I2C1, I2C_400K);

if (core_i2c_probe(&i2c, 0x68) == I2C_OK) {
    // device acked at 0x68
}

uint8_t found[16];
int n = core_i2c_scan(&i2c, found, /*count*/ 0, sizeof(found));

Reading & writing registers

Most I2C devices are register files. The *_reg / *_byte helpers do the write-address-then-read dance (repeated START) for you. Register addresses can be 8- or 16-bit:

uint8_t who;
core_i2c_read_byte(&i2c, 0x68, 0x75, &who);   // read WHO_AM_I

core_i2c_write_byte(&i2c, 0x68, 0x6B, 0x00);  // wake the device

uint8_t accel[6];
core_i2c_read_reg(&i2c, 0x68, 0x3B, accel, sizeof(accel));  // burst read
Studio is byte-level
The Tier 2 *_bus surface does single-byte register read/write/probe only — bulk transfers and scan are Tier 1.

Cross-architecture support

Standard and fast mode are the verified baseline everywhere they apply; fast-mode plus (1 MHz) needs stronger drivers and isn’t on every Core. Interrupt/DMA and slave mode are still ahead:

L0M0+L4M4W5M33H5M33WCH (RISC-V) · Nordic (nRF54) — in development

See the implementation status for the full matrix.

API reference

Default-instance · Tier 2
hal_status_t core_i2c_write_byte_bus(uint8_t bus, uint8_t addr, uint16_t reg, uint8_t value);
Write a single byte to a register on a device on `bus`. Returns I2C_OK on success, I2C_NACK / I2C_ERROR on bus failure, or I2C_ERROR if `bus` isn't declared in config.json.
int core_i2c_read_byte_bus(uint8_t bus, uint8_t addr, uint16_t reg);
Read a single byte from a register on a device on `bus`. Returns the byte value (0..255) on success, or -1 on any error (bus undeclared, NACK, timeout). The signed return lets DSL programs branch on `< 0` without an out-pointer.
int core_i2c_probe_bus(uint8_t bus, uint8_t addr);
Check if a device responds at `addr` on `bus`. Returns 1 if the device ACKs, 0 on NACK / timeout / undeclared bus.
Lower-level · Tier 1
uint32_t _core_i2c_timing(uint32_t speed_hz);
Resolve the TIMINGR value for a given speed using the compile-time I2C kernel clock (I2C_KERNEL_CLK_MHZ from core_config.h). Returns 0 if no pre-computed value exists.
hal_status_t core_i2c_init(core_i2c_t * h, I2C_TypeDef * instance, uint32_t speed_hz);
Initialize an I2C bus with automatic timing resolution. core_i2c_t bus; core_i2c_init(&bus, I2C1, I2C_400K); Resolves the TIMINGR value from the compile-time kernel clock. Enables FMP mode automatically when speed is I2C_1M.
hal_status_t core_i2c_init_cfg(core_i2c_t * h, I2C_TypeDef * instance, const hal_i2c_config_t * cfg);
Initialize I2C with explicit config struct (advanced). For most use cases, prefer core_i2c_init(h, instance, speed_hz).
hal_status_t core_i2c_write(core_i2c_t * h, uint8_t addr, const uint8_t * data, uint32_t len);
Write data to a 7-bit address device.
hal_status_t core_i2c_read(core_i2c_t * h, uint8_t addr, uint8_t * buf, uint32_t len);
Read data from a 7-bit address device.
hal_status_t core_i2c_write_reg(core_i2c_t * h, uint8_t addr, uint16_t reg, const uint8_t * data, uint32_t len);
Write to a device register (8 or 16-bit register address).
hal_status_t core_i2c_read_reg(core_i2c_t * h, uint8_t addr, uint16_t reg, uint8_t * buf, uint32_t len);
Read from a device register (repeated START).
hal_status_t core_i2c_write_byte(core_i2c_t * h, uint8_t addr, uint16_t reg, uint8_t value);
Write a single byte to a register.
hal_status_t core_i2c_read_byte(core_i2c_t * h, uint8_t addr, uint16_t reg, uint8_t * value);
Read a single byte from a register.
hal_status_t core_i2c_probe(core_i2c_t * h, uint8_t addr);
Check if a device responds at addr. Returns I2C_OK or I2C_NACK.
void core_i2c_scan(core_i2c_t * h, uint8_t * found, uint8_t * count, uint8_t max_count);
Scan the I2C bus (0x08–0x77). Fills found[] with responding addresses.

Generated from core_i2c.htiles@6bbf0d8.