i2c_bus
I2C bus abstraction.
Two types, because a controller and a device are not the same thing:
- [
I2cController] owns the physical driverP(by value) and speaks to the whole bus: it canscanthe address space and hand out adevicefor one slave. - [
I2cDevice] borrows the controller, bakes in one slave address, and is the [Bus] a logical driver talks through — every op it frames carries that address, unshifted, astx[0].
Before this split a single I2cBus baked one address in, so a bus scan or
a second device had to bypass Layer 2 and call exchange with the
tx[0]-is-address convention by hand — exactly the raw-transfer reach-round
the layering exists to stop. scan() and device(addr) keep it on the
near side of the boundary.
Ownership
Section titled “Ownership”The physical driver is held by value, not behind a &'static dyn, so one
Once<I2cController<Esp32I2c>> holds the whole stack. A caller with a
&'static driver can still pass it: &T is itself a [PhysicalTransfer]
(the blanket impl in hal::bus).
Locking (#116)
Section titled “Locking (#116)”Both the per-op transfer and each scan probe take an [api::mutex] lock
around the physical exchange, and [I2cDevice] holds it for the whole
op list so a compound transaction (write-then-read) is never split once a
board hands the same &'static I2cController to more than one task. That
lock is the kernel’s priority-inheritance mutex, a syscall the kernel
refuses from interrupt context — so nothing here may be called from an
ISR. An interrupt that must touch the peripheral should own the physical
driver directly (exchange is &self) and coordinate with the task side
through a CsCell.
Structs
Section titled “Structs”I2cController
Section titled “I2cController”struct I2cController<P> { /* private fields */ }An I2C controller: owns the physical driver and addresses the whole bus.
I2cDevice
Section titled “I2cDevice”struct I2cDevice<'a, P> { /* private fields */ }One slave on an [I2cController], addressed by addr. This is the [Bus]
a logical driver is handed.
Implements: Bus