In general, this commit allows the I2C slave to recognize when writes
are occuring in serial - and seperate them out into independant
commands. In order to achieve this it:
* Corrects some setup parameters for the I2C state machine.
- Enables clock stretching
- Enables recommendations from the datasheet
* Participates in clock stretching. This is done by leaving the
`R_RD_REQ` register of `IC_INTR_STAT` set until the
slave has responded with some bytes (in `respond_to_write`).
* Recognizes `FIRST_DATA_BYTE` of `IC_DATA_CMD`, which indicates to a
slave-receiver than the current byte is part of a new transaction.
* Uses a state machine heavily inspired by the one in rp-rs as an
implementation detail. This is no more correct than the existing
approach, but makes the code significantly easier to reason about.
* Two additional errors were added, both indicating that the provided
buffer is too small for the message from the master-sender. As a
convenience, they have the same assosciated data so that matching
can be performed in the event that the call site handles messages
in a consistent way.
Update the start and stop flags for all read/write/read_write methods to match
those in the default blocking implementation of these methods (as well as
other RP2040 I2C implementations, and expected I2C behavior).
Also adds a write_read_async method that doesnt require using embedded-hal, as
this is required to use I2C in an idiomatic fashion (see TI Application Report
SLVA704).
The RP2040 datasheet indicates that I2C pins should have a limited
slew rate (Page 440 - 4.3.1.3.). This configures that for both
`I2c` and `I2cSlave`.
In addition, the pin configuration has been centralized to a single
fn.
They're heavily spamming logs for HIL tests, and I don't believe
they're valuable now that the thing they helped debug in their young
age is now solid and mature.
Move i2c to mod, split device and controller
Remove mode generic:
I don't think it's reasonable to use the i2c in device mode while
blocking, so I'm cutting the generic.
this is "generic" in that it doesn't require the user to set up anything
specific to go to dormant sleep, unlike the C sdk which requires clock
sources to be configured explicitly and doesn't much care about PLLs. we
will instead take a snapshot of the current clock configuration, switch
to a known clock source (very slow rosc, in this case), go to sleep, and
on wakeup undo everything we've done (ensuring stability of PLLs and
such).
tested locally, but adding tests to HIL seems infeasible. we'd need at
least another pico or extensive modifications to teleprobe since
dormant-sleep breaks SWD (except to rescue-dp), neither of which is
feasible at this point. if we *did* want to add tests we should check
for both rtc wakeups (with an external rtc clock source) and gpio wakeups.
this temporarily takes ownership of pins because we need to clear edge
interrupts before waiting for them (otherwise we may wait indefinitely),
we want to clean up the dormant-wake bits after a wakeup, and doing
anything *else* with the input while we're waiting for a wakeup isn't
possible at all. doing it like this lets us not impose any cost on those
who don't use dormant wakes without entangling dormant waits too badly
with regular interrupt waits.