// 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` |
//! | The reset bit | A write that leaves the interface's bit of `RCC_APB1RSTR` set puts it back as it came out of reset: its registers and the transaction and the byte on the wire, with both lines and each request the controller heard rise lowered at once. ChibiOS pulses the bit as the driver starts. The chips and the clock the tree drives stay | 6.3.8 | `a_reset_bit_puts_its_interface_back_and_leaves_the_others_alone` |
//!
//! **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 while the bit of `RCC_APB1RSTR` stands | 6.3.8 | The interface is reset at each write that leaves the bit set and answers as usual between two of them. Held in reset it would answer its reset values and take no write, but ChibiOS sets and clears the bit in two writes, so nothing reaches it while the bit stands |
//!
//! **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 [`crate::chip::spi::Pattern`] and
/// [`crate::chip::uart::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));
}
}
/// Everything a reset clears goes back as built, and an open transaction ends with no stop on the
/// wire, its chip released as a part reset releases it. The chips stay on the bus. The clock stays
/// at the rate the tree drives.
fn reset(&mut self) {
let mut peers = std::mem::take(&mut self.peers);
peers.iter_mut().for_each(Place::release);
*self = Self {
peers,
..Self::with_clock(self.clock_hz)
};
}
/// The interface's reset line, RM0090 rev 22 section 6.3.8: the interface goes back as a reset
/// puts it, and each request the controller heard rise falls at once.
fn reset_line(&mut self, _registers: &mut RegisterFile, context: &mut DeviceContext<'_>) {
context.lower_requests(&self.requests);
self.reset();
}
}
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);
}
}