use crate::iomuxc::consts;
use crate::iomuxc::lpi2c;
use crate::ral;
use eh02::blocking::i2c as blocking;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
Tx,
Rx,
}
pub struct Pins<SCL, SDA>
where
SCL: lpi2c::Pin<Signal = lpi2c::Scl>,
SDA: lpi2c::Pin<Signal = lpi2c::Sda, Module = SCL::Module>,
{
pub scl: SCL,
pub sda: SDA,
}
pub struct Lpi2c<P, const N: u8> {
lpi2c: ral::lpi2c::Instance<N>,
pins: P,
}
impl<SCL, SDA, const N: u8> Lpi2c<Pins<SCL, SDA>, N>
where
SCL: lpi2c::Pin<Signal = lpi2c::Scl, Module = consts::Const<N>>,
SDA: lpi2c::Pin<Signal = lpi2c::Sda, Module = consts::Const<N>>,
{
pub fn new(
lpi2c: crate::ral::lpi2c::Instance<N>,
mut pins: Pins<SCL, SDA>,
timings: &Timing,
) -> Self {
lpi2c::prepare(&mut pins.scl);
lpi2c::prepare(&mut pins.sda);
Self::init(lpi2c, pins, timings)
}
}
impl<const N: u8> Lpi2c<(), N> {
pub fn without_pins(lpi2c: ral::lpi2c::Instance<N>, timings: &Timing) -> Self {
Self::init(lpi2c, (), timings)
}
}
impl<P, const N: u8> Lpi2c<P, N> {
pub const N: u8 = N;
fn init(mut lpi2c: ral::lpi2c::Instance<N>, pins: P, timings: &Timing) -> Self {
ral::write_reg!(ral::lpi2c, lpi2c, MCR, RST: RST_1);
while ral::read_reg!(ral::lpi2c, lpi2c, MCR, RST == RST_1) {
ral::write_reg!(ral::lpi2c, lpi2c, MCR, RST: RST_0);
}
set_timings(&mut lpi2c, timings);
ral::write_reg!(ral::lpi2c, lpi2c, MFCR, RXWATER: 0b01, TXWATER: 0b01);
ral::write_reg!(ral::lpi2c, lpi2c, MCR, MEN: MEN_1);
Lpi2c { lpi2c, pins }
}
pub fn is_controller_enabled(&self) -> bool {
ral::read_reg!(ral::lpi2c, self.lpi2c, MCR, MEN == MEN_1)
}
pub fn set_controller_enable(&mut self, enable: bool) {
ral::modify_reg!(ral::lpi2c, self.lpi2c, MCR, MEN: enable as u32)
}
pub fn reset_controller(&mut self) {
ral::modify_reg!(ral::lpi2c, self.lpi2c, MCR, RST: RST_1);
while ral::read_reg!(ral::lpi2c, self.lpi2c, MCR, RST == RST_1) {
ral::modify_reg!(ral::lpi2c, self.lpi2c, MCR, RST: RST_0);
}
}
pub fn release(self) -> (ral::lpi2c::Instance<N>, P) {
(self.lpi2c, self.pins)
}
#[inline]
pub fn controller_status(&self) -> ControllerStatus {
ControllerStatus::from_bits_truncate(ral::read_reg!(ral::lpi2c, self.lpi2c, MSR))
}
#[inline]
pub fn clear_controller_status(&self, status: ControllerStatus) {
let msr = status & ControllerStatus::W1C;
ral::write_reg!(ral::lpi2c, self.lpi2c, MSR, msr.bits());
}
#[inline(always)]
pub fn clear_fifo(&mut self) {
ral::modify_reg!(ral::lpi2c, self.lpi2c, MCR, RRF: RRF_1, RTF: RTF_1);
}
#[inline]
pub fn enqueue_controller_command(&self, command: ControllerCommand) {
ral::write_reg!(ral::lpi2c, self.lpi2c, MTDR, command.raw());
}
#[inline]
pub fn read_data_register(&self) -> Option<u8> {
let (empty, data) = ral::read_reg!(ral::lpi2c, self.lpi2c, MRDR, RXEMPTY, DATA);
if empty != 0 {
None
} else {
Some(data as u8)
}
}
pub fn disabled<R>(&mut self, func: impl FnOnce(&mut Disabled<N>) -> R) -> R {
let mut disabled = Disabled::new(&mut self.lpi2c);
func(&mut disabled)
}
fn check_busy(&self) -> Result<(), ControllerStatus> {
let status = self.controller_status();
if status.is_bus_busy() {
Err(status)
} else {
Ok(())
}
}
fn wait_for<T>(
&self,
what: impl Fn(ControllerStatus) -> Option<T>,
) -> Result<T, ControllerStatus> {
loop {
let status = self.controller_status();
if status.has_error() {
return Err(status);
}
if let Some(val) = what(status) {
return Ok(val);
}
}
}
fn wait_for_controller_idle(&self) -> Result<(), ControllerStatus> {
self.wait_for(ControllerStatus::break_controller_idle)
}
fn wait_for_transmit(&self) -> Result<(), ControllerStatus> {
self.wait_for(ControllerStatus::break_transmit_space)
}
fn wait_for_data(&self) -> Result<u8, ControllerStatus> {
self.wait_for(|_| self.read_data_register())
}
fn wait_for_end_of_packet(&self) -> Result<(), ControllerStatus> {
self.wait_for(ControllerStatus::break_end_of_packet)
}
pub fn pins(&self) -> &P {
&self.pins
}
pub fn pins_mut(&mut self) -> &mut P {
&mut self.pins
}
#[inline]
pub fn interrupts(&self) -> Interrupts {
let raw = ral::read_reg!(ral::lpi2c, self.lpi2c, MIER);
let interrupts = Interrupts::from_bits_truncate(raw);
interrupts ^ Interrupts::FIFO_ERROR
}
#[inline]
pub fn set_interrupts(&self, interrupts: Interrupts) {
let interrupts = interrupts ^ Interrupts::FIFO_ERROR;
ral::write_reg!(ral::lpi2c, self.lpi2c, MIER, interrupts.bits());
}
#[inline]
pub fn watermark(&self, direction: Direction) -> u8 {
(match direction {
Direction::Rx => ral::read_reg!(ral::lpi2c, self.lpi2c, MFCR, RXWATER),
Direction::Tx => ral::read_reg!(ral::lpi2c, self.lpi2c, MFCR, TXWATER),
}) as u8
}
#[inline]
pub fn controller_fifo_status(&self) -> ControllerFifoStatus {
let (rxcount, txcount) = ral::read_reg!(ral::lpi2c, self.lpi2c, MFSR, RXCOUNT, TXCOUNT);
ControllerFifoStatus {
rxcount: rxcount as u16,
txcount: txcount as u16,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ControllerFifoStatus {
pub rxcount: u16,
pub txcount: u16,
}
fn set_timings<const N: u8>(lpi2c: &mut ral::lpi2c::Instance<N>, timings: &Timing) {
let clock_config = timings.clock_configuration();
ral::write_reg!(ral::lpi2c, lpi2c, MCCR0,
CLKHI: clock_config.clkhi as u32,
CLKLO: clock_config.clklo as u32,
SETHOLD: clock_config.sethold as u32,
DATAVD: clock_config.datavd as u32
);
ral::modify_reg!(ral::lpi2c, lpi2c, MCFGR1, PRESCALE: timings.prescaler() as u32);
ral::modify_reg!(ral::lpi2c, lpi2c, MCFGR2,
FILTSDA: clock_config.filtsda as u32,
FILTSCL: clock_config.filtscl as u32,
BUSIDLE: timings.busidle
);
}
pub struct Disabled<'a, const N: u8> {
lpi2c: &'a mut ral::lpi2c::Instance<N>,
men: bool,
}
impl<'a, const N: u8> Disabled<'a, N> {
fn new(lpi2c: &'a mut ral::lpi2c::Instance<N>) -> Self {
let men = ral::read_reg!(ral::lpi2c, lpi2c, MCR, MEN == MEN_1);
ral::modify_reg!(ral::lpi2c, lpi2c, MCR, MEN: MEN_0);
Self { lpi2c, men }
}
pub fn set_timings(&mut self, timings: &Timing) {
set_timings(self.lpi2c, timings);
}
#[inline]
pub fn set_watermark(&mut self, direction: Direction, watermark: u8) -> u8 {
let max_watermark = match direction {
Direction::Rx => 1 << ral::read_reg!(ral::lpi2c, self.lpi2c, PARAM, MRXFIFO),
Direction::Tx => 1 << ral::read_reg!(ral::lpi2c, self.lpi2c, PARAM, MTXFIFO),
};
let watermark = watermark.min(max_watermark - 1);
match direction {
Direction::Rx => {
ral::modify_reg!(ral::lpi2c, self.lpi2c, MFCR, RXWATER: watermark as u32)
}
Direction::Tx => {
ral::modify_reg!(ral::lpi2c, self.lpi2c, MFCR, TXWATER: watermark as u32)
}
}
watermark
}
}
impl<const N: u8> Drop for Disabled<'_, N> {
fn drop(&mut self) {
ral::modify_reg!(ral::lpi2c, self.lpi2c, MCR, MEN: self.men as u32);
}
}
bitflags::bitflags! {
pub struct ControllerStatus : u32 {
const BUS_BUSY = 1 << 25;
const CONTROLLER_BUSY = 1 << 24;
const DATA_MATCH = 1 << 14;
const PIN_LOW_TIMEOUT = 1 << 13;
const FIFO_ERROR = 1 << 12;
const ARBITRATION_LOST = 1 << 11;
const NACK_DETECTED = 1 << 10;
const STOP_DETECTED = 1 << 9;
const END_PACKET = 1 << 8;
const RECEIVE_DATA = 1 << 1;
const TRANSMIT_DATA = 1 << 0;
}
}
impl ControllerStatus {
const W1C: Self = Self::from_bits_truncate(
Self::DATA_MATCH.bits()
| Self::PIN_LOW_TIMEOUT.bits()
| Self::FIFO_ERROR.bits()
| Self::ARBITRATION_LOST.bits()
| Self::NACK_DETECTED.bits()
| Self::STOP_DETECTED.bits()
| Self::END_PACKET.bits(),
);
const ERRORS: Self = Self::from_bits_truncate(
Self::PIN_LOW_TIMEOUT.bits()
| Self::FIFO_ERROR.bits()
| Self::ARBITRATION_LOST.bits()
| Self::NACK_DETECTED.bits(),
);
const fn is_bus_busy(self) -> bool {
self.contains(Self::BUS_BUSY) && !self.contains(Self::CONTROLLER_BUSY)
}
fn break_controller_idle(self) -> Option<()> {
(!self.contains(Self::CONTROLLER_BUSY)).then_some(())
}
fn break_end_of_packet(self) -> Option<()> {
self.contains(Self::END_PACKET).then_some(())
}
fn break_transmit_space(self) -> Option<()> {
self.contains(Self::TRANSMIT_DATA).then_some(())
}
const fn has_error(self) -> bool {
self.intersects(Self::ERRORS)
}
}
bitflags::bitflags! {
pub struct Interrupts : u32 {
const DATA_MATCH = 1 << 14;
const PIN_LOW_TIMEOUT = 1 << 13;
const FIFO_ERROR = 1 << 12;
const ARBITRATION_LOST = 1 << 11;
const NACK_DETECT = 1 << 10;
const STOP_DETECT = 1 << 9;
const END_PACKET = 1 << 8;
const RECEIVE_DATA = 1 << 1;
const TRANSMIT_DATA = 1 << 0;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Response {
Ack,
Nack,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ControllerCommand {
Transmit {
byte: u8,
},
Receive {
count: u8,
},
Stop,
ReceiveAndDiscard {
drop: u8,
},
Start {
addr: u8,
expect: Response,
},
}
impl ControllerCommand {
#[inline]
pub const fn read(addr: u8) -> Self {
Self::Start {
addr: (addr << 1) | 1,
expect: Response::Ack,
}
}
#[inline]
pub const fn write(addr: u8) -> Self {
Self::Start {
addr: addr << 1,
expect: Response::Ack,
}
}
}
impl ControllerCommand {
const fn raw(self) -> u32 {
use crate::ral::lpi2c::MTDR::CMD::{offset as OFFSET, RW::*};
match self {
Self::Transmit { byte } => (CMD_0 << OFFSET) | byte as u32,
Self::Receive { count } => (CMD_1 << OFFSET) | count.saturating_sub(1) as u32,
Self::Stop => CMD_2 << OFFSET,
Self::ReceiveAndDiscard { drop } => (CMD_3 << OFFSET) | drop.saturating_sub(1) as u32,
Self::Start {
expect: Response::Ack,
addr,
} => (CMD_4 << OFFSET) | addr as u32,
Self::Start {
expect: Response::Nack,
addr,
} => (CMD_5 << OFFSET) | addr as u32,
}
}
}
impl<P, const N: u8> blocking::TransactionalIter for Lpi2c<P, N> {
type Error = ControllerStatus;
fn exec_iter<'a, O>(&mut self, address: u8, operations: O) -> Result<(), Self::Error>
where
O: IntoIterator<Item = blocking::Operation<'a>>,
{
let mut runner = transaction::Runner::new(self)?;
for mut operation in operations {
runner.next_operation(address, &mut operation)?;
}
runner.stop()?;
Ok(())
}
}
impl<P, const N: u8> blocking::WriteIter for Lpi2c<P, N> {
type Error = ControllerStatus;
fn write<B>(&mut self, address: u8, bytes: B) -> Result<(), Self::Error>
where
B: IntoIterator<Item = u8>,
{
blocking::WriteIterRead::write_iter_read(self, address, bytes, &mut [])
}
}
impl<P, const N: u8> blocking::WriteIterRead for Lpi2c<P, N> {
type Error = ControllerStatus;
fn write_iter_read<B>(
&mut self,
address: u8,
bytes: B,
buffer: &mut [u8],
) -> Result<(), Self::Error>
where
B: IntoIterator<Item = u8>,
{
self.check_busy()?;
self.clear_fifo();
self.clear_controller_status(ControllerStatus::W1C);
self.wait_for_transmit()?;
self.enqueue_controller_command(ControllerCommand::write(address));
let cmds = bytes
.into_iter()
.map(|byte| ControllerCommand::Transmit { byte });
for cmd in cmds {
self.wait_for_transmit()?;
self.enqueue_controller_command(cmd);
}
if !buffer.is_empty() {
self.wait_for_transmit()?;
self.enqueue_controller_command(ControllerCommand::read(address));
self.wait_for_transmit()?;
self.enqueue_controller_command(ControllerCommand::Receive {
count: buffer.len() as u8,
});
for slot in buffer {
*slot = self.wait_for_data()?;
}
}
self.wait_for_transmit()?;
self.enqueue_controller_command(ControllerCommand::Stop);
self.wait_for_end_of_packet()?;
self.wait_for_controller_idle()?;
Ok(())
}
}
impl<P, const N: u8> blocking::Transactional for Lpi2c<P, N> {
type Error = ControllerStatus;
fn exec(
&mut self,
address: u8,
operations: &mut [blocking::Operation],
) -> Result<(), Self::Error> {
let mut runner = transaction::Runner::new(self)?;
for operation in operations {
runner.next_operation(address, operation)?;
}
runner.stop()?;
Ok(())
}
}
impl<P, const N: u8> blocking::Read for Lpi2c<P, N> {
type Error = ControllerStatus;
fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> {
blocking::Transactional::exec(self, address, &mut [blocking::Operation::Read(buffer)])
}
}
impl<P, const N: u8> blocking::Write for Lpi2c<P, N> {
type Error = ControllerStatus;
fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> {
blocking::Transactional::exec(self, address, &mut [blocking::Operation::Write(bytes)])
}
}
impl<P, const N: u8> blocking::WriteRead for Lpi2c<P, N> {
type Error = ControllerStatus;
fn write_read(
&mut self,
address: u8,
bytes: &[u8],
buffer: &mut [u8],
) -> Result<(), Self::Error> {
blocking::Transactional::exec(
self,
address,
&mut [
blocking::Operation::Write(bytes),
blocking::Operation::Read(buffer),
],
)
}
}
impl eh1::i2c::Error for ControllerStatus {
fn kind(&self) -> eh1::i2c::ErrorKind {
use eh1::i2c::{ErrorKind, NoAcknowledgeSource};
if self.contains(ControllerStatus::BUS_BUSY) {
return ErrorKind::Bus;
}
if self.contains(ControllerStatus::NACK_DETECTED) {
return ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown);
}
if self.contains(ControllerStatus::ARBITRATION_LOST) {
return ErrorKind::ArbitrationLoss;
}
ErrorKind::Other
}
}
impl<P, const N: u8> eh1::i2c::ErrorType for Lpi2c<P, N> {
type Error = ControllerStatus;
}
impl<P, const N: u8> eh1::i2c::I2c for Lpi2c<P, N> {
fn transaction(
&mut self,
address: u8,
operations: &mut [eh1::i2c::Operation<'_>],
) -> Result<(), Self::Error> {
let mut runner = transaction::Runner::new(self)?;
for operation in operations {
let mut operation = match operation {
eh1::i2c::Operation::Read(buffer) => blocking::Operation::Read(buffer),
eh1::i2c::Operation::Write(buffer) => blocking::Operation::Write(buffer),
};
runner.next_operation(address, &mut operation)?;
}
runner.stop()?;
Ok(())
}
}
mod transaction {
use super::{ControllerCommand, ControllerStatus, Direction, Lpi2c};
use eh02::blocking::i2c::Operation;
pub struct Runner<'a, I> {
lpi2c: &'a mut I,
direction: Option<Direction>,
}
impl<'a, P, const N: u8> Runner<'a, Lpi2c<P, N>> {
pub fn new(lpi2c: &'a mut Lpi2c<P, N>) -> Result<Self, ControllerStatus> {
lpi2c.check_busy()?;
lpi2c.clear_fifo();
lpi2c.clear_controller_status(ControllerStatus::W1C);
Ok(Self {
lpi2c,
direction: None,
})
}
pub fn next_operation(
&mut self,
address: u8,
operation: &mut Operation,
) -> Result<(), ControllerStatus> {
match (&self.direction, &operation) {
(Some(Direction::Tx), Operation::Write(_)) => {}
(Some(Direction::Rx), Operation::Read(_)) => {}
(Some(Direction::Rx) | None, Operation::Write(_)) => {
self.lpi2c.wait_for_transmit()?;
self.lpi2c
.enqueue_controller_command(ControllerCommand::write(address));
}
(Some(Direction::Tx) | None, Operation::Read(_)) => {
self.lpi2c.wait_for_transmit()?;
self.lpi2c
.enqueue_controller_command(ControllerCommand::read(address));
}
};
match operation {
Operation::Write(buffer) => {
for byte in *buffer {
self.lpi2c.wait_for_transmit()?;
self.lpi2c
.enqueue_controller_command(ControllerCommand::Transmit {
byte: *byte,
});
}
self.direction = Some(Direction::Tx);
}
Operation::Read(buffer) => {
if !buffer.is_empty() {
self.lpi2c.wait_for_transmit()?;
self.lpi2c
.enqueue_controller_command(ControllerCommand::Receive {
count: buffer.len() as u8,
});
for slot in buffer.iter_mut() {
*slot = self.lpi2c.wait_for_data()?;
}
}
self.direction = Some(Direction::Rx);
}
};
Ok(())
}
pub fn stop(self) -> Result<(), ControllerStatus> {
self.lpi2c.wait_for_transmit()?;
self.lpi2c
.enqueue_controller_command(ControllerCommand::Stop);
self.lpi2c.wait_for_end_of_packet()?;
self.lpi2c.wait_for_controller_idle()?;
Ok(())
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ClockConfiguration {
pub clkhi: u8,
pub clklo: u8,
pub sethold: u8,
pub datavd: u8,
pub filtsda: u8,
pub filtscl: u8,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u32)]
pub enum Prescaler {
Prescaler1,
Prescaler2,
Prescaler4,
Prescaler8,
Prescaler16,
Prescaler32,
Prescaler64,
Prescaler128,
}
impl Prescaler {
pub const fn divider(self) -> u8 {
1 << self as u8
}
}
const _: () = assert!(Prescaler::Prescaler1.divider() == 1);
const _: () = assert!(Prescaler::Prescaler128.divider() == 128);
#[derive(Clone, Copy, Debug)]
pub enum ClockSpeed {
KHz100,
KHz400,
MHz1,
}
impl ClockSpeed {
const fn frequency(self) -> u32 {
match self {
ClockSpeed::KHz100 => 100_000,
ClockSpeed::KHz400 => 400_000,
ClockSpeed::MHz1 => 1_000_000,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Timing {
clock_configuration: ClockConfiguration,
prescaler: Prescaler,
busidle: u32,
}
const fn line_latency_cycles(filter: u8, risetime: u8, prescaler: Prescaler) -> u8 {
(2 + filter + risetime) / prescaler.divider()
}
const fn compute_clk(hz: u32, baud: ClockSpeed, prescaler: Prescaler, scl_latency: u8) -> u8 {
let clk: u32 =
(hz / prescaler.divider() as u32 / baud.frequency() - scl_latency as u32 - 2) / 3;
if clk > 0xFF {
0xFFu8
} else {
clk as u8
}
}
impl Timing {
pub const fn ideal(clock_hz: u32, clock_speed: ClockSpeed) -> Self {
const PRESCALERS: [Prescaler; 8] = [
Prescaler::Prescaler1,
Prescaler::Prescaler2,
Prescaler::Prescaler4,
Prescaler::Prescaler8,
Prescaler::Prescaler16,
Prescaler::Prescaler32,
Prescaler::Prescaler64,
Prescaler::Prescaler128,
];
const CLOCK_PERIOD_MAX_VAL: u8 = 0x3Fu8;
let mut clk = 0xFFu8;
let mut idx = 0usize;
while idx < PRESCALERS.len() {
let scl_latency = line_latency_cycles(0, 0, PRESCALERS[idx]);
clk = compute_clk(clock_hz, clock_speed, PRESCALERS[idx], scl_latency);
if clk.saturating_mul(2) <= CLOCK_PERIOD_MAX_VAL {
break;
}
idx += 1;
}
assert!(
clk.saturating_mul(2) <= CLOCK_PERIOD_MAX_VAL,
"Could not compute CLKHI / CLKLO"
);
let prescaler = PRESCALERS[idx];
let mut clkhi = clk;
if clkhi < 0x01 {
clkhi = 0x01;
}
let mut clklo = clk * 2;
if clklo < 0x03 {
clklo = 0x03;
}
let mut sethold = clkhi;
if sethold < 0x02 {
sethold = 0x02;
}
let mut datavd = clkhi / 2;
if datavd < 0x01 {
datavd = 0x01;
}
Self::new(
ClockConfiguration {
clkhi,
clklo,
sethold,
datavd,
filtsda: 0,
filtscl: 0,
},
prescaler,
)
}
pub const fn new(clock_configuration: ClockConfiguration, prescaler: Prescaler) -> Self {
const fn max(left: u32, right: u32) -> u32 {
if left > right {
left
} else {
right
}
}
let busidle = max(
(clock_configuration.clklo as u32 + clock_configuration.sethold as u32 + 2) * 2,
clock_configuration.clkhi as u32 + 1,
);
Self {
clock_configuration,
prescaler,
busidle,
}
}
pub const fn clock_configuration(&self) -> ClockConfiguration {
self.clock_configuration
}
pub const fn prescaler(&self) -> Prescaler {
self.prescaler
}
pub const fn override_busidle(mut self, busidle: u32) -> Self {
self.busidle = busidle;
self
}
}
#[cfg(test)]
mod tests {
use super::{ClockSpeed, Prescaler, Timing};
#[test]
fn timing_ideal() {
let timings = Timing::ideal(8_000_000, ClockSpeed::KHz100);
assert_eq!(timings.prescaler, Prescaler::Prescaler1);
assert_eq!(timings.clock_configuration.clkhi, 25);
assert_eq!(timings.clock_configuration.clklo, 50);
assert_eq!(timings.clock_configuration.datavd, 12);
assert_eq!(timings.clock_configuration.sethold, 25);
assert_eq!(timings.clock_configuration.filtscl, 0);
assert_eq!(timings.clock_configuration.filtsda, 0);
let timings = Timing::ideal(8_000_000, ClockSpeed::KHz400);
assert_eq!(timings.prescaler, Prescaler::Prescaler1);
assert_eq!(timings.clock_configuration.clkhi, 5);
assert_eq!(timings.clock_configuration.clklo, 10);
assert_eq!(timings.clock_configuration.datavd, 2);
assert_eq!(timings.clock_configuration.sethold, 5);
assert_eq!(timings.clock_configuration.filtscl, 0);
assert_eq!(timings.clock_configuration.filtsda, 0);
let timings = Timing::ideal(8_000_000, ClockSpeed::MHz1);
assert_eq!(timings.prescaler, Prescaler::Prescaler1);
assert_eq!(timings.clock_configuration.clkhi, 1);
assert_eq!(timings.clock_configuration.clklo, 3);
assert_eq!(timings.clock_configuration.datavd, 1);
assert_eq!(timings.clock_configuration.sethold, 2);
assert_eq!(timings.clock_configuration.filtscl, 0);
assert_eq!(timings.clock_configuration.filtsda, 0);
}
}