#![macro_use] use core::future; use core::marker::PhantomData; use core::sync::atomic::{AtomicU32, Ordering}; use core::task::Poll; use embassy_embedded_hal::SetConfig; use embassy_hal_internal::PeripheralType; use embassy_sync::waitqueue::AtomicWaker; use mspm0_metapac::i2c; use crate::Peri; use crate::gpio::{AnyPin, PfType, Pull, SealedPin}; use crate::interrupt::typelevel::Binding; use crate::interrupt::{Interrupt, InterruptExt}; use crate::mode::{Async, Blocking, Mode}; use crate::pac::i2c::{I2c as Regs, vals}; use crate::pac::{self}; /// The clock source for the I2C. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ClockSel { /// Use the bus clock. /// /// Configurable clock. BusClk, /// Use the middle frequency clock. /// /// The MCLK runs at 4 MHz. MfClk, } /// The clock divider for the I2C. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum ClockDiv { // "Do not divide clock source. DivBy1, // "Divide clock source by 2. DivBy2, // "Divide clock source by 3. DivBy3, // "Divide clock source by 4. DivBy4, // "Divide clock source by 5. DivBy5, // "Divide clock source by 6. DivBy6, // "Divide clock source by 7. DivBy7, // "Divide clock source by 8. DivBy8, } impl ClockDiv { pub(crate) fn into(self) -> vals::Ratio { match self { Self::DivBy1 => vals::Ratio::DIV_BY_1, Self::DivBy2 => vals::Ratio::DIV_BY_2, Self::DivBy3 => vals::Ratio::DIV_BY_3, Self::DivBy4 => vals::Ratio::DIV_BY_4, Self::DivBy5 => vals::Ratio::DIV_BY_5, Self::DivBy6 => vals::Ratio::DIV_BY_6, Self::DivBy7 => vals::Ratio::DIV_BY_7, Self::DivBy8 => vals::Ratio::DIV_BY_8, } } fn divider(self) -> u32 { match self { Self::DivBy1 => 1, Self::DivBy2 => 2, Self::DivBy3 => 3, Self::DivBy4 => 4, Self::DivBy5 => 5, Self::DivBy6 => 6, Self::DivBy7 => 7, Self::DivBy8 => 8, } } } /// The I2C mode. #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum BusSpeed { /// Standard mode. /// /// The Standard mode runs at 100 kHz. Standard, /// Fast mode. /// /// The fast mode runs at 400 kHz. FastMode, /// Fast mode plus. /// /// The fast mode plus runs at 1 MHz. FastModePlus, /// Custom mode. /// /// The custom mode frequency (in Hz) can be set manually. Custom(u32), } impl BusSpeed { fn hertz(self) -> u32 { match self { Self::Standard => 100_000, Self::FastMode => 400_000, Self::FastModePlus => 1_000_000, Self::Custom(s) => s, } } } #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] /// Config Error pub enum ConfigError { /// Invalid clock rate. /// /// The clock rate could not be configured with the given conifguratoin. InvalidClockRate, /// Clock source not enabled. /// /// The clock soure is not enabled is SYSCTL. ClockSourceNotEnabled, /// Invalid target address. /// /// The target address is not 7-bit. InvalidTargetAddress, } #[non_exhaustive] #[derive(Clone, Copy, PartialEq, Eq, Debug)] /// Config pub struct Config { /// I2C clock source. pub(crate) clock_source: ClockSel, /// I2C clock divider. pub clock_div: ClockDiv, /// If true: invert SDA pin signal values (VDD = 0/mark, Gnd = 1/idle). pub invert_sda: bool, /// If true: invert SCL pin signal values (VDD = 0/mark, Gnd = 1/idle). pub invert_scl: bool, /// Set the pull configuration for the SDA pin. pub sda_pull: Pull, /// Set the pull configuration for the SCL pin. pub scl_pull: Pull, /// Set the pull configuration for the SCL pin. pub bus_speed: BusSpeed, } impl Default for Config { fn default() -> Self { Self { clock_source: ClockSel::MfClk, clock_div: ClockDiv::DivBy1, invert_sda: false, invert_scl: false, sda_pull: Pull::None, scl_pull: Pull::None, bus_speed: BusSpeed::Standard, } } } impl Config { pub fn sda_pf(&self) -> PfType { PfType::input(self.sda_pull, self.invert_sda) } pub fn scl_pf(&self) -> PfType { PfType::input(self.scl_pull, self.invert_scl) } fn calculate_timer_period(&self) -> u8 { // Sets the timer period to bring the clock frequency to the selected I2C speed // From the documentation: TPR = (I2C_CLK / (I2C_FREQ * (SCL_LP + SCL_HP))) - 1 where: // - I2C_FREQ is desired I2C frequency (= I2C_BASE_FREQ divided by I2C_DIV) // - TPR is the Timer Period register value (range of 1 to 127) // - SCL_LP is the SCL Low period (fixed at 6) // - SCL_HP is the SCL High period (fixed at 4) // - I2C_CLK is functional clock frequency return ((self.calculate_clock_source() / (self.bus_speed.hertz() * 10u32)) - 1) .try_into() .unwrap(); } #[cfg(any(mspm0c110x, mspm0c1105_c1106))] pub(crate) fn calculate_clock_source(&self) -> u32 { // Assume that BusClk has default value. // TODO: calculate BusClk more precisely. match self.clock_source { ClockSel::MfClk => 4_000_000 / self.clock_div.divider(), ClockSel::BusClk => 24_000_000 / self.clock_div.divider(), } } #[cfg(any( mspm0g110x, mspm0g150x, mspm0g151x, mspm0g310x, mspm0g350x, mspm0g351x, mspm0h321x, mspm0l110x, mspm0l122x, mspm0l130x, mspm0l134x, mspm0l222x ))] pub(crate) fn calculate_clock_source(&self) -> u32 { // Assume that BusClk has default value. // TODO: calculate BusClk more precisely. match self.clock_source { ClockSel::MfClk => 4_000_000 / self.clock_div.divider(), ClockSel::BusClk => 32_000_000 / self.clock_div.divider(), } } fn check_clock_i2c(&self) -> bool { // make sure source clock is ~20 faster than i2c clock let clk_ratio = 20; let i2c_clk = self.bus_speed.hertz() / self.clock_div.divider(); let src_clk = self.calculate_clock_source(); // check clock rate return src_clk >= i2c_clk * clk_ratio; } fn define_clock_source(&mut self) -> bool { // decide which clock source to choose based on i2c clock. // If i2c speed <= 200kHz, use MfClk, otherwise use BusClk if self.bus_speed.hertz() / self.clock_div.divider() > 200_000 { // TODO: check if BUSCLK enabled self.clock_source = ClockSel::BusClk; } else { // is MFCLK enabled if !pac::SYSCTL.mclkcfg().read().usemftick() { return false; } self.clock_source = ClockSel::MfClk; } return true; } /// Check the config. /// /// Make sure that configuration is valid and enabled by the system. pub fn check_config(&mut self) -> Result<(), ConfigError> { if !self.define_clock_source() { return Err(ConfigError::ClockSourceNotEnabled); } if !self.check_clock_i2c() { return Err(ConfigError::InvalidClockRate); } Ok(()) } } /// Serial error #[derive(Debug, Eq, PartialEq, Copy, Clone)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[non_exhaustive] pub enum Error { /// Bus error Bus, /// Arbitration lost Arbitration, /// ACK not received (either to the address or to a data byte) Nack, /// Timeout Timeout, /// CRC error Crc, /// Overrun error Overrun, /// Zero-length transfers are not allowed. ZeroLengthTransfer, /// Transfer length is over limit. TransferLengthIsOverLimit, } impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let message = match self { Self::Bus => "Bus Error", Self::Arbitration => "Arbitration Lost", Self::Nack => "ACK Not Received", Self::Timeout => "Request Timed Out", Self::Crc => "CRC Mismatch", Self::Overrun => "Buffer Overrun", Self::ZeroLengthTransfer => "Zero-Length Transfers are not allowed", Self::TransferLengthIsOverLimit => "Transfer length is over limit", }; write!(f, "{}", message) } } impl core::error::Error for Error {} /// I2C Driver. pub struct I2c<'d, M: Mode> { info: &'static Info, state: &'static State, scl: Option>, sda: Option>, _phantom: PhantomData, } impl<'d, M: Mode> SetConfig for I2c<'d, M> { type Config = Config; type ConfigError = ConfigError; fn set_config(&mut self, config: &Self::Config) -> Result<(), Self::ConfigError> { self.set_config(*config) } } impl<'d> I2c<'d, Blocking> { pub fn new_blocking( peri: Peri<'d, T>, scl: Peri<'d, impl SclPin>, sda: Peri<'d, impl SdaPin>, mut config: Config, ) -> Result { if let Err(err) = config.check_config() { return Err(err); } Self::new_inner(peri, scl, sda, config) } } impl<'d> I2c<'d, Async> { pub fn new_async( peri: Peri<'d, T>, scl: Peri<'d, impl SclPin>, sda: Peri<'d, impl SdaPin>, _irq: impl Binding> + 'd, mut config: Config, ) -> Result { if let Err(err) = config.check_config() { return Err(err); } let i2c = Self::new_inner(peri, scl, sda, config); T::info().interrupt.unpend(); unsafe { T::info().interrupt.enable() }; i2c } } impl<'d, M: Mode> I2c<'d, M> { /// Reconfigure the driver pub fn set_config(&mut self, mut config: Config) -> Result<(), ConfigError> { if let Err(err) = config.check_config() { return Err(err); } self.info.interrupt.disable(); if let Some(ref sda) = self.sda { sda.update_pf(config.sda_pf()); } if let Some(ref scl) = self.scl { scl.update_pf(config.scl_pf()); } self.init(&config) } fn init(&mut self, config: &Config) -> Result<(), ConfigError> { // Init I2C self.info.regs.clksel().write(|w| match config.clock_source { ClockSel::BusClk => { w.set_mfclk_sel(false); w.set_busclk_sel(true); } ClockSel::MfClk => { w.set_mfclk_sel(true); w.set_busclk_sel(false); } }); self.info.regs.clkdiv().write(|w| w.set_ratio(config.clock_div.into())); // set up glitch filter self.info.regs.gfctl().modify(|w| { w.set_agfen(false); w.set_agfsel(vals::Agfsel::AGLIT_50); w.set_chain(true); }); // Reset controller transfer, follow TI example self.info.regs.controller(0).cctr().modify(|w| { w.set_burstrun(false); w.set_start(false); w.set_stop(false); w.set_ack(false); w.set_cackoen(false); w.set_rd_on_txempty(false); w.set_cblen(0); }); self.state .clock .store(config.calculate_clock_source(), Ordering::Relaxed); self.info .regs .controller(0) .ctpr() .write(|w| w.set_tpr(config.calculate_timer_period())); // Set Tx Fifo threshold, follow TI example self.info .regs .controller(0) .cfifoctl() .write(|w| w.set_txtrig(vals::CfifoctlTxtrig::EMPTY)); // Set Rx Fifo threshold, follow TI example self.info .regs .controller(0) .cfifoctl() .write(|w| w.set_rxtrig(vals::CfifoctlRxtrig::LEVEL_1)); // Enable controller clock stretching, follow TI example self.info.regs.controller(0).ccr().modify(|w| { w.set_clkstretch(true); w.set_active(true); }); Ok(()) } fn master_stop(&mut self) { // not the first transaction, delay 1000 cycles cortex_m::asm::delay(1000); // Stop transaction self.info.regs.controller(0).cctr().modify(|w| { w.set_cblen(0); w.set_stop(true); w.set_start(false); }); } fn master_continue(&mut self, length: usize, send_ack_nack: bool, send_stop: bool) -> Result<(), Error> { // delay between ongoing transactions, 1000 cycles cortex_m::asm::delay(1000); // Update transaction to length amount of bytes self.info.regs.controller(0).cctr().modify(|w| { w.set_cblen(length as u16); w.set_start(false); w.set_ack(send_ack_nack); if send_stop { w.set_stop(true); } }); Ok(()) } fn master_read( &mut self, address: u8, length: usize, restart: bool, send_ack_nack: bool, send_stop: bool, ) -> Result<(), Error> { if restart { // not the first transaction, delay 1000 cycles cortex_m::asm::delay(1000); } // Set START and prepare to receive bytes into // `buffer`. The START bit can be set even if the bus // is BUSY or I2C is in slave mode. self.info.regs.controller(0).csa().modify(|w| { w.set_taddr(address as u16); w.set_cmode(vals::Mode::MODE7); w.set_dir(vals::Dir::RECEIVE); }); self.info.regs.controller(0).cctr().modify(|w| { w.set_cblen(length as u16); w.set_burstrun(true); w.set_ack(send_ack_nack); w.set_start(true); if send_stop { w.set_stop(true); } }); Ok(()) } fn master_write(&mut self, address: u8, length: usize, send_stop: bool) -> Result<(), Error> { // Start transfer of length amount of bytes self.info.regs.controller(0).csa().modify(|w| { w.set_taddr(address as u16); w.set_cmode(vals::Mode::MODE7); w.set_dir(vals::Dir::TRANSMIT); }); self.info.regs.controller(0).cctr().modify(|w| { w.set_cblen(length as u16); w.set_burstrun(true); w.set_start(true); if send_stop { w.set_stop(true); } }); Ok(()) } fn check_error(&self) -> Result<(), Error> { let csr = self.info.regs.controller(0).csr().read(); if csr.err() { return Err(Error::Nack); } else if csr.arblst() { return Err(Error::Arbitration); } Ok(()) } } impl<'d> I2c<'d, Blocking> { fn master_blocking_continue(&mut self, length: usize, send_ack_nack: bool, send_stop: bool) -> Result<(), Error> { // Perform transaction self.master_continue(length, send_ack_nack, send_stop)?; // Poll until the Controller process all bytes or NACK while self.info.regs.controller(0).csr().read().busy() {} Ok(()) } fn master_blocking_read( &mut self, address: u8, length: usize, restart: bool, send_ack_nack: bool, send_stop: bool, ) -> Result<(), Error> { // unless restart, Wait for the controller to be idle, if !restart { while !self.info.regs.controller(0).csr().read().idle() {} } self.master_read(address, length, restart, send_ack_nack, send_stop)?; // Poll until the Controller process all bytes or NACK while self.info.regs.controller(0).csr().read().busy() {} Ok(()) } fn master_blocking_write(&mut self, address: u8, length: usize, send_stop: bool) -> Result<(), Error> { // Wait for the controller to be idle while !self.info.regs.controller(0).csr().read().idle() {} // Perform writing self.master_write(address, length, send_stop)?; // Poll until the Controller writes all bytes or NACK while self.info.regs.controller(0).csr().read().busy() {} Ok(()) } fn read_blocking_internal( &mut self, address: u8, read: &mut [u8], restart: bool, end_w_stop: bool, ) -> Result<(), Error> { if read.is_empty() { return Err(Error::ZeroLengthTransfer); } if read.len() > self.info.fifo_size { return Err(Error::TransferLengthIsOverLimit); } let read_len = read.len(); let mut bytes_to_read = read_len; for (number, chunk) in read.chunks_mut(self.info.fifo_size).enumerate() { bytes_to_read -= chunk.len(); // if the current transaction is the last & end_w_stop, send stop let send_stop = bytes_to_read == 0 && end_w_stop; // if there are still bytes to read, send ACK let send_ack_nack = bytes_to_read != 0; if number == 0 { self.master_blocking_read( address, chunk.len().min(self.info.fifo_size), restart, send_ack_nack, send_stop, )? } else { self.master_blocking_continue(chunk.len(), send_ack_nack, send_stop)?; } // check errors if let Err(err) = self.check_error() { self.master_stop(); return Err(err); } for byte in chunk { *byte = self.info.regs.controller(0).crxdata().read().value(); } } Ok(()) } fn write_blocking_internal(&mut self, address: u8, write: &[u8], end_w_stop: bool) -> Result<(), Error> { if write.is_empty() { return Err(Error::ZeroLengthTransfer); } if write.len() > self.info.fifo_size { return Err(Error::TransferLengthIsOverLimit); } let mut bytes_to_send = write.len(); for (number, chunk) in write.chunks(self.info.fifo_size).enumerate() { for byte in chunk { let ctrl0 = self.info.regs.controller(0).ctxdata(); ctrl0.write(|w| w.set_value(*byte)); } // if the current transaction is the last & end_w_stop, send stop bytes_to_send -= chunk.len(); let send_stop = end_w_stop && bytes_to_send == 0; if number == 0 { self.master_blocking_write(address, chunk.len(), send_stop)?; } else { self.master_blocking_continue(chunk.len(), false, send_stop)?; } // check errors if let Err(err) = self.check_error() { self.master_stop(); return Err(err); } } Ok(()) } // ========================= // Blocking public API /// Blocking read. pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { // wait until bus is free while self.info.regs.controller(0).csr().read().busbsy() {} self.read_blocking_internal(address, read, false, true) } /// Blocking write. pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { // wait until bus is free while self.info.regs.controller(0).csr().read().busbsy() {} self.write_blocking_internal(address, write, true) } /// Blocking write, restart, read. pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { // wait until bus is free while self.info.regs.controller(0).csr().read().busbsy() {} let err = self.write_blocking_internal(address, write, false); if err != Ok(()) { return err; } self.read_blocking_internal(address, read, true, true) } } impl<'d> I2c<'d, Async> { async fn write_async_internal(&mut self, addr: u8, write: &[u8], end_w_stop: bool) -> Result<(), Error> { let ctrl = self.info.regs.controller(0); let mut bytes_to_send = write.len(); for (number, chunk) in write.chunks(self.info.fifo_size).enumerate() { self.info.regs.cpu_int(0).imask().modify(|w| { w.set_carblost(true); w.set_cnack(true); w.set_ctxdone(true); }); for byte in chunk { ctrl.ctxdata().write(|w| w.set_value(*byte)); } // if the current transaction is the last & end_w_stop, send stop bytes_to_send -= chunk.len(); let send_stop = end_w_stop && bytes_to_send == 0; if number == 0 { self.master_write(addr, chunk.len(), send_stop)?; } else { self.master_continue(chunk.len(), false, send_stop)?; } let res: Result<(), Error> = future::poll_fn(|cx| { use crate::i2c::vals::CpuIntIidxStat; // Register prior to checking the condition self.state.waker.register(cx.waker()); let result = match self.info.regs.cpu_int(0).iidx().read().stat() { CpuIntIidxStat::NO_INTR => Poll::Pending, CpuIntIidxStat::CNACKFG => Poll::Ready(Err(Error::Nack)), CpuIntIidxStat::CARBLOSTFG => Poll::Ready(Err(Error::Arbitration)), CpuIntIidxStat::CTXDONEFG => Poll::Ready(Ok(())), _ => Poll::Pending, }; if !result.is_pending() { self.info .regs .cpu_int(0) .imask() .write_value(i2c::regs::CpuInt::default()); } return result; }) .await; if res.is_err() { self.master_stop(); return res; } } Ok(()) } async fn read_async_internal( &mut self, addr: u8, read: &mut [u8], restart: bool, end_w_stop: bool, ) -> Result<(), Error> { let read_len = read.len(); let mut bytes_to_read = read_len; for (number, chunk) in read.chunks_mut(self.info.fifo_size).enumerate() { bytes_to_read -= chunk.len(); // if the current transaction is the last & end_w_stop, send stop let send_stop = bytes_to_read == 0 && end_w_stop; // if there are still bytes to read, send ACK let send_ack_nack = bytes_to_read != 0; self.info.regs.cpu_int(0).imask().modify(|w| { w.set_carblost(true); w.set_cnack(true); w.set_crxdone(true); }); if number == 0 { self.master_read(addr, chunk.len(), restart, send_ack_nack, send_stop)? } else { self.master_continue(chunk.len(), send_ack_nack, send_stop)?; } let res: Result<(), Error> = future::poll_fn(|cx| { use crate::i2c::vals::CpuIntIidxStat; // Register prior to checking the condition self.state.waker.register(cx.waker()); let result = match self.info.regs.cpu_int(0).iidx().read().stat() { CpuIntIidxStat::NO_INTR => Poll::Pending, CpuIntIidxStat::CNACKFG => Poll::Ready(Err(Error::Nack)), CpuIntIidxStat::CARBLOSTFG => Poll::Ready(Err(Error::Arbitration)), CpuIntIidxStat::CRXDONEFG => Poll::Ready(Ok(())), _ => Poll::Pending, }; if !result.is_pending() { self.info .regs .cpu_int(0) .imask() .write_value(i2c::regs::CpuInt::default()); } return result; }) .await; if res.is_err() { self.master_stop(); return res; } for byte in chunk { *byte = self.info.regs.controller(0).crxdata().read().value(); } } Ok(()) } // ========================= // Async public API pub async fn async_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { // wait until bus is free while self.info.regs.controller(0).csr().read().busbsy() {} self.write_async_internal(address, write, true).await } pub async fn async_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { // wait until bus is free while self.info.regs.controller(0).csr().read().busbsy() {} self.read_async_internal(address, read, false, true).await } pub async fn async_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { // wait until bus is free while self.info.regs.controller(0).csr().read().busbsy() {} let err = self.write_async_internal(address, write, false).await; if err != Ok(()) { return err; } self.read_async_internal(address, read, true, true).await } } impl<'d> embedded_hal_02::blocking::i2c::Read for I2c<'d, Blocking> { type Error = Error; fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { self.blocking_read(address, buffer) } } impl<'d> embedded_hal_02::blocking::i2c::Write for I2c<'d, Blocking> { type Error = Error; fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { self.blocking_write(address, bytes) } } impl<'d> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, Blocking> { type Error = Error; fn write_read(&mut self, address: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { self.blocking_write_read(address, bytes, buffer) } } impl<'d> embedded_hal_02::blocking::i2c::Transactional for I2c<'d, Blocking> { type Error = Error; fn exec( &mut self, address: u8, operations: &mut [embedded_hal_02::blocking::i2c::Operation<'_>], ) -> Result<(), Self::Error> { // wait until bus is free while self.info.regs.controller(0).csr().read().busbsy() {} for i in 0..operations.len() { match &mut operations[i] { embedded_hal_02::blocking::i2c::Operation::Read(buf) => { self.read_blocking_internal(address, buf, false, false)? } embedded_hal_02::blocking::i2c::Operation::Write(buf) => { self.write_blocking_internal(address, buf, false)? } } } self.master_stop(); Ok(()) } } impl embedded_hal::i2c::Error for Error { fn kind(&self) -> embedded_hal::i2c::ErrorKind { match *self { Self::Bus => embedded_hal::i2c::ErrorKind::Bus, Self::Arbitration => embedded_hal::i2c::ErrorKind::ArbitrationLoss, Self::Nack => embedded_hal::i2c::ErrorKind::NoAcknowledge(embedded_hal::i2c::NoAcknowledgeSource::Unknown), Self::Timeout => embedded_hal::i2c::ErrorKind::Other, Self::Crc => embedded_hal::i2c::ErrorKind::Other, Self::Overrun => embedded_hal::i2c::ErrorKind::Overrun, Self::ZeroLengthTransfer => embedded_hal::i2c::ErrorKind::Other, Self::TransferLengthIsOverLimit => embedded_hal::i2c::ErrorKind::Other, } } } impl<'d, M: Mode> embedded_hal::i2c::ErrorType for I2c<'d, M> { type Error = Error; } impl<'d> embedded_hal::i2c::I2c for I2c<'d, Blocking> { fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { self.blocking_read(address, read) } fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { self.blocking_write(address, write) } fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { self.blocking_write_read(address, write, read) } fn transaction( &mut self, address: u8, operations: &mut [embedded_hal::i2c::Operation<'_>], ) -> Result<(), Self::Error> { // wait until bus is free while self.info.regs.controller(0).csr().read().busbsy() {} for i in 0..operations.len() { match &mut operations[i] { embedded_hal::i2c::Operation::Read(buf) => self.read_blocking_internal(address, buf, false, false)?, embedded_hal::i2c::Operation::Write(buf) => self.write_blocking_internal(address, buf, false)?, } } self.master_stop(); Ok(()) } } impl<'d> embedded_hal_async::i2c::I2c for I2c<'d, Async> { async fn read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Self::Error> { self.async_read(address, read).await } async fn write(&mut self, address: u8, write: &[u8]) -> Result<(), Self::Error> { self.async_write(address, write).await } async fn write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { self.async_write_read(address, write, read).await } async fn transaction( &mut self, address: u8, operations: &mut [embedded_hal::i2c::Operation<'_>], ) -> Result<(), Self::Error> { // wait until bus is free while self.info.regs.controller(0).csr().read().busbsy() {} for i in 0..operations.len() { match &mut operations[i] { embedded_hal::i2c::Operation::Read(buf) => self.read_async_internal(address, buf, false, false).await?, embedded_hal::i2c::Operation::Write(buf) => self.write_async_internal(address, buf, false).await?, } } self.master_stop(); Ok(()) } } /// Interrupt handler. pub struct InterruptHandler { _i2c: PhantomData, } impl crate::interrupt::typelevel::Handler for InterruptHandler { // Mask interrupts and wake any task waiting for this interrupt unsafe fn on_interrupt() { T::state().waker.wake(); } } /// Peripheral instance trait. #[allow(private_bounds)] pub trait Instance: SealedInstance + PeripheralType { type Interrupt: crate::interrupt::typelevel::Interrupt; } /// I2C `SDA` pin trait pub trait SdaPin: crate::gpio::Pin { /// Get the PF number needed to use this pin as `SDA`. fn pf_num(&self) -> u8; } /// I2C `SCL` pin trait pub trait SclPin: crate::gpio::Pin { /// Get the PF number needed to use this pin as `SCL`. fn pf_num(&self) -> u8; } // ==== IMPL types ==== pub(crate) struct Info { pub(crate) regs: Regs, pub(crate) interrupt: Interrupt, pub fifo_size: usize, } pub(crate) struct State { /// The clock rate of the I2C. This might be configured. pub(crate) clock: AtomicU32, pub(crate) waker: AtomicWaker, } impl<'d, M: Mode> I2c<'d, M> { fn new_inner( _peri: Peri<'d, T>, scl: Peri<'d, impl SclPin>, sda: Peri<'d, impl SdaPin>, config: Config, ) -> Result { // Init power for I2C T::info().regs.gprcm(0).rstctl().write(|w| { w.set_resetstkyclr(true); w.set_resetassert(true); w.set_key(vals::ResetKey::KEY); }); T::info().regs.gprcm(0).pwren().write(|w| { w.set_enable(true); w.set_key(vals::PwrenKey::KEY); }); // init delay, 16 cycles cortex_m::asm::delay(16); // Init GPIO let scl_inner = new_pin!(scl, config.scl_pf()); let sda_inner = new_pin!(sda, config.sda_pf()); if let Some(ref scl) = scl_inner { let pincm = pac::IOMUX.pincm(scl._pin_cm() as usize); pincm.modify(|w| { w.set_hiz1(true); }); } if let Some(ref sda) = sda_inner { let pincm = pac::IOMUX.pincm(sda._pin_cm() as usize); pincm.modify(|w| { w.set_hiz1(true); }); } let mut this = Self { info: T::info(), state: T::state(), scl: scl_inner, sda: sda_inner, _phantom: PhantomData, }; this.init(&config)?; Ok(this) } } pub(crate) trait SealedInstance { fn info() -> &'static Info; fn state() -> &'static State; } macro_rules! impl_i2c_instance { ($instance: ident, $fifo_size: expr) => { impl crate::i2c::SealedInstance for crate::peripherals::$instance { fn info() -> &'static crate::i2c::Info { use crate::i2c::Info; use crate::interrupt::typelevel::Interrupt; const INFO: Info = Info { regs: crate::pac::$instance, interrupt: crate::interrupt::typelevel::$instance::IRQ, fifo_size: $fifo_size, }; &INFO } fn state() -> &'static crate::i2c::State { use crate::i2c::State; use crate::interrupt::typelevel::Interrupt; static STATE: State = State { clock: core::sync::atomic::AtomicU32::new(0), waker: embassy_sync::waitqueue::AtomicWaker::new(), }; &STATE } } impl crate::i2c::Instance for crate::peripherals::$instance { type Interrupt = crate::interrupt::typelevel::$instance; } }; } macro_rules! impl_i2c_sda_pin { ($instance: ident, $pin: ident, $pf: expr) => { impl crate::i2c::SdaPin for crate::peripherals::$pin { fn pf_num(&self) -> u8 { $pf } } }; } macro_rules! impl_i2c_scl_pin { ($instance: ident, $pin: ident, $pf: expr) => { impl crate::i2c::SclPin for crate::peripherals::$pin { fn pf_num(&self) -> u8 { $pf } } }; } #[cfg(test)] mod tests { use crate::i2c::{BusSpeed, ClockDiv, ClockSel, Config}; /// These tests are based on TI's reference caluclation. #[test] fn ti_calculate_timer_period() { let mut config = Config::default(); config.clock_div = ClockDiv::DivBy1; config.bus_speed = BusSpeed::FastMode; config.clock_source = ClockSel::BusClk; assert_eq!(config.calculate_timer_period(), 7u8); } #[test] fn ti_calculate_timer_period_2() { let mut config = Config::default(); config.clock_div = ClockDiv::DivBy2; config.bus_speed = BusSpeed::FastMode; config.clock_source = ClockSel::BusClk; assert_eq!(config.calculate_timer_period(), 3u8); } #[test] fn ti_calculate_timer_period_3() { let mut config = Config::default(); config.clock_div = ClockDiv::DivBy2; config.bus_speed = BusSpeed::Standard; config.clock_source = ClockSel::BusClk; assert_eq!(config.calculate_timer_period(), 15u8); } #[test] fn ti_calculate_timer_period_4() { let mut config = Config::default(); config.clock_div = ClockDiv::DivBy2; config.bus_speed = BusSpeed::Custom(100_000); config.clock_source = ClockSel::BusClk; assert_eq!(config.calculate_timer_period(), 15u8); } #[test] fn clock_check_fastmodeplus_rate_with_busclk() { let mut config = Config::default(); config.clock_source = ClockSel::BusClk; config.bus_speed = BusSpeed::FastModePlus; assert!(config.check_clock_i2c()); } #[test] fn clock_check_fastmode_rate_with_busclk() { let mut config = Config::default(); config.clock_source = ClockSel::BusClk; config.bus_speed = BusSpeed::FastMode; assert!(config.check_clock_i2c()); } #[test] fn clock_check_fastmodeplus_rate_with_mfclk() { let mut config = Config::default(); config.clock_source = ClockSel::MfClk; config.bus_speed = BusSpeed::FastModePlus; assert!(!config.check_clock_i2c()); } #[test] fn clock_check_fastmode_rate_with_mfclk() { let mut config = Config::default(); config.clock_source = ClockSel::MfClk; config.bus_speed = BusSpeed::FastMode; assert!(!config.check_clock_i2c()); } }