use super::{Config, ConfigError, Driver, RegisterBlock, configure_clock};
pub(super) fn set_frequency(driver: &Driver<'_>, clock_config: &Config) -> Result<(), ConfigError> {
let timeout = clock_config.timeout;
let bus_freq = clock_config.frequency.as_hz();
let source_clk = driver.info.clock_instance.function_clock_frequency();
let half_cycle: u32 = source_clk / bus_freq / 2;
let scl_low = half_cycle;
let scl_high = half_cycle;
let sda_hold = half_cycle / 2;
let sda_sample = scl_high / 2;
let setup = half_cycle;
let hold = half_cycle;
let scl_low = scl_low - 1;
let mut scl_high = scl_high;
scl_high -= 7 + 6;
let scl_high_period = scl_high;
let scl_low_period = scl_low;
let sda_hold_time = sda_hold;
let sda_sample_time = sda_sample;
let scl_rstart_setup_time = setup;
let scl_stop_setup_time = setup;
let scl_start_hold_time = hold;
let scl_stop_hold_time = hold;
configure_clock(
driver.info,
scl_low_period,
scl_high_period,
0,
sda_hold_time,
sda_sample_time,
scl_rstart_setup_time,
scl_stop_setup_time,
scl_start_hold_time,
scl_stop_hold_time,
timeout.apb_cycles(half_cycle)?,
)?;
Ok(())
}
pub(super) fn reset_fifo(driver: &Driver<'_>) {
driver.regs().fifo_conf().write(|w| unsafe {
w.tx_fifo_rst().set_bit();
w.rx_fifo_rst().set_bit();
w.nonfifo_en().clear_bit();
w.nonfifo_rx_thres().bits(1);
w.nonfifo_tx_thres().bits(32)
});
driver.regs().fifo_conf().modify(|_, w| {
w.tx_fifo_rst().clear_bit();
w.rx_fifo_rst().clear_bit()
});
driver
.regs()
.int_clr()
.write(|w| w.rxfifo_full().clear_bit_by_one());
}
pub(super) fn read_fifo(register_block: &RegisterBlock) -> u8 {
register_block.data().read().fifo_rdata().bits()
}
pub(super) fn write_fifo(register_block: &RegisterBlock, data: u8) {
let peri_offset =
register_block as *const _ as usize - crate::peripherals::I2C0::ptr() as usize;
let fifo_ptr =
(property!("i2c_master.i2c0_data_register_ahb_address") + peri_offset) as *mut u32;
unsafe {
fifo_ptr.write_volatile(data as u32);
}
}