Module mnemos_d1_core::drivers::twi
source · Expand description
Drivers for the Allwinner D1’s I²C/TWI peripherals.
This module contains an implementation of a driver for controlling the
I²C hardware on the D1, which the D1 manual calls a TWI
(Two-Wire Interface), likely due to I²C being a trademark of
Phillips Semiconductor. The I2c0
type in this module implements the
I2cService
trait using the TWI hardware mapped to the I2C0
pins on the
board’s 40-pin Raspberry Pi header.
The D1 has four separate TWI controllers, TWI0
, TWI1
, TWI2
, and
TWI3
. The pin mapping for the 40-pin Pi header I2C0
pins differs
between the MangoPi MQ Pro and the Lichee RV Dock. On the MQ Pro, TWI0
is used, with SCL
on pin PG12
and SDA
on pin PG13
. On the Lichee
RV Dock, TWI2
is used instead, with SCL
on pin PB0
and SDA
on
pin PB1
. Separate constructors for the I2c0
type,
I2c0::mq_pro
and I2c0::lichee_rv_dock
, are provided to
configure the appropriate pins for each board.
§Implementation Notes
The TWI hardware can be used in one of two modes: “TWI engine” mode, where individual bytes are written/read from the I²C bus in an interrupt handler, and “TWI driver” mode, where the TWI hardware can operate at the level of I²C register read/writes using a DMA buffer. This module currently only implements a driver for the “TWI engine” mode, since it can model all forms of I²C operations. In the future, we will likely want to opportunistically use the offload capabilities of the TWI driver when the I²C transaction has the correct shape for offloading, but this branch just implements the simpler TWI engine mode.
The TWI hardware is a bit difficult to use correctly, so implementing this
was a bit of a struggle. In particular, it turns out that the generation of
I²C clock pulses occurs when the
TWI_CNTR
register, which controls the TWI, is
written to.
The driver works by sharing state between a driver task and an ISR, since the TWI engine mode is interrupt driven. The shared state is “locked” by disabling TWI interrupts temporarily while the driver task is writing to the shared state, and resuming interrupts when a write to the shared state completes. In theory, this driver is also safe for use on multi-core hardware, since a single daemon task is responsible for all the non-ISR writes to this shared state, but this doesn’t actually matter, because the D1 is an inherently single-core CPU.
I believe that the I²C controller used in the D1 is from the Marvell MV64xxx family, although I’m not sure which one in particular. Linux has a driver for this device, which can be found here.
Structs§
- A TWI mapped to the Raspberry Pi header’s I²C0 pins.
- IsrData 🔒Data used by a TWI interrupt.
- TwiData 🔒
Enums§
Statics§
- I2C0_ISR 🔒