diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 27b3d21..8a842e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: toolchain: stable target: ${{ matrix.target }} override: true - components: llvm-tools-preview + components: llvm-tools-preview,clippy,rustfmt - name: Build run: cargo build --release --verbose --target ${{ matrix.target }} diff --git a/Cargo.toml b/Cargo.toml index 1db0ab3..8a28081 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,12 +20,13 @@ block-buffer = "0.10" cipher = "0.4" cortex-m = "0.7" digest = "0.10" -embedded-hal = { version = "0.2", features = ["unproven"] } +embedded-hal = { version = "1" } embedded-time = "0.12" generic-array = "1.0.0" lpc55-pac = "0.5" nb = "1" -rand_core = "0.6" +rand_core06 = { package = "rand_core", version = "0.6", optional = true} +rand_core09 = { package = "rand_core", version = "0.9", optional = true} usb-device = "0.2" vcell = "0.1" void = { version = "1", default-features = false } @@ -33,20 +34,22 @@ void = { version = "1", default-features = false } # optional dependencies # cortex-m-rtic = { version = "0.5", optional = true } littlefs2 = { version = "0.5", optional = true } +embedded-io = "0.6.1" [dev-dependencies] aes = "0.8" cortex-m-rt = "0.7" rtic = { package = "cortex-m-rtic", version = "1" } cortex-m-semihosting = "0.5" -heapless = "0.7" -panic-halt = "0.2" -panic-semihosting = { version = "0.5", features = ["jlink-quirks"] } -rtt-target = { version = "0.3", features = ["cortex-m"] } +heapless = "0.9" +panic-halt = "1" +panic-semihosting = { version = "0.6", features = ["jlink-quirks"] } +rtt-target = { version = "0.6" } sha2 = { version = "0.10", default-features = false } -ssd1306 = "0.3" +ssd1306 = "0.10" sha-1 = { version = "0.10", default-features = false } usbd-serial = "0.1" +embedded-hal-bus = "0.3.0" [features] default = ["rt"] @@ -54,9 +57,16 @@ littlefs = ["littlefs2"] rt = ["lpc55-pac/rt"] # no longer a HAL feature, just for the usb examples highspeed-usb-example = [] +rand-core-06 = ["dep:rand_core06"] +rand-core-09 = ["dep:rand_core09"] + +[[example]] +name = "rng" +required-features = ["rand-core-09"] [profile.release] codegen-units = 1 debug = true lto = true opt-level = "z" + diff --git a/examples/i2c.rs b/examples/i2c.rs index 23afad1..ab164c2 100644 --- a/examples/i2c.rs +++ b/examples/i2c.rs @@ -46,12 +46,12 @@ fn main() -> ! { let i2c = I2cMaster::new(i2c, (scl, sda), Hertz::try_from(1_u32.MHz()).unwrap()); // OLED - let mut display: TerminalMode<_> = ssd1306::Builder::new() - .size(DisplaySize::Display128x32) - // .size(DisplaySize::Display70x40) // <-- TODO - .with_i2c_addr(0x3c) - .connect_i2c(i2c) - .into(); + let mut display = ssd1306::Ssd1306::new( + ssd1306::I2CDisplayInterface::new(i2c), + ssd1306::size::DisplaySize128x32, + DisplayRotation::Rotate0, + ) + .into_terminal_mode(); display.init().ok(); display.clear().ok(); diff --git a/examples/late.rs b/examples/late.rs index abd30d5..c7356db 100644 --- a/examples/late.rs +++ b/examples/late.rs @@ -26,8 +26,8 @@ mod app { #[local] struct LocalResources { - p: Producer<'static, u32, 4>, - c: Consumer<'static, u32, 4>, + p: Producer<'static, u32>, + c: Consumer<'static, u32>, } #[init] diff --git a/examples/measure_frequency.rs b/examples/measure_frequency.rs index aade16a..024e464 100644 --- a/examples/measure_frequency.rs +++ b/examples/measure_frequency.rs @@ -7,8 +7,6 @@ extern crate panic_semihosting; // 4004 bytes use cortex_m_rt::entry; use cortex_m_semihosting::heprintln; -use hal::traits::wg::timer::Cancel; - use hal::{ drivers::{timer::Elapsed, Timer}, prelude::*, @@ -57,7 +55,7 @@ fn main() -> ! { delay_cycles(10_000_000); let us = timer.elapsed().0; - timer.cancel().ok(); + timer.cancel(); heprintln!("{} MHz", 10_000_000 / us); } diff --git a/examples/pwm.rs b/examples/pwm.rs index 37c0db1..cccc00c 100644 --- a/examples/pwm.rs +++ b/examples/pwm.rs @@ -11,6 +11,7 @@ use core::f32; use cortex_m_rt::entry; +use embedded_hal::pwm::SetDutyCycle; use hal::drivers::{Pins, Pwm, Timer}; use hal::prelude::*; pub use hal::typestates::pin::state; @@ -23,7 +24,7 @@ fn sin(x: f32) -> f32 { let mut fact = 1f32; for i in 0..5 { res += pow / fact; - pow *= -1f32 * x * x; + pow *= -x * x; fact *= ((2 * (i + 1)) * (2 * (i + 1) + 1)) as f32; } @@ -69,23 +70,22 @@ fn main() -> ! { let green = pins.pio0_5.into_match_output(&mut iocon); let blue = pins.pio1_19.into_match_output(&mut iocon); + pwm.scale_max_duty_by(10); + let (mut green_pwm, mut blue_pwm, mut red_pwm) = pwm.channels(); + green_pwm.set_duty_cycle(0).unwrap(); + red_pwm.set_duty_cycle(0).unwrap(); + blue_pwm.set_duty_cycle(0).unwrap(); // 0 = 100% high voltage / off // 128 = 50% high/low voltage // 255 = 0% high voltage/ fully on - pwm.set_duty(green.get_channel(), 0); - pwm.set_duty(red.get_channel(), 0); - pwm.set_duty(blue.get_channel(), 0); - pwm.enable(green.get_channel()); - pwm.enable(red.get_channel()); - pwm.enable(blue.get_channel()); + print_type_of(&red); + print_type_of(&green); print_type_of(&blue); let mut duties = [0f32, 30f32, 60f32]; let increments = [0.3f32, 0.2f32, 0.1f32]; - pwm.scale_max_duty_by(10); - loop { delay_timer.start(5_000.microseconds()); block!(delay_timer.wait()).unwrap(); @@ -103,14 +103,10 @@ fn main() -> ! { match i { 0 => { // need to tune down red some - pwm.set_duty(red.get_channel(), duty as u16); - } - 1 => { - pwm.set_duty(green.get_channel(), duty * 2); - } - 2 => { - pwm.set_duty(blue.get_channel(), duty * 2); + red_pwm.set_duty_cycle(duty).unwrap() } + 1 => green_pwm.set_duty_cycle(duty * 2).unwrap(), + 2 => blue_pwm.set_duty_cycle(duty * 2).unwrap(), _ => {} } } diff --git a/examples/rng.rs b/examples/rng.rs index a03ffe0..d7f40b9 100644 --- a/examples/rng.rs +++ b/examples/rng.rs @@ -6,8 +6,8 @@ use cortex_m::asm; use cortex_m_rt::entry; use cortex_m_semihosting::dbg; -use hal::traits::rand_core::RngCore; use lpc55_hal as hal; +use rand_core09::RngCore; #[entry] fn main() -> ! { diff --git a/examples/serial.rs b/examples/serial.rs index d255520..cfe2e48 100644 --- a/examples/serial.rs +++ b/examples/serial.rs @@ -6,6 +6,7 @@ extern crate panic_semihosting; use cortex_m_rt::entry; // use core::fmt::Write; +use embedded_io::{Read, Write}; use hal::prelude::*; use lpc55_hal as hal; @@ -13,7 +14,6 @@ use hal::drivers::{Pins, Serial}; #[allow(unused_imports)] use cortex_m_semihosting::{dbg, hprintln}; -use nb::block; #[entry] fn main() -> ! { @@ -54,16 +54,18 @@ fn main() -> ! { // The `block!` macro makes an operation block until it finishes - block!(tx.write(sent)).ok(); + tx.write(&[sent]).ok(); hprintln!("sent"); - block!(tx.flush()).ok(); + tx.flush().ok(); hprintln!("flushed"); - let received = block!(rx.read()).unwrap(); + let mut buf = [0]; + let received = rx.read(&mut buf).unwrap(); hprintln!("received"); - assert_eq!(received, sent); + assert_eq!(received, 1); + assert_eq!(buf, [sent]); hprintln!("equal"); loop { diff --git a/examples/spi.rs b/examples/spi.rs index cecc4ab..98392cc 100644 --- a/examples/spi.rs +++ b/examples/spi.rs @@ -6,12 +6,12 @@ extern crate panic_halt; use core::{convert::TryFrom, fmt::Write}; use cortex_m_rt::entry; -use lpc55_hal as hal; +use lpc55_hal::{self as hal, drivers::pins::Level}; use hal::{ drivers::{Pins, SpiMaster}, time::{Hertz, RateExtensions}, - traits::wg::spi::{Mode, Phase, Polarity}, + traits::wg1::spi::{Mode, Phase, Polarity}, typestates::pin::flexcomm::{NoCs, NoMiso}, }; @@ -44,7 +44,6 @@ fn main() -> ! { let mosi = pins.pio0_26.into_spi8_mosi_pin(&mut iocon); // let miso = pins.pio1_3.into_spi8_miso_pin(&mut iocon); let miso = NoMiso; - // let cs = pins.pio1_1.into_spi8_cs_pin(&mut iocon); let cs = NoCs; // try this: currently no way to use SWCLK pin @@ -63,6 +62,11 @@ fn main() -> ! { Hertz::try_from(100_u32.kHz()).unwrap(), spi_mode, ); + let cs = pins + .pio1_1 + .into_gpio_pin(&mut iocon, &mut gpio) + .into_output(Level::Low); + let spi = embedded_hal_bus::spi::ExclusiveDevice::new_no_delay(spi, cs).unwrap(); let dc = pins .pio1_5 @@ -70,14 +74,13 @@ fn main() -> ! { .into_output_high(); // OLED - let mut display: TerminalMode<_> = ssd1306::Builder::new() - .size(DisplaySize::Display128x32) - // .size(DisplaySize::Display70x40) // <-- TODO - // .with_rotation(DisplayRotation::Rotate90) - .connect_spi(spi, dc) - .into(); - - display.init().unwrap(); + let mut display = ssd1306::Ssd1306::new( + SPIInterface::new(spi, dc), + DisplaySize128x32, + DisplayRotation::Rotate0, + ) + .into_terminal_mode(); + display.clear().ok(); loop { diff --git a/src/drivers.rs b/src/drivers.rs index ab58f32..4d89ace 100644 --- a/src/drivers.rs +++ b/src/drivers.rs @@ -49,3 +49,5 @@ pub use timer::Timer; pub mod touch; pub use touch::TouchSensor; + +pub mod delay; diff --git a/src/drivers/delay.rs b/src/drivers/delay.rs new file mode 100644 index 0000000..9d32979 --- /dev/null +++ b/src/drivers/delay.rs @@ -0,0 +1,15 @@ +use embedded_time::duration::Microseconds; + +use super::Timer; + +use crate::{peripherals::ctimer::Ctimer, traits::wg1::delay::DelayNs, typestates::init_state}; + +impl DelayNs for Timer +where + TIMER: Ctimer, +{ + fn delay_ns(&mut self, ns: u32) { + self.start(Microseconds::new(ns.max(1).saturating_mul(1000))); + nb::block!(self.wait()).ok(); + } +} diff --git a/src/drivers/i2c.rs b/src/drivers/i2c.rs index 397cf9d..ac2ddf1 100644 --- a/src/drivers/i2c.rs +++ b/src/drivers/i2c.rs @@ -1,5 +1,7 @@ +use embedded_hal::i2c::{NoAcknowledgeSource, Operation}; + use crate::time::Hertz; -use crate::traits::wg::blocking::i2c::{Read, Write, WriteRead}; +use crate::traits::wg1::i2c::{Error as ErrorTrait, ErrorType, I2c as I2cTrait}; use crate::typestates::pin::{ flexcomm::{ // Trait marking I2C peripherals and pins @@ -33,6 +35,29 @@ pub enum Error { StartStop, } +impl ErrorTrait for Error { + fn kind(&self) -> embedded_hal::i2c::ErrorKind { + use embedded_hal::i2c::ErrorKind; + match self { + Self::Bus => ErrorKind::Bus, + Self::ArbitrationLoss => ErrorKind::ArbitrationLoss, + Self::NackAddress => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Address), + Self::NackData => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Data), + Self::StartStop => ErrorKind::Other, + } + } +} + +impl ErrorType for I2cMaster +where + PIO1: PinId, + PIO2: PinId, + I2C: I2c, + PINS: I2cPins, +{ + type Error = Error; +} + pub type Result = core::result::Result; // TODO: Parametrize with Master/Slave MODE @@ -153,27 +178,7 @@ where Ok(()) } - fn write_without_stop(&mut self, addr: u8, bytes: &[u8]) -> Result<()> { - self.return_on_error()?; - - // Write the slave address with the RW bit set to 0 to the master data register MSTDAT. - self.i2c - .mstdat - .modify(|_, w| unsafe { w.data().bits(addr << 1) }); - // Start the transmission by setting the MSTSTART bit to 1 in the master control register. - self.i2c.mstctl.write(|w| w.mststart().start()); - // Wait for the pending status to be set (MSTPENDING = 1) by polling the STAT register - // TODO: Consider implementing a timeout (loop at most N times...) :TODO - while self.i2c.stat.read().mstpending().is_in_progress() { - continue; - } - - self.return_on_error()?; - if !self.i2c.stat.read().mststate().is_transmit_ready() { - // dbg!(Error::Bus); - return Err(Error::Bus); - } - + fn write_inner_bytes(&mut self, bytes: &[u8]) -> Result<()> { // Send bytes for byte in bytes { // write a byte @@ -194,6 +199,35 @@ where return Err(Error::Bus); } } + Ok(()) + } + + fn start_write(&mut self, addr: u8) -> Result<()> { + self.return_on_error()?; + + // Write the slave address with the RW bit set to 0 to the master data register MSTDAT. + self.i2c + .mstdat + .modify(|_, w| unsafe { w.data().bits(addr << 1) }); + // Start the transmission by setting the MSTSTART bit to 1 in the master control register. + self.i2c.mstctl.write(|w| w.mststart().start()); + // Wait for the pending status to be set (MSTPENDING = 1) by polling the STAT register + // TODO: Consider implementing a timeout (loop at most N times...) :TODO + while self.i2c.stat.read().mstpending().is_in_progress() { + continue; + } + + self.return_on_error()?; + if !self.i2c.stat.read().mststate().is_transmit_ready() { + // dbg!(Error::Bus); + return Err(Error::Bus); + } + Ok(()) + } + + fn write_without_stop(&mut self, addr: u8, bytes: &[u8]) -> Result<()> { + self.start_write(addr)?; + self.write_inner_bytes(bytes)?; // Fallthrough is success Ok(()) @@ -214,89 +248,120 @@ where // Fallthrough is success Ok(()) } -} -impl Write for I2cMaster -where - PIO1: PinId, - PIO2: PinId, - I2C: I2c, - PINS: I2cPins, -{ - type Error = Error; - - fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<()> { - self.write_without_stop(addr, bytes)?; - self.stop() + fn read_byte(&mut self) -> u8 { + self.i2c.mstdat.read().data().bits() } -} -impl Read for I2cMaster -where - PIO1: PinId, - PIO2: PinId, - I2C: I2c, - PINS: I2cPins, -{ - type Error = Error; + fn wait_for_byte_ready(&mut self) -> Result<()> { + // Wait for next byte + while self.i2c.stat.read().mstpending().is_in_progress() {} - fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<()> { - if let Some((last, buffer)) = buffer.split_last_mut() { - // Write the slave address with the RW bit set to 1 to the master data register MSTDAT. - self.i2c - .mstdat - .modify(|_, w| unsafe { w.data().bits((addr << 1) | 1) }); - // Start the transmission by setting the MSTSTART bit to 1 in the master control register. - self.i2c.mstctl.write(|w| w.mststart().start()); + self.return_on_error()?; + if !self.i2c.stat.read().mststate().is_receive_ready() { + return Err(Error::Bus); + } - // Wait for the pending status to be set (MSTPENDING = 1) by polling the STAT register - while self.i2c.stat.read().mstpending().is_in_progress() {} + Ok(()) + } - self.return_on_error()?; - if !self.i2c.stat.read().mststate().is_receive_ready() { - return Err(Error::Bus); - } + fn wait_for_next_byte(&mut self) -> Result { + // Instruct master to continue + self.i2c.mstctl.write(|w| w.mstcontinue().continue_()); - for byte in buffer { - // Read a byte - *byte = self.i2c.mstdat.read().data().bits(); - // Instruct master to continue - self.i2c.mstctl.write(|w| w.mstcontinue().continue_()); + self.wait_for_byte_ready()?; + Ok(self.read_byte()) + } - // Wait for next byte - while self.i2c.stat.read().mstpending().is_in_progress() {} + fn start_read(&mut self, addr: u8) -> Result<()> { + // Write the slave address with the RW bit set to 1 to the master data register MSTDAT. + self.i2c + .mstdat + .modify(|_, w| unsafe { w.data().bits((addr << 1) | 1) }); + // Start the transmission by setting the MSTSTART bit to 1 in the master control register. + self.i2c.mstctl.write(|w| w.mststart().start()); + Ok(()) + } - self.return_on_error()?; - if !self.i2c.stat.read().mststate().is_receive_ready() { - return Err(Error::Bus); - } - } + fn read_inner_bytes(&mut self, buffer: &mut [u8]) -> Result<()> { + for byte in buffer { + // Read a byte + *byte = self.wait_for_next_byte()?; + } + Ok(()) + } - // Read last byte - *last = self.i2c.mstdat.read().data().bits(); + fn read_without_stop(&mut self, addr: u8, buffer: &mut [u8]) -> Result<()> { + if let Some((first, buffer)) = buffer.split_first_mut() { + self.start_read(addr)?; - self.stop()?; + self.wait_for_byte_ready()?; + // read first byte + *first = self.read_byte(); + self.read_inner_bytes(buffer)?; } - // Fallthrough is success + // Reading to an empty buffer is a noop Ok(()) } } -impl WriteRead for I2cMaster +impl I2cTrait for I2cMaster where PIO1: PinId, PIO2: PinId, I2C: I2c, PINS: I2cPins, { - type Error = Error; + fn transaction( + &mut self, + address: u8, + operations: &mut [embedded_hal::i2c::Operation<'_>], + ) -> core::result::Result<(), Self::Error> { + let [ref mut current, ref mut rem @ ..] = operations else { + // No operations mean noop + return Ok(()); + }; + + // mut ref mut doesn't work above + let mut current = current; + let mut rem = rem; + // None: first iteration + // Some(true) iterating after a read + // Some(false) iterating after a write + let mut previous_was_read = None; + + loop { + match current { + Operation::Read(buf) => { + if previous_was_read == Some(true) { + self.read_inner_bytes(buf)?; + } else { + self.read_without_stop(address, buf)?; + } + + previous_was_read = Some(true); + } + Operation::Write(buf) => { + if previous_was_read == Some(false) { + self.write_inner_bytes(buf)?; + } else { + self.write_without_stop(address, buf)?; + } + + previous_was_read = Some(false); + } + } - fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<()> { - self.write_without_stop(addr, bytes)?; - self.read(addr, buffer)?; + let Some((new_current, new_rem)) = rem.split_first_mut() else { + // No operations left + self.stop()?; + return Ok(()); + }; - Ok(()) + current = new_current; + rem = new_rem; + } } } diff --git a/src/drivers/pins/gpio.rs b/src/drivers/pins/gpio.rs index 44d89e2..89540d5 100644 --- a/src/drivers/pins/gpio.rs +++ b/src/drivers/pins/gpio.rs @@ -1,4 +1,5 @@ -use crate::traits::wg::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin}; +use crate::drivers::pins::direction::Direction; +use crate::traits::wg1::digital; use crate::typestates::{ pin::{ @@ -31,52 +32,52 @@ reg_cluster!(PIN, PIN, raw::GPIO, pin); reg_cluster!(SET, SET, raw::GPIO, set); reg_cluster!(CLR, CLR, raw::GPIO, clr); -impl OutputPin for Pin> +impl digital::ErrorType for Pin> where T: PinId, + D: Direction, { type Error = core::convert::Infallible; +} - /// Set the pin output to HIGH - fn set_high(&mut self) -> Result<(), Self::Error> { - self.state.set[T::PORT].write(|w| unsafe { w.setp().bits(T::MASK) }); +impl digital::OutputPin for Pin> +where + T: PinId, +{ + fn set_low(&mut self) -> Result<(), Self::Error> { + self.state.clr[T::PORT].write(|w| unsafe { w.clrp().bits(T::MASK) }); Ok(()) } - /// Set the pin output to LOW - fn set_low(&mut self) -> Result<(), Self::Error> { - self.state.clr[T::PORT].write(|w| unsafe { w.clrp().bits(T::MASK) }); + fn set_high(&mut self) -> Result<(), Self::Error> { + self.state.set[T::PORT].write(|w| unsafe { w.setp().bits(T::MASK) }); Ok(()) } } -impl StatefulOutputPin for Pin> +impl digital::StatefulOutputPin for Pin> where T: PinId, { - fn is_set_high(&self) -> Result { + fn is_set_high(&mut self) -> Result { Ok(self.state.pin[T::PORT].read().port().bits() & T::MASK == T::MASK) } - fn is_set_low(&self) -> Result { + fn is_set_low(&mut self) -> Result { Ok(!self.state.pin[T::PORT].read().port().bits() & T::MASK == T::MASK) } } -impl toggleable::Default for Pin> {} - -impl InputPin for Pin> +impl digital::InputPin for Pin> where T: PinId, { - type Error = core::convert::Infallible; - - fn is_high(&self) -> Result { + fn is_high(&mut self) -> Result { // Ok(self.state.b[T::OFFSET].b_.read().pbyte()) Ok(self.state.pin[T::PORT].read().port().bits() & T::MASK == T::MASK) } - fn is_low(&self) -> Result { + fn is_low(&mut self) -> Result { // Ok(!self.state.b.b_[T::OFFSET].read().pbyte()) Ok(!self.state.pin[T::PORT].read().port().bits() & T::MASK == T::MASK) } diff --git a/src/drivers/pwm.rs b/src/drivers/pwm.rs index b6bcf2f..c33bb8b 100644 --- a/src/drivers/pwm.rs +++ b/src/drivers/pwm.rs @@ -1,4 +1,4 @@ -use crate::{peripherals::ctimer::Ctimer, time::Microseconds, traits::wg, typestates::init_state}; +use crate::{peripherals::ctimer::Ctimer, traits::wg1, typestates::init_state}; pub struct Pwm where @@ -67,72 +67,51 @@ where pub fn scale_max_duty_by(&mut self, duty: u32) { self.timer.mr[3].write(|w| unsafe { w.bits(0xff * duty) }); } + + pub fn channels(&mut self) -> (PwmPin<'_, TIMER>, PwmPin<'_, TIMER>, PwmPin<'_, TIMER>) { + ( + PwmPin { + timer: self, + channel: 0, + }, + PwmPin { + timer: self, + channel: 1, + }, + PwmPin { + timer: self, + channel: 2, + }, + ) + } } //pin: & Pin> -impl wg::Pwm for Pwm +pub struct PwmPin<'timer, TIMER> where TIMER: Ctimer, { - type Channel = u8; - type Time = Microseconds; - type Duty = u16; - - fn enable(&mut self, channel: Self::Channel) { - match channel { - 0..=2 => {} - _ => { - panic!("Cannot use channel outside 0-2 for PWM."); - } - } - } - - fn disable(&mut self, channel: Self::Channel) { - match channel { - 0 => { - self.timer - .mcr - .modify(|_, w| w.mr0i().clear_bit().mr0r().clear_bit().mr0s().clear_bit()); - self.timer.pwmc.modify(|_, w| w.pwmen0().clear_bit()); - } - 1 => { - self.timer - .mcr - .modify(|_, w| w.mr1i().clear_bit().mr1r().clear_bit().mr1s().clear_bit()); - self.timer.pwmc.modify(|_, w| w.pwmen1().clear_bit()); - } - 2 => { - self.timer - .mcr - .modify(|_, w| w.mr2i().clear_bit().mr2r().clear_bit().mr2s().clear_bit()); - self.timer.pwmc.modify(|_, w| w.pwmen2().clear_bit()); - } - _ => { - panic!("Cannot use channel outside 0-2 for PWM."); - } - } - } - - fn get_period(&self) -> Self::Time { - Microseconds(1_000_000 / self.get_max_duty() as u32) - } - - fn set_period

(&mut self, _period: P) - where - P: Into, - { - panic!("Currently period is fixed."); - } + timer: &'timer Pwm, + channel: u8, +} - fn get_duty(&self, channel: Self::Channel) -> Self::Duty { - self.timer.mr[channel as usize].read().bits() as Self::Duty - } +impl<'timer, TIMER> wg1::pwm::ErrorType for PwmPin<'timer, TIMER> +where + TIMER: Ctimer, +{ + type Error = wg1::pwm::ErrorKind; +} - fn get_max_duty(&self) -> Self::Duty { - self.timer.mr[3].read().bits() as Self::Duty +impl<'timer, TIMER> wg1::pwm::SetDutyCycle for PwmPin<'timer, TIMER> +where + TIMER: Ctimer, +{ + fn max_duty_cycle(&self) -> u16 { + self.timer.timer.mr[3].read().bits() as _ } - fn set_duty(&mut self, channel: Self::Channel, duty: Self::Duty) { - self.timer.mr[channel as usize].write(|w| unsafe { w.bits(duty as u32) }); + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + self.timer.timer.mr[self.channel as usize].write(|w| unsafe { w.bits(duty as u32) }); + Ok(()) } } diff --git a/src/drivers/rng.rs b/src/drivers/rng.rs index 197b5db..60d41c0 100644 --- a/src/drivers/rng.rs +++ b/src/drivers/rng.rs @@ -1,49 +1,55 @@ -use crate::traits::{rand_core, wg::blocking::rng}; - -use crate::typestates::init_state; - -use crate::Rng; - #[derive(Debug)] pub enum Error {} -impl rng::Read for Rng { - type Error = Error; +#[cfg(feature = "rand-core-06")] +mod rand06 { + use crate::typestates::init_state; + use crate::Rng; - fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> { - let mut i = 0usize; - while i < buffer.len() { - // get 4 bytes - let random_word: u32 = self.get_random_u32(); - let bytes: [u8; 4] = random_word.to_ne_bytes(); + use rand_core06::RngCore; + + impl RngCore for Rng { + fn next_u32(&mut self) -> u32 { + self.get_random_u32() + } - // copy to buffer as needed - let n = core::cmp::min(4, buffer.len() - i); - buffer[i..i + n].copy_from_slice(&bytes[..n]); - i += n; + fn next_u64(&mut self) -> u64 { + rand_core06::impls::next_u64_via_u32(self) } - Ok(()) + fn fill_bytes(&mut self, dest: &mut [u8]) { + rand_core06::impls::fill_bytes_via_next(self, dest) + } + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core06::Error> { + self.fill_bytes(dest); + Ok(()) + } } + + impl rand_core06::CryptoRng for Rng {} } -impl rand_core::RngCore for Rng { - fn next_u32(&mut self) -> u32 { - self.get_random_u32() - } +#[cfg(feature = "rand-core-09")] +mod rand09 { + use crate::typestates::init_state; + use crate::Rng; - fn next_u64(&mut self) -> u64 { - rand_core::impls::next_u64_via_u32(self) - } + use rand_core09::RngCore; - fn fill_bytes(&mut self, dest: &mut [u8]) { - rand_core::impls::fill_bytes_via_next(self, dest) - } + impl RngCore for Rng { + fn next_u32(&mut self) -> u32 { + self.get_random_u32() + } - fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { - self.fill_bytes(dest); - Ok(()) + fn next_u64(&mut self) -> u64 { + rand_core09::impls::next_u64_via_u32(self) + } + + fn fill_bytes(&mut self, dest: &mut [u8]) { + rand_core09::impls::fill_bytes_via_next(self, dest) + } } -} -impl rand_core::CryptoRng for Rng {} + impl rand_core09::CryptoRng for Rng {} +} diff --git a/src/drivers/serial.rs b/src/drivers/serial.rs index 739724d..ab54f09 100644 --- a/src/drivers/serial.rs +++ b/src/drivers/serial.rs @@ -1,10 +1,8 @@ -use core::fmt; use core::marker::PhantomData; use core::ops::Deref; use crate::{ time::Hertz, - traits::wg::serial, typestates::pin::{ flexcomm::{ // Trait marking USART peripherals and pins @@ -222,9 +220,28 @@ where pub fn release(self) -> (USART, PINS) { (self.usart, self.pins) } + + fn read_(&mut self) -> nb::Result { + let mut rx: Rx = Rx { + addr: self.addr(), + _usart: PhantomData, + }; + rx.read_() + } } -impl serial::Read for Serial +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + match self { + Self::Framing => embedded_io::ErrorKind::InvalidData, + Self::Noise => embedded_io::ErrorKind::InvalidData, + Self::Overrun => embedded_io::ErrorKind::OutOfMemory, + Self::Parity => embedded_io::ErrorKind::InvalidData, + } + } +} + +impl embedded_io::ErrorType for Serial where TX: PinId, RX: PinId, @@ -232,20 +249,80 @@ where PINS: UsartPins, { type Error = Error; +} - fn read(&mut self) -> nb::Result { - let mut rx: Rx = Rx { - addr: self.addr(), - _usart: PhantomData, - }; - rx.read() +impl embedded_io::Read for Serial +where + TX: PinId, + RX: PinId, + USART: Usart, + PINS: UsartPins, +{ + fn read(&mut self, buf: &mut [u8]) -> Result { + let len = buf.len(); + for el in buf { + *el = nb::block!(self.read_())?; + } + Ok(len) } } -impl serial::Read for Rx { +impl embedded_io::ErrorType for Tx { + type Error = Error; +} + +impl embedded_io::ErrorType for Rx { type Error = Error; +} + +impl embedded_io::Write for Tx { + fn flush(&mut self) -> Result<(), Self::Error> { + while !self.stat.read().txidle().bit() {} + Ok(()) + } + fn write(&mut self, buf: &[u8]) -> Result { + for byte in buf { + while !self.fifostat.read().txnotfull().bit() {} + // TODO: figure out if we need to perform an 8-bit write + // This would not be possible via svd2rust API, and need some acrobatics + self.fifowr.write(|w| unsafe { w.bits(*byte as u32) }); + } + Ok(buf.len()) + } +} - fn read(&mut self) -> nb::Result { +impl embedded_io::Write for Serial +where + TX: PinId, + RX: PinId, + USART: Usart, + PINS: UsartPins, +{ + fn flush(&mut self) -> Result<(), Self::Error> { + while !self.usart.stat.read().txidle().bit() {} + Ok(()) + } + fn write(&mut self, buf: &[u8]) -> Result { + for byte in buf { + while !self.usart.fifostat.read().txnotfull().bit() {} + // TODO: figure out if we need to perform an 8-bit write + // This would not be possible via svd2rust API, and need some acrobatics + self.usart.fifowr.write(|w| unsafe { w.bits(*byte as u32) }); + } + Ok(buf.len()) + } +} +impl embedded_io::Read for Rx { + fn read(&mut self, buf: &mut [u8]) -> Result { + let len = buf.len(); + for b in buf { + *b = nb::block!(self.read_())?; + } + Ok(len) + } +} +impl Rx { + fn read_(&mut self) -> nb::Result { let fifostat = self.fifostat.read(); if fifostat.rxnotempty().bit() { @@ -279,68 +356,3 @@ impl serial::Read for Rx { } } } - -impl serial::Write for Serial -where - TX: PinId, - RX: PinId, - USART: Usart, - PINS: UsartPins, -{ - type Error = Error; - - fn flush(&mut self) -> nb::Result<(), Self::Error> { - let mut tx: Tx = Tx { - addr: self.addr(), - _usart: PhantomData, - }; - tx.flush() - } - - fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { - let mut tx: Tx = Tx { - addr: self.addr(), - _usart: PhantomData, - }; - tx.write(byte) - } -} - -impl serial::Write for Tx { - type Error = Error; - - fn flush(&mut self) -> nb::Result<(), Self::Error> { - if self.stat.read().txidle().bit() { - Ok(()) - } else { - Err(nb::Error::WouldBlock) - } - } - - fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { - if self.fifostat.read().txnotfull().bit() { - // TODO: figure out if we need to perform an 8-bit write - // This would not be possible via svd2rust API, and need some acrobatics - self.fifowr.write(|w| unsafe { w.bits(byte as u32) }); - - Ok(()) - } else { - Err(nb::Error::WouldBlock) - } - } -} - -impl fmt::Write for Tx -where - Tx: serial::Write, -{ - fn write_str(&mut self, s: &str) -> fmt::Result { - use crate::traits::wg::serial::Write; - let _ = s - .as_bytes() - .iter() - .map(|c| nb::block!(self.write(*c))) - .last(); - Ok(()) - } -} diff --git a/src/drivers/spi.rs b/src/drivers/spi.rs index 5bf0e2d..5ef2a74 100644 --- a/src/drivers/spi.rs +++ b/src/drivers/spi.rs @@ -7,15 +7,14 @@ use core::marker::PhantomData; +use embedded_hal::spi::SpiBus; + use crate::time::Hertz; -pub use crate::traits::wg::spi::{FullDuplex, Mode, Phase, Polarity}; +pub use crate::traits::wg1::spi::{ + Error as ErrorTrait, ErrorKind, ErrorType, Mode, Operation, Phase, Polarity, SpiDevice, +}; use crate::typestates::pin::{ - flexcomm::{ - ChipSelect, - // Trait marking I2C peripherals and pins - Spi, - SpiPins, - }, + flexcomm::{ChipSelect, NoPio, Spi, SpiPins}, PinId, }; @@ -38,7 +37,7 @@ pub enum Error { Crc, } -pub type Result = nb::Result; +pub type Result = core::result::Result; /// SPI peripheral operating in master mode pub struct SpiMaster @@ -136,7 +135,17 @@ where } } -impl FullDuplex for SpiMaster +impl ErrorTrait for Error { + fn kind(&self) -> ErrorKind { + match self { + Self::Overrun => ErrorKind::Overrun, + Self::ModeFault => ErrorKind::ModeFault, + Self::Crc => ErrorKind::FrameFormat, + } + } +} + +impl ErrorType for SpiMaster where SCK: PinId, MOSI: PinId, @@ -147,8 +156,18 @@ where // CSPIN: SpiSselPin, { type Error = Error; +} - fn read(&mut self) -> Result { +impl SpiMaster +where + SCK: PinId, + MOSI: PinId, + MISO: PinId, + CS: PinId, + SPI: Spi, + PINS: SpiPins, +{ + fn read_one(&mut self) -> nb::Result { // self.return_on_error()?; if self.spi.fifostat.read().rxnotempty().bit_is_set() { // TODO: not sure how to turn this from u32 (or u16??) into u8 @@ -160,7 +179,7 @@ where } } - fn send(&mut self, byte: u8) -> Result<()> { + fn send_one(&mut self, byte: u8) -> nb::Result<(), Error> { // NB: UM says "Do not read-modify-write the register." // - writing 0 to upper-half word means: keep previous control settings @@ -241,28 +260,52 @@ where } } -impl crate::traits::wg::blocking::spi::transfer::Default - for SpiMaster +impl SpiBus for SpiMaster where SCK: PinId, MOSI: PinId, MISO: PinId, - CS: PinId, SPI: Spi, - PINS: SpiPins, + PINS: SpiPins, + // CSPIN: SpiSselPin, { -} + fn read(&mut self, words: &mut [u8]) -> Result<()> { + for w in words { + *w = nb::block!(self.read_one())?; + } + Ok(()) + } + fn write(&mut self, words: &[u8]) -> Result<()> { + for w in words { + nb::block!(self.send_one(*w))?; + } + Ok(()) + } -impl crate::traits::wg::blocking::spi::write::Default - for SpiMaster -where - SCK: PinId, - MOSI: PinId, - MISO: PinId, - CS: PinId, - SPI: Spi, - PINS: SpiPins, -{ + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<()> { + for i in 0..read.len().max(write.len()) { + let w = write.get(i).copied().unwrap_or(0xFF); + nb::block!(self.send_one(w))?; + let r = nb::block!(self.read_one())?; + if let Some(w) = read.get_mut(i) { + *w = r; + } + } + Ok(()) + } + + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<()> { + for w in words { + // Corresponds to the previous implementation through embedded_hal_027::blocking::spi::transfer::Default + nb::block!(self.send_one(*w))?; + *w = nb::block!(self.read_one())?; + } + Ok(()) + } + + fn flush(&mut self) -> core::result::Result<(), Self::Error> { + Ok(()) + } } // impl crate::traits::wg::blocking::spi::transfer::Default for SpiMaster diff --git a/src/drivers/timer.rs b/src/drivers/timer.rs index d8b9c10..2ecd8f0 100644 --- a/src/drivers/timer.rs +++ b/src/drivers/timer.rs @@ -1,16 +1,12 @@ -use core::convert::Infallible; - use nb; use void::Void; -use crate::{ - peripherals::ctimer::Ctimer, time::Microseconds, traits::wg::timer, typestates::init_state, -}; +use crate::{peripherals::ctimer::Ctimer, time::Microseconds, typestates::init_state}; /// Return the current time elapsed for the timer. /// If the timer has not started or stopped, this unit may not be accurate. -pub trait Elapsed: timer::CountDown { - fn elapsed(&self) -> Self::Time; +pub trait Elapsed { + fn elapsed(&self) -> Microseconds; } pub struct Timer @@ -44,15 +40,13 @@ where } } -impl timer::CountDown for Timer +impl Timer where TIMER: Ctimer, { - type Time = TimeUnits; - - fn start(&mut self, count: T) + pub fn start(&mut self, count: T) where - T: Into, + T: Into, { // Match should reset and stop timer, and generate interrupt. self.timer @@ -74,7 +68,7 @@ where .write(|w| w.crst().clear_bit().cen().set_bit()); } - fn wait(&mut self) -> nb::Result<(), Void> { + pub fn wait(&mut self) -> nb::Result<(), Void> { if self.timer.ir.read().mr0int().bit_is_set() { self.timer .tcr @@ -86,16 +80,14 @@ where } } -impl timer::Cancel for Timer +impl Timer where TIMER: Ctimer, { - type Error = Infallible; - fn cancel(&mut self) -> Result<(), Self::Error> { + pub fn cancel(&mut self) { self.timer .tcr .write(|w| w.crst().set_bit().cen().clear_bit()); self.timer.ir.write(|w| w.mr0int().set_bit()); - Ok(()) } } diff --git a/src/drivers/touch.rs b/src/drivers/touch.rs index 5bfd1c9..36a4dfe 100644 --- a/src/drivers/touch.rs +++ b/src/drivers/touch.rs @@ -1,7 +1,6 @@ use core::ops::{Deref, DerefMut}; use embedded_time::duration::Extensions; -use crate::traits::wg::timer::CountDown; use crate::{ drivers::{pins, timer, timer::Elapsed, Pin}, peripherals::{ctimer, dma::Dma}, diff --git a/src/peripherals/usbhs.rs b/src/peripherals/usbhs.rs index c76cc4f..a66baa3 100644 --- a/src/peripherals/usbhs.rs +++ b/src/peripherals/usbhs.rs @@ -4,7 +4,6 @@ use embedded_time::duration::Extensions; use crate::drivers::timer; use crate::peripherals::{anactrl, ctimer, pmc, syscon}; use crate::raw; -use crate::traits::wg::timer::CountDown; use crate::typestates::{ init_state, usbhs_mode, diff --git a/src/peripherals/utick.rs b/src/peripherals/utick.rs index 501adf0..b49907a 100644 --- a/src/peripherals/utick.rs +++ b/src/peripherals/utick.rs @@ -10,10 +10,7 @@ // TODO: move this to drivers section, // possibly merge with ctimers when they're implemented -use core::convert::Infallible; -use embedded_hal::timer; -use nb; -use void::Void; +use crate::traits::wg1; use crate::{ peripherals::syscon, @@ -48,37 +45,13 @@ impl Utick { _state: init_state::Disabled, } } -} - -// TODO: This does not feel like it belongs here. - -impl timer::Cancel for EnabledUtick { - type Error = Infallible; - - fn cancel(&mut self) -> Result<(), Self::Error> { - // A value of 0 stops the timer. - self.raw.ctrl.write(|w| unsafe { w.delayval().bits(0) }); - Ok(()) - } -} - -// TODO: also implement Periodic for UTICK -impl timer::CountDown for EnabledUtick { - type Time = u32; - - fn start(&mut self, timeout: T) - where - T: Into, - { - // The delay will be equal to DELAYVAL + 1 periods of the timer clock. - // The minimum usable value is 1, for a delay of 2 timer clocks. A value of 0 stops the timer. - let time = timeout.into(); + pub fn start(&mut self, timeout_ms: u32) { // Maybe remove again? Empirically, nothing much happens when // writing 1 to `delayval`. - assert!(time >= 2); + assert!(timeout_ms >= 2); self.raw .ctrl - .write(|w| unsafe { w.delayval().bits(time - 1) }); + .write(|w| unsafe { w.delayval().bits(timeout_ms - 1) }); // So... this seems a bit unsafe (what if time is 2?) // But: without it, in --release builds the timer behaves erratically. // The UM says this on the topic: "Note that the Micro-tick Timer operates from a different @@ -86,14 +59,6 @@ impl timer::CountDown for EnabledUtick { // synchronization delay when accessing Micro-tick Timer registers." while self.raw.stat.read().active().bit_is_clear() {} } - - fn wait(&mut self) -> nb::Result<(), Void> { - if self.raw.stat.read().active().bit_is_clear() { - return Ok(()); - } - - Err(nb::Error::WouldBlock) - } } // TODO: Either get rid of `nb` or get rid of this @@ -102,3 +67,10 @@ impl EnabledUtick { while self.raw.stat.read().active().bit_is_set() {} } } + +impl wg1::delay::DelayNs for EnabledUtick { + fn delay_ns(&mut self, ns: u32) { + self.start(ns.saturating_mul(1000)); + self.blocking_wait(); + } +} diff --git a/src/prelude.rs b/src/prelude.rs index 004f36f..a60a0f6 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,9 +1,6 @@ -// TODO: clean this up, *-imports are horrible -pub use crate::traits::wg::prelude::*; - // Uhh get rid of this as soon as Vadim did v3 -pub use crate::traits::wg::digital::v2::OutputPin as _; -pub use crate::traits::wg::digital::v2::StatefulOutputPin as _; +pub use crate::traits::wg1::digital::OutputPin as _; +pub use crate::traits::wg1::digital::StatefulOutputPin as _; pub use crate::time::DurationExtensions as _; pub use crate::time::RateExtensions as _; diff --git a/src/traits.rs b/src/traits.rs index e0bd3b3..002392d 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -9,9 +9,7 @@ pub use digest; // TODO: this pulls in the not-very-well-organised // entire library, in particular not just traits and types. // Would be worth being more explicit. -pub use embedded_hal as wg; - -pub use rand_core; +pub use embedded_hal as wg1; // TODO: Add more as needed, // - internal diff --git a/src/traits/flash.rs b/src/traits/flash.rs index 17908a8..fcee75e 100644 --- a/src/traits/flash.rs +++ b/src/traits/flash.rs @@ -39,8 +39,8 @@ pub trait Read { // TODO: offer a version without restrictions? // can round down address, round up buffer length, // but where to get the buffer from? - assert!(buf.len() % ReadSize::to_usize() == 0); - assert!(address % ReadSize::to_usize() == 0); + assert!(buf.len().is_multiple_of(ReadSize::to_usize())); + assert!(address.is_multiple_of(ReadSize::to_usize())); for i in (0..buf.len()).step_by(ReadSize::to_usize()) { self.read_native( @@ -69,8 +69,8 @@ pub trait WriteErase { fn write(&mut self, address: usize, data: &[u8]) -> Result { let write_size = WriteSize::to_usize(); - assert!(data.len() % write_size == 0); - assert!(address % write_size == 0); + assert!(data.len().is_multiple_of(write_size)); + assert!(address.is_multiple_of(write_size)); // interrupt::free(|cs| { for i in (0..data.len()).step_by(write_size) {