From 3d146e5793a2ef0e3c52867b25e14df854949238 Mon Sep 17 00:00:00 2001 From: Benjamin Koch <bbbsnowball@gmail.com> Date: Sat, 20 May 2023 16:46:23 +0200 Subject: [PATCH] remove our copy of embassy_rp::i2c because we cannot use it for zero-length writes anyway --- firmware/rust1/src/rp/i2c.rs | 961 ----------------------------------- firmware/rust1/src/rp/mod.rs | 1 - 2 files changed, 962 deletions(-) delete mode 100644 firmware/rust1/src/rp/i2c.rs diff --git a/firmware/rust1/src/rp/i2c.rs b/firmware/rust1/src/rp/i2c.rs deleted file mode 100644 index 48c3e32..0000000 --- a/firmware/rust1/src/rp/i2c.rs +++ /dev/null @@ -1,961 +0,0 @@ -// This is a modified copy of embassy/embassy-rp/src/i2c.rs. -// We have changed: -// - allow empty buffer for write (for I2C scan) -// - don't block access to reserved addresses (also for I2C scan) - -use core::future; -use core::marker::PhantomData; -use core::task::Poll; - -use embassy_cortex_m::interrupt::InterruptExt; -use embassy_hal_common::{into_ref, PeripheralRef}; -use embassy_sync::waitqueue::AtomicWaker; -use pac::i2c; - -use embassy_rp::gpio::Pin; -use embassy_rp::gpio::AnyPin; -use embassy_rp::{pac, peripherals, Peripheral}; - -/// I2C error abort reason -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum AbortReason { - /// A bus operation was not acknowledged, e.g. due to the addressed device - /// not being available on the bus or the device not being ready to process - /// requests at the moment - NoAcknowledge, - /// The arbitration was lost, e.g. electrical problems with the clock signal - ArbitrationLoss, - Other(u32), -} - -/// I2C error -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Error { - /// I2C abort with error - Abort(AbortReason), - /// User passed in a read buffer that was 0 length - InvalidReadBufferLength, - /// User passed in a write buffer that was 0 length - InvalidWriteBufferLength, - /// Target i2c address is out of range - AddressOutOfRange(u16), - /// Target i2c address is reserved - AddressReserved(u16), -} - -#[non_exhaustive] -#[derive(Copy, Clone)] -pub struct Config { - pub frequency: u32, -} - -impl Default for Config { - fn default() -> Self { - Self { frequency: 100_000 } - } -} - -const FIFO_SIZE: u8 = 16; - -pub struct I2c<'d, T: Instance, M: Mode> { - phantom: PhantomData<(&'d mut T, M)>, -} - -/* -impl<'d, T: Instance> I2c<'d, T, Blocking> { - pub fn new_blocking( - peri: impl Peripheral<P = T> + 'd, - scl: impl Peripheral<P = impl SclPin<T>> + 'd, - sda: impl Peripheral<P = impl SdaPin<T>> + 'd, - config: Config, - ) -> Self { - into_ref!(scl, sda); - Self::new_inner(peri, scl.map_into(), sda.map_into(), config) - } -} -*/ - -impl<'d, T: Instance> I2c<'d, T, Async> { - pub fn new_async( - peri: impl Peripheral<P = T> + 'd, - scl: impl Peripheral<P = impl SclPin<T>> + 'd, - sda: impl Peripheral<P = impl SdaPin<T>> + 'd, - irq: impl Peripheral<P = T::Interrupt> + 'd, - config: Config, - ) -> Self { - into_ref!(scl, sda, irq); - - let i2c = Self::new_inner(peri, scl.map_into(), sda.map_into(), config); - - irq.set_handler(Self::on_interrupt); - unsafe { - let i2c = T::regs(); - - // mask everything initially - i2c.ic_intr_mask().write_value(i2c::regs::IcIntrMask(0)); - } - irq.unpend(); - debug_assert!(!irq.is_pending()); - irq.enable(); - - i2c - } - - /// Calls `f` to check if we are ready or not. - /// If not, `g` is called once the waker is set (to eg enable the required interrupts). - async fn wait_on<F, U, G>(&mut self, mut f: F, mut g: G) -> U - where - F: FnMut(&mut Self) -> Poll<U>, - G: FnMut(&mut Self), - { - future::poll_fn(|cx| { - let r = f(self); - - if r.is_pending() { - T::waker().register(cx.waker()); - g(self); - } - r - }) - .await - } - - // Mask interrupts and wake any task waiting for this interrupt - unsafe fn on_interrupt(_: *mut ()) { - let i2c = T::regs(); - i2c.ic_intr_mask().write_value(pac::i2c::regs::IcIntrMask::default()); - - T::waker().wake(); - } - - async fn read_async_internal(&mut self, buffer: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { - if buffer.is_empty() { - return Err(Error::InvalidReadBufferLength); - } - - let p = T::regs(); - - let mut remaining = buffer.len(); - let mut remaining_queue = buffer.len(); - - let mut abort_reason = Ok(()); - - while remaining > 0 { - // Waggle SCK - basically the same as write - let tx_fifo_space = Self::tx_fifo_capacity(); - let mut batch = 0; - - debug_assert!(remaining_queue > 0); - - for _ in 0..remaining_queue.min(tx_fifo_space as usize) { - remaining_queue -= 1; - let last = remaining_queue == 0; - batch += 1; - - unsafe { - p.ic_data_cmd().write(|w| { - w.set_restart(restart && remaining_queue == buffer.len() - 1); - w.set_stop(last && send_stop); - w.set_cmd(true); - }); - } - } - - // We've either run out of txfifo or just plain finished setting up - // the clocks for the message - either way we need to wait for rx - // data. - - debug_assert!(batch > 0); - let res = self - .wait_on( - |me| { - let rxfifo = Self::rx_fifo_len(); - if let Err(abort_reason) = me.read_and_clear_abort_reason(false) { - Poll::Ready(Err(abort_reason)) - } else if rxfifo >= batch { - Poll::Ready(Ok(rxfifo)) - } else { - Poll::Pending - } - }, - |_me| unsafe { - // Set the read threshold to the number of bytes we're - // expecting so we don't get spurious interrupts. - p.ic_rx_tl().write(|w| w.set_rx_tl(batch - 1)); - - p.ic_intr_mask().modify(|w| { - w.set_m_rx_full(true); - w.set_m_tx_abrt(true); - }); - }, - ) - .await; - - match res { - Err(reason) => { - abort_reason = Err(reason); - break; - } - Ok(rxfifo) => { - // Fetch things from rx fifo. We're assuming we're the only - // rxfifo reader, so nothing else can take things from it. - let rxbytes = (rxfifo as usize).min(remaining); - let received = buffer.len() - remaining; - for b in &mut buffer[received..received + rxbytes] { - *b = unsafe { p.ic_data_cmd().read().dat() }; - } - remaining -= rxbytes; - } - }; - } - - self.wait_stop_det(abort_reason, send_stop, false).await - } - - async fn write_async_internal( - &mut self, - bytes: impl IntoIterator<Item = u8>, - send_stop: bool, - ) -> Result<(), Error> { - let p = T::regs(); - - let mut bytes = bytes.into_iter().peekable(); - let mut empty_transfer = true; - - let status = unsafe { p.ic_status().read() }; - defmt::info!("ic_status: {:?}, {}", status.0, status.mst_activity()); - - let res = 'xmit: loop { - let tx_fifo_space = Self::tx_fifo_capacity(); - - for _ in 0..tx_fifo_space { - if let Some(byte) = bytes.next() { - let last = bytes.peek().is_none(); - empty_transfer = false; - - unsafe { - p.ic_data_cmd().write(|w| { - w.set_stop(last && send_stop); - w.set_cmd(false); - w.set_dat(byte); - }); - } - } else if empty_transfer && send_stop { - // This is no good because it will still send one byte before stopping. - //p.ic_data_cmd().write(|w| { - // w.set_stop(send_stop); - //}); - - // The Arduino code that we used before resorts to bitbanging in this case: - // https://github.com/earlephilhower/arduino-pico/blob/6e52b72523b11470b2ad2b0578ca1500be238108/libraries/Wire/src/Wire.cpp#L257 - - // We can abort the transfer to send a STOP but we have to wait for the address - // to be sent. If we set TX_EMPTY_CTRL=1, it should wait until the address has - // been sent. - //FIXME I think we set this in any case. - unsafe { - p.ic_con().modify(|w| { - w.set_tx_empty_ctrl(true); - }); - } - } else { - break 'xmit Ok(()); - } - } - - let res = self - .wait_on( - |me| { - if let abort_reason @ Err(_) = me.read_and_clear_abort_reason(false) { - Poll::Ready(abort_reason) - } else if !Self::tx_fifo_full() { - // resume if there's any space free in the tx fifo - Poll::Ready(Ok(())) - } else { - Poll::Pending - } - }, - |_me| unsafe { - // Set tx "free" threshold a little high so that we get - // woken before the fifo completely drains to minimize - // transfer stalls. - p.ic_tx_tl().write(|w| w.set_tx_tl(1)); - - p.ic_intr_mask().modify(|w| { - w.set_m_tx_empty(true); - w.set_m_tx_abrt(true); - }) - }, - ) - .await; - //defmt::info!("got tx empty: {:?}", res); - if res.is_err() { - break res; - } - - if empty_transfer && send_stop { - let status = unsafe { p.ic_status().read() }; - let abort_reason = unsafe { p.ic_tx_abrt_source().read() }; - defmt::info!("ic_status: {:?}, {}, {:?}", status.0, status.mst_activity(), abort_reason.0); - unsafe { - p.ic_enable().modify(|w| { - w.set_abort(true); - }) - } - let status = unsafe { p.ic_status().read() }; - let abort_reason = unsafe { p.ic_tx_abrt_source().read() }; - defmt::info!("ic_status: {:?}, {}, {:?}", status.0, status.mst_activity(), abort_reason.0); - - defmt::info!("wait_stop_det"); - let x = self.wait_stop_det(res, send_stop, empty_transfer && send_stop && false).await; - return match x { - Ok(()) => Ok(()), - Err(Error::Abort(AbortReason::Other(65536))) => Ok(()), // user abort is expected - Err(e) => Err(e), - } - } - }; - - self.wait_stop_det(res, send_stop, empty_transfer && send_stop && false).await - } - - /// Helper to wait for a stop bit, for both tx and rx. If we had an abort, - /// then we'll get a hardware-generated stop, otherwise wait for a stop if - /// we're expecting it. - /// - /// Also handles an abort which arises while processing the tx fifo. - async fn wait_stop_det(&mut self, had_abort: Result<(), Error>, do_stop: bool, user_abort_is_ok: bool) -> Result<(), Error> { - if had_abort.is_err() || do_stop { - let p = T::regs(); - - let had_abort2 = self - .wait_on( - |me| unsafe { - // We could see an abort while processing fifo backlog, - // so handle it here. - let abort = me.read_and_clear_abort_reason(user_abort_is_ok); - if had_abort.is_ok() && abort.is_err() { - Poll::Ready(abort) - } else if p.ic_raw_intr_stat().read().stop_det() { - Poll::Ready(Ok(())) - } else { - Poll::Pending - } - }, - |_me| unsafe { - p.ic_intr_mask().modify(|w| { - w.set_m_stop_det(true); - w.set_m_tx_abrt(true); - }); - }, - ) - .await; - unsafe { - p.ic_clr_stop_det().read(); - } - - had_abort.and(had_abort2) - } else { - had_abort - } - } - - pub async fn read_async(&mut self, addr: u16, buffer: &mut [u8]) -> Result<(), Error> { - Self::setup(addr)?; - self.read_async_internal(buffer, false, true).await - } - - pub async fn write_async(&mut self, addr: u16, bytes: impl IntoIterator<Item = u8>) -> Result<(), Error> { - Self::setup(addr)?; - self.write_async_internal(bytes, true).await - } -} - -// copy of internal method because we need it here -fn io<'d>(pin : &PeripheralRef<'d, AnyPin>) -> pac::io::Gpio { - use embassy_rp::gpio::Bank; - let block = match pin.bank() { - Bank::Bank0 => embassy_rp::pac::IO_BANK0, - Bank::Qspi => embassy_rp::pac::IO_QSPI, - }; - block.gpio(pin.pin() as _) -} - -// copy of internal method because we need it here -fn pad_ctrl<'d>(pin : &PeripheralRef<'d, AnyPin>) -> embassy_rp::pac::common::Reg<pac::pads::regs::GpioCtrl, embassy_rp::pac::common::RW> { - use embassy_rp::gpio::Bank; - let block = match pin.bank() { - Bank::Bank0 => embassy_rp::pac::PADS_BANK0, - Bank::Qspi => embassy_rp::pac::PADS_QSPI, - }; - block.gpio(pin.pin() as _) -} - -// copy of internal method because we need it here -pub unsafe fn reset(peris: embassy_rp::pac::resets::regs::Peripherals) { - embassy_rp::pac::RESETS.reset().write_value(peris); -} - -// copy of internal method because we need it here -pub unsafe fn unreset_wait(peris: embassy_rp::pac::resets::regs::Peripherals) { - // TODO use the "atomic clear" register version - embassy_rp::pac::RESETS.reset().modify(|v| *v = embassy_rp::pac::resets::regs::Peripherals(v.0 & !peris.0)); - while ((!embassy_rp::pac::RESETS.reset_done().read().0) & peris.0) != 0 {} -} - - -impl<'d, T: Instance + 'd, M: Mode> I2c<'d, T, M> { - fn new_inner( - _peri: impl Peripheral<P = T> + 'd, - scl: PeripheralRef<'d, AnyPin>, - sda: PeripheralRef<'d, AnyPin>, - config: Config, - ) -> Self { - into_ref!(_peri); - - assert!(config.frequency <= 1_000_000); - assert!(config.frequency > 0); - - let p = T::regs(); - - unsafe { - let reset = T::reset(); - self::reset(reset); - unreset_wait(reset); - - p.ic_enable().write(|w| w.set_enable(false)); - - // Select controller mode & speed - p.ic_con().modify(|w| { - // Always use "fast" mode (<= 400 kHz, works fine for standard - // mode too) - w.set_speed(i2c::vals::Speed::FAST); - w.set_master_mode(true); - w.set_ic_slave_disable(true); - w.set_ic_restart_en(true); - w.set_tx_empty_ctrl(true); - }); - - // Set FIFO watermarks to 1 to make things simpler. This is encoded - // by a register value of 0. - p.ic_tx_tl().write(|w| w.set_tx_tl(0)); - p.ic_rx_tl().write(|w| w.set_rx_tl(0)); - - // Configure SCL & SDA pins - io(&scl).ctrl().write(|w| w.set_funcsel(3)); - io(&sda).ctrl().write(|w| w.set_funcsel(3)); - - pad_ctrl(&scl).write(|w| { - w.set_schmitt(true); - w.set_ie(true); - w.set_od(false); - w.set_pue(true); - w.set_pde(false); - }); - pad_ctrl(&sda).write(|w| { - w.set_schmitt(true); - w.set_ie(true); - w.set_od(false); - w.set_pue(true); - w.set_pde(false); - }); - - // Configure baudrate - - // There are some subtleties to I2C timing which we are completely - // ignoring here See: - // https://github.com/raspberrypi/pico-sdk/blob/bfcbefafc5d2a210551a4d9d80b4303d4ae0adf7/src/rp2_common/hardware_i2c/i2c.c#L69 - let clk_base = embassy_rp::clocks::clk_peri_freq(); - - let period = (clk_base + config.frequency / 2) / config.frequency; - let lcnt = period * 3 / 5; // spend 3/5 (60%) of the period low - let hcnt = period - lcnt; // and 2/5 (40%) of the period high - - // Check for out-of-range divisors: - assert!(hcnt <= 0xffff); - assert!(lcnt <= 0xffff); - assert!(hcnt >= 8); - assert!(lcnt >= 8); - - // Per I2C-bus specification a device in standard or fast mode must - // internally provide a hold time of at least 300ns for the SDA - // signal to bridge the undefined region of the falling edge of SCL. - // A smaller hold time of 120ns is used for fast mode plus. - let sda_tx_hold_count = if config.frequency < 1_000_000 { - // sda_tx_hold_count = clk_base [cycles/s] * 300ns * (1s / - // 1e9ns) Reduce 300/1e9 to 3/1e7 to avoid numbers that don't - // fit in uint. Add 1 to avoid division truncation. - ((clk_base * 3) / 10_000_000) + 1 - } else { - // fast mode plus requires a clk_base > 32MHz - assert!(clk_base >= 32_000_000); - - // sda_tx_hold_count = clk_base [cycles/s] * 120ns * (1s / - // 1e9ns) Reduce 120/1e9 to 3/25e6 to avoid numbers that don't - // fit in uint. Add 1 to avoid division truncation. - ((clk_base * 3) / 25_000_000) + 1 - }; - assert!(sda_tx_hold_count <= lcnt - 2); - - p.ic_fs_scl_hcnt().write(|w| w.set_ic_fs_scl_hcnt(hcnt as u16)); - p.ic_fs_scl_lcnt().write(|w| w.set_ic_fs_scl_lcnt(lcnt as u16)); - p.ic_fs_spklen() - .write(|w| w.set_ic_fs_spklen(if lcnt < 16 { 1 } else { (lcnt / 16) as u8 })); - p.ic_sda_hold() - .modify(|w| w.set_ic_sda_tx_hold(sda_tx_hold_count as u16)); - - // Enable I2C block - p.ic_enable().write(|w| w.set_enable(true)); - } - - Self { phantom: PhantomData } - } - - fn setup(addr: u16) -> Result<(), Error> { - if addr >= 0x80 { - return Err(Error::AddressOutOfRange(addr)); - } - - //if i2c_reserved_addr(addr) { - // return Err(Error::AddressReserved(addr)); - //} - - let p = T::regs(); - unsafe { - p.ic_enable().write(|w| w.set_enable(false)); - p.ic_tar().write(|w| w.set_ic_tar(addr)); - p.ic_enable().write(|w| w.set_enable(true)); - } - Ok(()) - } - - #[inline] - fn tx_fifo_full() -> bool { - Self::tx_fifo_capacity() == 0 - } - - #[inline] - fn tx_fifo_capacity() -> u8 { - let p = T::regs(); - unsafe { FIFO_SIZE - p.ic_txflr().read().txflr() } - } - - #[inline] - fn rx_fifo_len() -> u8 { - let p = T::regs(); - unsafe { p.ic_rxflr().read().rxflr() } - } - - fn read_and_clear_abort_reason(&mut self, user_abort_is_ok: bool) -> Result<(), Error> { - let p = T::regs(); - unsafe { - let abort_reason = p.ic_tx_abrt_source().read(); - if abort_reason.0 != 0 { - // Note clearing the abort flag also clears the reason, and this - // instance of flag is clear-on-read! Note also the - // IC_CLR_TX_ABRT register always reads as 0. - p.ic_clr_tx_abrt().read(); - - let reason = if abort_reason.abrt_7b_addr_noack() - | abort_reason.abrt_10addr1_noack() - | abort_reason.abrt_10addr2_noack() - { - AbortReason::NoAcknowledge - } else if abort_reason.arb_lost() { - AbortReason::ArbitrationLoss - } else if user_abort_is_ok && abort_reason.abrt_user_abrt() { - return Ok(()) - } else { - AbortReason::Other(abort_reason.0) - }; - - Err(Error::Abort(reason)) - } else { - Ok(()) - } - } - } - - fn read_blocking_internal(&mut self, read: &mut [u8], restart: bool, send_stop: bool) -> Result<(), Error> { - if read.is_empty() { - return Err(Error::InvalidReadBufferLength); - } - - let p = T::regs(); - let lastindex = read.len() - 1; - for (i, byte) in read.iter_mut().enumerate() { - let first = i == 0; - let last = i == lastindex; - - // NOTE(unsafe) We have &mut self - unsafe { - // wait until there is space in the FIFO to write the next byte - while Self::tx_fifo_full() {} - - p.ic_data_cmd().write(|w| { - w.set_restart(restart && first); - w.set_stop(send_stop && last); - - w.set_cmd(true); - }); - - while Self::rx_fifo_len() == 0 { - self.read_and_clear_abort_reason(false)?; - } - - *byte = p.ic_data_cmd().read().dat(); - } - } - - Ok(()) - } - - fn write_blocking_internal(&mut self, write: &[u8], send_stop: bool) -> Result<(), Error> { - if write.is_empty() { - return Err(Error::InvalidWriteBufferLength); - } - - let p = T::regs(); - - for (i, byte) in write.iter().enumerate() { - let last = i == write.len() - 1; - - // NOTE(unsafe) We have &mut self - unsafe { - p.ic_data_cmd().write(|w| { - w.set_stop(send_stop && last); - w.set_dat(*byte); - }); - - // Wait until the transmission of the address/data from the - // internal shift register has completed. For this to function - // correctly, the TX_EMPTY_CTRL flag in IC_CON must be set. The - // TX_EMPTY_CTRL flag was set in i2c_init. - while !p.ic_raw_intr_stat().read().tx_empty() {} - - let abort_reason = self.read_and_clear_abort_reason(false); - - if abort_reason.is_err() || (send_stop && last) { - // If the transaction was aborted or if it completed - // successfully wait until the STOP condition has occurred. - - while !p.ic_raw_intr_stat().read().stop_det() {} - - p.ic_clr_stop_det().read().clr_stop_det(); - } - - // Note the hardware issues a STOP automatically on an abort - // condition. Note also the hardware clears RX FIFO as well as - // TX on abort, ecause we set hwparam - // IC_AVOID_RX_FIFO_FLUSH_ON_TX_ABRT to 0. - abort_reason?; - } - } - Ok(()) - } - - // ========================= - // Blocking public API - // ========================= - - pub fn blocking_read(&mut self, address: u8, read: &mut [u8]) -> Result<(), Error> { - Self::setup(address.into())?; - self.read_blocking_internal(read, true, true) - // Automatic Stop - } - - pub fn blocking_write(&mut self, address: u8, write: &[u8]) -> Result<(), Error> { - Self::setup(address.into())?; - self.write_blocking_internal(write, true) - } - - pub fn blocking_write_read(&mut self, address: u8, write: &[u8], read: &mut [u8]) -> Result<(), Error> { - Self::setup(address.into())?; - self.write_blocking_internal(write, false)?; - self.read_blocking_internal(read, true, true) - // Automatic Stop - } -} - -/* -mod eh02 { - use super::*; - - impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Read for I2c<'d, T, M> { - type Error = Error; - - fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { - self.blocking_read(address, buffer) - } - } - - impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Write for I2c<'d, T, M> { - type Error = Error; - - fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.blocking_write(address, bytes) - } - } - - impl<'d, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::WriteRead for I2c<'d, T, M> { - 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, T: Instance, M: Mode> embedded_hal_02::blocking::i2c::Transactional for I2c<'d, T, M> { - type Error = Error; - - fn exec( - &mut self, - address: u8, - operations: &mut [embedded_hal_02::blocking::i2c::Operation<'_>], - ) -> Result<(), Self::Error> { - Self::setup(address.into())?; - for i in 0..operations.len() { - let last = i == operations.len() - 1; - match &mut operations[i] { - embedded_hal_02::blocking::i2c::Operation::Read(buf) => { - self.read_blocking_internal(buf, false, last)? - } - embedded_hal_02::blocking::i2c::Operation::Write(buf) => self.write_blocking_internal(buf, last)?, - } - } - Ok(()) - } - } -} -*/ - -#[cfg(feature = "unstable-traits")] -mod eh1 { - use super::*; - - impl embedded_hal_1::i2c::Error for Error { - fn kind(&self) -> embedded_hal_1::i2c::ErrorKind { - match *self { - Self::Abort(AbortReason::ArbitrationLoss) => embedded_hal_1::i2c::ErrorKind::ArbitrationLoss, - Self::Abort(AbortReason::NoAcknowledge) => { - embedded_hal_1::i2c::ErrorKind::NoAcknowledge(embedded_hal_1::i2c::NoAcknowledgeSource::Address) - } - Self::Abort(AbortReason::Other(_)) => embedded_hal_1::i2c::ErrorKind::Other, - Self::InvalidReadBufferLength => embedded_hal_1::i2c::ErrorKind::Other, - Self::InvalidWriteBufferLength => embedded_hal_1::i2c::ErrorKind::Other, - Self::AddressOutOfRange(_) => embedded_hal_1::i2c::ErrorKind::Other, - Self::AddressReserved(_) => embedded_hal_1::i2c::ErrorKind::Other, - } - } - } - - impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::ErrorType for I2c<'d, T, M> { - type Error = Error; - } - - impl<'d, T: Instance, M: Mode> embedded_hal_1::i2c::I2c for I2c<'d, T, M> { - 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_1::i2c::Operation<'_>], - ) -> Result<(), Self::Error> { - Self::setup(address.into())?; - for i in 0..operations.len() { - let last = i == operations.len() - 1; - match &mut operations[i] { - embedded_hal_1::i2c::Operation::Read(buf) => self.read_blocking_internal(buf, false, last)?, - embedded_hal_1::i2c::Operation::Write(buf) => self.write_blocking_internal(buf, last)?, - } - } - Ok(()) - } - } -} -#[cfg(all(feature = "unstable-traits", feature = "nightly"))] -mod nightly { - use embedded_hal_1::i2c::Operation; - use embedded_hal_async::i2c::AddressMode; - - use super::*; - - impl<'d, A, T> embedded_hal_async::i2c::I2c<A> for I2c<'d, T, Async> - where - A: AddressMode + Into<u16> + 'static, - T: Instance + 'd, - { - async fn read(&mut self, address: A, read: &mut [u8]) -> Result<(), Self::Error> { - let addr: u16 = address.into(); - - Self::setup(addr)?; - self.read_async_internal(read, false, true).await - } - - async fn write(&mut self, address: A, write: &[u8]) -> Result<(), Self::Error> { - let addr: u16 = address.into(); - - Self::setup(addr)?; - self.write_async_internal(write.iter().copied(), true).await - } - - async fn write_read(&mut self, address: A, write: &[u8], read: &mut [u8]) -> Result<(), Self::Error> { - let addr: u16 = address.into(); - - Self::setup(addr)?; - self.write_async_internal(write.iter().cloned(), false).await?; - self.read_async_internal(read, false, true).await - } - - async fn transaction(&mut self, address: A, operations: &mut [Operation<'_>]) -> Result<(), Self::Error> { - let addr: u16 = address.into(); - - let mut iterator = operations.iter_mut(); - - while let Some(op) = iterator.next() { - let last = iterator.len() == 0; - - match op { - Operation::Read(buffer) => { - Self::setup(addr)?; - self.read_async_internal(buffer, false, last).await?; - } - Operation::Write(buffer) => { - Self::setup(addr)?; - self.write_async_internal(buffer.into_iter().cloned(), last).await?; - } - } - } - Ok(()) - } - } -} - -fn _i2c_reserved_addr(addr: u16) -> bool { - (addr & 0x78) == 0 || (addr & 0x78) == 0x78 -} - -mod sealed { - use embassy_cortex_m::interrupt::Interrupt; - use embassy_sync::waitqueue::AtomicWaker; - - pub trait Instance { - const TX_DREQ: u8; - const RX_DREQ: u8; - - type Interrupt: Interrupt; - - fn regs() -> embassy_rp::pac::i2c::I2c; - fn reset() -> embassy_rp::pac::resets::regs::Peripherals; - fn waker() -> &'static AtomicWaker; - } - - pub trait Mode {} - - pub trait SdaPin<T: Instance> {} - pub trait SclPin<T: Instance> {} -} - -pub trait Mode: sealed::Mode {} - -macro_rules! impl_mode { - ($name:ident) => { - impl sealed::Mode for $name {} - impl Mode for $name {} - }; -} - -pub struct Blocking; -pub struct Async; - -impl_mode!(Blocking); -impl_mode!(Async); - -pub trait Instance: sealed::Instance {} - -macro_rules! impl_instance { - ($type:ident, $irq:ident, $reset:ident, $tx_dreq:expr, $rx_dreq:expr) => { - impl sealed::Instance for peripherals::$type { - const TX_DREQ: u8 = $tx_dreq; - const RX_DREQ: u8 = $rx_dreq; - - type Interrupt = embassy_rp::interrupt::$irq; - - #[inline] - fn regs() -> pac::i2c::I2c { - pac::$type - } - - #[inline] - fn reset() -> pac::resets::regs::Peripherals { - let mut ret = pac::resets::regs::Peripherals::default(); - ret.$reset(true); - ret - } - - #[inline] - fn waker() -> &'static AtomicWaker { - static WAKER: AtomicWaker = AtomicWaker::new(); - - &WAKER - } - } - impl Instance for peripherals::$type {} - }; -} - -impl_instance!(I2C0, I2C0_IRQ, set_i2c0, 32, 33); -impl_instance!(I2C1, I2C1_IRQ, set_i2c1, 34, 35); - -pub trait SdaPin<T: Instance>: sealed::SdaPin<T> + embassy_rp::gpio::Pin {} -pub trait SclPin<T: Instance>: sealed::SclPin<T> + embassy_rp::gpio::Pin {} - -macro_rules! impl_pin { - ($pin:ident, $instance:ident, $function:ident) => { - impl sealed::$function<peripherals::$instance> for peripherals::$pin {} - impl $function<peripherals::$instance> for peripherals::$pin {} - }; -} - -impl_pin!(PIN_0, I2C0, SdaPin); -impl_pin!(PIN_1, I2C0, SclPin); -impl_pin!(PIN_2, I2C1, SdaPin); -impl_pin!(PIN_3, I2C1, SclPin); -impl_pin!(PIN_4, I2C0, SdaPin); -impl_pin!(PIN_5, I2C0, SclPin); -impl_pin!(PIN_6, I2C1, SdaPin); -impl_pin!(PIN_7, I2C1, SclPin); -impl_pin!(PIN_8, I2C0, SdaPin); -impl_pin!(PIN_9, I2C0, SclPin); -impl_pin!(PIN_10, I2C1, SdaPin); -impl_pin!(PIN_11, I2C1, SclPin); -impl_pin!(PIN_12, I2C0, SdaPin); -impl_pin!(PIN_13, I2C0, SclPin); -impl_pin!(PIN_14, I2C1, SdaPin); -impl_pin!(PIN_15, I2C1, SclPin); -impl_pin!(PIN_16, I2C0, SdaPin); -impl_pin!(PIN_17, I2C0, SclPin); -impl_pin!(PIN_18, I2C1, SdaPin); -impl_pin!(PIN_19, I2C1, SclPin); -impl_pin!(PIN_20, I2C0, SdaPin); -impl_pin!(PIN_21, I2C0, SclPin); -impl_pin!(PIN_22, I2C1, SdaPin); -impl_pin!(PIN_23, I2C1, SclPin); -impl_pin!(PIN_24, I2C0, SdaPin); -impl_pin!(PIN_25, I2C0, SclPin); -impl_pin!(PIN_26, I2C1, SdaPin); -impl_pin!(PIN_27, I2C1, SclPin); -impl_pin!(PIN_28, I2C0, SdaPin); -impl_pin!(PIN_29, I2C0, SclPin); diff --git a/firmware/rust1/src/rp/mod.rs b/firmware/rust1/src/rp/mod.rs index eec2637..e69de29 100644 --- a/firmware/rust1/src/rp/mod.rs +++ b/firmware/rust1/src/rp/mod.rs @@ -1 +0,0 @@ -pub mod i2c; -- GitLab