From 5a6227e76411b42936e430fbb25203c6fb961d03 Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Thu, 4 Jul 2024 17:46:17 +0200 Subject: [PATCH] HAL update finished --- .cargo/def-config.toml | 3 +- va108xx-hal/CHANGELOG.md | 5 +- va108xx-hal/src/i2c.rs | 930 ++++++++++++------ va108xx-hal/src/prelude.rs | 2 + vorago-reb1/Cargo.toml | 10 +- vorago-reb1/examples/adt75-temp-sensor.rs | 2 +- vorago-reb1/examples/adxl343-accelerometer.rs | 6 +- vorago-reb1/examples/blinky-button-rtic.rs | 13 +- vorago-reb1/examples/max11619-adc.rs | 6 +- vorago-reb1/src/temp_sensor.rs | 34 +- 10 files changed, 666 insertions(+), 345 deletions(-) diff --git a/.cargo/def-config.toml b/.cargo/def-config.toml index 1887082..26a3517 100644 --- a/.cargo/def-config.toml +++ b/.cargo/def-config.toml @@ -24,8 +24,7 @@ rustflags = [ # "-C", "link-arg=-Tdefmt.x", # Can be useful for debugging. - "-Clink-args=-Map=app.map" - + # "-Clink-args=-Map=app.map" ] [build] diff --git a/va108xx-hal/CHANGELOG.md b/va108xx-hal/CHANGELOG.md index c8cc308..71210f0 100644 --- a/va108xx-hal/CHANGELOG.md +++ b/va108xx-hal/CHANGELOG.md @@ -8,7 +8,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [v0.7.0] 2024-07-04 -- Replace `uarta` and `uartb` `Uart` constructors by `new` method. +- Replace `uarta` and `uartb` `Uart` constructors by `new` constructor. +- Replace SPI `spia`, `spib` and `spic` constructors by `new` constructor. +- Replace I2C `i2ca`, `i2cb` constructors by `new` constructor. Update constructor + to fail on invalid fast I2C speed system clock values. ## [v0.6.0] 2024-06-16 diff --git a/va108xx-hal/src/i2c.rs b/va108xx-hal/src/i2c.rs index 88d1d6d..f743b37 100644 --- a/va108xx-hal/src/i2c.rs +++ b/va108xx-hal/src/i2c.rs @@ -4,24 +4,29 @@ //! //! - [REB1 I2C temperature sensor example](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/adt75-temp-sensor.rs) use crate::{ - clock::{enable_peripheral_clock, PeripheralClocks}, - pac, - time::Hertz, - typelevel::Sealed, + clock::enable_peripheral_clock, pac, time::Hertz, typelevel::Sealed, PeripheralSelect, }; -use core::marker::PhantomData; +use core::{marker::PhantomData, ops::Deref}; use embedded_hal::i2c::{self, Operation, SevenBitAddress, TenBitAddress}; //================================================================================================== // Defintions //================================================================================================== +const CLK_100K: Hertz = Hertz::from_raw(100_000); +const CLK_400K: Hertz = Hertz::from_raw(400_000); +const MIN_CLK_400K: Hertz = Hertz::from_raw(8_000_000); + #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum FifoEmptyMode { Stall = 0, EndTransaction = 1, } +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct ClockTooSlowForFastI2c; + #[derive(Debug, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { @@ -34,7 +39,21 @@ pub enum Error { InsufficientDataReceived, /// Number of bytes in transfer too large (larger than 0x7fe) DataTooLarge, +} + +#[derive(Debug, PartialEq, Eq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum InitError { + /// Wrong address used in constructor WrongAddrMode, + /// APB1 clock is too slow for fast I2C mode. + ClkTooSlow(ClockTooSlowForFastI2c), +} + +impl From for InitError { + fn from(value: ClockTooSlowForFastI2c) -> Self { + Self::ClkTooSlow(value) + } } impl embedded_hal::i2c::Error for Error { @@ -47,10 +66,9 @@ impl embedded_hal::i2c::Error for Error { Error::NackData => { embedded_hal::i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Data) } - Error::DataTooLarge - | Error::WrongAddrMode - | Error::InsufficientDataReceived - | Error::InvalidTimingParams => embedded_hal::i2c::ErrorKind::Other, + Error::DataTooLarge | Error::InsufficientDataReceived | Error::InvalidTimingParams => { + embedded_hal::i2c::ErrorKind::Other + } } } } @@ -81,6 +99,37 @@ pub enum I2cAddress { TenBit(u16), } +pub type I2cRegBlock = pac::i2ca::RegisterBlock; + +/// Common trait implemented by all PAC peripheral access structures. The register block +/// format is the same for all SPI blocks. +pub trait Instance: Deref { + const IDX: u8; + const PERIPH_SEL: PeripheralSelect; + + fn ptr() -> *const I2cRegBlock; +} + +impl Instance for pac::I2ca { + const IDX: u8 = 0; + const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c0; + + #[inline(always)] + fn ptr() -> *const I2cRegBlock { + Self::ptr() + } +} + +impl Instance for pac::I2cb { + const IDX: u8 = 1; + const PERIPH_SEL: PeripheralSelect = PeripheralSelect::I2c1; + + #[inline(always)] + fn ptr() -> *const I2cRegBlock { + Self::ptr() + } +} + //================================================================================================== // Config //================================================================================================== @@ -242,149 +291,149 @@ impl I2cBase { } } -macro_rules! i2c_base { - ($($I2CX:path: ($i2cx:ident, $clk_enb:path),)+) => { - $( - impl I2cBase<$I2CX> { - pub fn $i2cx( - i2c: $I2CX, - sys_clk: impl Into, - speed_mode: I2cSpeed, - ms_cfg: Option<&MasterConfig>, - sl_cfg: Option<&SlaveConfig>, - sys_cfg: Option<&mut va108xx::Sysconfig>, - ) -> Self { - if let Some(sys_cfg) = sys_cfg { - enable_peripheral_clock(sys_cfg, $clk_enb); - } - let mut i2c_base = I2cBase { - i2c, - sys_clk: sys_clk.into(), - }; - if let Some(ms_cfg) = ms_cfg { - i2c_base.cfg_master(ms_cfg); - } +impl I2cBase { + pub fn new( + syscfg: &mut pac::Sysconfig, + sysclk: impl Into, + i2c: I2c, + speed_mode: I2cSpeed, + ms_cfg: Option<&MasterConfig>, + sl_cfg: Option<&SlaveConfig>, + ) -> Result { + enable_peripheral_clock(syscfg, I2c::PERIPH_SEL); + + let mut i2c_base = I2cBase { + i2c, + sys_clk: sysclk.into(), + }; + if let Some(ms_cfg) = ms_cfg { + i2c_base.cfg_master(ms_cfg); + } - if let Some(sl_cfg) = sl_cfg { - i2c_base.cfg_slave(sl_cfg); - } - i2c_base.cfg_clk_scale(speed_mode); - i2c_base - } + if let Some(sl_cfg) = sl_cfg { + i2c_base.cfg_slave(sl_cfg); + } + i2c_base.cfg_clk_scale(speed_mode)?; + Ok(i2c_base) + } - fn cfg_master(&mut self, ms_cfg: &MasterConfig) { - let (txfemd, rxfemd) = match (ms_cfg.tx_fe_mode, ms_cfg.rx_fe_mode) { - (FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false), - (FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true), - (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), - (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), - }; - self.i2c.ctrl().modify(|_, w| { - w.txfemd().bit(txfemd); - w.rxffmd().bit(rxfemd); - w.dlgfilter().bit(ms_cfg.dlg_filt); - w.algfilter().bit(ms_cfg.alg_filt) - }); - if let Some(ref tm_cfg) = ms_cfg.tm_cfg { - self.i2c.tmconfig().write(|w| unsafe { w.bits(tm_cfg.reg()) }); - } - self.i2c.fifo_clr().write(|w| { - w.rxfifo().set_bit(); - w.txfifo().set_bit() - }); - } + fn cfg_master(&mut self, ms_cfg: &MasterConfig) { + let (txfemd, rxfemd) = match (ms_cfg.tx_fe_mode, ms_cfg.rx_fe_mode) { + (FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false), + (FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true), + (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), + (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), + }; + self.i2c.ctrl().modify(|_, w| { + w.txfemd().bit(txfemd); + w.rxffmd().bit(rxfemd); + w.dlgfilter().bit(ms_cfg.dlg_filt); + w.algfilter().bit(ms_cfg.alg_filt) + }); + if let Some(ref tm_cfg) = ms_cfg.tm_cfg { + self.i2c + .tmconfig() + .write(|w| unsafe { w.bits(tm_cfg.reg()) }); + } + self.i2c.fifo_clr().write(|w| { + w.rxfifo().set_bit(); + w.txfifo().set_bit() + }); + } - fn cfg_slave(&mut self, sl_cfg: &SlaveConfig) { - let (txfemd, rxfemd) = match (sl_cfg.tx_fe_mode, sl_cfg.rx_fe_mode) { - (FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false), - (FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true), - (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), - (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), - }; - self.i2c.s0_ctrl().modify(|_, w| { - w.txfemd().bit(txfemd); - w.rxffmd().bit(rxfemd) - }); - self.i2c.s0_fifo_clr().write(|w| { - w.rxfifo().set_bit(); - w.txfifo().set_bit() - }); - let max_words = sl_cfg.max_words; - if let Some(max_words) = max_words { - self.i2c - .s0_maxwords() - .write(|w| unsafe { w.bits(1 << 31 | max_words as u32) }); - } - let (addr, addr_mode_mask) = Self::unwrap_addr(sl_cfg.addr); - // The first bit is the read/write value. Normally, both read and write are matched - // using the RWMASK bit of the address mask register - self.i2c - .s0_address() - .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }); - if let Some(addr_mask) = sl_cfg.addr_mask { - self.i2c - .s0_addressmask() - .write(|w| unsafe { w.bits((addr_mask << 1) as u32) }); - } - if let Some(addr_b) = sl_cfg.addr_b { - let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b); - self.i2c - .s0_addressb() - .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }) - } - if let Some(addr_b_mask) = sl_cfg.addr_b_mask { - self.i2c - .s0_addressmaskb() - .write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) }) - } - } + fn cfg_slave(&mut self, sl_cfg: &SlaveConfig) { + let (txfemd, rxfemd) = match (sl_cfg.tx_fe_mode, sl_cfg.rx_fe_mode) { + (FifoEmptyMode::Stall, FifoEmptyMode::Stall) => (false, false), + (FifoEmptyMode::Stall, FifoEmptyMode::EndTransaction) => (false, true), + (FifoEmptyMode::EndTransaction, FifoEmptyMode::Stall) => (true, false), + (FifoEmptyMode::EndTransaction, FifoEmptyMode::EndTransaction) => (true, true), + }; + self.i2c.s0_ctrl().modify(|_, w| { + w.txfemd().bit(txfemd); + w.rxffmd().bit(rxfemd) + }); + self.i2c.s0_fifo_clr().write(|w| { + w.rxfifo().set_bit(); + w.txfifo().set_bit() + }); + let max_words = sl_cfg.max_words; + if let Some(max_words) = max_words { + self.i2c + .s0_maxwords() + .write(|w| unsafe { w.bits(1 << 31 | max_words as u32) }); + } + let (addr, addr_mode_mask) = Self::unwrap_addr(sl_cfg.addr); + // The first bit is the read/write value. Normally, both read and write are matched + // using the RWMASK bit of the address mask register + self.i2c + .s0_address() + .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }); + if let Some(addr_mask) = sl_cfg.addr_mask { + self.i2c + .s0_addressmask() + .write(|w| unsafe { w.bits((addr_mask << 1) as u32) }); + } + if let Some(addr_b) = sl_cfg.addr_b { + let (addr, addr_mode_mask) = Self::unwrap_addr(addr_b); + self.i2c + .s0_addressb() + .write(|w| unsafe { w.bits((addr << 1) as u32 | addr_mode_mask) }) + } + if let Some(addr_b_mask) = sl_cfg.addr_b_mask { + self.i2c + .s0_addressmaskb() + .write(|w| unsafe { w.bits((addr_b_mask << 1) as u32) }) + } + } - #[inline] - pub fn filters(&mut self, digital_filt: bool, analog_filt: bool) { - self.i2c.ctrl().modify(|_, w| { - w.dlgfilter().bit(digital_filt); - w.algfilter().bit(analog_filt) - }); - } + #[inline] + pub fn filters(&mut self, digital_filt: bool, analog_filt: bool) { + self.i2c.ctrl().modify(|_, w| { + w.dlgfilter().bit(digital_filt); + w.algfilter().bit(analog_filt) + }); + } - #[inline] - pub fn fifo_empty_mode(&mut self, rx: FifoEmptyMode, tx: FifoEmptyMode) { - self.i2c.ctrl().modify(|_, w| { - w.txfemd().bit(tx as u8 != 0); - w.rxffmd().bit(rx as u8 != 0) - }); - } + #[inline] + pub fn fifo_empty_mode(&mut self, rx: FifoEmptyMode, tx: FifoEmptyMode) { + self.i2c.ctrl().modify(|_, w| { + w.txfemd().bit(tx as u8 != 0); + w.rxffmd().bit(rx as u8 != 0) + }); + } - fn calc_clk_div(&self, speed_mode: I2cSpeed) -> u8 { - if speed_mode == I2cSpeed::Regular100khz { - ((self.sys_clk.raw() / (u32::pow(10, 5) * 20)) - 1) as u8 - } else { - (((10 * self.sys_clk.raw()) / u32::pow(10, 8)) - 1) as u8 - } - } + fn calc_clk_div(&self, speed_mode: I2cSpeed) -> Result { + if speed_mode == I2cSpeed::Regular100khz { + Ok(((self.sys_clk.raw() / CLK_100K.raw() / 20) - 1) as u8) + } else { + if self.sys_clk.raw() < MIN_CLK_400K.raw() { + return Err(ClockTooSlowForFastI2c); + } + Ok(((self.sys_clk.raw() / CLK_400K.raw() / 25) - 1) as u8) + } + } - /// Configures the clock scale for a given speed mode setting - pub fn cfg_clk_scale(&mut self, speed_mode: I2cSpeed) { - self.i2c.clkscale().write(|w| unsafe { - w.bits((speed_mode as u32) << 31 | self.calc_clk_div(speed_mode) as u32) - }); - } + /// Configures the clock scale for a given speed mode setting + pub fn cfg_clk_scale(&mut self, speed_mode: I2cSpeed) -> Result<(), ClockTooSlowForFastI2c> { + let clk_div = self.calc_clk_div(speed_mode)?; + self.i2c + .clkscale() + .write(|w| unsafe { w.bits((speed_mode as u32) << 31 | clk_div as u32) }); + Ok(()) + } - pub fn load_address(&mut self, addr: u16) { - // Load address - self.i2c - .address() - .write(|w| unsafe { w.bits((addr << 1) as u32) }); - } + pub fn load_address(&mut self, addr: u16) { + // Load address + self.i2c + .address() + .write(|w| unsafe { w.bits((addr << 1) as u32) }); + } - #[inline] - fn stop_cmd(&mut self) { - self.i2c - .cmd() - .write(|w| unsafe { w.bits(I2cCmd::Stop as u32) }); - } - } - )+ + #[inline] + fn stop_cmd(&mut self) { + self.i2c + .cmd() + .write(|w| unsafe { w.bits(I2cCmd::Stop as u32) }); } } @@ -395,20 +444,218 @@ macro_rules! i2c_base { // slave_cfg: SlaveConfig, // } -i2c_base!( - pac::I2ca: (i2ca, PeripheralClocks::I2c0), - pac::I2cb: (i2cb, PeripheralClocks::I2c1), -); - //================================================================================================== // I2C Master //================================================================================================== -pub struct I2cMaster { - i2c_base: I2cBase, - _addr: PhantomData, +pub struct I2cMaster { + i2c_base: I2cBase, + addr: PhantomData, +} + +impl I2cMaster { + pub fn new( + syscfg: &mut pac::Sysconfig, + sysclk: impl Into, + i2c: I2c, + cfg: MasterConfig, + speed_mode: I2cSpeed, + ) -> Result { + Ok(I2cMaster { + i2c_base: I2cBase::new(syscfg, sysclk, i2c, speed_mode, Some(&cfg), None)?, + addr: PhantomData, + } + .enable_master()) + } + + #[inline] + pub fn cancel_transfer(&self) { + self.i2c_base + .i2c + .cmd() + .write(|w| unsafe { w.bits(I2cCmd::Cancel as u32) }); + } + + #[inline] + pub fn clear_tx_fifo(&self) { + self.i2c_base.i2c.fifo_clr().write(|w| w.txfifo().set_bit()); + } + + #[inline] + pub fn clear_rx_fifo(&self) { + self.i2c_base.i2c.fifo_clr().write(|w| w.rxfifo().set_bit()); + } + + #[inline] + pub fn enable_master(self) -> Self { + self.i2c_base.i2c.ctrl().modify(|_, w| w.enable().set_bit()); + self + } + + #[inline] + pub fn disable_master(self) -> Self { + self.i2c_base + .i2c + .ctrl() + .modify(|_, w| w.enable().clear_bit()); + self + } + + #[inline(always)] + fn load_fifo(&self, word: u8) { + self.i2c_base + .i2c + .data() + .write(|w| unsafe { w.bits(word as u32) }); + } + + #[inline(always)] + fn read_fifo(&self) -> u8 { + self.i2c_base.i2c.data().read().bits() as u8 + } + + fn error_handler_write(&mut self, init_cmd: &I2cCmd) { + self.clear_tx_fifo(); + if *init_cmd == I2cCmd::Start { + self.i2c_base.stop_cmd() + } + } + + fn write_base( + &mut self, + addr: I2cAddress, + init_cmd: I2cCmd, + bytes: impl IntoIterator, + ) -> Result<(), Error> { + let mut iter = bytes.into_iter(); + // Load address + let (addr, addr_mode_bit) = I2cBase::::unwrap_addr(addr); + self.i2c_base.i2c.address().write(|w| unsafe { + w.bits(I2cDirection::Send as u32 | (addr << 1) as u32 | addr_mode_bit) + }); + + self.i2c_base + .i2c + .cmd() + .write(|w| unsafe { w.bits(init_cmd as u32) }); + let mut load_if_next_available = || { + if let Some(next_byte) = iter.next() { + self.load_fifo(next_byte); + } + }; + loop { + let status_reader = self.i2c_base.i2c.status().read(); + if status_reader.arblost().bit_is_set() { + self.error_handler_write(&init_cmd); + return Err(Error::ArbitrationLost); + } else if status_reader.nackaddr().bit_is_set() { + self.error_handler_write(&init_cmd); + return Err(Error::NackAddr); + } else if status_reader.nackdata().bit_is_set() { + self.error_handler_write(&init_cmd); + return Err(Error::NackData); + } else if status_reader.idle().bit_is_set() { + return Ok(()); + } else { + while !status_reader.txnfull().bit_is_set() { + load_if_next_available(); + } + } + } + } + + fn write_from_buffer( + &mut self, + init_cmd: I2cCmd, + addr: I2cAddress, + output: &[u8], + ) -> Result<(), Error> { + let len = output.len(); + // It should theoretically possible to transfer larger data sizes by tracking + // the number of sent words and setting it to 0x7fe as soon as only that many + // bytes are remaining. However, large transfer like this are not common. This + // feature will therefore not be supported for now. + if len > 0x7fe { + return Err(Error::DataTooLarge); + } + // Load number of words + self.i2c_base + .i2c + .words() + .write(|w| unsafe { w.bits(len as u32) }); + let mut bytes = output.iter(); + // FIFO has a depth of 16. We load slightly above the trigger level + // but not all of it because the transaction might fail immediately + const FILL_DEPTH: usize = 12; + + // load the FIFO + for _ in 0..core::cmp::min(FILL_DEPTH, len) { + self.load_fifo(*bytes.next().unwrap()); + } + + self.write_base(addr, init_cmd, output.iter().cloned()) + } + + fn read_internal(&mut self, addr: I2cAddress, buffer: &mut [u8]) -> Result<(), Error> { + let len = buffer.len(); + // It should theoretically possible to transfer larger data sizes by tracking + // the number of sent words and setting it to 0x7fe as soon as only that many + // bytes are remaining. However, large transfer like this are not common. This + // feature will therefore not be supported for now. + if len > 0x7fe { + return Err(Error::DataTooLarge); + } + // Clear the receive FIFO + self.clear_rx_fifo(); + + // Load number of words + self.i2c_base + .i2c + .words() + .write(|w| unsafe { w.bits(len as u32) }); + let (addr, addr_mode_bit) = match addr { + I2cAddress::Regular(addr) => (addr as u16, 0 << 15), + I2cAddress::TenBit(addr) => (addr, 1 << 15), + }; + // Load address + self.i2c_base.i2c.address().write(|w| unsafe { + w.bits(I2cDirection::Read as u32 | (addr << 1) as u32 | addr_mode_bit) + }); + + let mut buf_iter = buffer.iter_mut(); + let mut read_bytes = 0; + // Start receive transfer + self.i2c_base + .i2c + .cmd() + .write(|w| unsafe { w.bits(I2cCmd::StartWithStop as u32) }); + let mut read_if_next_available = || { + if let Some(next_byte) = buf_iter.next() { + *next_byte = self.read_fifo(); + } + }; + loop { + let status_reader = self.i2c_base.i2c.status().read(); + if status_reader.arblost().bit_is_set() { + self.clear_rx_fifo(); + return Err(Error::ArbitrationLost); + } else if status_reader.nackaddr().bit_is_set() { + self.clear_rx_fifo(); + return Err(Error::NackAddr); + } else if status_reader.idle().bit_is_set() { + if read_bytes != len { + return Err(Error::InsufficientDataReceived); + } + return Ok(()); + } else if status_reader.rxnempty().bit_is_set() { + read_if_next_available(); + read_bytes += 1; + } + } + } } +/* macro_rules! i2c_master { ($($I2CX:path: ($i2cx:ident, $clk_enb:path),)+) => { $( @@ -675,204 +922,237 @@ i2c_master!( pac::I2ca: (i2ca, PeripheralClocks::I2c0), pac::I2cb: (i2cb, PeripheralClocks::I2c1), ); +*/ -//================================================================================================== -// I2C Slave -//================================================================================================== +//====================================================================================== +// Embedded HAL I2C implementations +//====================================================================================== -pub struct I2cSlave { - i2c_base: I2cBase, - _addr: PhantomData, +impl embedded_hal::i2c::ErrorType for I2cMaster { + type Error = Error; } -macro_rules! i2c_slave { - ($($I2CX:path: ($i2cx:ident, $i2cx_slave:ident),)+) => { - $( - impl I2cSlave<$I2CX, ADDR> { - fn $i2cx_slave( - i2c: $I2CX, - cfg: SlaveConfig, - sys_clk: impl Into, - speed_mode: I2cSpeed, - sys_cfg: Option<&mut pac::Sysconfig>, - ) -> Self { - I2cSlave { - i2c_base: I2cBase::$i2cx( - i2c, - sys_clk, - speed_mode, - None, - Some(&cfg), - sys_cfg - ), - _addr: PhantomData, - } - .enable_slave() - } +impl embedded_hal::i2c::I2c for I2cMaster { + fn transaction( + &mut self, + address: SevenBitAddress, + operations: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + for operation in operations { + match operation { + Operation::Read(buf) => self.read_internal(I2cAddress::Regular(address), buf)?, + Operation::Write(buf) => self.write_from_buffer( + I2cCmd::StartWithStop, + I2cAddress::Regular(address), + buf, + )?, + } + } + Ok(()) + } +} - #[inline] - pub fn enable_slave(self) -> Self { - self.i2c_base - .i2c - .s0_ctrl() - .modify(|_, w| w.enable().set_bit()); - self - } +impl embedded_hal::i2c::ErrorType for I2cMaster { + type Error = Error; +} - #[inline] - pub fn disable_slave(self) -> Self { - self.i2c_base - .i2c - .s0_ctrl() - .modify(|_, w| w.enable().clear_bit()); - self +impl embedded_hal::i2c::I2c for I2cMaster { + fn transaction( + &mut self, + address: TenBitAddress, + operations: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + for operation in operations { + match operation { + Operation::Read(buf) => self.read_internal(I2cAddress::TenBit(address), buf)?, + Operation::Write(buf) => { + self.write_from_buffer(I2cCmd::StartWithStop, I2cAddress::TenBit(address), buf)? } + } + } + Ok(()) + } +} - #[inline(always)] - fn load_fifo(&self, word: u8) { - self.i2c_base - .i2c - .s0_data() - .write(|w| unsafe { w.bits(word as u32) }); - } +//================================================================================================== +// I2C Slave +//================================================================================================== - #[inline(always)] - fn read_fifo(&self) -> u8 { - self.i2c_base.i2c.s0_data().read().bits() as u8 - } +pub struct I2cSlave { + i2c_base: I2cBase, + addr: PhantomData, +} - #[inline] - fn clear_tx_fifo(&self) { - self.i2c_base - .i2c - .s0_fifo_clr() - .write(|w| w.txfifo().set_bit()); - } +impl I2cSlave { + fn new_generic( + sys_cfg: &mut pac::Sysconfig, + sys_clk: impl Into, + i2c: I2c, + cfg: SlaveConfig, + speed_mode: I2cSpeed, + ) -> Result { + Ok(I2cSlave { + i2c_base: I2cBase::new(sys_cfg, sys_clk, i2c, speed_mode, None, Some(&cfg))?, + addr: PhantomData, + } + .enable_slave()) + } - #[inline] - fn clear_rx_fifo(&self) { - self.i2c_base - .i2c - .s0_fifo_clr() - .write(|w| w.rxfifo().set_bit()); - } + #[inline] + pub fn enable_slave(self) -> Self { + self.i2c_base + .i2c + .s0_ctrl() + .modify(|_, w| w.enable().set_bit()); + self + } - /// Get the last address that was matched by the slave control and the corresponding - /// master direction - pub fn last_address(&self) -> (I2cDirection, u32) { - let bits = self.i2c_base.i2c.s0_lastaddress().read().bits(); - match bits & 0x01 { - 0 => (I2cDirection::Send, bits >> 1), - 1 => (I2cDirection::Read, bits >> 1), - _ => (I2cDirection::Send, bits >> 1), - } - } + #[inline] + pub fn disable_slave(self) -> Self { + self.i2c_base + .i2c + .s0_ctrl() + .modify(|_, w| w.enable().clear_bit()); + self + } - pub fn write(&mut self, output: &[u8]) -> Result<(), Error> { - let len = output.len(); - // It should theoretically possible to transfer larger data sizes by tracking - // the number of sent words and setting it to 0x7fe as soon as only that many - // bytes are remaining. However, large transfer like this are not common. This - // feature will therefore not be supported for now. - if len > 0x7fe { - return Err(Error::DataTooLarge); - } - let mut bytes = output.iter(); - // FIFO has a depth of 16. We load slightly above the trigger level - // but not all of it because the transaction might fail immediately - const FILL_DEPTH: usize = 12; + #[inline(always)] + fn load_fifo(&self, word: u8) { + self.i2c_base + .i2c + .s0_data() + .write(|w| unsafe { w.bits(word as u32) }); + } - // load the FIFO - for _ in 0..core::cmp::min(FILL_DEPTH, len) { - self.load_fifo(*bytes.next().unwrap()); - } + #[inline(always)] + fn read_fifo(&self) -> u8 { + self.i2c_base.i2c.s0_data().read().bits() as u8 + } - let status_reader = self.i2c_base.i2c.s0_status().read(); - let mut load_if_next_available = || { - if let Some(next_byte) = bytes.next() { - self.load_fifo(*next_byte); - } - }; - loop { - if status_reader.nackdata().bit_is_set() { - self.clear_tx_fifo(); - return Err(Error::NackData); - } else if status_reader.idle().bit_is_set() { - return Ok(()); - } else { - while !status_reader.txnfull().bit_is_set() { - load_if_next_available(); - } - } - } - } + #[inline] + fn clear_tx_fifo(&self) { + self.i2c_base + .i2c + .s0_fifo_clr() + .write(|w| w.txfifo().set_bit()); + } - pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { - let len = buffer.len(); - // It should theoretically possible to transfer larger data sizes by tracking - // the number of sent words and setting it to 0x7fe as soon as only that many - // bytes are remaining. However, large transfer like this are not common. This - // feature will therefore not be supported for now. - if len > 0x7fe { - return Err(Error::DataTooLarge); - } - // Clear the receive FIFO - self.clear_rx_fifo(); + #[inline] + fn clear_rx_fifo(&self) { + self.i2c_base + .i2c + .s0_fifo_clr() + .write(|w| w.rxfifo().set_bit()); + } - let mut buf_iter = buffer.iter_mut(); - let mut read_bytes = 0; - let mut read_if_next_available = || { - if let Some(next_byte) = buf_iter.next() { - *next_byte = self.read_fifo(); - } - }; - loop { - let status_reader = self.i2c_base.i2c.s0_status().read(); - if status_reader.idle().bit_is_set() { - if read_bytes != len { - return Err(Error::InsufficientDataReceived); - } - return Ok(()); - } else if status_reader.rxnempty().bit_is_set() { - read_bytes += 1; - read_if_next_available(); - } - } - } - } + /// Get the last address that was matched by the slave control and the corresponding + /// master direction + pub fn last_address(&self) -> (I2cDirection, u32) { + let bits = self.i2c_base.i2c.s0_lastaddress().read().bits(); + match bits & 0x01 { + 0 => (I2cDirection::Send, bits >> 1), + 1 => (I2cDirection::Read, bits >> 1), + _ => (I2cDirection::Send, bits >> 1), + } + } + pub fn write(&mut self, output: &[u8]) -> Result<(), Error> { + let len = output.len(); + // It should theoretically possible to transfer larger data sizes by tracking + // the number of sent words and setting it to 0x7fe as soon as only that many + // bytes are remaining. However, large transfer like this are not common. This + // feature will therefore not be supported for now. + if len > 0x7fe { + return Err(Error::DataTooLarge); + } + let mut bytes = output.iter(); + // FIFO has a depth of 16. We load slightly above the trigger level + // but not all of it because the transaction might fail immediately + const FILL_DEPTH: usize = 12; + + // load the FIFO + for _ in 0..core::cmp::min(FILL_DEPTH, len) { + self.load_fifo(*bytes.next().unwrap()); + } - impl I2cSlave<$I2CX, SevenBitAddress> { - /// Create a new I2C slave for seven bit addresses - /// - /// Returns a [`Error::WrongAddrMode`] error if a ten bit address is passed - pub fn i2ca( - i2c: $I2CX, - cfg: SlaveConfig, - sys_clk: impl Into, - speed_mode: I2cSpeed, - sys_cfg: Option<&mut pac::Sysconfig>, - ) -> Result { - if let I2cAddress::TenBit(_) = cfg.addr { - return Err(Error::WrongAddrMode); - } - Ok(Self::$i2cx_slave(i2c, cfg, sys_clk, speed_mode, sys_cfg)) + let status_reader = self.i2c_base.i2c.s0_status().read(); + let mut load_if_next_available = || { + if let Some(next_byte) = bytes.next() { + self.load_fifo(*next_byte); + } + }; + loop { + if status_reader.nackdata().bit_is_set() { + self.clear_tx_fifo(); + return Err(Error::NackData); + } else if status_reader.idle().bit_is_set() { + return Ok(()); + } else { + while !status_reader.txnfull().bit_is_set() { + load_if_next_available(); } } + } + } - impl I2cSlave<$I2CX, TenBitAddress> { - pub fn $i2cx( - i2c: $I2CX, - cfg: SlaveConfig, - sys_clk: impl Into, - speed_mode: I2cSpeed, - sys_cfg: Option<&mut pac::Sysconfig>, - ) -> Self { - Self::$i2cx_slave(i2c, cfg, sys_clk, speed_mode, sys_cfg) + pub fn read(&mut self, buffer: &mut [u8]) -> Result<(), Error> { + let len = buffer.len(); + // It should theoretically possible to transfer larger data sizes by tracking + // the number of sent words and setting it to 0x7fe as soon as only that many + // bytes are remaining. However, large transfer like this are not common. This + // feature will therefore not be supported for now. + if len > 0x7fe { + return Err(Error::DataTooLarge); + } + // Clear the receive FIFO + self.clear_rx_fifo(); + + let mut buf_iter = buffer.iter_mut(); + let mut read_bytes = 0; + let mut read_if_next_available = || { + if let Some(next_byte) = buf_iter.next() { + *next_byte = self.read_fifo(); + } + }; + loop { + let status_reader = self.i2c_base.i2c.s0_status().read(); + if status_reader.idle().bit_is_set() { + if read_bytes != len { + return Err(Error::InsufficientDataReceived); } + return Ok(()); + } else if status_reader.rxnempty().bit_is_set() { + read_bytes += 1; + read_if_next_available(); } - )+ + } } } -i2c_slave!(pac::I2ca: (i2ca, i2ca_slave), pac::I2cb: (i2cb, i2cb_slave),); +impl I2cSlave { + /// Create a new I2C slave for seven bit addresses + pub fn new( + sys_cfg: &mut pac::Sysconfig, + sys_clk: impl Into, + i2c: I2c, + cfg: SlaveConfig, + speed_mode: I2cSpeed, + ) -> Result { + if let I2cAddress::TenBit(_) = cfg.addr { + return Err(InitError::WrongAddrMode); + } + Ok(Self::new_generic(sys_cfg, sys_clk, i2c, cfg, speed_mode)?) + } +} + +impl I2cSlave { + pub fn new_ten_bit_addr( + sys_cfg: &mut pac::Sysconfig, + sys_clk: impl Into, + i2c: I2c, + cfg: SlaveConfig, + speed_mode: I2cSpeed, + ) -> Result { + Self::new_generic(sys_cfg, sys_clk, i2c, cfg, speed_mode) + } +} diff --git a/va108xx-hal/src/prelude.rs b/va108xx-hal/src/prelude.rs index 435a2f7..516618f 100644 --- a/va108xx-hal/src/prelude.rs +++ b/va108xx-hal/src/prelude.rs @@ -1,3 +1,5 @@ //! Prelude pub use fugit::ExtU32 as _; pub use fugit::RateExtU32 as _; + +pub use crate::time::*; diff --git a/vorago-reb1/Cargo.toml b/vorago-reb1/Cargo.toml index 4a833f6..94c0afc 100644 --- a/vorago-reb1/Cargo.toml +++ b/vorago-reb1/Cargo.toml @@ -19,6 +19,7 @@ embedded-hal = "1" version = "0.3" [dependencies.va108xx-hal] +path = "../va108xx-hal" version = "0.6" features = ["rt"] @@ -26,7 +27,6 @@ features = ["rt"] rt = ["va108xx-hal/rt"] [dev-dependencies] -cortex-m-rtic = "1.1" panic-halt = "0.2" nb = "1" @@ -36,6 +36,14 @@ version = "0.5" [dev-dependencies.panic-rtt-target] version = "0.1" +[dev-dependencies.rtic] +version = "2" +features = ["thumbv6-backend"] + +[dev-dependencies.rtic-monotonics] +version = "1" +features = ["cortex-m-systick"] + [package.metadata.docs.rs] all-features = true rustdoc-args = ["--generate-link-to-definition"] diff --git a/vorago-reb1/examples/adt75-temp-sensor.rs b/vorago-reb1/examples/adt75-temp-sensor.rs index 9326643..40187bd 100644 --- a/vorago-reb1/examples/adt75-temp-sensor.rs +++ b/vorago-reb1/examples/adt75-temp-sensor.rs @@ -13,7 +13,7 @@ fn main() -> ! { rprintln!("-- Vorago Temperature Sensor and I2C Example --"); let mut dp = pac::Peripherals::take().unwrap(); let mut delay = set_up_ms_delay_provider(&mut dp.sysconfig, 50.MHz(), dp.tim0); - let mut temp_sensor = Adt75TempSensor::new(dp.i2ca, 50.MHz(), Some(&mut dp.sysconfig)) + let mut temp_sensor = Adt75TempSensor::new(&mut dp.sysconfig, 50.MHz(), dp.i2ca) .expect("Creating temperature sensor struct failed"); loop { let temp = temp_sensor diff --git a/vorago-reb1/examples/adxl343-accelerometer.rs b/vorago-reb1/examples/adxl343-accelerometer.rs index 5bd6a9a..483d4dc 100644 --- a/vorago-reb1/examples/adxl343-accelerometer.rs +++ b/vorago-reb1/examples/adxl343-accelerometer.rs @@ -52,12 +52,12 @@ fn main() -> ! { false, true, ); - let mut spi = Spi::spib( + let mut spi = Spi::new( + &mut dp.sysconfig, + 50.MHz(), dp.spib, (sck, miso, mosi), - 50.MHz(), spi_cfg, - Some(&mut dp.sysconfig), Some(&transfer_cfg.downgrade()), ); diff --git a/vorago-reb1/examples/blinky-button-rtic.rs b/vorago-reb1/examples/blinky-button-rtic.rs index ecfa587..c869cb7 100644 --- a/vorago-reb1/examples/blinky-button-rtic.rs +++ b/vorago-reb1/examples/blinky-button-rtic.rs @@ -5,6 +5,7 @@ #[rtic::app(device = pac)] mod app { use panic_rtt_target as _; + use rtic_monotonics::systick::Systick; use rtt_target::{rprintln, rtt_init_default, set_print_channel}; use va108xx_hal::{ clock::{set_clk_div_register, FilterClkSel}, @@ -43,10 +44,18 @@ mod app { struct Shared {} #[init] - fn init(ctx: init::Context) -> (Shared, Local, init::Monotonics) { + fn init(ctx: init::Context) -> (Shared, Local) { let channels = rtt_init_default!(); set_print_channel(channels.up.0); rprintln!("-- Vorago Button IRQ Example --"); + // Initialize the systick interrupt & obtain the token to prove that we did + let systick_mono_token = rtic_monotonics::create_systick_token!(); + Systick::start( + ctx.core.SYST, + Hertz::from(50.MHz()).raw(), + systick_mono_token, + ); + let mode = match CFG_MODE { // Ask mode from user via RTT CfgMode::Prompt => prompt_mode(channels.down.0), @@ -90,7 +99,7 @@ mod app { 50.MHz(), dp.tim0, ); - (Shared {}, Local { leds, button, mode }, init::Monotonics()) + (Shared {}, Local { leds, button, mode }) } // `shared` cannot be accessed from this context diff --git a/vorago-reb1/examples/max11619-adc.rs b/vorago-reb1/examples/max11619-adc.rs index 73eda4e..ec3a34c 100644 --- a/vorago-reb1/examples/max11619-adc.rs +++ b/vorago-reb1/examples/max11619-adc.rs @@ -139,12 +139,12 @@ fn main() -> ! { .expect("Setting accelerometer chip select high failed"); let transfer_cfg = TransferConfig::::new(3.MHz(), spi::MODE_0, None, true, false); - let spi = Spi::spib( + let spi = Spi::new( + &mut dp.sysconfig, + 50.MHz(), dp.spib, (sck, miso, mosi), - 50.MHz(), spi_cfg, - Some(&mut dp.sysconfig), Some(&transfer_cfg.downgrade()), ) .downgrade(); diff --git a/vorago-reb1/src/temp_sensor.rs b/vorago-reb1/src/temp_sensor.rs index 3cffe55..6dc4cfd 100644 --- a/vorago-reb1/src/temp_sensor.rs +++ b/vorago-reb1/src/temp_sensor.rs @@ -7,7 +7,7 @@ //! - [Temperature Sensor example](https://egit.irs.uni-stuttgart.de/rust/vorago-reb1/src/branch/main/examples/adt75-temp-sensor.rs) use embedded_hal::i2c::{I2c, SevenBitAddress}; use va108xx_hal::{ - i2c::{Error, I2cMaster, I2cSpeed, MasterConfig}, + i2c::{Error, I2cMaster, I2cSpeed, InitError, MasterConfig}, pac, time::Hertz, }; @@ -29,20 +29,40 @@ pub enum RegAddresses { OneShot = 0x04, } +#[derive(Debug)] +pub enum AdtInitError { + Init(InitError), + I2c(Error), +} + +impl From for AdtInitError { + fn from(value: InitError) -> Self { + Self::Init(value) + } +} + +impl From for AdtInitError { + fn from(value: Error) -> Self { + Self::I2c(value) + } +} + impl Adt75TempSensor { pub fn new( - i2ca: pac::I2ca, + sys_cfg: &mut pac::Sysconfig, sys_clk: impl Into + Copy, - sys_cfg: Option<&mut pac::Sysconfig>, + i2ca: pac::I2ca, ) -> Result { let mut sensor = Adt75TempSensor { - sensor_if: I2cMaster::i2ca( + // The master construction can not fail for regular I2C speed. + sensor_if: I2cMaster::new( + sys_cfg, + sys_clk, i2ca, MasterConfig::default(), - sys_clk, I2cSpeed::Regular100khz, - sys_cfg, - ), + ) + .unwrap(), cmd_buf: [RegAddresses::Temperature as u8], current_reg: RegAddresses::Temperature, };