From d27cbdcf3b32825a9eca27e522890196ee9b5a30 Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 12 Mar 2024 09:11:34 +0100 Subject: [PATCH 1/7] Add embedded-hal 1.0.0 dependency --- Cargo.toml | 7 +-- src/adc.rs | 112 ++++++++++++++++++++++++++++++++---------------- src/delay.rs | 19 ++++---- src/gpio.rs | 20 ++++----- src/i2c.rs | 30 ++++--------- src/lib.rs | 1 + src/prelude.rs | 2 +- src/pwm.rs | 4 +- src/serial.rs | 55 +++++++++++------------- src/spi.rs | 94 +++++++++++++++++++++------------------- src/timer.rs | 2 +- src/watchdog.rs | 2 +- 12 files changed, 188 insertions(+), 160 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 158fc8f..0cc27ac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,10 @@ cast = { version = "0.2.3", default-features = false } vcell = "0.1.2" embedded-dma = "0.1.2" -[dependencies.embedded-hal] -version = "0.2.3" -features = ["unproven"] +embedded-hal = { package = "embedded-hal", version = "1.0.0" } +embedded-hal-02 = { package = "embedded-hal", version = "0.2.7", features = [ + "unproven", +] } [features] rt = ["gd32vf103-pac/rt"] diff --git a/src/adc.rs b/src/adc.rs index 877af12..501487e 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -5,10 +5,10 @@ use core::sync::atomic::{self, Ordering}; use crate::dma::{dma0::C0, CircBuffer, CircReadDma, Receive, RxDma, Transfer, TransferPayload, W}; use crate::gpio::{gpioa, gpiob, gpioc, Analog}; +use crate::hal_02::adc::{Channel, OneShot}; use crate::pac::{ADC0, ADC1}; use crate::rcu::{BaseFrequency, Clocks, Enable, Rcu, Reset}; use embedded_dma::StaticWriteBuffer; -use embedded_hal::adc::{Channel, OneShot}; #[doc(hidden)] pub trait AdcX {} @@ -163,14 +163,14 @@ pub enum ETSRC_A { impl From for u8 { fn from(src: ETSRC_A) -> u8 { match src { - ETSRC_A::TIM0CH0 => 0b000, - ETSRC_A::TIM0CH1 => 0b001, - ETSRC_A::TIM0CH2 => 0b010, - ETSRC_A::TIM1CH1 => 0b011, + ETSRC_A::TIM0CH0 => 0b000, + ETSRC_A::TIM0CH1 => 0b001, + ETSRC_A::TIM0CH2 => 0b010, + ETSRC_A::TIM1CH1 => 0b011, ETSRC_A::TIM2TRGO => 0b100, - ETSRC_A::TIM3CH3 => 0b101, - ETSRC_A::EXTI11 => 0b110, - ETSRC_A::SWRCST => 0b111, + ETSRC_A::TIM3CH3 => 0b101, + ETSRC_A::EXTI11 => 0b110, + ETSRC_A::SWRCST => 0b111, } } } @@ -615,28 +615,52 @@ impl Adc { self.rb.ctl0.modify(|_, w| w.disrc().clear_bit()); self.rb.ctl1.modify(|_, w| w.dal().bit(self.align.into())); self.set_channel_sample_time(PIN::channel(), self.sample_time); - self.rb.rsq2.modify(|_, w| unsafe { w.rsq0().bits(PIN::channel()) }); + self.rb + .rsq2 + .modify(|_, w| unsafe { w.rsq0().bits(PIN::channel()) }); self.rb.ctl1.modify(|_, w| w.dma().set_bit()); - RxDma { payload: AdcPayload { adc: self, pins, _mode: PhantomData }, channel: dma_ch } + RxDma { + payload: AdcPayload { + adc: self, + pins, + _mode: PhantomData, + }, + channel: dma_ch, + } } pub fn with_scan_dma(mut self, pins: PINS, dma_ch: C0) -> AdcDma where Self: SetChannels, { - self.rb.ctl1.modify(|_, w| w - .adcon().clear_bit() - .dma().clear_bit() - .ctn().clear_bit() - .dal().bit(self.align.into()) - ); - self.rb.ctl0.modify(|_, w| w.sm().set_bit().disrc().clear_bit()); + self.rb.ctl1.modify(|_, w| { + w.adcon() + .clear_bit() + .dma() + .clear_bit() + .ctn() + .clear_bit() + .dal() + .bit(self.align.into()) + }); + self.rb + .ctl0 + .modify(|_, w| w.sm().set_bit().disrc().clear_bit()); self.set_samples(); self.set_sequence(); - self.rb.ctl1.modify(|_, w| w.dma().set_bit().adcon().set_bit()); - - RxDma { payload: AdcPayload { adc: self, pins, _mode: PhantomData }, channel: dma_ch } + self.rb + .ctl1 + .modify(|_, w| w.dma().set_bit().adcon().set_bit()); + + RxDma { + payload: AdcPayload { + adc: self, + pins, + _mode: PhantomData, + }, + channel: dma_ch, + } } } @@ -657,7 +681,7 @@ where impl AdcDma where - Self: TransferPayload + Self: TransferPayload, { pub fn split(mut self) -> (Adc, PINS, C0) { self.stop(); @@ -682,19 +706,26 @@ where // the transfer let (ptr, len) = unsafe { buffer.static_write_buffer() }; unsafe { - self.channel.set_peripheral_address(&(*ADC0::ptr()).rdata as *const _ as u32, false); + self.channel + .set_peripheral_address(&(*ADC0::ptr()).rdata as *const _ as u32, false); self.channel.set_memory_address(ptr as u32, true); } self.channel.set_transfer_length(len); atomic::compiler_fence(Ordering::Release); - self.channel.ctl().modify(|_, w| unsafe { w - .m2m().clear_bit() - .prio().bits(0b01) // Medium - .mwidth().bits(0b01) // 16 bits - .pwidth().bits(0b01) // 16 bits - .cmen().set_bit() - .dir().clear_bit() + self.channel.ctl().modify(|_, w| unsafe { + w.m2m() + .clear_bit() + .prio() + .bits(0b01) // Medium + .mwidth() + .bits(0b01) // 16 bits + .pwidth() + .bits(0b01) // 16 bits + .cmen() + .set_bit() + .dir() + .clear_bit() }); self.start(); @@ -712,19 +743,26 @@ where // until the end of the transfer. let (ptr, len) = unsafe { buffer.static_write_buffer() }; unsafe { - self.channel.set_peripheral_address(&(*ADC0::ptr()).rdata as *const _ as u32, false); + self.channel + .set_peripheral_address(&(*ADC0::ptr()).rdata as *const _ as u32, false); self.channel.set_memory_address(ptr as u32, true); } self.channel.set_transfer_length(len); atomic::compiler_fence(Ordering::Release); - self.channel.ctl().modify(|_, w| unsafe { w - .m2m().clear_bit() - .prio().bits(0b01) // Medium - .mwidth().bits(0b01) // 16 bits - .pwidth().bits(0b01) // 16 bits - .cmen().clear_bit() - .dir().clear_bit() + self.channel.ctl().modify(|_, w| unsafe { + w.m2m() + .clear_bit() + .prio() + .bits(0b01) // Medium + .mwidth() + .bits(0b01) // 16 bits + .pwidth() + .bits(0b01) // 16 bits + .cmen() + .clear_bit() + .dir() + .clear_bit() }); self.start(); diff --git a/src/delay.rs b/src/delay.rs index eb65ec0..217c9d7 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -1,25 +1,25 @@ //! Delays -use crate::timer::Timer; use crate::time::U32Ext; +use crate::timer::Timer; +use crate::hal_02::blocking::delay::{DelayMs, DelayUs}; +use crate::hal_02::timer::CountDown; +use crate::rcu::Clocks; use cast::u32; -use embedded_hal::blocking::delay::{DelayMs, DelayUs}; -use embedded_hal::timer::CountDown; use gd32vf103_pac::{TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5, TIMER6}; -use crate::rcu::Clocks; /// Machine mode cycle counter (`mcycle`) as a delay provider #[derive(Copy, Clone)] pub struct McycleDelay { - core_frequency: u32 + core_frequency: u32, } impl McycleDelay { /// Constructs the delay provider pub fn new(clocks: &Clocks) -> Self { Self { - core_frequency: clocks.sysclk().0 + core_frequency: clocks.sysclk().0, } } } @@ -28,7 +28,7 @@ impl DelayUs for McycleDelay { fn delay_us(&mut self, us: u64) { let t0 = riscv::register::mcycle::read64(); let clocks = (us * (self.core_frequency as u64)) / 1_000_000; - while riscv::register::mcycle::read64().wrapping_sub(t0) <= clocks { } + while riscv::register::mcycle::read64().wrapping_sub(t0) <= clocks {} } } @@ -92,7 +92,10 @@ impl DelayMs for McycleDelay { } /// TIMER as a delay provider -pub struct Delay where Timer: CountDown { +pub struct Delay +where + Timer: CountDown, +{ timer: Timer, } diff --git a/src/gpio.rs b/src/gpio.rs index 8cced3c..31e3537 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,8 +1,8 @@ //! General Purpose Input / Output +use crate::rcu::Rcu; use core::marker::PhantomData; use riscv::interrupt; -use crate::rcu::Rcu; /// Extension trait to split a GPIO peripheral in independent pins and registers pub trait GpioExt { @@ -97,9 +97,9 @@ impl PortMode { #[inline(always)] pub fn into_bits(self) -> u8 { match self { - PortMode::Input(conf) => (conf as u8) | 0b00, + PortMode::Input(conf) => (conf as u8) | 0b00, PortMode::Output10Mhz(conf) => (conf as u8) | 0b01, - PortMode::Output2Mhz(conf) => (conf as u8) | 0b10, + PortMode::Output2Mhz(conf) => (conf as u8) | 0b10, PortMode::Output50Mhz(conf) => (conf as u8) | 0b11, } } @@ -119,13 +119,11 @@ trait PeripheralAccess { interrupt::free(|_| { if index < 8 { - regs.ctl0.modify(|r, w| unsafe { - w.bits((r.bits() & mask) | value) - }); + regs.ctl0 + .modify(|r, w| unsafe { w.bits((r.bits() & mask) | value) }); } else { - regs.ctl1.modify(|r, w| unsafe { - w.bits((r.bits() & mask) | value) - }); + regs.ctl1 + .modify(|r, w| unsafe { w.bits((r.bits() & mask) | value) }); } }); } @@ -179,7 +177,7 @@ macro_rules! gpio { pub mod $gpiox { use core::convert::Infallible; use core::marker::PhantomData; - use crate::hal::digital::v2::{OutputPin, InputPin, StatefulOutputPin, toggleable}; + use crate::hal_02::digital::v2::{OutputPin, InputPin, StatefulOutputPin, toggleable}; use crate::pac::$GPIOX; use crate::rcu::{Rcu, Enable, Reset}; use super::{ @@ -507,7 +505,7 @@ macro_rules! gpio { macro_rules! impl_pxx { ($(($port:ident :: $pin:ident)),*) => { use core::convert::Infallible; - use embedded_hal::digital::v2::{InputPin, StatefulOutputPin, OutputPin}; + use crate::hal_02::digital::v2::{InputPin, StatefulOutputPin, OutputPin}; pub enum Pxx { $( diff --git a/src/i2c.rs b/src/i2c.rs index bf7e10b..8cb3f35 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -1,15 +1,15 @@ //! Inter-Integrated Circuit (I2C) bus +use crate::afio::{Afio, Remap}; use crate::gpio::gpiob::{PB10, PB11, PB6, PB7, PB8, PB9}; use crate::gpio::{Alternate, OpenDrain}; -use crate::hal::blocking::i2c::{Read, Write, WriteRead}; +use crate::hal_02::blocking::i2c::{Read, Write, WriteRead}; use crate::pac::{I2C0, I2C1}; -use crate::rcu::{Rcu, Clocks, Enable, Reset, BaseFrequency}; +use crate::rcu::{BaseFrequency, Clocks, Enable, Rcu, Reset}; use crate::time::Hertz; -use crate::afio::{Afio, Remap}; -use riscv::register::mcycle; use nb::Error::{Other, WouldBlock}; use nb::{Error as NbError, Result as NbResult}; +use riscv::register::mcycle; /// I2C error #[derive(Debug, Eq, PartialEq)] @@ -47,7 +47,7 @@ pub enum Mode { FastPlus { frequency: Hertz, duty_cycle: DutyCycle, - } + }, } impl Mode { @@ -116,13 +116,7 @@ pub struct BlockingI2c { impl I2c { /// Creates a generic I2C0 object on pins PB6 and PB7 or PB8 and PB9 (if remapped) - pub fn i2c0( - i2c: I2C0, - pins: PINS, - afio: &mut Afio, - mode: Mode, - rcu: &mut Rcu, - ) -> Self + pub fn i2c0(i2c: I2C0, pins: PINS, afio: &mut Afio, mode: Mode, rcu: &mut Rcu) -> Self where PINS: Pins, { @@ -163,12 +157,7 @@ impl BlockingI2c { impl I2c { /// Creates a generic I2C1 object on pins PB10 and PB11 using the embedded-hal `BlockingI2c` trait. - pub fn i2c1( - i2c: I2C1, - pins: PINS, - mode: Mode, - rcu: &mut Rcu, - ) -> Self + pub fn i2c1(i2c: I2C1, pins: PINS, mode: Mode, rcu: &mut Rcu) -> Self where PINS: Pins, { @@ -265,10 +254,7 @@ macro_rules! busy_wait_cycles { ($nb_expr:expr, $cycles:expr) => {{ let started = mcycle::read(); let cycles = $cycles as usize; - busy_wait!( - $nb_expr, - mcycle::read().wrapping_sub(started) >= cycles - ) + busy_wait!($nb_expr, mcycle::read().wrapping_sub(started) >= cycles) }}; } diff --git a/src/lib.rs b/src/lib.rs index 583a0e1..0edbb62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ pub use gd32vf103_pac as pac; use embedded_hal as hal; +use embedded_hal_02 as hal_02; pub mod adc; pub mod afio; diff --git a/src/prelude.rs b/src/prelude.rs index 4d239ab..1503090 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,6 +1,6 @@ //! Prelude -pub use crate::hal::prelude::*; +pub use crate::hal_02::prelude::*; pub use crate::afio::AfioExt as _gd32vf103xx_hal_afio_AfioExt; pub use crate::backup_domain::BkpExt as _gd32vf103xx_hal_backup_domain_BkpExt; diff --git a/src/pwm.rs b/src/pwm.rs index 2b183eb..119f88a 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -1,6 +1,6 @@ //! Pulse width modulation -use embedded_hal::Pwm; +use crate::hal_02::Pwm; use gd32vf103_pac::{TIMER0, TIMER1, TIMER2, TIMER3, TIMER4}; use crate::afio::{Afio, Remap}; @@ -134,7 +134,7 @@ impl From for u8 { /// use hal::rcu::RcuExt; /// use hal::afio::AfioExt; /// use hal::pwm::{PwmTimer, Channel, NoRemap}; -/// use embedded_hal::Pwm; +/// use crate::hal_02::Pwm; /// /// // ... /// let dp = Peripherals::take().unwrap(); diff --git a/src/serial.rs b/src/serial.rs index da4c404..c433e2c 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -34,13 +34,13 @@ use core::marker::PhantomData; use core::ptr; -use nb; +use crate::hal_02::serial::Write; use core::convert::Infallible; -use embedded_hal::serial::Write; +use nb; -use crate::rcu::Rcu; -use crate::time::{U32Ext, Bps}; use crate::afio::Afio; +use crate::rcu::Rcu; +use crate::time::{Bps, U32Ext}; /// Interrupt event pub enum Event { @@ -66,17 +66,19 @@ pub enum Error { } mod closed_traits { - use gd32vf103_pac::{USART0, USART1, USART2, usart0::RegisterBlock}; - use core::ops::Deref; - use crate::rcu::{Enable, Reset, BaseFrequency}; use crate::afio::Remap; - use crate::gpio::{Alternate, Floating, Input, PushPull}; use crate::gpio::gpioa::{PA10, PA2, PA3, PA9}; - use crate::gpio::gpiob::{PB6, PB7, PB10, PB11}; + use crate::gpio::gpiob::{PB10, PB11, PB6, PB7}; use crate::gpio::gpioc::{PC10, PC11}; use crate::gpio::gpiod::{PD5, PD6, PD8, PD9}; + use crate::gpio::{Alternate, Floating, Input, PushPull}; + use crate::rcu::{BaseFrequency, Enable, Reset}; + use core::ops::Deref; + use gd32vf103_pac::{usart0::RegisterBlock, USART0, USART1, USART2}; - pub trait UsartX : Deref + Enable + Reset + BaseFrequency + Remap { + pub trait UsartX: + Deref + Enable + Reset + BaseFrequency + Remap + { fn ptr() -> *const RegisterBlock; } @@ -92,7 +94,7 @@ mod closed_traits { impl crate::serial::Pins<$usart> for ($tx, $rx) where TM: crate::gpio::Active, - RM: crate::gpio::Active + RM: crate::gpio::Active, { const REMAP: $remap_type = $remap_value; type Tx = $tx>; @@ -105,7 +107,7 @@ mod closed_traits { (tx, rx) } } - } + }; } impl UsartX for USART0 { @@ -141,7 +143,6 @@ mod closed_traits { } use closed_traits::*; - pub enum Parity { ParityNone, ParityEven, @@ -220,8 +221,7 @@ pub struct Tx { _usart: PhantomData, } -impl Serial -{ +impl Serial { /// Configures the serial interface and creates the interface /// struct. /// @@ -242,9 +242,10 @@ impl Serial pins: PINS, config: Config, afio: &mut Afio, - rcu: &mut Rcu + rcu: &mut Rcu, ) -> Self - where PINS: Pins + where + PINS: Pins, { // enable and reset USART USART::enable(rcu); @@ -288,9 +289,9 @@ impl Serial StopBits::STOP2 => 0b10, StopBits::STOP1P5 => 0b11, }; - usart.ctl1.modify(|_r, w| unsafe { - w.stb().bits(stop_bits) - }); + usart + .ctl1 + .modify(|_r, w| unsafe { w.stb().bits(stop_bits) }); // UE: enable USART // RE: enable receiver @@ -363,7 +364,7 @@ impl Rx { } } -impl crate::hal::serial::Read for Rx { +impl crate::hal_02::serial::Read for Rx { type Error = Error; fn read(&mut self) -> nb::Result { @@ -398,9 +399,7 @@ impl crate::hal::serial::Read for Rx { if sr.rbne().bit_is_set() { // Read the received byte // NOTE(read_volatile) see `write_volatile` below - Ok(unsafe { - ptr::read_volatile(&(*USART::ptr()).data as *const _ as *const _) - }) + Ok(unsafe { ptr::read_volatile(&(*USART::ptr()).data as *const _ as *const _) }) } else { Err(nb::Error::WouldBlock) } @@ -408,7 +407,7 @@ impl crate::hal::serial::Read for Rx { } } -impl crate::hal::serial::Write for Tx { +impl crate::hal_02::serial::Write for Tx { type Error = Infallible; fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { @@ -418,9 +417,7 @@ impl crate::hal::serial::Write for Tx { if sr.tbe().bit_is_set() { // NOTE(unsafe) atomic write to stateless register // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API - unsafe { - ptr::write_volatile(&(*USART::ptr()).data as *const _ as *mut _, byte) - } + unsafe { ptr::write_volatile(&(*USART::ptr()).data as *const _ as *mut _, byte) } Ok(()) } else { Err(nb::Error::WouldBlock) @@ -441,7 +438,7 @@ impl crate::hal::serial::Write for Tx { impl core::fmt::Write for Tx where - Tx: embedded_hal::serial::Write, + Tx: crate::hal_02::serial::Write, { fn write_str(&mut self, s: &str) -> core::fmt::Result { s.as_bytes() diff --git a/src/spi.rs b/src/spi.rs index dc1c68b..b85d7e5 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -2,14 +2,14 @@ use nb; -pub use crate::hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; -use crate::pac::{spi0, SPI0, SPI1}; +use crate::afio::{Afio, Remap}; use crate::gpio::gpioa::{PA5, PA6, PA7}; use crate::gpio::gpiob::{PB13, PB14, PB15, PB3, PB4, PB5}; use crate::gpio::{Alternate, Floating, Input, PushPull}; -use crate::rcu::{Rcu, Enable, Reset, BaseFrequency}; +pub use crate::hal_02::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +use crate::pac::{spi0, SPI0, SPI1}; +use crate::rcu::{BaseFrequency, Enable, Rcu, Reset}; use crate::time::Hertz; -use crate::afio::{Afio, Remap}; use core::ops::Deref; /// SPI error @@ -77,36 +77,27 @@ impl> Spi { afio: &mut Afio, mode: Mode, freq: impl Into, - rcu: &mut Rcu - ) -> Self - { + rcu: &mut Rcu, + ) -> Self { SPI0::remap(afio, PINS::REMAP); Spi::new(spi, pins, mode, freq, rcu) } } impl> Spi { - pub fn spi1( - spi: SPI1, - pins: PINS, - mode: Mode, - freq: impl Into, - rcu: &mut Rcu - ) -> Self - { + pub fn spi1(spi: SPI1, pins: PINS, mode: Mode, freq: impl Into, rcu: &mut Rcu) -> Self { Spi::new(spi, pins, mode, freq, rcu) } } -impl Spi where SPI: SpiX +impl Spi +where + SPI: SpiX, { - fn new( - spi: SPI, - pins: PINS, - mode: Mode, - freq: impl Into, - rcu: &mut Rcu - ) -> Self where SPI: Enable + Reset + BaseFrequency { + fn new(spi: SPI, pins: PINS, mode: Mode, freq: impl Into, rcu: &mut Rcu) -> Self + where + SPI: Enable + Reset + BaseFrequency, + { SPI::enable(rcu); SPI::reset(rcu); @@ -131,21 +122,36 @@ impl Spi where SPI: SpiX // lsbfirst: MSB first // ssm: enable software slave management (NSS pin free for other uses) // ssi: set nss high = master mode - spi.ctl0.write(|w| unsafe { w - .ckph().bit(mode.phase == Phase::CaptureOnSecondTransition) - .ckpl().bit(mode.polarity == Polarity::IdleHigh) - .mstmod().set_bit() // Master mode - .psc().bits(br) // Master clock prescaler selection - .lf().clear_bit() // Transmit MSB first - .swnss().set_bit() // NSS pin is pulled high - .swnssen().set_bit() // NSS software mode. The NSS level depends on SWNSS bit. - .ro().clear_bit() // Full-duplex mode - .ff16().clear_bit() // 8-bit data frame format - .bden().clear_bit() // 2-line unidirectional mode - .spien().set_bit() // Enable SPI peripheral + spi.ctl0.write(|w| unsafe { + w.ckph() + .bit(mode.phase == Phase::CaptureOnSecondTransition) + .ckpl() + .bit(mode.polarity == Polarity::IdleHigh) + .mstmod() + .set_bit() // Master mode + .psc() + .bits(br) // Master clock prescaler selection + .lf() + .clear_bit() // Transmit MSB first + .swnss() + .set_bit() // NSS pin is pulled high + .swnssen() + .set_bit() // NSS software mode. The NSS level depends on SWNSS bit. + .ro() + .clear_bit() // Full-duplex mode + .ff16() + .clear_bit() // 8-bit data frame format + .bden() + .clear_bit() // 2-line unidirectional mode + .spien() + .set_bit() // Enable SPI peripheral }); - Spi { spi, pins, base_freq } + Spi { + spi, + pins, + base_freq, + } } /// Change the frequency of operation of the SPI bus. @@ -166,13 +172,12 @@ impl Spi where SPI: SpiX }; // Disable SPI - self.spi.ctl0.modify(|_, w| { w.spien().clear_bit()}); + self.spi.ctl0.modify(|_, w| w.spien().clear_bit()); // Restore config, change frequency and re-enable SPI - self.spi.ctl0.modify( |_, w| unsafe { w - .psc().bits(br) - .spien().set_bit() - }); + self.spi + .ctl0 + .modify(|_, w| unsafe { w.psc().bits(br).spien().set_bit() }); } pub fn free(self) -> (SPI, PINS) { @@ -180,7 +185,7 @@ impl Spi where SPI: SpiX } } -impl crate::hal::spi::FullDuplex for Spi { +impl crate::hal_02::spi::FullDuplex for Spi { type Error = Error; fn read(&mut self) -> nb::Result { @@ -216,9 +221,8 @@ impl crate::hal::spi::FullDuplex for Spi { nb::Error::WouldBlock }) } - } -impl crate::hal::blocking::spi::transfer::Default for Spi {} +impl crate::hal_02::blocking::spi::transfer::Default for Spi {} -impl crate::hal::blocking::spi::write::Default for Spi {} +impl crate::hal_02::blocking::spi::write::Default for Spi {} diff --git a/src/timer.rs b/src/timer.rs index 70d78b2..c7a0f38 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -3,7 +3,7 @@ use crate::rcu::{BaseFrequency, Enable, Rcu, Reset}; use crate::time::Hertz; -use embedded_hal::timer::{CountDown, Periodic}; +use crate::hal_02::timer::{CountDown, Periodic}; use gd32vf103_pac::{TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5, TIMER6}; use void::Void; diff --git a/src/watchdog.rs b/src/watchdog.rs index 79bfd8f..66482ed 100644 --- a/src/watchdog.rs +++ b/src/watchdog.rs @@ -1,7 +1,7 @@ //! Watchdog peripherals use crate::{ - hal::watchdog::{Watchdog, WatchdogEnable}, + hal_02::watchdog::{Watchdog, WatchdogEnable}, pac::{DBG, FWDGT}, time::MilliSeconds, }; From 5cb638cc3f350e2eb2483281fc688a7a8debfe94 Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 12 Mar 2024 09:13:55 +0100 Subject: [PATCH 2/7] Fix assigning to `&T` is undefined behavior --- src/serial.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/serial.rs b/src/serial.rs index c433e2c..ef8164f 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -31,6 +31,7 @@ //! let received = block!(rx.read()).unwrap(); //! ``` +use core::cell::UnsafeCell; use core::marker::PhantomData; use core::ptr; @@ -417,7 +418,10 @@ impl crate::hal_02::serial::Write for Tx { if sr.tbe().bit_is_set() { // NOTE(unsafe) atomic write to stateless register // NOTE(write_volatile) 8-bit write that's not possible through the svd2rust API - unsafe { ptr::write_volatile(&(*USART::ptr()).data as *const _ as *mut _, byte) } + unsafe { + let data = &(*USART::ptr()).data as *const _ as *const UnsafeCell; + ptr::write_volatile(UnsafeCell::raw_get(data), byte) + } Ok(()) } else { Err(nb::Error::WouldBlock) From 662beff105373bff4ef1627656172760781263e3 Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 12 Mar 2024 09:28:55 +0100 Subject: [PATCH 3/7] Implement embedded-hal 1.0.0 for gpio --- src/gpio.rs | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) diff --git a/src/gpio.rs b/src/gpio.rs index 31e3537..0ae2da8 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -295,6 +295,57 @@ macro_rules! gpio { pub type $PXx = Pxx; + // Start embedded-hal 1.0.0 implementations + impl crate::hal::digital::ErrorType for Generic> { + type Error = Infallible; + } + + impl crate::hal::digital::ErrorType for Generic> { + type Error = Infallible; + } + + impl crate::hal::digital::OutputPin for Generic> { + fn set_high(&mut self) -> Result<(), Self::Error> { + $GPIOX::set_bit(self.i); + Ok(()) + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + $GPIOX::clear_bit(self.i); + Ok(()) + } + } + + impl crate::hal::digital::InputPin for Generic> { + fn is_high(&mut self) -> Result { + Ok($GPIOX::is_high(self.i)) + } + + fn is_low(&mut self) -> Result { + Ok(!$GPIOX::is_high(self.i)) + } + } + + impl crate::hal::digital::StatefulOutputPin for Generic> { + fn is_set_high(&mut self) -> Result { + Ok($GPIOX::is_set_high(self.i)) + } + + fn is_set_low(&mut self) -> Result { + Ok(!$GPIOX::is_set_high(self.i)) + } + } + + impl crate::hal::digital::InputPin for Generic> { + fn is_high(&mut self) -> Result { + Ok($GPIOX::is_high(self.i)) + } + + fn is_low(&mut self) -> Result { + Ok(!$GPIOX::is_high(self.i)) + } + } + // Stop embedded-hal 1.0.0 implementations $( @@ -497,6 +548,58 @@ macro_rules! gpio { Ok(!$GPIOX::is_high($i)) } } + + // Start embedded-hal 1.0.0 implementations + impl crate::hal::digital::ErrorType for $PXi> { + type Error = Infallible; + } + + impl crate::hal::digital::ErrorType for $PXi> { + type Error = Infallible; + } + + impl crate::hal::digital::OutputPin for $PXi> { + fn set_high(&mut self) -> Result<(), Self::Error> { + $GPIOX::set_bit($i); + Ok(()) + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + $GPIOX::clear_bit($i); + Ok(()) + } + } + + impl crate::hal::digital::StatefulOutputPin for $PXi> { + fn is_set_high(&mut self) -> Result { + Ok($GPIOX::is_set_high($i)) + } + + fn is_set_low(&mut self) -> Result { + Ok(!$GPIOX::is_set_high($i)) + } + } + + impl crate::hal::digital::InputPin for $PXi> { + fn is_high(&mut self) -> Result { + Ok($GPIOX::is_high($i)) + } + + fn is_low(&mut self) -> Result { + Ok(!$GPIOX::is_high($i)) + } + } + + impl crate::hal::digital::InputPin for $PXi> { + fn is_high(&mut self) -> Result { + Ok($GPIOX::is_high($i)) + } + + fn is_low(&mut self) -> Result { + Ok(!$GPIOX::is_high($i)) + } + } + // Stop embedded-hal 1.0.0 implementations )+ } } @@ -564,6 +667,58 @@ macro_rules! impl_pxx { } } } + + // Start embedded-hal 1.0.0 implementations + impl crate::hal::digital::ErrorType for Pxx> { + type Error = Infallible; + } + + impl crate::hal::digital::ErrorType for Pxx> { + type Error = Infallible; + } + + impl crate::hal::digital::OutputPin for Pxx> { + fn set_high(&mut self) -> Result<(), Self::Error> { + match self { + $(Pxx::$pin(pin) => crate::hal::digital::OutputPin::set_high(pin)),* + } + } + + fn set_low(&mut self) -> Result<(), Self::Error> { + match self { + $(Pxx::$pin(pin) => crate::hal::digital::OutputPin::set_low(pin)),* + } + } + } + + impl crate::hal::digital::StatefulOutputPin for Pxx> { + fn is_set_high(&mut self) -> Result { + match self { + $(Pxx::$pin(pin) => pin.is_set_high()),* + } + } + + fn is_set_low(&mut self) -> Result { + match self { + $(Pxx::$pin(pin) => pin.is_set_low()),* + } + } + } + + impl crate::hal::digital::InputPin for Pxx> { + fn is_high(&mut self) -> Result { + match self { + $(Pxx::$pin(pin) => pin.is_high()),* + } + } + + fn is_low(&mut self) -> Result { + match self { + $(Pxx::$pin(pin) => pin.is_low()),* + } + } + } + // Stop embedded-hal 1.0.0 implementations } } From 9c085e6ec6709ea906d597aa3ec1af2ea8d5e24d Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 12 Mar 2024 10:08:32 +0100 Subject: [PATCH 4/7] Implement embedded-hal 1.0.0 for delay --- src/delay.rs | 54 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/src/delay.rs b/src/delay.rs index 217c9d7..bca7082 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -3,10 +3,10 @@ use crate::time::U32Ext; use crate::timer::Timer; +use crate::hal::delay::DelayNs; use crate::hal_02::blocking::delay::{DelayMs, DelayUs}; use crate::hal_02::timer::CountDown; use crate::rcu::Clocks; -use cast::u32; use gd32vf103_pac::{TIMER0, TIMER1, TIMER2, TIMER3, TIMER4, TIMER5, TIMER6}; /// Machine mode cycle counter (`mcycle`) as a delay provider @@ -24,18 +24,24 @@ impl McycleDelay { } } -impl DelayUs for McycleDelay { - fn delay_us(&mut self, us: u64) { +impl DelayNs for McycleDelay { + fn delay_ns(&mut self, ns: u32) { let t0 = riscv::register::mcycle::read64(); - let clocks = (us * (self.core_frequency as u64)) / 1_000_000; + let clocks = (ns as u64 * (self.core_frequency as u64)) / 1_000_000_000; while riscv::register::mcycle::read64().wrapping_sub(t0) <= clocks {} } } +impl DelayUs for McycleDelay { + fn delay_us(&mut self, us: u64) { + self.delay_ns((us * 1_000) as u32); + } +} + impl DelayUs for McycleDelay { #[inline(always)] fn delay_us(&mut self, us: u32) { - self.delay_us(us as u64) + DelayNs::delay_us(self, us); } } @@ -44,27 +50,27 @@ impl DelayUs for McycleDelay { #[inline(always)] fn delay_us(&mut self, us: i32) { assert!(us >= 0); - self.delay_us(us as u32); + DelayNs::delay_us(self, us as u32); } } impl DelayUs for McycleDelay { #[inline(always)] fn delay_us(&mut self, us: u16) { - self.delay_us(us as u32) + DelayNs::delay_us(self, us as u32); } } impl DelayUs for McycleDelay { #[inline(always)] fn delay_us(&mut self, us: u8) { - self.delay_us(us as u32) + DelayNs::delay_us(self, us as u32); } } impl DelayMs for McycleDelay { fn delay_ms(&mut self, ms: u32) { - self.delay_us((ms as u64) * 1000) + DelayNs::delay_us(self, ms * 1000); } } @@ -73,21 +79,21 @@ impl DelayMs for McycleDelay { #[inline(always)] fn delay_ms(&mut self, ms: i32) { assert!(ms >= 0); - self.delay_ms(ms as u32); + DelayNs::delay_ms(self, ms as u32); } } impl DelayMs for McycleDelay { #[inline(always)] fn delay_ms(&mut self, ms: u16) { - self.delay_ms(ms as u32) + DelayNs::delay_ms(self, ms as u32); } } impl DelayMs for McycleDelay { #[inline(always)] fn delay_ms(&mut self, ms: u8) { - self.delay_ms(ms as u32) + DelayNs::delay_ms(self, ms as u32); } } @@ -115,42 +121,48 @@ macro_rules! delay { } } + impl DelayNs for Delay<$TIMER> { + fn delay_ns(&mut self, ns: u32) { + let freq = 1_000_000_000 / ns; + self.timer.start(freq.hz()); + while let Err(_) = self.timer.wait() { } + self.timer.tim.ctl0.modify(|_, w| w.cen().clear_bit()); + } + } + impl DelayMs for Delay<$TIMER> { fn delay_ms(&mut self, ms: u32) { - self.delay_us(ms * 1_000); + DelayNs::delay_ms(self, ms * 1_000); } } impl DelayMs for Delay<$TIMER> { fn delay_ms(&mut self, ms: u16) { - self.delay_ms(u32(ms)); + DelayNs::delay_ms(self, ms as u32); } } impl DelayMs for Delay<$TIMER> { fn delay_ms(&mut self, ms: u8) { - self.delay_ms(u32(ms)); + DelayNs::delay_ms(self, ms as u32); } } impl DelayUs for Delay<$TIMER> { fn delay_us(&mut self, us: u32) { - let freq = 1_000_000 / us; - self.timer.start(freq.hz()); - while let Err(_) = self.timer.wait() { } - self.timer.tim.ctl0.modify(|_, w| w.cen().clear_bit()); + DelayNs::delay_us(self, us); } } impl DelayUs for Delay<$TIMER> { fn delay_us(&mut self, us: u16) { - self.delay_us(u32(us)) + DelayNs::delay_us(self, us as u32); } } impl DelayUs for Delay<$TIMER> { fn delay_us(&mut self, us: u8) { - self.delay_us(u32(us)) + DelayNs::delay_us(self, us as u32); } } )+ From bd563447a5e8f546b79ef4b6ae8397844fb84106 Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 12 Mar 2024 10:48:52 +0100 Subject: [PATCH 5/7] Implement embedded-hal 1.0.0 for pwm --- src/pwm.rs | 55 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 15 deletions(-) diff --git a/src/pwm.rs b/src/pwm.rs index 119f88a..580e126 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -309,30 +309,55 @@ macro_rules! pwm_timer { self.timer.chctl0_output().modify(|_r, w| unsafe { w // Enable PWM Mode 0 for channel 0 and 1 - .ch0comctl().bits(0b110) - .ch1comctl().bits(0b110) - + .ch0comctl() + .bits(0b110) + .ch1comctl() + .bits(0b110) // Output mode for channel 0 and 1 - .ch0ms().bits(0b00) - .ch1ms().bits(0b00) + .ch0ms() + .bits(0b00) + .ch1ms() + .bits(0b00) }); self.timer.chctl1_output().modify(|_r, w| unsafe { w // Enable PWM Mode 0 for channel 2 and 3 - .ch2comctl().bits(0b110) - .ch3comctl().bits(0b110) - + .ch2comctl() + .bits(0b110) + .ch3comctl() + .bits(0b110) // Output mode for channel 2 and 3 - .ch2ms().bits(0b00) - .ch3ms().bits(0b00) + .ch2ms() + .bits(0b00) + .ch3ms() + .bits(0b00) }); // Enable the timer - self.timer.ctl0.write(|w| { - w - .updis().clear_bit() - .cen().set_bit() - }); + self.timer + .ctl0 + .write(|w| w.updis().clear_bit().cen().set_bit()); + } + } + + impl crate::hal::pwm::ErrorType for PwmTimer<$TIM, REMAP> { + type Error = core::convert::Infallible; + } + + impl crate::hal::pwm::SetDutyCycle for PwmTimer<$TIM, REMAP> { + fn max_duty_cycle(&self) -> u16 { + self.max_duty_cycle + } + + // NOTE: The structure of the PwnTimer struct does not lend itself well + // to the embedded-hal 1.0.0 trait. Users of this trait will, for now, be + // limmited to using only Channel::CH0, until we put the channel into the + // type defiinition. + fn set_duty_cycle( + &mut self, + duty: u16, + ) -> Result<(), ::Error> { + Ok(self.set_duty(Channel::CH0, duty)) } } }; From df20008026c6e14f2f69eb4390729e3be4b72670 Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 12 Mar 2024 11:34:11 +0100 Subject: [PATCH 6/7] Implement embedded-hal 1.0.0 for spi --- src/spi.rs | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/spi.rs b/src/spi.rs index b85d7e5..01f063f 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -25,6 +25,17 @@ pub enum Error { _Extensible, } +impl crate::hal::spi::Error for Error { + fn kind(&self) -> crate::hal::spi::ErrorKind { + match self { + Error::Overrun => crate::hal::spi::ErrorKind::Overrun, + Error::ModeFault => crate::hal::spi::ErrorKind::ModeFault, + Error::Crc => crate::hal::spi::ErrorKind::Other, + Error::_Extensible => crate::hal::spi::ErrorKind::Other, + } + } +} + #[doc(hidden)] pub trait SpiX: Deref {} impl SpiX for SPI0 {} @@ -226,3 +237,53 @@ impl crate::hal_02::spi::FullDuplex for Spi { impl crate::hal_02::blocking::spi::transfer::Default for Spi {} impl crate::hal_02::blocking::spi::write::Default for Spi {} + +impl crate::hal::spi::ErrorType for Spi { + type Error = Error; +} + +// NOTE: All embedded-hal 1.0.0 functions are blocking. +// Maybe add a small FIFO buffer to the Spi struct? +impl crate::hal::spi::SpiBus for Spi { + fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + for word in words { + nb::block!(crate::hal_02::spi::FullDuplex::send(self, u8::default()))?; + *word = nb::block!(crate::hal_02::spi::FullDuplex::read(self))?; + } + + Ok(()) + } + + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + for word in words { + nb::block!(crate::hal_02::spi::FullDuplex::send(self, *word))?; + nb::block!(crate::hal_02::spi::FullDuplex::read(self))?; + } + + Ok(()) + } + + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { + assert_eq!(write.len(), read.len()); + + for (d, b) in write.iter().cloned().zip(read.iter_mut()) { + nb::block!(crate::hal_02::spi::FullDuplex::send(self, d))?; + *b = nb::block!(crate::hal_02::spi::FullDuplex::read(self))?; + } + + Ok(()) + } + + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + for word in words { + nb::block!(crate::hal_02::spi::FullDuplex::send(self, *word))?; + *word = nb::block!(crate::hal_02::spi::FullDuplex::read(self))?; + } + + Ok(()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + Ok(()) + } +} From 904472012e5a24f06fb342a727267b0d58092b20 Mon Sep 17 00:00:00 2001 From: Thom de Jong Date: Tue, 12 Mar 2024 13:14:13 +0100 Subject: [PATCH 7/7] Implement embedded-hal 1.0.0 for i2c --- src/i2c.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/i2c.rs b/src/i2c.rs index 8cb3f35..7694269 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -29,6 +29,20 @@ pub enum Error { _Extensible, } +impl crate::hal::i2c::Error for Error { + fn kind(&self) -> crate::hal::i2c::ErrorKind { + match self { + Error::Bus => crate::hal::i2c::ErrorKind::Bus, + Error::Arbitration => crate::hal::i2c::ErrorKind::ArbitrationLoss, + Error::Acknowledge => crate::hal::i2c::ErrorKind::NoAcknowledge( + embedded_hal::i2c::NoAcknowledgeSource::Unknown, + ), + Error::Overrun => crate::hal::i2c::ErrorKind::Overrun, + Error::_Extensible => crate::hal::i2c::ErrorKind::Other, + } + } +} + #[derive(Eq, PartialEq)] pub enum DutyCycle { Ratio2to1, @@ -546,6 +560,33 @@ macro_rules! hal { Ok(()) } } + + impl crate::hal::i2c::ErrorType for BlockingI2c<$I2CX, PINS> { + type Error = Error; + } + + impl crate::hal::i2c::I2c for BlockingI2c<$I2CX, PINS> { + fn transaction(&mut self, address: u8, operations: &mut [crate::hal::i2c::Operation<'_>]) -> Result<(), Self::Error> { + use crate::hal::i2c::Operation; + + // TODO: Optimize, every byte is now send in its own transaction. + // This should pack Reads and Writes into a single transaction. + if let Some(mut prev_op) = operations.iter_mut().next() { + let _ = match &mut prev_op { + Operation::Read(buffer) => crate::hal_02::blocking::i2c::Read::read(self, address, *buffer), + Operation::Write(buffer) => crate::hal_02::blocking::i2c::Write::write(self, address, buffer), + }; + } + Ok(()) + } + } + + // NOTE: No support for the TenBitAddress + // impl crate::hal::i2c::I2c for BlockingI2c<$I2CX, PINS> { + // fn transaction(&mut self, address: u16, operations: &mut [crate::hal::i2c::Operation<'_>]) -> Result<(), Self::Error> { + // // ... + // } + // } )+ } }