// Copyright (c) 2026 Rigless Labs.
// SPDX-License-Identifier: MIT OR Apache-2.0
//! The inter-integrated circuit interface of RM0090 rev 22 chapter 27, written against the `i2c3`
//! layout. One layout serves all three instances: I2C1, I2C2 and I2C3 carry the same ten registers
//! at the same offsets.
//!
//! **Controller mode only.** By default the interface "operates in target mode", 27.3.1, and
//! switches to controller mode the moment software generates a start. This model never receives a
//! start from the wire, so it is always the controller and never a target: OAR1, OAR2, and the
//! target-only flags are stored and inert, in the second table. A firmware that runs the part as a
//! target, answering another controller, gets nothing here yet.
//!
//! **Addressing is read from the byte, because the register file carries no bit that says how many
//! address bytes a controller is about to send.** A byte matching `11110xxx` after `START` is a
//! 10-bit header, and its own bit 0 says whether this is the two-byte write-direction sequence of
//! 27.3.3 (header, then a plain second byte, `ADD10` between them) or the one-byte header a repeated
//! start resends to turn the same transfer around into a read, page 843's "To enter Receiver mode"
//! case. Every other byte is a 7-bit address. This is the same distinction the ChibiOS `I2Cv1`
//! driver constructs on `EV5` (`hal_i2c_lld.c` line 392, `0xF0 | (0x6 & (addr >> 8)) | (0x1 & addr)`)
//! and a target recognizes on the wire. Nothing here invents a rate or a delay to reach it.
//!
//! **A byte takes nine SCL periods**, eight data bits and the acknowledge bit, at the rate `CCR`,
//! `DUTY` and `F/S` give against the peripheral clock the part's tree feeds this instance, 27.6.8.
//! The start and stop conditions themselves carry no register-configurable duration RM0090
//! gives a number for, so they take none here: `SB` and the effect of `STOP` land at the instant of
//! the write that asks for them, except where a byte is already on the wire, which section 27.3.3
//! itself defers to that byte's end.
//!
//! **`START` and `STOP` read back set until they are carried out.** Deferred behind a byte, or a
//! `START` held by a `BUSY` this transaction does not own, the bit stays exactly as software wrote
//! it, and the CR1 note above 27.6.2 warns against a second write while that is true, precisely because
//! hardware has not cleared it yet. Both can be pending together, carried out start-to-finish in the
//! order they were written, never one replacing the other.
//!
//! | Register or section | Behavior | Source | Test |
//! |---|---|---|---|
//! | Reset state | Every register at zero but `TRISE`, which resets to `0x0002` | 27.6.1 to 27.6.10 | `reset_leaves_every_register_at_the_manuals_values` |
//! | `START`, `SB` | Sets `SB`, `MSL` and `BUSY` and clears `TxE`, `BTF` and `TRA` at the write, unless a byte is already on the wire, which defers all of it to that byte's end, 27.3.3's note on a restart | 27.3.3 | `setting_start_on_an_idle_bus_sets_sb_and_raises_msl_and_busy`, `a_repeated_start_mid_byte_waits_for_the_byte_to_finish`, `a_repeated_start_after_a_write_leaves_the_status_chibios_checks_for_ev5` |
//! | `SR1` read, paired two ways | Arms the `SB`/`ADD10` pairing, completed only by the next write of `DR`, and the `ADDR` pairing, completed only by the next read of `SR2`, apart from each other: whichever access the register file currently supports consumes it, so neither a `CR1` write between them nor the other pairing's own access wrongly uses it up | 27.6.7's note on the clearing sequence | `a_cr1_write_between_sr1_and_sr2_does_not_stop_sr2_from_clearing_addr`, `a_one_byte_read_that_clears_ack_between_sr1_and_sr2_as_ev6_says` |
//! | 7-bit addressing | One byte, its LSB the direction, always taken as the transfer's own direction from here. Acknowledged: `ADDR` sets. Not acknowledged: `AF` sets and nothing is started | 27.3.3 | `a_seven_bit_address_that_is_acknowledged_sets_addr_and_tra_and_addr_clears_by_sr1_then_sr2`, `a_nacked_address_sets_af_and_the_peer_is_never_started`, `a_ten_bit_write_after_a_seven_bit_read_turns_the_transfer_around` |
//! | 10-bit addressing, the header | `11110xx0` sets `ADD10`, cleared by a read of `SR1` then a write of `DR` with the second byte, which then sets `ADDR` | 27.3.3 | `a_ten_bit_address_sends_the_header_then_the_second_byte_before_addr` |
//! | 10-bit addressing, a repeated start to read | `11110xx1` alone sets `ADDR`, with no second byte: page 843's worked case | 27.3.3 | `a_repeated_start_in_ten_bit_mode_resends_only_the_header_with_the_read_bit` |
//! | `ADDR` cleared, `TRA` | A read of `SR1` then of `SR2` clears `ADDR` once both have happened, in that order, whichever flag was standing when the second lands. `TRA` is the address byte's direction | 27.3.3, 27.6.7 | `a_seven_bit_address_that_is_acknowledged_sets_addr_and_tra_and_addr_clears_by_sr1_then_sr2` |
//! | Controller transmitter, `TxE`, `BTF` | `TxE` sets the instant the address phase hands the transmitter an empty buffer, `EV8_1`, and a write that finds the shift register idle never actually clears it, since the byte flows onto the wire at once: 27.6.6 bit 7's own exception for the first byte and for one written while `BTF` stands. A write that instead finds a byte already on the wire fills `DR` and does clear it. `BTF` sets once an acknowledged byte's shift register empties with nothing queued behind it, and clears on either a read or a write of `DR` | 27.3.3, 27.6.6 bits 2 and 7 | `txe_stands_once_addressed_to_write_before_any_byte_is_written`, `a_byte_written_goes_out_and_txe_and_btf_both_follow_it_when_nothing_queues_behind`, `a_second_byte_written_before_the_first_acknowledges_keeps_txe_low_until_it_reaches_the_wire`, `a_dummy_read_of_dr_clears_btf_the_way_chibios_ev8_2_does` |
//! | Controller receiver, one byte | `ACK` cleared during `EV6`, read at the byte's own end rather than when it was scheduled, NACKs the only byte | 27.3.3, 27.6.1 bit 11 | `the_one_byte_receive_procedure_nacks_the_only_byte` |
//! | Controller receiver, two bytes, `POS` | `ACK` cleared and `POS` set before `ADDR` clears delays the acknowledge bit one byte, so the first byte is acknowledged and the second is not | 27.3.3, 27.6.1 bit 11 | `the_two_byte_receive_procedure_uses_pos_to_delay_the_nack_one_byte` |
//! | Controller receiver, more than two bytes | The controller free-runs a byte at a time. A byte landing with `DR` still unread by the last one sets `BTF` and holds there until `DR` is read, which is the manual's own `N-2` procedure. `ACK` governs whichever byte is on the wire at the instant its own period ends, so clearing it while that byte is already shifting still lands on it | 27.3.3, 27.6.1 bit 11 | `the_more_than_two_byte_receive_procedure_stalls_on_btf_until_dr_is_read`, `clearing_ack_mid_byte_still_nacks_the_byte_already_shifting` |
//! | `STOP` | Ends the transaction at the write, unless a byte is on the wire, deferred to its end, releases the peer and clears `MSL`, `BUSY` and `TRA`. Nothing is scheduled once a `STOP` or `START` is pending or the transaction is already closed, so no byte, transmitted or received, is clocked after it. A byte still buffered in `DR`, or held behind it, reads back afterwards exactly as 27.3.3's `N > 2` procedure needs it to | 27.3.3, 27.6.1 bit 9, 27.6.7 bit 1 | `a_write_ends_with_stop_and_releases_the_peer`, `stop_set_mid_procedure_leaves_the_still_buffered_bytes_readable`, `nothing_is_clocked_after_a_stop_closes_the_more_than_two_byte_procedure`, `a_byte_queued_behind_a_deferred_stop_does_not_go_out` |
//! | `AF` | A NACK on the address or on a data byte in transmission sets it, and drops whatever was queued in `DR` behind the `NACKed` byte, since that byte does not survive the repeated start 27.3.4 assumes follows. Cleared by a written zero, which the vendor's file needs correcting for, or by `PE=0` | 27.3.4, 27.6.6 bit 10 | `a_nacked_address_sets_af_and_the_peer_is_never_started`, `a_nacked_data_byte_sets_af_mid_transfer`, `a_written_zero_clears_af_and_a_written_one_leaves_it`, `a_queued_byte_does_not_survive_a_nack_and_a_repeated_start` |
//! | `ITEVTEN`, `ITBUFEN` | The event line rises for `SB`, `ADDR`, `ADD10` and `BTF` under `ITEVTEN` alone, and for bare `TxE` or `RxNE` only with `ITBUFEN` set too | 27.4, table 124 | `itevten_raises_the_event_line_for_sb_addr_add10_and_btf_without_itbufen`, `itbufen_is_needed_only_for_bare_txe_and_rxne` |
//! | `ITERREN` | The error line rises for `AF`, the one error condition this controller-only model can raise | 27.4 | `iterren_raises_the_error_line_for_af` |
//! | `DMAEN` | Drives the receive request off `RxNE` and the transmit request off `TxE`, on the streams table 43 gives each instance | 27.3.8, table 43 | `dmaen_drives_the_two_requests_off_rxne_and_txe` |
//! | `CCR`, `DUTY`, `F/S` | The byte period, standard mode `2 x CCR`, fast mode `3 x CCR` or, under `DUTY`, `25 x CCR`, SCL periods of the peripheral clock | 27.6.8 | `a_byte_takes_nine_scl_periods_at_the_ccr_rate`, `fast_mode_changes_the_periods_the_formula_gives`, `fast_mode_duty_changes_the_periods_the_formula_gives`, `a_run_of_bytes_does_not_drift` |
//! | `fPCLK1` | The peripheral clock the tree feeds this instance, followed as it changes: the byte already on the wire keeps the rate it began at, and the next one's carry is dropped with the rate it was a fraction of | 27.3.2, 6.2 | `a_change_of_clock_applies_from_the_next_byte`, `a_change_of_clock_times_the_next_byte_at_the_new_rate` |
//! | `SWRST` | Puts the interface "under reset state": the peer released and every register of the instance, `BUSY` among them, back to its reset value, which is also the manual's own way out of a `BUSY` a glitch left locked. The bit is software's to clear, and until it does the instance stays there, `SWRST` reading back set and every other write landing nothing | 27.6.1 bit 15 | `swrst_resets_every_register_and_releases_the_peer`, `swrst_is_the_only_way_out_of_a_busy_a_pending_start_left_locked` |
//! | `PE` cleared mid-communication | 27.6.1 bit 0 defers the disable to the end of the communication and then says a controller "must not" clear it before then, giving that case no outcome. The model's own: the communication ends at the write, the peer released as by `STOP`, and every bit `PE=0` resets is reset there, `START`, `ACK` and `POS` among them. `BUSY` is the one flag the manual keeps "still updated" through it and is left alone | 27.6.1 bits 0, 8, 10, 11, 27.6.7 bit 1 | `clearing_pe_aborts_the_transaction_but_leaves_busy_as_hardware_would` |
//! | `PE` cleared, held clear | `START`, `ACK` and `POS` read back clear for as long as `PE` is clear, whatever was last written to them, 27.6.1 bits 8, 10 and 11's own hardware-clear-at-`PE=0` note | 27.6.1 bit 0 | `start_written_with_pe_clear_stays_in_cr1` |
//! | `START` against a set `BUSY` | Taken at once when this transaction already holds the bus, the ordinary repeated start. Held pending, not taken, when `BUSY` is set and `MSL` is not, which is what `PE=0` mid-transaction can leave behind. Only `SWRST` gets out of that | 27.3.3, 27.6.1 bit 15's note | `swrst_is_the_only_way_out_of_a_busy_a_pending_start_left_locked` |
//! | The driver's own sequence | `SWRST`, the clock and filter setup, `PE`, `ITEVTEN`, `START`, and the NACK an empty bus answers with, replayed at the values a run of `ArduCopter` recorded | 27.3.3, 27.3.4 | `the_chibios_driver_probes_an_empty_bus_and_gets_its_nack` |
//! | A silent chip | A chip the board has silenced, a board condition, isn't on the wire: it never acknowledges its address, so the controller sets `AF` as it does with nobody at that address. A silence the board asks for while the chip is in the open transaction waits for the `STOP`, `SWRST` or `PE` cleared that ends it, and a part reset | 27.3.3 | `a_silent_chip_is_not_acknowledged_and_answers_again_after`, `a_silence_waits_for_the_stop` |
//!
//! **What the model leaves out, and why.**
//!
//! | Behavior | Source | Reason |
//! |---|---|---|
//! | Target mode entire: address matching against `OAR1`/`OAR2`, `ENGC`, `NOSTRETCH`, `ENDUAL`, the `SMBus` address types, `GENCALL`/`SMBHOST`/`SMBDEFAULT`/`DUALF` | 27.3.2, 27.3.7 | The runtime has no seam for it: [`Peer`] is the far end a controller addresses, and nothing on a board's side is a second controller that addresses the part. The registers are stored |
//! | `STOPF` | 27.3.2 | Target-mode only, "Stop detection (target mode)." Never set |
//! | `OVR` | 27.3.4 | Target mode with `NOSTRETCH` set. Never set |
//! | `BERR` | 27.3.4 | "Detects an external Stop or Start condition" from a second controller or a glitch on the wire. This model is the bus's only controller and drives every transition itself, so the condition cannot arise |
//! | `ARLO` | 27.3.4 | Multi-controller arbitration. The same reason as `BERR` |
//! | `TIMEOUT`, the `SMBus` clock-low timeout | 27.3.7 | Times a target's own clock-stretching, and [`Peer`]'s calls answer synchronously: nothing on this bus can hold `SCL` for a duration to time out on |
//! | Debug mode: "The `SMBUS` timeout either continues to work normally or stops" under the `DBG` module's own configuration bits while the core is halted | 27.5 | The timeout it freezes isn't modeled either, the row above |
//! | `SMBALERT`, the `SMBA` pin | 27.3.7 | No pin carries it |
//! | A peer holding `SDA` or `SCL` low | 27.3.4, 27.3.6 | Looks, on the wire, like a lost arbitration with `BUSY` never clearing, but [`Peer`]'s three calls answer synchronously in the call that makes them: nothing lets a peer hold a line down for a stretch of virtual time, the same gap that leaves clock stretching out below |
//! | PEC | 27.3.9 | A CRC-8 over every address and data byte, workable the way `spi.rs`'s CRC is. Left for a pass of its own rather than folded into an already wide chapter |
//! | `TRISE` | 27.6.9 | Stored. Section 27.6.8's own frequency formula, the only timing this chapter gives a number for, never reads it. Its job is compensating a measured rise time against the controller's own loopback delay, which a deterministic model with no analog edge has nothing to compensate |
//! | `FLTR`, `DNF`, `ANOFF` | 27.6.10, 27.3.5 | Stored. There is no noise to filter, the same reason `usart.rs` gives its own noise flags. The hold-time extension the section states is a sub-bit margin, not a term in the byte period |
//! | DMA's anticipatory NACK, `LAST` acted on | 27.3.8 | The controller must NACK the byte before the last one a DMA stream will take, on a signal the DMA controller alone can compute from its own count. Every join this part has runs a peripheral's flag into the DMA controller. None yet runs the other way, from the controller into a peripheral, which is what this needs. `LAST` is stored and the two request lines are driven. The early NACK is not: a real driver's three-byte DMA read, ChibiOS's own `EV6_MASTER_REC_MODE_SELECTED`, leaves `ACK` set for that count, so this model ACKs the third byte like any other and a fourth is already on the wire when DMA stops asking for one, rather than the transfer ending in `STOP` on its own. `ardupilots_own_dma_read_of_three_bytes_never_nacks_the_last_one` pins exactly that |
//! | Clock stretching by a peer | 27.3.6 | [`Peer::start`], `write` and `read` answer in the call that makes them: nothing lets a peer hold `SCL` down for a stretch of virtual time. The controller's own wait for software, holding a byte off the wire until `DR` is written, is real and modeled, since it falls out of nothing being scheduled until then |
//! | Word and half-word access: "The peripheral registers have to be accessed by half-words (16 bits) or words (32 bits)." | 27.6 | The manual names the widths a write must use and not the effect of a narrower one, so a narrower access lands in its lane on the bus rather than in this model. The same shape as the timer's own access-width row |
//! | Two peers acknowledging the same address | 27.3.3 | Unlike a chip select's push-pull line, an acknowledge is open-drain: two peers pulling it low at once is indistinguishable on the wire from one, so there is no SPI-shaped contention to invent. The first peer in attachment order that acknowledges is the one addressed |
//! | ES0206 rev 24, 2.10.1: bus error detected spuriously in controller mode | ES0206 rev 24 | Not modeled: the sheet names no condition that triggers it, only that it "can be detected spuriously" and that "any such transfer continues normally." Its workaround, "the `BERR` flag must be cleared by software. No other action is required," is already satisfied, since this model never sets `BERR` for the workaround to act on |
//! | ES0206 rev 24, 2.10.2: `SMBus` not fully `SMBus` 2.0 compliant | ES0206 rev 24 | Not modeled, for the reason PEC and the `SMBus` address types above are not |
//! | ES0206 rev 24, 2.10.3: start not generated after a misplaced stop | ES0206 rev 24 | Unreachable here, though Table 3 marks it on every revision. The misplaced stop it answers needs a second controller, the same reason as 2.10.1's own register condition, `BERR` |
//! | ES0206 rev 24, 2.10.4: repeated-start setup time violated near 100 kHz | ES0206 rev 24 | An analog AC timing margin in nanoseconds on the physical wire, not a register behavior, the same shape as `rcc.rs`'s PC13-disturbs-the-LSE entry |
//! | ES0206 rev 24, 2.10.5: data valid time violated without `OVR` | ES0206 rev 24 | Unreachable here, though Table 3 marks it on every revision. It's target-mode only, "in Target transmit mode." |
//! | ES0206 rev 24, 2.10.6: SDA/SCL rise time violated above a bus voltage | ES0206 rev 24 | A board-level electrical condition between `VDD_I2C` and the rail, not a register behavior |
//! | ES0206 rev 24, 2.2.7: a delay between an `RCC` clock enable and the peripheral answering | ES0206 rev 24 | Recorded once in `rcc.rs`, for the same reason: a gate opens at the write. I2C sits on APB1, so the sheet's own number for it is "1 + (AHB/APB prescaler) cycles," not the two AHB cycles an AHB peripheral gets |
//! | Being held at reset by `RCC_APB1RSTR` | 6.3.8 | The gate is the part's. Being held at reset is a third behavior the runtime has no verb for, the same note every other peripheral's table carries |
//!
//! **Where this model departs from the vendor's file.** Section 27.6.6 types `SR1`'s error flags,
//! `BERR` through `SMBALERT`, `rc_w0`: a written zero clears the bit and a written one leaves it.
//! ST's file gives every one of them plain read-write with no write rule, which would let a written
//! one set a flag no condition raised. `memory_map.rs` corrects the register's write rule. The seven
//! bits below it, `SB` through `TxE`, are already read-only in ST's file and need no correction, since
//! this model clears them itself through the sequences above.
use crate::chip::i2c::Peer;
use crate::chip::{Place, Timeline};
use crate::device::{Device, DeviceContext, Level, RegisterFile};
use crate::snapshot::store;
use crate::soc::stm32f427::generated::i2c3::{Register, ccr, cr1, cr2, sr1, sr2};
use crate::time::{EventId, VirtualNanos};
/// The event line, position zero of the instance's table: `I2C1_EV` at RM0090 rev 22 table 63's
/// line 31 for `I2C1`, and the instance's own pair for `I2C2` and `I2C3`.
const EVENT: usize = 0;
/// The error line, position one: `I2C1_ER`.
const ERROR: usize = 1;
/// The request `DMAEN` drives off `RxNE`, this instance's request output zero, RM0090 rev 22
/// section 27.3.8.
pub const RECEIVE_REQUEST: usize = 0;
/// The request `DMAEN` drives off `TxE`, request output one.
pub const TRANSMIT_REQUEST: usize = 1;
/// A 10-bit header's fixed top bits, RM0090 rev 22 section 27.3.2's note: `11110xx0`, masked to the
/// five bits no address chooses.
const TEN_BIT_HEADER: u8 = 0xF0;
const TEN_BIT_MASK: u8 = 0xF8;
/// A peer that answers one address, holds a known sequence, repeats its last byte once that drains,
/// and records every byte it was sent, the same job `spi::Pattern` and `usart::Pattern` do for their
/// own buses: what it answers is known and different from what it was given, so a controller reading
/// its own write back is caught, and what it records is the far end's own evidence the bytes crossed.
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct Pattern {
address: u8,
answers: std::collections::VecDeque<u8>,
held: u8,
received: Vec<u8>,
/// Every acknowledge this peer was asked to give a read byte, oldest first, so a check can tell
/// the controller actually `NACKed` the last one of a bounded read rather than merely stopped
/// asking for more.
lasts: Vec<bool>,
}
impl Pattern {
/// A peer at `address` answering `bytes`, oldest first, then repeating the last one.
#[must_use]
pub fn answering(address: u8, bytes: impl IntoIterator<Item = u8>) -> Self {
Self {
address,
answers: bytes.into_iter().collect(),
held: 0,
received: Vec::new(),
lasts: Vec::new(),
}
}
/// Every acknowledge the controller gave a byte this peer answered, oldest first.
#[must_use]
pub fn lasts(&self) -> &[bool] {
&self.lasts
}
}
store!(Pattern);
impl Peer for Pattern {
fn start(&mut self, address: u8, _read: bool, _context: &mut Timeline<'_, '_>) -> bool {
address == self.address
}
fn write(&mut self, byte: u8, _context: &mut Timeline<'_, '_>) -> bool {
self.received.push(byte);
true
}
fn read(&mut self, last: bool, _context: &mut Timeline<'_, '_>) -> u8 {
self.lasts.push(last);
if let Some(byte) = self.answers.pop_front() {
self.held = byte;
}
self.held
}
fn received(&self) -> &[u8] {
&self.received
}
fn stop(&mut self, _context: &mut Timeline<'_, '_>) {}
}
/// A 10-bit-addressed stand-in for a bench with no 10-bit chip model yet, RM0090 rev 22 section
/// 27.3.2's note: it acknowledges the header carrying its own top two bits, then its own second
/// byte, and a repeated header with the read bit turns it around with no second byte at all.
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub struct TenBit {
address: u16,
expecting_second_byte: bool,
received: Vec<u8>,
answers: std::collections::VecDeque<u8>,
held: u8,
}
impl TenBit {
/// A peer at the 10-bit `address` answering `bytes`, oldest first, then repeating the last one.
#[must_use]
pub fn answering(address: u16, bytes: impl IntoIterator<Item = u8>) -> Self {
Self {
address,
expecting_second_byte: false,
received: Vec::new(),
answers: bytes.into_iter().collect(),
held: 0,
}
}
}
store!(TenBit);
impl Peer for TenBit {
fn start(&mut self, header: u8, read: bool, _context: &mut Timeline<'_, '_>) -> bool {
let top = u8::try_from((self.address >> 8) & 0x3).unwrap_or(0);
if header != TEN_BIT_HEADER >> 1 | top {
return false;
}
self.expecting_second_byte = !read;
true
}
fn write(&mut self, byte: u8, _context: &mut Timeline<'_, '_>) -> bool {
if self.expecting_second_byte {
self.expecting_second_byte = false;
return byte == u8::try_from(self.address & 0xFF).unwrap_or(0);
}
self.received.push(byte);
true
}
fn read(&mut self, _last: bool, _context: &mut Timeline<'_, '_>) -> u8 {
if let Some(byte) = self.answers.pop_front() {
self.held = byte;
}
self.held
}
fn received(&self) -> &[u8] {
&self.received
}
fn stop(&mut self, _context: &mut Timeline<'_, '_>) {}
}
/// What the byte-period event ends.
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
enum Phase {
/// The address phase's one byte: a 7-bit address, a 10-bit header, or a 10-bit sequence's second
/// byte.
Address { byte: u8, second: bool },
/// A data byte going out.
Write(u8),
/// A data byte coming in. Its acknowledge is decided when it ends, not when it was scheduled,
/// since `ACK` governs whichever byte is on the wire at that instant, RM0090 rev 22 section
/// 27.6.1 bit 11.
Read,
}
/// A byte-period elapsing, RM0090 rev 22 section 27.6.8: nine SCL periods, ending at `event`.
#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize)]
struct Shift {
event: EventId,
phase: Phase,
}
/// The open transaction's direction, the address byte's LSB, RM0090 rev 22 section 27.3.3.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum Direction {
Write,
Read,
}
impl Direction {
fn of(read: bool) -> Self {
if read { Self::Read } else { Self::Write }
}
fn is_read(self) -> bool {
self == Self::Read
}
}
/// A `START` or a `STOP` written while a byte was on the wire, RM0090 rev 22 section 27.3.3: both
/// wait for that byte to finish rather than land at the write. Both can be waiting at once, carried
/// out in the order they were written.
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
enum Pending {
Start,
Stop,
}
/// One inter-integrated circuit interface of an STM32F42xxx, RM0090 rev 22 chapter 27, in controller
/// mode.
#[derive(Debug)]
pub struct I2c {
clock_hz: u64,
peers: Vec<Place<dyn Peer>>,
/// The peer that acknowledged the open transaction's address, if one did.
active: Option<usize>,
reading: Direction,
/// `SR1` was read and nothing has consumed the pairing yet: the next write of `DR` that finds
/// `SB` or `ADD10` standing, or the next read of `SR2` that finds `ADDR` standing, completes
/// whichever sequence it belongs to and consumes this. Neither consumes it on the other's behalf.
sr1_read: bool,
shifting: Option<Shift>,
/// `DR`'s buffer half in the transmit direction, filled only once a byte is already shifting,
/// RM0090 rev 22 section 27.6.6 bit 7's exception for an idle shift register.
transmit: Option<u8>,
/// `DR`'s buffer half in the receive direction.
holding: Option<u8>,
/// A second received byte, landed while `holding` was still full: `BTF`'s condition.
stuck: Option<u8>,
/// The acknowledge bit as it stood one byte back, for `POS`'s "the next byte" reading of it.
delayed_ack: bool,
/// The nanosecond a byte period's division drops, carried into the next byte of the same
/// transaction.
carry: u128,
/// `START` and `STOP` requests waiting behind a byte on the wire, carried out in this order once
/// it ends.
pending: Vec<Pending>,
interrupt: [Level; 2],
requests: [Level; 2],
control: u64,
}
store!(I2c {
values: [
clock_hz,
active,
reading,
sr1_read,
shifting,
transmit,
holding,
stuck,
delayed_ack,
carry,
pending,
interrupt,
requests,
control,
],
parts: [peers],
built: [],
});
impl I2c {
/// The interface of an instance whose peripheral bus runs at `clock_hz`, which `CCR` divides,
/// until the part's tree drives it otherwise.
#[must_use]
pub fn with_clock(clock_hz: u64) -> Self {
Self {
clock_hz,
peers: Vec::new(),
active: None,
reading: Direction::Write,
sr1_read: false,
shifting: None,
transmit: None,
holding: None,
stuck: None,
delayed_ack: true,
carry: 0,
pending: Vec::new(),
interrupt: [Level::Low; 2],
requests: [Level::Low; 2],
control: 0,
}
}
/// Hangs a chip on this bus's wires, behind whatever address it answers to.
pub fn attach(&mut self, peer: impl Peer + 'static) {
let peer: Box<dyn Peer> = Box::new(peer);
// ceiling: a trigger never counts or faults a chip here; upgrade when a board names an I2C chip to one
self.peers.push(Place::new(peer));
}
/// Takes the chips off `from`'s wires and hangs them on these, silent if they were. A part reset
/// ends the open transaction, so a silence that was waiting for it has had it.
pub fn inherit(&mut self, from: &mut Self) {
self.peers = std::mem::take(&mut from.peers);
self.peers.iter_mut().for_each(Place::release);
}
/// Stops the nth chip on these wires answering, or lets it answer again: a board condition,
/// [`Place::silence`]. A chip in the open transaction keeps answering until it ends, so a
/// transfer is never cut in half. Answers whether a chip hangs there.
#[must_use]
pub fn silence(&mut self, nth: usize, silent: bool) -> bool {
let Some(place) = self.peers.get_mut(nth) else {
return false;
};
if self.active == Some(nth) {
place.silence_at_release(silent);
} else {
place.silence(silent);
}
true
}
/// The first chip on this bus, to ask what it saw, or `None` where nothing is hung.
#[must_use]
pub fn peer(&self) -> Option<&dyn Peer> {
self.peers.first().map(Place::chip)
}
/// The nth chip on this bus as the type it was hung as, or `None` where nothing hangs there or
/// another chip does.
pub fn chip_mut<P: Peer>(&mut self, nth: usize) -> Option<&mut P> {
self.peers.get_mut(nth)?.chip_as()
}
/// Tells every chip on this bus that the part restarted, at the instant `context` gives.
pub(crate) fn chips_restarted(&mut self, context: &mut DeviceContext<'_>) {
for place in &mut self.peers {
place.chip_mut().restarted(&mut Timeline::new(context));
}
}
/// The chip the open transaction addressed, if it acknowledged and still answers.
fn active_peer(&mut self) -> Option<&mut dyn Peer> {
self.peers.get_mut(self.active?)?.answering()
}
/// Ends the open transaction with the chip it addressed, which then takes a silence that was
/// waiting for it.
fn release(&mut self, context: &mut DeviceContext<'_>) {
if let Some(peer) = self.active_peer() {
peer.stop(&mut Timeline::new(context));
}
if let Some(place) = self
.active
.take()
.and_then(|index| self.peers.get_mut(index))
{
place.release();
}
}
/// A byte's nine SCL periods as a fraction of a nanosecond, RM0090 rev 22 section 27.6.8:
/// standard mode `2 x CCR`, fast mode `3 x CCR`, or `25 x CCR` under `DUTY`. `None` where `CCR`
/// or the peripheral clock is zero: nothing to divide by, nothing to schedule.
fn byte_period(&self, registers: &RegisterFile) -> Option<(u128, u128)> {
let value = registers.get(Register::Ccr);
let count = ccr::CCR.get(value);
if count == 0 || self.clock_hz == 0 {
return None;
}
let periods: u128 = if !ccr::F_S.is_set(value) {
2
} else if ccr::DUTY.is_set(value) {
25
} else {
3
};
let numerator = 9 * periods * u128::from(count) * 1_000_000_000;
Some((numerator, u128::from(self.clock_hz)))
}
/// Schedules `phase` to end a byte period from `context.now()`, carrying the remainder a
/// division drops into the next byte of the same transaction so a run of them does not drift.
fn schedule(
&mut self,
phase: Phase,
registers: &RegisterFile,
context: &mut DeviceContext<'_>,
) {
let Some((numerator, denominator)) = self.byte_period(registers) else {
return;
};
let total = numerator + self.carry;
let nanos = u64::try_from(total / denominator).unwrap_or(u64::MAX);
self.carry = total % denominator;
let at = VirtualNanos(context.now().0 + nanos);
self.shifting = Some(Shift {
event: context.schedule(at),
phase,
});
}
/// `START` carried out, RM0090 rev 22 section 27.3.3: `SB`, `MSL` and `BUSY` set, `TxE`, `BTF`
/// and `TRA` cleared, at the instant nothing is on the wire to defer it behind, which ChibiOS's
/// own `I2C_EV5_MASTER_MODE_SELECT` reads as `SR1` and `SR2` holding nothing else. A new
/// transaction starts the byte-period carry over, drops a byte still queued behind the last one,
/// and starts the next address phase fresh, 27.3.4: neither survives into it.
fn start_transaction(&mut self, registers: &mut RegisterFile) {
self.carry = 0;
self.transmit = None;
let sr1 = registers.get(Register::Sr1);
registers.set(
Register::Sr1,
sr1::TXE.set(sr1::BTF.set(sr1::SB.set(sr1, 1), 0), 0),
);
let sr2 = registers.get(Register::Sr2);
registers.set(
Register::Sr2,
sr2::TRA.set(sr2::MSL.set(sr2::BUSY.set(sr2, 1), 1), 0),
);
}
/// `START` requested with `PE` set. Deferred behind a byte already on the wire, RM0090 rev 22
/// section 27.3.3, or behind a `BUSY` this transaction does not hold, which is what
/// [`I2c::abort`] can leave standing. Only `SWRST` gets out of that, 27.6.1 bit 15's own note. A
/// repeated start, `BUSY` and `MSL` both already this transaction's own, is taken at once.
fn request_start(&mut self, registers: &mut RegisterFile) {
if self.shifting.is_some() {
self.pending.push(Pending::Start);
return;
}
let sr2 = registers.get(Register::Sr2);
if sr2::BUSY.is_set(sr2) && !sr2::MSL.is_set(sr2) {
return;
}
let cr1 = cr1::START.set(registers.get(Register::Cr1), 0);
registers.set(Register::Cr1, cr1);
self.start_transaction(registers);
}
/// `STOP` requested with `PE` set. Deferred behind a byte already on the wire the same way a
/// `START` is, RM0090 rev 22 sections 27.3.3 and 27.6.1 bit 9.
fn request_stop(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
if self.shifting.is_some() {
self.pending.push(Pending::Stop);
return;
}
let cr1 = cr1::STOP.set(registers.get(Register::Cr1), 0);
registers.set(Register::Cr1, cr1);
self.close(registers, context);
}
/// Searches every peer for one that acknowledges `address`, RM0090 rev 22 section 27.3.3: the
/// controller learns nothing about a peer that does not, and a silent one never does.
fn address(&mut self, address: u8, read: bool, context: &mut DeviceContext<'_>) -> bool {
for (index, place) in self.peers.iter_mut().enumerate() {
if place
.answering()
.is_some_and(|peer| peer.start(address, read, &mut Timeline::new(context)))
{
self.active = Some(index);
return true;
}
}
false
}
/// The address phase's byte has crossed. `second` is a 10-bit sequence's own second byte, sent
/// as a plain byte to the peer the header already selected.
fn finish_address(
&mut self,
byte: u8,
second: bool,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
// A repeated start's 10-bit header carries the read bit and completes the address phase by
// itself, section 27.3.3's "10-bit addressing mode" case. Only the write-direction header
// waits for a second byte, so the mask alone cannot tell the two apart.
let read = byte & 1 != 0;
let ten_bit_header = !second && byte & TEN_BIT_MASK == TEN_BIT_HEADER;
let acked = if second {
self.active_peer()
.is_some_and(|peer| peer.write(byte, &mut Timeline::new(context)))
} else {
// Every first address byte sets the transfer's direction from its own LSB: a 10-bit
// write header is as definite about it as a 7-bit address is.
self.reading = Direction::of(read);
// `mpu9250.rs`'s internal master strips the direction bit the same way before calling
// `Peer::start`, which takes it as its own argument.
self.address(byte >> 1, read, context)
};
if !acked {
registers.set(Register::Sr1, sr1::AF.set(registers.get(Register::Sr1), 1));
return;
}
if ten_bit_header && !read {
registers.set(
Register::Sr1,
sr1::ADD10.set(registers.get(Register::Sr1), 1),
);
return;
}
let sr1 = registers.get(Register::Sr1);
// RM0090 rev 22 section 27.3.3, `EV8_1`.
let sr1 = if self.reading.is_read() {
sr1::ADDR.set(sr1, 1)
} else {
sr1::TXE.set(sr1::ADDR.set(sr1, 1), 1)
};
registers.set(Register::Sr1, sr1);
let sr2 = registers.get(Register::Sr2);
registers.set(
Register::Sr2,
sr2::TRA.set(sr2, u64::from(!self.reading.is_read())),
);
}
/// A transmitted byte's acknowledge has crossed, RM0090 rev 22 section 27.6.6 bits 2 and 7. A
/// NACK sets `AF` and drops whatever was queued behind it, 27.3.4: it does not survive into the
/// repeated start that section assumes follows. An ACK with a byte queued moves it onto the wire
/// at once, `TxE` standing throughout. With nothing queued, `BTF` sets, unless a `STOP` or
/// `START` is already waiting, which carries out its own final state instead.
fn finish_write(
&mut self,
byte: u8,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
let acked = self
.active_peer()
.is_some_and(|peer| peer.write(byte, &mut Timeline::new(context)));
if !acked {
registers.set(Register::Sr1, sr1::AF.set(registers.get(Register::Sr1), 1));
self.transmit = None;
} else if self.active.is_some() && self.pending.is_empty() {
if let Some(next) = self.transmit.take() {
// 27.3.3: the acknowledge moves the queued byte into the shift register, which
// leaves `DR` empty for the next one, `EV8`.
registers.set(Register::Sr1, sr1::TXE.set(registers.get(Register::Sr1), 1));
self.schedule(Phase::Write(next), registers, context);
} else {
let sr1 = registers.get(Register::Sr1);
registers.set(Register::Sr1, sr1::TXE.set(sr1::BTF.set(sr1, 1), 1));
}
}
}
/// A received byte's period has ended: RM0090 rev 22 section 27.6.1 bit 11 reads `ACK` now,
/// against the byte that was actually in the shift register for it, rather than at the instant
/// the byte was scheduled, since 27.3.3's closing sequence clears `ACK` while that byte is still
/// on the wire. `POS` set reads back one byte, banking today's value for the one after.
fn finish_read(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
let cr1_value = registers.get(Register::Cr1);
let live = cr1::ACK.is_set(cr1_value);
let acked = if cr1::POS.is_set(cr1_value) {
self.delayed_ack
} else {
live
};
self.delayed_ack = live;
let last = !acked;
let byte = self
.active_peer()
.map_or(0, |peer| peer.read(last, &mut Timeline::new(context)));
if self.holding.is_none() {
self.holding = Some(byte);
registers.set(
Register::Sr1,
sr1::RXNE.set(registers.get(Register::Sr1), 1),
);
if !last {
self.schedule_read(registers, context);
}
} else {
self.stuck = Some(byte);
registers.set(Register::Sr1, sr1::BTF.set(registers.get(Register::Sr1), 1));
}
}
/// The manual's controller-receiver free run, RM0090 rev 22 section 27.3.3: one byte every
/// period. Nothing is scheduled once a `STOP` or `START` is waiting, or the peer has already
/// been released, so no byte lands after the transaction has ended.
fn schedule_read(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
if self.stuck.is_some()
|| self.shifting.is_some()
|| self.active.is_none()
|| !self.pending.is_empty()
{
return;
}
self.schedule(Phase::Read, registers, context);
}
/// The controller enters receiver mode once `ADDR` clears in the read direction, RM0090 rev 22
/// section 27.3.3.
fn begin_receiving(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
self.delayed_ack = true;
self.schedule_read(registers, context);
}
/// `STOP`'s effect: the peer released, the transaction's flags cleared, RM0090 rev 22 sections
/// 27.6.6 and 27.6.7, `BUSY` among them, its own rule rather than a side effect of the others.
fn close(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
self.release(context);
let sr2 = registers.get(Register::Sr2);
// 27.6.7 bit 1: `BUSY` clears "on detection of a Stop condition", which is this, and no
// other bit's rule: [`I2c::abort`] leaves it exactly as it found it.
let sr2 = sr2::BUSY.set(sr2::MSL.set(sr2::TRA.set(sr2, 0), 0), 0);
registers.set(Register::Sr2, sr2);
let sr1 = registers.get(Register::Sr1);
let sr1 = sr1::TXE.set(sr1, 0);
// RM0090 rev 22 section 27.6.6 bit 2: a stop condition clears `BTF` in transmission alone.
// In reception, `data N-1 and N` are still to be read after it, section 27.3.3.
let sr1 = if self.reading.is_read() {
sr1
} else {
sr1::BTF.set(sr1, 0)
};
registers.set(Register::Sr1, sr1);
self.transmit = None;
self.pending.clear();
}
/// `SWRST` set, RM0090 rev 22 section 27.6.1 bit 15: the interface "under reset state," and its
/// own note gives this bit as the way out of a `BUSY` a glitch left locked. The reset reaches the
/// whole register file, not only the flags a transaction touches, since nothing short of that
/// promise recovers the locked case: [`I2c::abort`], `PE=0`, keeps `BUSY` standing on purpose.
fn swrst(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
self.release(context);
registers.reset();
self.shifting = None;
self.transmit = None;
self.holding = None;
self.stuck = None;
self.pending.clear();
self.reading = Direction::Write;
self.sr1_read = false;
self.delayed_ack = true;
self.carry = 0;
}
/// 27.6.1 bit 15: set and cleared by software, and the interface stays under reset state for as
/// long as it stands, so nothing written anywhere lands but the bit itself.
fn hold_in_reset(registers: &mut RegisterFile) {
registers.reset();
registers.set(Register::Cr1, cr1::SWRST.mask());
}
/// `PE` cleared while a transaction was open, RM0090 rev 22 section 27.6.1 bit 0: releases a peer
/// mid-transaction and drops what was on the wire. [`I2c::close`] clears `BUSY`, its own rule
/// from a stop condition, 27.6.7 bit 1. Here it is put back, since that section's own note keeps
/// it "still updated" through `PE=0`. `AF`, the one error this model can raise, names its own
/// hardware clear at `PE=0` in 27.6.6 bit 10, on top of the written zero [`I2c::write`] already
/// gives it.
fn abort(&mut self, registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
let busy = sr2::BUSY.is_set(registers.get(Register::Sr2));
self.close(registers, context);
registers.set(
Register::Sr2,
sr2::BUSY.set(registers.get(Register::Sr2), u64::from(busy)),
);
self.shifting = None;
self.holding = None;
self.stuck = None;
self.reading = Direction::Write;
let sr1 = registers.get(Register::Sr1);
registers.set(
Register::Sr1,
sr1::SB.set(
sr1::BTF.set(
sr1::ADDR.set(sr1::ADD10.set(sr1::RXNE.set(sr1::AF.set(sr1, 0), 0), 0), 0),
0,
),
0,
),
);
}
fn write_cr1(
&mut self,
value: u64,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
let was = self.control;
if cr1::SWRST.is_set(value) {
if !cr1::SWRST.is_set(was) {
self.swrst(registers, context);
}
Self::hold_in_reset(registers);
} else if !cr1::PE.is_set(value) && cr1::PE.is_set(was) {
self.abort(registers, context);
let cleared = cr1::POS.set(cr1::ACK.set(cr1::START.set(value, 0), 0), 0);
registers.set(Register::Cr1, cleared);
} else if cr1::PE.is_set(value) {
if cr1::START.is_set(value) && !cr1::START.is_set(was) {
self.request_start(registers);
}
if cr1::STOP.is_set(value) && !cr1::STOP.is_set(was) {
self.request_stop(registers, context);
}
} else {
// 27.6.1 bit 0: `PE=0` holds `START`, `ACK` and `POS` clear regardless of what is
// written, bits 8, 10 and 11's own hardware-clear note.
let cleared = cr1::POS.set(cr1::ACK.set(cr1::START.set(value, 0), 0), 0);
registers.set(Register::Cr1, cleared);
}
self.control = registers.get(Register::Cr1);
}
/// `DR` written: the address phase's byte while `SB` or `ADD10` stands and `SR1` was just read,
/// or an outgoing data byte otherwise.
fn write_dr(
&mut self,
byte: u8,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
let sr1_now = registers.get(Register::Sr1);
if self.sr1_read && sr1::SB.is_set(sr1_now) {
self.sr1_read = false;
registers.set(Register::Sr1, sr1::SB.set(sr1_now, 0));
self.schedule(
Phase::Address {
byte,
second: false,
},
registers,
context,
);
return;
}
if self.sr1_read && sr1::ADD10.is_set(sr1_now) {
self.sr1_read = false;
registers.set(Register::Sr1, sr1::ADD10.set(sr1_now, 0));
self.schedule(Phase::Address { byte, second: true }, registers, context);
return;
}
if self.reading.is_read() || self.active.is_none() {
return;
}
if self.shifting.is_some() {
// 27.6.6 bit 7: `DR` really is full now, waiting behind the byte already on the wire.
registers.set(Register::Sr1, sr1::TXE.set(sr1_now, 0));
self.transmit = Some(byte);
} else {
// 27.6.6 bit 7's exception: the shift register was idle, so the byte flows straight
// through and `TxE` is never actually cleared by this write.
registers.set(Register::Sr1, sr1::BTF.set(sr1_now, 0));
self.schedule(Phase::Write(byte), registers, context);
}
}
/// The line of table 124: `SB`, `ADDR`, `ADD10` and `BTF` raise it under `ITEVTEN` alone, and
/// bare `TxE` or `RxNE` need `ITBUFEN` as well. `AF`, the one error this model raises, needs
/// `ITERREN`. The two requests of section 27.3.8 follow `RxNE` and `TxE` under `DMAEN`.
fn refresh_signals(&mut self, registers: &RegisterFile, context: &mut DeviceContext<'_>) {
let sr1 = registers.get(Register::Sr1);
let cr2 = registers.get(Register::Cr2);
for (output, level) in [
(
RECEIVE_REQUEST,
cr2::DMAEN.is_set(cr2) && sr1::RXNE.is_set(sr1),
),
(
TRANSMIT_REQUEST,
cr2::DMAEN.is_set(cr2) && sr1::TXE.is_set(sr1),
),
] {
let wanted = Level::from(level);
if wanted != self.requests[output] {
self.requests[output] = wanted;
context.request(output, wanted);
}
}
let event = cr2::ITEVTEN.is_set(cr2)
&& (sr1::SB.is_set(sr1)
|| sr1::ADDR.is_set(sr1)
|| sr1::ADD10.is_set(sr1)
|| sr1::BTF.is_set(sr1)
|| (cr2::ITBUFEN.is_set(cr2) && (sr1::TXE.is_set(sr1) || sr1::RXNE.is_set(sr1))));
let error = cr2::ITERREN.is_set(cr2) && sr1::AF.is_set(sr1);
for (position, wanted) in [(EVENT, event), (ERROR, error)] {
let wanted = Level::from(wanted);
if wanted != self.interrupt[position] {
self.interrupt[position] = wanted;
context.interrupt(position, wanted);
}
}
}
}
impl Device for I2c {
type Register = Register;
/// The peripheral clock has changed. A byte on the wire keeps the rate it began at: nothing here
/// re-times a period already scheduled. `carry` is a remainder in the old clock's units, so it is
/// dropped with the rate it was a fraction of, the way `usart.rs` and `spi.rs` drop theirs.
fn on_clock(
&mut self,
hz: u64,
_registers: &mut RegisterFile,
_context: &mut DeviceContext<'_>,
) {
self.clock_hz = hz;
self.carry = 0;
}
fn read(
&mut self,
register: Register,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) -> Option<u64> {
match register {
Register::Sr1 => {
self.sr1_read = true;
None
}
Register::Sr2 => {
let value = registers.get(Register::Sr2);
let sr1 = registers.get(Register::Sr1);
if self.sr1_read && sr1::ADDR.is_set(sr1) {
self.sr1_read = false;
registers.set(Register::Sr1, sr1::ADDR.set(sr1, 0));
if self.reading.is_read() {
self.begin_receiving(registers, context);
}
self.refresh_signals(registers, context);
}
Some(value)
}
Register::Dr => {
if self.reading.is_read() {
let byte = self.holding.take();
let sr1 = registers.get(Register::Sr1);
registers.set(Register::Sr1, sr1::RXNE.set(sr1, 0));
if let Some(stuck) = self.stuck.take() {
self.holding = Some(stuck);
let sr1 = registers.get(Register::Sr1);
registers.set(Register::Sr1, sr1::RXNE.set(sr1::BTF.set(sr1, 0), 1));
self.schedule_read(registers, context);
}
self.refresh_signals(registers, context);
return Some(u64::from(byte.unwrap_or(0)));
}
// 27.6.6 bit 2: `BTF` clears on a read of `DR` as well as a write, ChibiOS's own
// `EV8_2` dummy read.
let sr1 = registers.get(Register::Sr1);
if sr1::BTF.is_set(sr1) {
registers.set(Register::Sr1, sr1::BTF.set(sr1, 0));
self.refresh_signals(registers, context);
}
None
}
_ => None,
}
}
/// `DR` receiving is the byte a read would take. `SR1` and `SR2` read as they stand.
fn peek(
&self,
register: Register,
_registers: &RegisterFile,
_now: VirtualNanos,
) -> Option<u64> {
(register == Register::Dr && self.reading.is_read())
.then(|| u64::from(self.holding.unwrap_or(0)))
}
fn write(
&mut self,
register: Register,
value: u64,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
if cr1::SWRST.is_set(self.control) && !matches!(register, Register::Cr1) {
Self::hold_in_reset(registers);
return;
}
match register {
Register::Cr1 => self.write_cr1(value, registers, context),
Register::Dr => {
let byte = u8::try_from(value & 0xFF).expect("masked to eight bits");
self.write_dr(byte, registers, context);
}
_ => {}
}
self.refresh_signals(registers, context);
}
fn on_event(
&mut self,
event: EventId,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
if let Some(shift) = self.shifting.filter(|shift| shift.event == event) {
self.shifted(shift, registers, context);
}
for place in &mut self.peers {
place
.chip_mut()
.on_event(event, &mut Timeline::new(context));
}
}
}
impl I2c {
/// The byte or the address `shift` was moving has crossed, and what waited for it follows.
fn shifted(
&mut self,
shift: Shift,
registers: &mut RegisterFile,
context: &mut DeviceContext<'_>,
) {
self.shifting = None;
match shift.phase {
Phase::Address { byte, second } => {
self.finish_address(byte, second, registers, context);
}
Phase::Write(byte) => self.finish_write(byte, registers, context),
Phase::Read => self.finish_read(registers, context),
}
for pending in std::mem::take(&mut self.pending) {
match pending {
Pending::Stop => {
let cr1 = cr1::STOP.set(registers.get(Register::Cr1), 0);
registers.set(Register::Cr1, cr1);
self.close(registers, context);
}
Pending::Start => {
let cr1 = cr1::START.set(registers.get(Register::Cr1), 0);
registers.set(Register::Cr1, cr1);
self.start_transaction(registers);
}
}
}
self.refresh_signals(registers, context);
}
}