diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 000000000000..54874e2ffc42 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,4 @@ +[workspace] +resolver = "2" +members = ["hal", "atsamd-hal-macros"] +exclude = ["pac", "boards"] \ No newline at end of file diff --git a/README.md b/README.md index db0ed7c57f9e..ab7e1ea289af 100644 --- a/README.md +++ b/README.md @@ -12,14 +12,14 @@ The Hardware Abstraction Layer (HAL - [![Crates.io](https://img.shields.io/crate | Chip family | Documented features | |:------------|:----------------------| -| [samd11c] | samd11c unproven | -| [samd11d] | samd11d unproven | -| [samd21g] | samd21g unproven usb | -| [samd21j] | samd21j unproven usb | -| [samd51g] | samd51g unproven usb | -| [samd51j] | samd51j unproven usb | -| [samd51n] | samd51n unproven usb | -| [samd51p] | samd51p unproven usb | +| [samd11c] | samd11c | +| [samd11d] | samd11d | +| [samd21g] | samd21g usb | +| [samd21j] | samd21j usb | +| [samd51g] | samd51g usb | +| [samd51j] | samd51j usb | +| [samd51n] | samd51n usb | +| [samd51p] | samd51p usb | [samd11c]: https://atsamd-rs.github.io/docs/samd11c/thumbv6m-none-eabi/doc/atsamd_hal/index.html [samd11d]: https://atsamd-rs.github.io/docs/samd11d/thumbv6m-none-eabi/doc/atsamd_hal/index.html diff --git a/boards/atsame54_xpro/CHANGELOG.md b/boards/atsame54_xpro/CHANGELOG.md index 8eda981f90cd..c9fb5dc7e074 100644 --- a/boards/atsame54_xpro/CHANGELOG.md +++ b/boards/atsame54_xpro/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.6.0 diff --git a/boards/atsame54_xpro/Cargo.toml b/boards/atsame54_xpro/Cargo.toml index fc721f0fdf3f..ad427bcce310 100644 --- a/boards/atsame54_xpro/Cargo.toml +++ b/boards/atsame54_xpro/Cargo.toml @@ -38,9 +38,8 @@ panic-rtt-target = { version = "0.1", features = ["cortex-m"] } rtt-target = { version = "0.3", features = ["cortex-m"] } [features] -default = ["rt", "atsamd-hal/same54p", "atsamd-hal/unproven"] +default = ["rt", "atsamd-hal/same54p"] rt = ["cortex-m-rt", "atsamd-hal/same54p-rt"] -unproven = ["atsamd-hal/unproven"] usb = ["atsamd-hal/usb", "usb-device"] can = ["atsamd-hal/can"] diff --git a/boards/atsame54_xpro/examples/blinky_rtic.rs b/boards/atsame54_xpro/examples/blinky_rtic.rs index 60e6e0d2eccf..2a8d6563f081 100644 --- a/boards/atsame54_xpro/examples/blinky_rtic.rs +++ b/boards/atsame54_xpro/examples/blinky_rtic.rs @@ -5,10 +5,9 @@ use atsame54_xpro as bsp; use bsp::hal; use bsp::hal::clock::v2 as clock; use dwt_systick_monotonic::DwtSystick; -use dwt_systick_monotonic::ExtU32 as _; +use dwt_systick_monotonic::{fugit::RateExtU32, ExtU32}; // TODO: Any reason this cannot be in a HAL's prelude? -use hal::ehal::digital::v2::StatefulOutputPin as _; -use hal::prelude::*; +use hal::ehal::digital::StatefulOutputPin; use panic_rtt_target as _; use rtt_target::{rprintln, rtt_init_print}; @@ -45,7 +44,7 @@ mod app { bsp::pin_alias!(pins.xosc1_x_in), bsp::pin_alias!(pins.xosc1_x_out), // Xosc1 on Same54Xpro is 12 MHz - 12.MHz(), + 12_u32.MHz(), ) .enable(); diff --git a/boards/feather_m0/CHANGELOG.md b/boards/feather_m0/CHANGELOG.md index c0551c59500b..1b8a61f6aae2 100644 --- a/boards/feather_m0/CHANGELOG.md +++ b/boards/feather_m0/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.13.0 diff --git a/boards/feather_m0/Cargo.toml b/boards/feather_m0/Cargo.toml index 1f802aca4129..e1408fb85623 100644 --- a/boards/feather_m0/Cargo.toml +++ b/boards/feather_m0/Cargo.toml @@ -53,7 +53,6 @@ panic-semihosting = "0.5" # ask the HAL to enable atsamd21g support default = ["rt", "atsamd-hal/samd21g"] rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"] -unproven = ["atsamd-hal/unproven"] use_rtt = ["atsamd-hal/use_rtt"] usb = ["atsamd-hal/usb", "usb-device"] # Enable pins for the radio on "RadioFruits" with RFM95, RFM96, RFM69 @@ -87,11 +86,9 @@ name = "timers" [[example]] name = "pwm" -required-features = ["unproven"] [[example]] name = "adc" -required-features = ["unproven"] [[example]] name = "ssd1306_graphicsmode_128x64_i2c" @@ -113,7 +110,7 @@ name = "ssd1306_terminalmode_128x64_spi" [[example]] name = "usb_echo" -required-features = ["usb", "unproven"] +required-features = ["usb"] [[example]] name = "sleeping_timer" @@ -127,15 +124,15 @@ required-features = ["dma"] [[example]] name = "clock" -required-features = ["usb", "unproven"] +required-features = ["usb"] [[example]] name = "adalogger" -required-features = ["adalogger", "usb", "sdmmc", "unproven"] +required-features = ["adalogger", "usb", "sdmmc"] [[example]] name = "blinky_rtic" -required-features = ["rtic", "unproven"] +required-features = ["rtic"] [[example]] name = "uart" diff --git a/boards/feather_m0/examples/i2c.rs b/boards/feather_m0/examples/i2c.rs index 33abce390bdd..8c3f421f4356 100644 --- a/boards/feather_m0/examples/i2c.rs +++ b/boards/feather_m0/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; @@ -57,7 +57,7 @@ fn main() -> ! { let sercom3_clock = &clocks.sercom3_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let mut i2c = i2c::Config::new(&pm, peripherals.SERCOM3, pads, sercom3_clock.freq()) - .baud(100.khz()) + .baud(100.kHz()) .enable(); let mut buffer = [0x00; 1]; diff --git a/boards/feather_m0/examples/pwm.rs b/boards/feather_m0/examples/pwm.rs index 11d9ce2a9aec..3dc284a79f9f 100644 --- a/boards/feather_m0/examples/pwm.rs +++ b/boards/feather_m0/examples/pwm.rs @@ -15,7 +15,8 @@ use feather_m0 as bsp; use bsp::pin_alias; use hal::clock::GenericClockController; use hal::delay::Delay; -use hal::prelude::*; +use hal::ehal::{delay::DelayNs, pwm::SetDutyCycle}; +use hal::fugit::RateExtU32; use hal::pwm::Pwm3; use pac::{CorePeripherals, Peripherals}; @@ -38,16 +39,18 @@ fn main() -> ! { let gclk0 = clocks.gclk0(); let mut pwm3 = Pwm3::new( &clocks.tcc2_tc3(&gclk0).unwrap(), - 1.khz(), + 1.kHz(), peripherals.TC3, &mut peripherals.PM, ); - let max_duty = pwm3.get_max_duty(); + let max_duty = pwm3.max_duty_cycle(); loop { - pwm3.set_duty(max_duty / 2); - delay.delay_ms(1000u16); - pwm3.set_duty(max_duty / 8); - delay.delay_ms(1000u16); + // The embedded-hal spec requires that set_duty_cycle returns a Result. + // In our case, the function is infaillible so we can safely ignore the result. + let _ = pwm3.set_duty_cycle(max_duty / 2); + delay.delay_ms(1000); + let _ = pwm3.set_duty_cycle(max_duty / 8); + delay.delay_ms(1000); } } diff --git a/boards/feather_m0/examples/timers.rs b/boards/feather_m0/examples/timers.rs index 9e7907e6aa5e..5618649e3fbf 100644 --- a/boards/feather_m0/examples/timers.rs +++ b/boards/feather_m0/examples/timers.rs @@ -12,9 +12,11 @@ use feather_m0 as bsp; use bsp::{entry, pin_alias}; use hal::clock::GenericClockController; -use hal::prelude::*; +use hal::ehal::digital::OutputPin; +use hal::nb; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use pac::Peripherals; #[entry] diff --git a/boards/feather_m0/examples/uart.rs b/boards/feather_m0/examples/uart.rs index a51495e0fcf3..68c25c3a66b8 100644 --- a/boards/feather_m0/examples/uart.rs +++ b/boards/feather_m0/examples/uart.rs @@ -16,7 +16,7 @@ use feather_m0 as bsp; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::prelude::*; +use hal::fugit::RateExtU32; use pac::Peripherals; @@ -49,7 +49,7 @@ fn main() -> ! { // Setup UART peripheral let uart = bsp::uart( &mut clocks, - 9600.hz(), + 9600.Hz(), uart_sercom, &mut pm, uart_rx, diff --git a/boards/feather_m4/CHANGELOG.md b/boards/feather_m4/CHANGELOG.md index 5e2d7184e94a..e9282103a41c 100644 --- a/boards/feather_m4/CHANGELOG.md +++ b/boards/feather_m4/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.11.0 diff --git a/boards/feather_m4/Cargo.toml b/boards/feather_m4/Cargo.toml index b8f7fbede7f8..03ea190917f2 100644 --- a/boards/feather_m4/Cargo.toml +++ b/boards/feather_m4/Cargo.toml @@ -45,9 +45,8 @@ heapless = "0.7" # ask the HAL to enable atsamd51j support default = ["rt", "atsamd-hal/samd51j"] rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"] -unproven = ["atsamd-hal/unproven"] usb = ["atsamd-hal/usb", "usb-device"] -dma = ["atsamd-hal/dma", "unproven"] +dma = ["atsamd-hal/dma"] max-channels = ["dma", "atsamd-hal/dma"] @@ -64,7 +63,6 @@ opt-level = "s" [[example]] name = "pwm" -required-features = ["unproven"] [[example]] name = "usb_echo" @@ -80,15 +78,15 @@ required-features = ["dma"] [[example]] name = "pukcc_test" -required-features = ["unproven", "usb"] +required-features = ["usb"] [[example]] name = "nvm_dsu" -required-features = ["unproven", "usb"] +required-features = ["usb"] [[example]] name = "smart_eeprom" -required-features = ["unproven", "usb"] +required-features = [ "usb"] [[example]] name = "i2c" diff --git a/boards/feather_m4/examples/clocking_v2.rs b/boards/feather_m4/examples/clocking_v2.rs index a7bbbff2d57a..92714758d04e 100644 --- a/boards/feather_m4/examples/clocking_v2.rs +++ b/boards/feather_m4/examples/clocking_v2.rs @@ -3,8 +3,6 @@ use panic_halt as _; -use core::fmt::Write as _; - use atsamd_hal::{ clock::v2::{ self as clock, @@ -15,10 +13,9 @@ use atsamd_hal::{ rtcosc::RtcOsc, xosc32k::{ControlGainMode, Xosc1k, Xosc32k, Xosc32kBase}, }, - ehal::serial::Read as _, - ehal::serial::Write, + embedded_io::{Read, Write}, + fugit::RateExtU32, gpio::{Pins, PA04, PA05}, - prelude::*, rtc::{ClockMode, Rtc}, sercom::{ uart::{self, BaudMode, Flags, Oversampling}, @@ -142,7 +139,7 @@ mod app { // In the future, the `Rtc` will take ownership of the `RtcOsc` let rtc = Rtc::clock_mode(device.RTC, rtc_osc.freq(), &mut mclk); - writeln!(&mut uart as &mut dyn Write<_, Error = _>, "RTIC booted!").unwrap(); + writeln!(&mut uart as &mut dyn Write, "RTIC booted!").unwrap(); ( SharedResources { uart, rtc }, @@ -156,12 +153,13 @@ mod app { let mut uart = cx.shared.uart; let mut rtc = cx.shared.rtc; // Read from `Uart` to clean interrupt flag - let _ = uart.lock(|u| u.read().unwrap()); + let mut buf = [0]; + let _ = uart.lock(|u| u.read(&mut buf).unwrap()); // Print out `DateTime` coming from `Rtc` uart.lock(|u| { writeln!( - u as &mut dyn Write<_, Error = _>, + u as &mut dyn Write, "{:#?}", rtc.lock(|r| r.current_time()) ) diff --git a/boards/feather_m4/examples/i2c.rs b/boards/feather_m4/examples/i2c.rs index 2925ee62f822..6305b62460b1 100644 --- a/boards/feather_m4/examples/i2c.rs +++ b/boards/feather_m4/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; diff --git a/boards/feather_m4/examples/neopixel_rainbow.rs b/boards/feather_m4/examples/neopixel_rainbow.rs index 5bd27f58d621..2dbfe83187ac 100644 --- a/boards/feather_m4/examples/neopixel_rainbow.rs +++ b/boards/feather_m4/examples/neopixel_rainbow.rs @@ -19,10 +19,11 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; use hal::time::Hertz; use hal::timer::*; +use hal::timer_traits::InterruptDrivenTimer; use smart_leds::{ hsv::{hsv2rgb, Hsv}, @@ -62,7 +63,7 @@ fn main() -> ! { val: 2, })]; neopixel.write(colors.iter().cloned()).unwrap(); - delay.delay_ms(5u8); + delay.delay_ms(5); } } } diff --git a/boards/feather_m4/examples/nvm_dsu.rs b/boards/feather_m4/examples/nvm_dsu.rs index 4f69d0342b02..761914b5288c 100644 --- a/boards/feather_m4/examples/nvm_dsu.rs +++ b/boards/feather_m4/examples/nvm_dsu.rs @@ -12,7 +12,7 @@ use panic_halt as _; use panic_semihosting as _; use bsp::entry; -use ehal::digital::v2::ToggleableOutputPin; +use ehal::digital::StatefulOutputPin; use hal::clock::GenericClockController; use hal::dsu::Dsu; use hal::nvm::{retrieve_bank_size, Bank, Nvm, WriteGranularity, BLOCKSIZE}; diff --git a/boards/feather_m4/examples/pukcc_test.rs b/boards/feather_m4/examples/pukcc_test.rs index ae2389b1e8bf..e1adb33c2d2e 100644 --- a/boards/feather_m4/examples/pukcc_test.rs +++ b/boards/feather_m4/examples/pukcc_test.rs @@ -12,7 +12,7 @@ use panic_halt as _; use panic_semihosting as _; use bsp::entry; -use ehal::digital::v2::ToggleableOutputPin; +use ehal::digital::StatefulOutputPin; use hal::clock::GenericClockController; use hal::pac::{interrupt, CorePeripherals, Peripherals}; use hal::{pukcc::*, usb::UsbBus}; diff --git a/boards/feather_m4/examples/pwm.rs b/boards/feather_m4/examples/pwm.rs index 5bc77252596e..2b887e4466c9 100644 --- a/boards/feather_m4/examples/pwm.rs +++ b/boards/feather_m4/examples/pwm.rs @@ -2,8 +2,6 @@ #![no_main] // Pulse Width Modulation -// -// cargo build --features="unproven" use bsp::hal; use feather_m4 as bsp; diff --git a/boards/feather_m4/examples/serial.rs b/boards/feather_m4/examples/serial.rs index 6f84c465c8e5..6351ffead447 100644 --- a/boards/feather_m4/examples/serial.rs +++ b/boards/feather_m4/examples/serial.rs @@ -12,10 +12,13 @@ use panic_semihosting as _; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; +use hal::ehal_nb::serial::Write; +use hal::fugit::RateExtU32; +use hal::nb; use hal::pac::gclk::genctrl::SRCSELECT_A; use hal::pac::gclk::pchctrl::GENSELECT_A; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; #[entry] fn main() -> ! { @@ -49,6 +52,6 @@ fn main() -> ! { for byte in b"Hello, world!" { nb::block!(uart.write(*byte)).unwrap(); } - delay.delay_ms(1000u16); + delay.delay_ms(1000); } } diff --git a/boards/feather_m4/examples/smart_eeprom.rs b/boards/feather_m4/examples/smart_eeprom.rs index 9474b72d9ae3..59a80b284b60 100644 --- a/boards/feather_m4/examples/smart_eeprom.rs +++ b/boards/feather_m4/examples/smart_eeprom.rs @@ -12,7 +12,7 @@ use panic_halt as _; use panic_semihosting as _; use bsp::entry; -use ehal::digital::v2::ToggleableOutputPin; +use ehal::digital::StatefulOutputPin; use hal::clock::GenericClockController; use hal::nvm::{smart_eeprom, Nvm}; use hal::pac::{interrupt, CorePeripherals, Peripherals}; diff --git a/boards/feather_m4/examples/timers.rs b/boards/feather_m4/examples/timers.rs index 84e0851af524..abdceed60dbf 100644 --- a/boards/feather_m4/examples/timers.rs +++ b/boards/feather_m4/examples/timers.rs @@ -13,9 +13,11 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; +use hal::ehal::digital::OutputPin; +use hal::nb; use hal::pac::Peripherals; -use hal::prelude::*; use hal::time::Hertz; +use hal::timer_traits::InterruptDrivenTimer; use hal::timer::TimerCounter; diff --git a/boards/feather_m4/examples/uart.rs b/boards/feather_m4/examples/uart.rs index eed5be270ea8..be57264a23cc 100644 --- a/boards/feather_m4/examples/uart.rs +++ b/boards/feather_m4/examples/uart.rs @@ -13,7 +13,9 @@ use feather_m4 as bsp; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::prelude::*; +use hal::ehal_nb::serial::{Read, Write}; +use hal::fugit::RateExtU32; +use hal::nb; use pac::Peripherals; diff --git a/boards/feather_m4/examples/uart_poll_echo.rs b/boards/feather_m4/examples/uart_poll_echo.rs index 5d923087573c..5b4414ed5832 100644 --- a/boards/feather_m4/examples/uart_poll_echo.rs +++ b/boards/feather_m4/examples/uart_poll_echo.rs @@ -19,10 +19,14 @@ use panic_semihosting as _; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; +use hal::ehal::digital::OutputPin; +use hal::ehal_nb::serial::{Read, Write}; +use hal::fugit::RateExtU32; +use hal::nb; use hal::pac::gclk::genctrl::SRCSELECT_A; use hal::pac::gclk::pchctrl::GENSELECT_A; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; #[entry] fn main() -> ! { @@ -67,10 +71,10 @@ fn main() -> ! { // Blink the red led to show that a character has arrived red_led.set_high().unwrap(); - delay.delay_ms(2u16); + delay.delay_ms(2); red_led.set_low().unwrap(); } - Err(_) => delay.delay_ms(5u16), + Err(_) => delay.delay_ms(5), }; } } diff --git a/boards/metro_m0/CHANGELOG.md b/boards/metro_m0/CHANGELOG.md index 79cabefc76d1..42791da46be0 100644 --- a/boards/metro_m0/CHANGELOG.md +++ b/boards/metro_m0/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.13.0 diff --git a/boards/metro_m0/Cargo.toml b/boards/metro_m0/Cargo.toml index e14644a312c1..bbcaa5a9e0d2 100644 --- a/boards/metro_m0/Cargo.toml +++ b/boards/metro_m0/Cargo.toml @@ -41,9 +41,10 @@ cortex-m-rtic = "1.0" [features] # ask the HAL to enable atsamd21g support default = ["rt", "atsamd-hal/samd21g"] +dma = ["atsamd-hal/dma"] +max-channels = ["dma", "atsamd-hal/max-channels"] rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"] rtic = ["atsamd-hal/rtic"] -unproven = ["atsamd-hal/unproven"] use_rtt = ["atsamd-hal/use_rtt"] usb = ["atsamd-hal/usb", "usb-device"] use_semihosting = [] @@ -61,15 +62,15 @@ opt-level = "s" [[example]] name = "usb_echo" -required-features = ["usb", "unproven"] +required-features = ["usb"] [[example]] name = "blinky_rtic" -required-features = ["rtic", "unproven"] +required-features = ["rtic"] [[example]] name = "blinky_basic" [[example]] name = "i2c" -required-features = ["atsamd-hal/dma"] +required-features = ["dma"] diff --git a/boards/metro_m0/examples/blinky_rtic.rs b/boards/metro_m0/examples/blinky_rtic.rs index 460e6a63757c..8a2757dce7b3 100644 --- a/boards/metro_m0/examples/blinky_rtic.rs +++ b/boards/metro_m0/examples/blinky_rtic.rs @@ -10,7 +10,6 @@ use metro_m0 as bsp; use panic_halt as _; #[cfg(feature = "use_semihosting")] use panic_semihosting as _; -use rtic; #[rtic::app(device = bsp::pac, peripherals = true, dispatchers = [EVSYS])] mod app { diff --git a/boards/metro_m0/examples/i2c.rs b/boards/metro_m0/examples/i2c.rs index c6add5dfe4cb..eca5fd5889a1 100644 --- a/boards/metro_m0/examples/i2c.rs +++ b/boards/metro_m0/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; @@ -57,7 +57,7 @@ fn main() -> ! { let sercom3_clock = &clocks.sercom3_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let mut i2c = i2c::Config::new(&pm, peripherals.SERCOM3, pads, sercom3_clock.freq()) - .baud(100.khz()) + .baud(100.kHz()) .enable(); let mut buffer = [0x00; 1]; diff --git a/boards/metro_m4/CHANGELOG.md b/boards/metro_m4/CHANGELOG.md index c1a934dca59c..06e86ef25f9f 100644 --- a/boards/metro_m4/CHANGELOG.md +++ b/boards/metro_m4/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.12.0 diff --git a/boards/metro_m4/Cargo.toml b/boards/metro_m4/Cargo.toml index 2722c9a728b9..7f2bcd0d64f8 100644 --- a/boards/metro_m4/Cargo.toml +++ b/boards/metro_m4/Cargo.toml @@ -33,6 +33,8 @@ features = ["critical-section-single-core"] [dev-dependencies] cortex-m = "0.7" +embedded-hal = "1.0" +embedded-hal-nb = "1.0" usbd-serial = "0.2" panic-probe = "0.3" panic-halt = "0.2" @@ -48,8 +50,9 @@ version = "0.3" [features] # ask the HAL to enable atsamd51j support default = ["rt", "atsamd-hal/samd51j"] +dma = ["atsamd-hal/dma"] +max-channels = ["dma", "atsamd-hal/max-channels"] rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"] -unproven = ["atsamd-hal/unproven"] usb = ["atsamd-hal/usb", "usb-device"] [profile.dev] @@ -76,7 +79,6 @@ name = "neopixel_rainbow" [[example]] name = "pwm" -required-features = ["unproven"] [[example]] name = "serial" @@ -89,15 +91,14 @@ name = "timer" [[example]] name = "adc" -required-features = ["unproven"] [[example]] name = "trng" [[example]] name = "usb_logging" -required-features = ["usb", "unproven"] +required-features = ["usb"] [[example]] name = "i2c" -required-features = ["atsamd-hal/dma"] +required-features = ["dma"] diff --git a/boards/metro_m4/examples/blinky_basic.rs b/boards/metro_m4/examples/blinky_basic.rs index 1a3b7b226f9f..0fc83d25e9f1 100644 --- a/boards/metro_m4/examples/blinky_basic.rs +++ b/boards/metro_m4/examples/blinky_basic.rs @@ -3,7 +3,6 @@ use metro_m4 as bsp; -use bsp::ehal; use bsp::hal; use bsp::pac; @@ -17,7 +16,6 @@ use hal::clock::GenericClockController; use hal::prelude::*; use pac::{CorePeripherals, Peripherals}; -use ehal::blocking::delay::DelayMs; use hal::delay::Delay; #[entry] diff --git a/boards/metro_m4/examples/i2c.rs b/boards/metro_m4/examples/i2c.rs index 93efdd97b96e..9c30c3be0b52 100644 --- a/boards/metro_m4/examples/i2c.rs +++ b/boards/metro_m4/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; @@ -59,7 +59,7 @@ fn main() -> ! { let pads = i2c::Pads::new(sda, scl); let i2c_sercom = periph_alias!(peripherals.i2c_sercom); let mut i2c = i2c::Config::new(&mclk, i2c_sercom, pads, sercom5_clock.freq()) - .baud(100.khz()) + .baud(100.kHz()) .enable(); let mut buffer = [0x00; 1]; diff --git a/boards/metro_m4/examples/neopixel_blink.rs b/boards/metro_m4/examples/neopixel_blink.rs index 1196499853b2..ed52cf8d2c67 100644 --- a/boards/metro_m4/examples/neopixel_blink.rs +++ b/boards/metro_m4/examples/neopixel_blink.rs @@ -14,9 +14,10 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; use hal::delay::Delay; -use hal::prelude::*; +use hal::ehal::delay::DelayNs; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use pac::{CorePeripherals, Peripherals}; use ws2812_timer_delay as ws2812; @@ -49,11 +50,11 @@ fn main() -> ! { neopixel .write(brightness(data.iter().cloned(), 32)) .unwrap(); - delay.delay_ms(250u8); + delay.delay_ms(250); let data2 = [RGB8::default(); 1]; neopixel .write(brightness(data2.iter().cloned(), 32)) .unwrap(); - delay.delay_ms(250u8); + delay.delay_ms(250); } } diff --git a/boards/metro_m4/examples/neopixel_rainbow.rs b/boards/metro_m4/examples/neopixel_rainbow.rs index 29a0ed91fe32..761bdd4a08b7 100644 --- a/boards/metro_m4/examples/neopixel_rainbow.rs +++ b/boards/metro_m4/examples/neopixel_rainbow.rs @@ -14,9 +14,10 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; use hal::delay::Delay; -use hal::prelude::*; +use hal::ehal::delay::DelayNs; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use pac::{CorePeripherals, Peripherals}; use smart_leds::{ @@ -54,7 +55,7 @@ fn main() -> ! { val: 32, })]; neopixel.write(colors.iter().cloned()).unwrap(); - delay.delay_ms(5u8); + delay.delay_ms(5); } } } diff --git a/boards/metro_m4/examples/serial.rs b/boards/metro_m4/examples/serial.rs index b671ba90f1ec..50ce36e66848 100644 --- a/boards/metro_m4/examples/serial.rs +++ b/boards/metro_m4/examples/serial.rs @@ -13,8 +13,11 @@ use panic_semihosting as _; use bsp::{entry, periph_alias, pin_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; +use hal::ehal_nb::serial::Write; +use hal::fugit::RateExtU32; +use hal::nb; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; #[entry] fn main() -> ! { @@ -49,6 +52,6 @@ fn main() -> ! { // `Result<(), Error>` nb::block!(uart.write(*byte)).unwrap(); } - delay.delay_ms(1000u16); + delay.delay_ms(1000); } } diff --git a/boards/metro_m4/examples/spi.rs b/boards/metro_m4/examples/spi.rs index 56266536d16f..beb3021bcc24 100644 --- a/boards/metro_m4/examples/spi.rs +++ b/boards/metro_m4/examples/spi.rs @@ -13,8 +13,11 @@ use panic_semihosting as _; use bsp::{entry, periph_alias}; use hal::clock::GenericClockController; use hal::delay::Delay; +use hal::ehal::delay::DelayNs; +use hal::ehal_nb::spi::FullDuplex; +use hal::fugit::RateExtU32; +use hal::nb; use hal::pac::{CorePeripherals, Peripherals}; -use hal::prelude::*; #[entry] fn main() -> ! { @@ -41,8 +44,8 @@ fn main() -> ! { loop { for byte in b"Hello, world!" { - nb::block!(spi.send(*byte)).unwrap(); + nb::block!(spi.write(*byte)).unwrap(); } - delay.delay_ms(1000u16); + delay.delay_ms(1000); } } diff --git a/boards/metro_m4/examples/timer.rs b/boards/metro_m4/examples/timer.rs index c2a90b71ecc4..3ddff29493b6 100644 --- a/boards/metro_m4/examples/timer.rs +++ b/boards/metro_m4/examples/timer.rs @@ -12,10 +12,12 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::GenericClockController; +use hal::ehal::digital::OutputPin; +use hal::nb; use hal::pac::Peripherals; -use hal::prelude::*; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use nb::block; diff --git a/boards/metro_m4/examples/usb_logging.rs b/boards/metro_m4/examples/usb_logging.rs index 92b64d7cb552..8185f24335eb 100644 --- a/boards/metro_m4/examples/usb_logging.rs +++ b/boards/metro_m4/examples/usb_logging.rs @@ -9,7 +9,7 @@ use bsp::pac; use cortex_m::asm::delay as cycle_delay; use cortex_m::peripheral::NVIC; -use ehal::digital::v2::ToggleableOutputPin; +use ehal::digital::StatefulOutputPin; use usb_device::bus::UsbBusAllocator; use usb_device::prelude::*; use usbd_serial::{SerialPort, USB_CLASS_CDC}; diff --git a/boards/samd11_bare/CHANGELOG.md b/boards/samd11_bare/CHANGELOG.md index 78f114a1fde4..350c0846ed9b 100644 --- a/boards/samd11_bare/CHANGELOG.md +++ b/boards/samd11_bare/CHANGELOG.md @@ -1,5 +1,6 @@ # Unreleased +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART and fix examples - Update the PACs to svd2rust 0.30.2. # v0.9.0 diff --git a/boards/samd11_bare/Cargo.toml b/boards/samd11_bare/Cargo.toml index 74d7810b3ae5..068aaea8c1a7 100644 --- a/boards/samd11_bare/Cargo.toml +++ b/boards/samd11_bare/Cargo.toml @@ -36,8 +36,9 @@ rtt-target = { version = "0.3.0", features = ["cortex-m"] } [features] # ask the HAL to enable atsamd11c support default = ["rt", "atsamd-hal/samd11c"] +dma = ["atsamd-hal/dma"] +max-channels = ["dma", "atsamd-hal/max-channels"] rt = ["cortex-m-rt", "atsamd-hal/samd11c-rt"] -unproven = ["atsamd-hal/unproven"] use_semihosting = [] [profile.release] @@ -48,14 +49,13 @@ opt-level = "s" [[example]] name = "adc" -required-features = ["unproven", "rt", "use_semihosting"] +required-features = ["rt", "use_semihosting"] [[example]] name = "blinky_basic" [[example]] name = "pwm" -required-features = ["unproven"] [[example]] name = "serial" @@ -65,4 +65,4 @@ name = "timer" [[example]] name = "i2c" -required-features = ["atsamd-hal/dma"] +required-features = ["dma"] diff --git a/boards/samd11_bare/README.md b/boards/samd11_bare/README.md index de966c9faf62..c8ff68eb05f7 100644 --- a/boards/samd11_bare/README.md +++ b/boards/samd11_bare/README.md @@ -23,7 +23,7 @@ Cargo flash needs to know the specific id of your chip, but its included in the Then cargo flash simply replaces your cargo build command! ```bash -$ cargo flash --example blinky_basic --features unproven --release +$ cargo flash --example blinky_basic --release ``` ## Debugging: probe-run @@ -42,7 +42,7 @@ $ cargo install probe-run Then simply use your ide's run or play button, or run: ```bash -$ cargo run --release --example adc --features=unproven +$ cargo run --release --example adc Finished release [optimized + debuginfo] target(s) in 0.99s Running `probe-run --chip ATSAMD11C14A target\thumbv6m-none-eabi\release\examples\adc` (HOST) INFO flashing program (7.18 KiB) diff --git a/boards/samd11_bare/examples/adc.rs b/boards/samd11_bare/examples/adc.rs index f887525e313c..e580c59b0ee5 100644 --- a/boards/samd11_bare/examples/adc.rs +++ b/boards/samd11_bare/examples/adc.rs @@ -9,7 +9,7 @@ //! on your command line. You can also force an exit with a //! cortex_m::asm::bkpt() //! -//! `cargo run --release --example adc --features=unproven` +//! `cargo run --release --example adc` #![no_std] #![no_main] diff --git a/boards/samd11_bare/examples/i2c.rs b/boards/samd11_bare/examples/i2c.rs index ce6e7a35e742..7c5d37c14e28 100644 --- a/boards/samd11_bare/examples/i2c.rs +++ b/boards/samd11_bare/examples/i2c.rs @@ -19,8 +19,8 @@ use pac::Peripherals; use hal::clock::GenericClockController; use hal::dmac::{DmaController, PriorityLevel}; -use hal::ehal::blocking::i2c::WriteRead; -use hal::prelude::*; +use hal::ehal::i2c::I2c; +use hal::fugit::RateExtU32; use hal::sercom::i2c; const LENGTH: usize = 1; @@ -57,7 +57,7 @@ fn main() -> ! { let sercom0_clock = &clocks.sercom0_core(&gclk0).unwrap(); let pads = i2c::Pads::new(sda, scl); let mut i2c = i2c::Config::new(&pm, peripherals.SERCOM0, pads, sercom0_clock.freq()) - .baud(100.khz()) + .baud(100.kHz()) .enable(); let mut buffer = [0x00; 1]; diff --git a/boards/samd11_bare/examples/serial.rs b/boards/samd11_bare/examples/serial.rs index 375e76414d23..a47350fb3b2f 100644 --- a/boards/samd11_bare/examples/serial.rs +++ b/boards/samd11_bare/examples/serial.rs @@ -6,7 +6,10 @@ use samd11_bare as bsp; use bsp::entry; use hal::clock::GenericClockController; -use hal::prelude::*; +use hal::ehal::delay::DelayNs; +use hal::ehal_nb::serial::Write; +use hal::fugit::RateExtU32; +use hal::nb; #[cfg(not(feature = "use_semihosting"))] use panic_halt as _; @@ -61,6 +64,6 @@ fn main() -> ! { // `Result<(), Error>` nb::block!(uart.write(*byte)).unwrap(); } - delay.delay_ms(1000u16); + delay.delay_ms(1000); } } diff --git a/boards/samd11_bare/examples/timer.rs b/boards/samd11_bare/examples/timer.rs index 15be06be8233..6026dcad8a4e 100644 --- a/boards/samd11_bare/examples/timer.rs +++ b/boards/samd11_bare/examples/timer.rs @@ -13,9 +13,11 @@ use bsp::pac; use bsp::entry; use hal::clock::GenericClockController; -use hal::prelude::*; +use hal::ehal::digital::OutputPin; +use hal::nb; use hal::time::Hertz; use hal::timer::TimerCounter; +use hal::timer_traits::InterruptDrivenTimer; use pac::Peripherals; #[entry] diff --git a/crates.json b/crates.json index cae374805a1d..41192c503206 100644 --- a/crates.json +++ b/crates.json @@ -1,5 +1,35 @@ { "boards": { + "atsame54_xpro": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv7em-none-eabihf" + }, + "feather_m0": { + "tier": 1, + "build": "cargo build --examples", + "target": "thumbv6m-none-eabi" + }, + "feather_m4": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv7em-none-eabihf" + }, + "metro_m0": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv6m-none-eabi" + }, + "metro_m4": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv7em-none-eabihf" + }, + "samd11_bare": { + "tier": 1, + "build": "cargo build --examples --all-features", + "target": "thumbv6m-none-eabi" + }, "arduino_mkr1000": { "tier": 2, "build": "cargo build --examples --all-features", @@ -20,11 +50,6 @@ "build": "cargo build --examples --all-features", "target": "thumbv6m-none-eabi" }, - "atsame54_xpro": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv7em-none-eabihf" - }, "circuit_playground_express": { "tier": 2, "build": "cargo build --examples --all-features", @@ -35,16 +60,6 @@ "build": "cargo build --examples --all-features", "target": "thumbv7em-none-eabihf" }, - "feather_m0": { - "tier": 1, - "build": "cargo build --examples", - "target": "thumbv6m-none-eabi" - }, - "feather_m4": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv7em-none-eabihf" - }, "gemma_m0": { "tier": 2, "build": "cargo build --examples --all-features", @@ -70,16 +85,6 @@ "build": "cargo build --examples --all-features", "target": "thumbv7em-none-eabihf" }, - "metro_m0": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv6m-none-eabi" - }, - "metro_m4": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv7em-none-eabihf" - }, "neo_trinkey": { "tier": 2, "build": "cargo build --examples --all-features", @@ -110,11 +115,6 @@ "build": "cargo build --examples --all-features", "target": "thumbv7em-none-eabihf" }, - "samd11_bare": { - "tier": 1, - "build": "cargo build --examples --all-features", - "target": "thumbv6m-none-eabi" - }, "samd21_mini": { "tier": 2, "build": "cargo build --examples --all-features", @@ -175,7 +175,6 @@ "samd11c": { "features": [ "samd11c", - "unproven", "dma", "defmt" ], @@ -184,7 +183,6 @@ "samd11d": { "features": [ "samd11d", - "unproven", "dma", "defmt" ], @@ -193,7 +191,6 @@ "samd21g": { "features": [ "samd21g", - "unproven", "usb", "dma", "defmt" @@ -203,7 +200,6 @@ "samd21j": { "features": [ "samd21j", - "unproven", "usb", "dma", "defmt" @@ -213,7 +209,6 @@ "samd51g": { "features": [ "samd51g", - "unproven", "usb", "sdmmc", "dma", @@ -224,7 +219,6 @@ "samd51j": { "features": [ "samd51j", - "unproven", "usb", "sdmmc", "dma", @@ -235,7 +229,6 @@ "samd51n": { "features": [ "samd51n", - "unproven", "usb", "sdmmc", "dma", @@ -246,7 +239,6 @@ "samd51p": { "features": [ "samd51p", - "unproven", "usb", "sdmmc", "dma", @@ -257,75 +249,75 @@ }, "hal_build_variants": { "samd11c": { - "features": [ "samd11c", "unproven", "dma", "rtic", "defmt" ], + "features": [ "samd11c", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd11d": { - "features": [ "samd11d", "unproven", "dma", "rtic", "defmt" ], + "features": [ "samd11d", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21e": { - "features": [ "samd21e", "unproven", "usb", "dma", "rtic", "defmt" ], + "features": [ "samd21e", "usb", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21el": { - "features": [ "samd21el", "unproven", "dma", "rtic", "defmt" ], + "features": [ "samd21el", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21g": { - "features": [ "samd21g", "unproven", "usb", "dma", "rtic", "defmt" ], + "features": [ "samd21g", "usb", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21gl": { - "features": [ "samd21gl", "unproven", "dma", "rtic", "defmt" ], + "features": [ "samd21gl", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd21j": { - "features": [ "samd21j", "unproven", "usb", "dma", "rtic", "defmt" ], + "features": [ "samd21j", "usb", "dma", "rtic", "defmt" ], "target": "thumbv6m-none-eabi" }, "samd51g": { - "features": [ "samd51g", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "samd51g", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "samd51j": { - "features": [ "samd51j", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "samd51j", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "samd51n": { - "features": [ "samd51n", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "samd51n", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "samd51p": { - "features": [ "samd51p", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "samd51p", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same51g": { - "features": [ "same51g", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same51g", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same51j": { - "features": [ "same51j", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same51j", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same51n": { - "features": [ "same51n", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same51n", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same53j": { - "features": [ "same53j", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "same53j", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same53n": { - "features": [ "same53n", "unproven", "usb", "dma", "sdmmc", "rtic", "defmt" ], + "features": [ "same53n", "usb", "dma", "sdmmc", "rtic", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same54n": { - "features": [ "same54n", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same54n", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" }, "same54p": { - "features": [ "same54p", "unproven", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], + "features": [ "same54p", "usb", "dma", "sdmmc", "rtic", "can", "defmt" ], "target": "thumbv7em-none-eabihf" } } diff --git a/hal/CHANGELOG.md b/hal/CHANGELOG.md index 0e051eca2564..beebaa75ba67 100644 --- a/hal/CHANGELOG.md +++ b/hal/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased Changes +- Remove `unproven` Cargo feature +- Implement `embedded-hal` `1.0` for GPIO, SPI, I2C, UART, delay and PWM - CI/CD pipeline now uses `cargo clippy` instead of `cargo build` and denies clippy warnings by default - Fix HAL clippy lints - Add compile error for combined `library` and `dma` features diff --git a/hal/Cargo.toml b/hal/Cargo.toml index f7f2efebb566..dced5199a59d 100644 --- a/hal/Cargo.toml +++ b/hal/Cargo.toml @@ -23,7 +23,7 @@ rust-version = "1.65" version = "0.16.0" [package.metadata.docs.rs] -features = ["samd21g", "samd21g-rt", "unproven", "usb", "dma"] +features = ["samd21g", "samd21g-rt", "usb", "dma"] #=============================================================================== # Required depdendencies @@ -36,7 +36,10 @@ bitfield = "0.13" bitflags = "1.2.1" cipher = "0.3" cortex-m = "0.7" -embedded-hal = "0.2" +embedded-hal-02 = {package = "embedded-hal", version = "0.2", features = ["unproven"]} +embedded-hal-1 = {package = "embedded-hal", version = "1.0.0"} +embedded-hal-nb = "1.0.0" +embedded-io = "0.6" fugit = "0.3" modular-bitfield = "0.11" nb = "1.0" @@ -171,20 +174,13 @@ same54p-rt = ["same54p", "atsame54p/rt"] # These features are user-selectable and enable additional features within the # HAL, like USB or DMA support. - -# Many essential traits within embedded-hal are locked behind the `unproven` -# feature. This is unfortunate, but it should be resolved with embedded-hal 1.0. -# Until then, we make `unproven` a default feature. -default = ["unproven"] - can = ["mcan-core"] -dma = ["unproven"] +dma = [] defmt = ["dep:defmt"] enable_unsafe_aes_newblock_cipher = [] max-channels = ["dma"] rtic = ["rtic-monotonic"] sdmmc = ["embedded-sdmmc"] -unproven = ["embedded-hal/unproven"] usb = ["usb-device"] use_rtt = ["jlink_rtt"] diff --git a/hal/src/delay.rs b/hal/src/delay.rs index 94acd83c9376..b683a97c8da9 100644 --- a/hal/src/delay.rs +++ b/hal/src/delay.rs @@ -4,7 +4,8 @@ use cortex_m::peripheral::syst::SystClkSource; use cortex_m::peripheral::SYST; use crate::clock::GenericClockController; -use crate::ehal::blocking::delay::{DelayMs, DelayUs}; +use crate::ehal::delay::DelayNs; +use crate::ehal_02; use crate::time::Hertz; /// System timer (SysTick) as a delay provider @@ -30,25 +31,15 @@ impl Delay { } } -impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u32) { - self.delay_us(ms * 1_000); - } -} - -impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u16) { - self.delay_ms(ms as u32); +impl DelayNs for Delay { + // The default method is delay_ns. If we don't provide implementations for + // delay_us and delay_ms, the trait impl will use delay_ns to implement the + // other two methods. As the delay implementation is actually defined in terms + // of microseconds, we need to provide implementations for all three methods. + fn delay_ns(&mut self, ns: u32) { + self.delay_us(ns / 1000); } -} -impl DelayMs for Delay { - fn delay_ms(&mut self, ms: u8) { - self.delay_ms(ms as u32); - } -} - -impl DelayUs for Delay { fn delay_us(&mut self, us: u32) { // The SysTick Reload Value register supports values between 1 and 0x00FFFFFF. const MAX_RVR: u32 = 0x00FF_FFFF; @@ -74,16 +65,44 @@ impl DelayUs for Delay { self.syst.disable_counter(); } } + + fn delay_ms(&mut self, ms: u32) { + self.delay_us(ms * 1000); + } +} + +impl ehal_02::blocking::delay::DelayMs for Delay { + fn delay_ms(&mut self, ms: u32) { + ::delay_us(self, ms * 1_000); + } +} + +impl ehal_02::blocking::delay::DelayMs for Delay { + fn delay_ms(&mut self, ms: u16) { + >::delay_ms(self, ms as u32); + } +} + +impl ehal_02::blocking::delay::DelayMs for Delay { + fn delay_ms(&mut self, ms: u8) { + >::delay_ms(self, ms as u32); + } +} + +impl ehal_02::blocking::delay::DelayUs for Delay { + fn delay_us(&mut self, us: u32) { + ::delay_us(self, us); + } } -impl DelayUs for Delay { +impl ehal_02::blocking::delay::DelayUs for Delay { fn delay_us(&mut self, us: u16) { - self.delay_us(us as u32) + >::delay_us(self, us as u32); } } -impl DelayUs for Delay { +impl ehal_02::blocking::delay::DelayUs for Delay { fn delay_us(&mut self, us: u8) { - self.delay_us(us as u32) + >::delay_us(self, us as u32); } } diff --git a/hal/src/gpio/dynpin.rs b/hal/src/gpio/dynpin.rs index 88ee48762944..6be2d8cf9486 100644 --- a/hal/src/gpio/dynpin.rs +++ b/hal/src/gpio/dynpin.rs @@ -61,12 +61,9 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; +use crate::ehal::digital::{ErrorKind, ErrorType, InputPin, OutputPin, StatefulOutputPin}; use paste::paste; -use crate::ehal::digital::v2::OutputPin; -#[cfg(feature = "unproven")] -use crate::ehal::digital::v2::{InputPin, StatefulOutputPin, ToggleableOutputPin}; - use super::pin::*; use super::reg::RegisterInterface; @@ -258,12 +255,19 @@ impl DynRegisters { /// /// [`DynPin`]s are not tracked and verified at compile-time, so run-time /// operations are fallible. This `enum` represents the corresponding errors. +#[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum Error { /// The pin did not have the correct ID or mode for the requested operation InvalidPinType, } +impl crate::ehal::digital::Error for Error { + fn kind(&self) -> crate::ehal::digital::ErrorKind { + ErrorKind::Other + } +} + //============================================================================== // DynPin //============================================================================== @@ -509,11 +513,13 @@ where } //============================================================================== -// Embedded HAL traits +// Embedded HAL v1 traits //============================================================================== +impl ErrorType for DynPin { + type Error = Error; +} impl OutputPin for DynPin { - type Error = Error; #[inline] fn set_high(&mut self) -> Result<(), Self::Error> { self._set_high() @@ -524,8 +530,45 @@ impl OutputPin for DynPin { } } -#[cfg(feature = "unproven")] impl InputPin for DynPin { + #[inline] + fn is_high(&mut self) -> Result { + self._is_high() + } + #[inline] + fn is_low(&mut self) -> Result { + self._is_low() + } +} + +impl StatefulOutputPin for DynPin { + #[inline] + fn is_set_high(&mut self) -> Result { + self._is_set_high() + } + #[inline] + fn is_set_low(&mut self) -> Result { + self._is_set_low() + } +} + +//============================================================================== +// Embedded HAL v0.2 traits +//============================================================================== + +impl crate::ehal_02::digital::v2::OutputPin for DynPin { + type Error = Error; + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self._set_high() + } + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self._set_low() + } +} + +impl crate::ehal_02::digital::v2::InputPin for DynPin { type Error = Error; #[inline] fn is_high(&self) -> Result { @@ -537,8 +580,7 @@ impl InputPin for DynPin { } } -#[cfg(feature = "unproven")] -impl ToggleableOutputPin for DynPin { +impl crate::ehal_02::digital::v2::ToggleableOutputPin for DynPin { type Error = Error; #[inline] fn toggle(&mut self) -> Result<(), Self::Error> { @@ -546,8 +588,7 @@ impl ToggleableOutputPin for DynPin { } } -#[cfg(feature = "unproven")] -impl StatefulOutputPin for DynPin { +impl crate::ehal_02::digital::v2::StatefulOutputPin for DynPin { #[inline] fn is_set_high(&self) -> Result { self._is_set_high() diff --git a/hal/src/gpio/pin.rs b/hal/src/gpio/pin.rs index 024874160b77..af5ca781f6ba 100644 --- a/hal/src/gpio/pin.rs +++ b/hal/src/gpio/pin.rs @@ -71,7 +71,7 @@ //! ``` //! use atsamd_hal::pac::Peripherals; //! use atsamd_hal::gpio::Pins; -//! use embedded_hal::digital::v2::OutputPin; +//! use crate::ehal_02::digital::v2::OutputPin; //! //! let mut peripherals = Peripherals::take().unwrap(); //! let mut pins = Pins::new(peripherals.PORT); @@ -102,9 +102,7 @@ use core::convert::Infallible; use core::marker::PhantomData; use core::mem::transmute; -use crate::ehal::digital::v2::OutputPin; -#[cfg(feature = "unproven")] -use crate::ehal::digital::v2::{InputPin, StatefulOutputPin, ToggleableOutputPin}; +use crate::ehal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; use paste::paste; use crate::pac::PORT; @@ -882,10 +880,99 @@ pub trait SomePin: AnyPin {} impl SomePin for P {} //============================================================================== -// Embedded HAL traits +// Embedded HAL v1 traits //============================================================================== +impl ErrorType for Pin +where + I: PinId, + M: PinMode, +{ + type Error = Infallible; +} + impl OutputPin for Pin> +where + I: PinId, + C: OutputConfig, +{ + #[inline] + fn set_low(&mut self) -> Result<(), Self::Error> { + self._set_low(); + Ok(()) + } + + #[inline] + fn set_high(&mut self) -> Result<(), Self::Error> { + self._set_high(); + Ok(()) + } +} + +impl InputPin for Pin +where + I: PinId, +{ + #[inline] + fn is_high(&mut self) -> Result { + Ok(self._is_high()) + } + #[inline] + fn is_low(&mut self) -> Result { + Ok(self._is_low()) + } +} + +impl InputPin for Pin> +where + I: PinId, + C: InputConfig, +{ + #[inline] + fn is_high(&mut self) -> Result { + Ok(self._is_high()) + } + #[inline] + fn is_low(&mut self) -> Result { + Ok(self._is_low()) + } +} + +impl InputPin for Pin> +where + I: PinId, + C: InterruptConfig, +{ + #[inline] + fn is_high(&mut self) -> Result { + Ok(self._is_high()) + } + #[inline] + fn is_low(&mut self) -> Result { + Ok(self._is_low()) + } +} + +impl StatefulOutputPin for Pin> +where + I: PinId, + C: OutputConfig, +{ + #[inline] + fn is_set_high(&mut self) -> Result { + Ok(self._is_set_high()) + } + #[inline] + fn is_set_low(&mut self) -> Result { + Ok(self._is_set_low()) + } +} + +//============================================================================== +// Embedded HAL v0.2 traits +//============================================================================== + +impl crate::ehal_02::digital::v2::OutputPin for Pin> where I: PinId, C: OutputConfig, @@ -903,8 +990,7 @@ where } } -#[cfg(feature = "unproven")] -impl InputPin for Pin +impl crate::ehal_02::digital::v2::InputPin for Pin where I: PinId, { @@ -919,8 +1005,7 @@ where } } -#[cfg(feature = "unproven")] -impl InputPin for Pin> +impl crate::ehal_02::digital::v2::InputPin for Pin> where I: PinId, C: InputConfig, @@ -936,8 +1021,7 @@ where } } -#[cfg(feature = "unproven")] -impl InputPin for Pin> +impl crate::ehal_02::digital::v2::InputPin for Pin> where I: PinId, C: InterruptConfig, @@ -953,8 +1037,7 @@ where } } -#[cfg(feature = "unproven")] -impl ToggleableOutputPin for Pin> +impl crate::ehal_02::digital::v2::ToggleableOutputPin for Pin> where I: PinId, C: OutputConfig, @@ -967,8 +1050,7 @@ where } } -#[cfg(feature = "unproven")] -impl StatefulOutputPin for Pin> +impl crate::ehal_02::digital::v2::StatefulOutputPin for Pin> where I: PinId, C: OutputConfig, diff --git a/hal/src/lib.rs b/hal/src/lib.rs index 9cc0c53c0b2f..b96934e528a5 100644 --- a/hal/src/lib.rs +++ b/hal/src/lib.rs @@ -1,7 +1,11 @@ #![no_std] -pub use embedded_hal as ehal; +use embedded_hal_02 as ehal_02; +pub use embedded_hal_1 as ehal; +pub use embedded_hal_nb as ehal_nb; +pub use embedded_io; pub use fugit; +pub use nb; pub use paste; pub mod typelevel; @@ -77,6 +81,7 @@ pub mod dmac; #[doc(hidden)] mod peripherals; #[doc(inline)] +#[allow(unused_imports)] pub use crate::peripherals::*; #[macro_use] diff --git a/hal/src/peripherals/adc/d11.rs b/hal/src/peripherals/adc/d11.rs index 9b95942da393..556538eede99 100644 --- a/hal/src/peripherals/adc/d11.rs +++ b/hal/src/peripherals/adc/d11.rs @@ -2,7 +2,7 @@ use atsamd_hal_macros::hal_cfg; use crate::clock::GenericClockController; -use crate::ehal::adc::{Channel, OneShot}; +use crate::ehal_02::adc::{Channel, OneShot}; use crate::gpio::*; use crate::pac::{adc, ADC, PM}; diff --git a/hal/src/peripherals/adc/d5x.rs b/hal/src/peripherals/adc/d5x.rs index 349ee5d128ed..1ccff38f7822 100644 --- a/hal/src/peripherals/adc/d5x.rs +++ b/hal/src/peripherals/adc/d5x.rs @@ -4,7 +4,7 @@ use atsamd_hal_macros::hal_cfg; use crate::clock::GenericClockController; #[rustfmt::skip] use crate::gpio::*; -use crate::ehal::adc::{Channel, OneShot}; +use crate::ehal_02::adc::{Channel, OneShot}; use crate::pac::gclk::genctrl::SRCSELECT_A::DFLL; use crate::pac::gclk::pchctrl::GENSELECT_A; use crate::pac::{adc0, ADC0, ADC1, MCLK}; diff --git a/hal/src/peripherals/eic/d11/pin.rs b/hal/src/peripherals/eic/d11/pin.rs index 55686b395b34..c537dfb57a2c 100644 --- a/hal/src/peripherals/eic/d11/pin.rs +++ b/hal/src/peripherals/eic/d11/pin.rs @@ -1,5 +1,4 @@ -#[cfg(feature = "unproven")] -use crate::ehal::digital::v2::InputPin; +use crate::ehal_02::digital::v2::InputPin; use crate::gpio::{ self, pin::*, AnyPin, FloatingInterrupt, PinMode, PullDownInterrupt, PullUpInterrupt, }; @@ -157,7 +156,6 @@ crate::paste::item! { } } - #[cfg(feature = "unproven")] impl InputPin for [<$PadType $num>] where GPIO: AnyPin>, diff --git a/hal/src/peripherals/eic/d5x/pin.rs b/hal/src/peripherals/eic/d5x/pin.rs index 6eadaf441318..8c1d57bb6749 100644 --- a/hal/src/peripherals/eic/d5x/pin.rs +++ b/hal/src/peripherals/eic/d5x/pin.rs @@ -1,5 +1,4 @@ -#[cfg(feature = "unproven")] -use crate::ehal::digital::v2::InputPin; +use crate::ehal_02::digital::v2::InputPin; use crate::gpio::{ self, pin::*, AnyPin, FloatingInterrupt, PinMode, PullDownInterrupt, PullUpInterrupt, }; @@ -155,7 +154,6 @@ crate::paste::item! { } } - #[cfg(feature = "unproven")] impl InputPin for [<$PadType $num>] where GPIO: AnyPin>, diff --git a/hal/src/peripherals/mod.rs b/hal/src/peripherals/mod.rs index f7e060756175..34e271e6dd5d 100644 --- a/hal/src/peripherals/mod.rs +++ b/hal/src/peripherals/mod.rs @@ -1,6 +1,5 @@ use atsamd_hal_macros::{hal_cfg, hal_module}; -#[cfg(feature = "unproven")] #[hal_module( any("adc-d11", "adc-d21") => "adc/d11.rs", "adc-d5x" => "adc/d5x.rs", @@ -32,7 +31,6 @@ pub mod eic {} )] pub mod usb {} -#[cfg(feature = "unproven")] #[hal_module( any("clock-d11", "clock-d21") => "pwm/d11.rs", "clock-d5x" => "pwm/d5x.rs", @@ -60,7 +58,6 @@ pub mod qspi {} #[hal_module("trng")] pub mod trng {} -#[cfg(feature = "unproven")] #[hal_module("icm")] pub mod icm {} @@ -71,7 +68,6 @@ pub mod nvm {} #[hal_module(any("can0", "can1"))] pub mod can {} -#[cfg(feature = "unproven")] #[hal_module("wdt")] pub mod watchdog {} diff --git a/hal/src/peripherals/pukcc/c_abi.rs b/hal/src/peripherals/pukcc/c_abi.rs index a4c149bcc660..350b85c2ea41 100644 --- a/hal/src/peripherals/pukcc/c_abi.rs +++ b/hal/src/peripherals/pukcc/c_abi.rs @@ -675,7 +675,7 @@ pub trait Service: crate::typelevel::Sealed { pukcl_params.header.u2Status = super::PukclReturnCode::Severe(super::PukclReturnCodeSevere::ComputationNotStarted) .into(); - core::mem::transmute::<_, extern "C" fn(*mut PukclParams)>(Self::FUNCTION_ADDRESS)( + core::mem::transmute::(Self::FUNCTION_ADDRESS)( pukcl_params, ) } diff --git a/hal/src/peripherals/pwm/d11.rs b/hal/src/peripherals/pwm/d11.rs index 1d6be00d9235..a841d266a8a5 100644 --- a/hal/src/peripherals/pwm/d11.rs +++ b/hal/src/peripherals/pwm/d11.rs @@ -1,7 +1,6 @@ use atsamd_hal_macros::hal_cfg; use crate::clock; -use crate::ehal::{Pwm, PwmPin}; use crate::pac::PM; use crate::time::Hertz; use crate::timer_params::TimerParams; @@ -86,7 +85,25 @@ impl $TYPE { } } -impl PwmPin for $TYPE { +impl $crate::ehal::pwm::ErrorType for$TYPE { + type Error = ::core::convert::Infallible; +} + +impl $crate::ehal::pwm::SetDutyCycle for $TYPE { + fn max_duty_cycle(&self) -> u16 { + let count = self.tc.count16(); + let top = count.cc[0].read().cc().bits(); + top + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + let count = self.tc.count16(); + unsafe { count.cc[1].write(|w| w.cc().bits(duty)); } + Ok(()) + } +} + +impl $crate::ehal_02::PwmPin for $TYPE { type Duty = u16; fn disable(&mut self) { @@ -106,14 +123,13 @@ impl PwmPin for $TYPE { } fn get_max_duty(&self) -> Self::Duty { - let count = self.tc.count16(); - let top = count.cc[0].read().cc().bits(); - top + use $crate::ehal::pwm::SetDutyCycle; + self.max_duty_cycle() } fn set_duty(&mut self, duty: Self::Duty) { - let count = self.tc.count16(); - count.cc[1].write(|w| unsafe { w.cc().bits(duty) }); + use $crate::ehal::pwm::SetDutyCycle; + let _ignore_infaillible = self.set_duty_cycle(duty); } } @@ -199,7 +215,7 @@ impl $TYPE { } } -impl Pwm for $TYPE { +impl $crate::ehal_02::Pwm for $TYPE { type Channel = Channel; type Time = Hertz; type Duty = u32; diff --git a/hal/src/peripherals/pwm/d5x.rs b/hal/src/peripherals/pwm/d5x.rs index 98b24edc32b2..423aaa9bdaaf 100644 --- a/hal/src/peripherals/pwm/d5x.rs +++ b/hal/src/peripherals/pwm/d5x.rs @@ -3,7 +3,6 @@ use atsamd_hal_macros::hal_cfg; use crate::clock; -use crate::ehal::{Pwm, PwmPin}; use crate::gpio::*; use crate::gpio::{AlternateE, AnyPin, Pin}; use crate::pac::MCLK; @@ -216,7 +215,25 @@ impl $TYPE { } } -impl PwmPin for $TYPE { +impl $crate::ehal::pwm::ErrorType for$TYPE { + type Error = ::core::convert::Infallible; +} + +impl $crate::ehal::pwm::SetDutyCycle for $TYPE { + fn max_duty_cycle(&self) -> u16 { + let count = self.tc.count16(); + let top = count.cc[0].read().cc().bits(); + top + } + + fn set_duty_cycle(&mut self, duty: u16) -> Result<(), Self::Error> { + let count = self.tc.count16(); + unsafe { count.ccbuf[1].write(|w| w.ccbuf().bits(duty)); } + Ok(()) + } +} + +impl $crate::ehal_02::PwmPin for $TYPE { type Duty = u16; fn disable(&mut self) { @@ -237,17 +254,18 @@ impl PwmPin for $TYPE { } fn get_max_duty(&self) -> Self::Duty { - let count = self.tc.count16(); - let top = count.cc[0].read().cc().bits(); - top + use $crate::ehal::pwm::SetDutyCycle; + self.max_duty_cycle() } fn set_duty(&mut self, duty: Self::Duty) { - let count = self.tc.count16(); - count.ccbuf[1].write(|w| unsafe {w.ccbuf().bits(duty)}); + use $crate::ehal::pwm::SetDutyCycle; + let _ignore_infaillible = self.set_duty_cycle(duty); } } + + )+}} #[hal_cfg("tc0")] @@ -582,7 +600,7 @@ impl $TYPE { } } -impl Pwm for $TYPE { +impl $crate::ehal_02::Pwm for $TYPE { type Channel = Channel; type Time = Hertz; type Duty = u32; diff --git a/hal/src/peripherals/timer/d11.rs b/hal/src/peripherals/timer/d11.rs index e31ab1c3c15e..aadc0e67e316 100644 --- a/hal/src/peripherals/timer/d11.rs +++ b/hal/src/peripherals/timer/d11.rs @@ -1,7 +1,10 @@ //! Working with timer counter hardware +use core::convert::Infallible; + use atsamd_hal_macros::hal_cfg; +use fugit::NanosDurationU32; -use crate::ehal::timer::{CountDown, Periodic}; +use crate::ehal_02::timer::{CountDown, Periodic}; use crate::pac::PM; #[hal_cfg("tc1-d11")] use crate::pac::{tc1::COUNT16, TC1}; @@ -12,7 +15,6 @@ use crate::timer_params::TimerParams; use crate::clock; use crate::time::{Hertz, Nanoseconds}; use crate::timer_traits::InterruptDrivenTimer; -use void::Void; // Note: // TC3 + TC4 can be paired to make a 32-bit counter @@ -33,6 +35,8 @@ pub struct TimerCounter { tc: TC, } +impl TimerCounter {} + /// This is a helper trait to make it easier to make most of the /// TimerCounter impl generic. It doesn't make too much sense to /// to try to implement this trait outside of this module. @@ -51,7 +55,30 @@ where where T: Into, { - let params = TimerParams::new_us(timeout.into(), self.freq); + ::start(self, timeout); + } + + fn wait(&mut self) -> nb::Result<(), void::Void> { + // Unwrapping an unreacheable error is totally OK + ::wait(self).unwrap(); + Ok(()) + } +} + +impl InterruptDrivenTimer for TimerCounter +where + TC: Count16, +{ + /// Enable the interrupt generation for this hardware timer. + /// This method only sets the clock configuration to trigger + /// the interrupt; it does not configure the interrupt controller + /// or define an interrupt handler. + fn enable_interrupt(&mut self) { + self.tc.count_16().intenset.write(|w| w.ovf().set_bit()); + } + + fn start>(&mut self, timeout: T) { + let params = TimerParams::new_ns(timeout.into(), self.freq); let divider = params.divider; let cycles = params.cycles; @@ -98,7 +125,7 @@ where }); } - fn wait(&mut self) -> nb::Result<(), Void> { + fn wait(&mut self) -> nb::Result<(), Infallible> { let count = self.tc.count_16(); if count.intflag.read().ovf().bit_is_set() { // Writing a 1 clears the flag @@ -108,19 +135,6 @@ where Err(nb::Error::WouldBlock) } } -} - -impl InterruptDrivenTimer for TimerCounter -where - TC: Count16, -{ - /// Enable the interrupt generation for this hardware timer. - /// This method only sets the clock configuration to trigger - /// the interrupt; it does not configure the interrupt controller - /// or define an interrupt handler. - fn enable_interrupt(&mut self) { - self.tc.count_16().intenset.write(|w| w.ovf().set_bit()); - } /// Disables interrupt generation for this hardware timer. /// This method only sets the clock configuration to prevent diff --git a/hal/src/peripherals/timer/d5x.rs b/hal/src/peripherals/timer/d5x.rs index b841f2ee1e19..3d5877e01638 100644 --- a/hal/src/peripherals/timer/d5x.rs +++ b/hal/src/peripherals/timer/d5x.rs @@ -1,7 +1,10 @@ //! Working with timer counter hardware +use core::convert::Infallible; + use atsamd_hal_macros::hal_cfg; +use fugit::NanosDurationU32; -use crate::ehal::timer::{CountDown, Periodic}; +use crate::ehal_02::timer::{CountDown, Periodic}; use crate::pac::tc0::COUNT16; use crate::pac::{MCLK, TC2, TC3}; #[hal_cfg(all("tc4", "tc5"))] @@ -11,7 +14,6 @@ use crate::timer_traits::InterruptDrivenTimer; use crate::clock; use crate::time::{Hertz, Nanoseconds}; -use void::Void; // Note: // TC3 + TC4 can be paired to make a 32-bit counter @@ -50,7 +52,33 @@ where where T: Into, { - let params = TimerParams::new_us(timeout.into(), self.freq); + ::start(self, timeout); + } + + fn wait(&mut self) -> nb::Result<(), void::Void> { + // Unwrapping an unreacheable error is totally OK + ::wait(self).unwrap(); + Ok(()) + } +} + +impl InterruptDrivenTimer for TimerCounter +where + TC: Count16, +{ + /// Enable the interrupt generation for this hardware timer. + /// This method only sets the clock configuration to trigger + /// the interrupt; it does not configure the interrupt controller + /// or define an interrupt handler. + fn enable_interrupt(&mut self) { + self.tc.count_16().intenset.write(|w| w.ovf().set_bit()); + } + + fn start(&mut self, timeout: T) + where + T: Into, + { + let params = TimerParams::new_ns(timeout.into(), self.freq); let divider = params.divider; let cycles = params.cycles; let count = self.tc.count_16(); @@ -98,7 +126,7 @@ where }); } - fn wait(&mut self) -> nb::Result<(), Void> { + fn wait(&mut self) -> nb::Result<(), Infallible> { let count = self.tc.count_16(); if count.intflag.read().ovf().bit_is_set() { // Writing a 1 clears the flag @@ -108,19 +136,6 @@ where Err(nb::Error::WouldBlock) } } -} - -impl InterruptDrivenTimer for TimerCounter -where - TC: Count16, -{ - /// Enable the interrupt generation for this hardware timer. - /// This method only sets the clock configuration to trigger - /// the interrupt; it does not configure the interrupt controller - /// or define an interrupt handler. - fn enable_interrupt(&mut self) { - self.tc.count_16().intenset.write(|w| w.ovf().set_bit()); - } /// Disables interrupt generation for this hardware timer. /// This method only sets the clock configuration to prevent diff --git a/hal/src/peripherals/trng.rs b/hal/src/peripherals/trng.rs index 226aa53c1f4d..35379b583c0a 100644 --- a/hal/src/peripherals/trng.rs +++ b/hal/src/peripherals/trng.rs @@ -2,8 +2,7 @@ use crate::pac::{MCLK, TRNG}; use rand_core::{CryptoRng, RngCore}; -#[cfg(feature = "unproven")] -use embedded_hal::blocking::rng::Read; +use crate::ehal_02::blocking::rng::Read; pub struct Trng(TRNG); @@ -63,7 +62,6 @@ impl RngCore for Trng { impl CryptoRng for Trng {} -#[cfg(feature = "unproven")] impl Read for Trng { type Error = (); fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> { diff --git a/hal/src/peripherals/watchdog.rs b/hal/src/peripherals/watchdog.rs index 9fbba9ac6489..1aee5d4dd926 100644 --- a/hal/src/peripherals/watchdog.rs +++ b/hal/src/peripherals/watchdog.rs @@ -1,4 +1,4 @@ -use crate::ehal::watchdog; +use crate::ehal_02::watchdog; use crate::pac::WDT; use atsamd_hal_macros::hal_macro_helper; diff --git a/hal/src/prelude.rs b/hal/src/prelude.rs index d4a5cb869188..e68cca365ac9 100644 --- a/hal/src/prelude.rs +++ b/hal/src/prelude.rs @@ -1,17 +1,13 @@ //! Import the prelude to gain convenient access to helper traits pub use crate::eic::pin::EicPin; -pub use crate::timer_traits::InterruptDrivenTimer as _atsamd_hal_timer_traits_InterruptDrivenTimer; +pub use crate::timer_traits::InterruptDrivenTimer; pub use fugit::ExtU32 as _; pub use fugit::RateExtU32 as _; // embedded-hal doesn’t yet have v2 in its prelude, so we need to // export it ourselves -#[cfg(feature = "unproven")] -pub use crate::ehal::digital::v2::InputPin as _atsamd_hal_embedded_hal_digital_v2_InputPin; -pub use crate::ehal::digital::v2::OutputPin as _atsamd_hal_embedded_hal_digital_v2_OutputPin; -#[cfg(feature = "unproven")] -pub use crate::ehal::digital::v2::ToggleableOutputPin as _atsamd_hal_embedded_hal_digital_v2_ToggleableOutputPin; +pub use crate::ehal_02::digital::v2::InputPin as _atsamd_hal_embedded_hal_digital_v2_InputPin; +pub use crate::ehal_02::digital::v2::OutputPin as _atsamd_hal_embedded_hal_digital_v2_OutputPin; +pub use crate::ehal_02::digital::v2::ToggleableOutputPin as _atsamd_hal_embedded_hal_digital_v2_ToggleableOutputPin; -pub use crate::ehal::prelude::*; - -pub use nb; +pub use crate::ehal_02::prelude::*; diff --git a/hal/src/rtc.rs b/hal/src/rtc.rs index 35937e6d2449..5259178abde8 100644 --- a/hal/src/rtc.rs +++ b/hal/src/rtc.rs @@ -1,14 +1,15 @@ //! Real-time clock/counter use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; +use fugit::NanosDurationU32; -use crate::ehal::timer::{CountDown, Periodic}; +use crate::ehal_02; use crate::pac::rtc::{MODE0, MODE2}; use crate::pac::RTC; use crate::time::{Hertz, Nanoseconds}; use crate::timer_traits::InterruptDrivenTimer; use crate::typelevel::Sealed; +use core::convert::Infallible; use core::marker::PhantomData; -use void::Void; #[cfg(feature = "sdmmc")] use embedded_sdmmc::{TimeSource, Timestamp}; @@ -277,7 +278,7 @@ impl Rtc { /// This resets the internal counter and sets the prescaler to match the /// provided timeout. You should configure the prescaler using the longest /// timeout you plan to measure. - pub fn reset_and_compute_prescaler::Time>>( + pub fn reset_and_compute_prescaler::Time>>( &mut self, timeout: T, ) -> &Self { @@ -344,13 +345,36 @@ impl Rtc { // --- Timer / Counter Functionality -impl Periodic for Rtc {} -impl CountDown for Rtc { +impl ehal_02::timer::Periodic for Rtc {} +impl ehal_02::timer::CountDown for Rtc { type Time = Nanoseconds; fn start(&mut self, timeout: T) where T: Into, + { + ::start(self, timeout); + } + + fn wait(&mut self) -> nb::Result<(), void::Void> { + // Unwrapping an unreacheable error is totally OK + ::wait(self).unwrap(); + Ok(()) + } +} + +impl InterruptDrivenTimer for Rtc { + /// Enable the interrupt generation for this hardware timer. + /// This method only sets the clock configuration to trigger + /// the interrupt; it does not configure the interrupt controller + /// or define an interrupt handler. + fn enable_interrupt(&mut self) { + self.mode0().intenset.write(|w| w.cmp0().set_bit()); + } + + fn start(&mut self, timeout: T) + where + T: Into, { let params = TimerParams::new_us(timeout, self.rtc_clock_freq); let divider = params.divider; @@ -376,7 +400,7 @@ impl CountDown for Rtc { }); } - fn wait(&mut self) -> nb::Result<(), Void> { + fn wait(&mut self) -> nb::Result<(), Infallible> { if self.mode0().intflag.read().cmp0().bit_is_set() { // Writing a 1 clears the flag self.mode0().intflag.modify(|_, w| w.cmp0().set_bit()); @@ -385,16 +409,6 @@ impl CountDown for Rtc { Err(nb::Error::WouldBlock) } } -} - -impl InterruptDrivenTimer for Rtc { - /// Enable the interrupt generation for this hardware timer. - /// This method only sets the clock configuration to trigger - /// the interrupt; it does not configure the interrupt controller - /// or define an interrupt handler. - fn enable_interrupt(&mut self) { - self.mode0().intenset.write(|w| w.cmp0().set_bit()); - } /// Disables interrupt generation for this hardware timer. /// This method only sets the clock configuration to prevent diff --git a/hal/src/sercom/i2c/impl_ehal.rs b/hal/src/sercom/i2c/impl_ehal.rs index c582c6dbb4fc..6b4c19297ae7 100644 --- a/hal/src/sercom/i2c/impl_ehal.rs +++ b/hal/src/sercom/i2c/impl_ehal.rs @@ -1,9 +1,71 @@ -//! `embedded-hal` trait implementations for [`I2c`]s +//! [`embedded-hal`] trait implementations for [`I2c`]s use super::{config::AnyConfig, flags::Error, I2c}; -use embedded_hal::blocking::i2c::{Read, Write, WriteRead}; +use crate::ehal::i2c::{self, ErrorKind, ErrorType, NoAcknowledgeSource}; -impl Write for I2c { +impl i2c::Error for Error { + fn kind(&self) -> ErrorKind { + match self { + Error::BusError => ErrorKind::Bus, + Error::ArbitrationLost => ErrorKind::ArbitrationLoss, + Error::LengthError => ErrorKind::Other, + Error::Nack => ErrorKind::NoAcknowledge(NoAcknowledgeSource::Unknown), + Error::Timeout => ErrorKind::Other, + } + } +} + +impl ErrorType for I2c { + type Error = Error; +} + +impl i2c::I2c for I2c { + fn transaction( + &mut self, + address: u8, + operations: &mut [i2c::Operation<'_>], + ) -> Result<(), Self::Error> { + for op in operations { + match op { + i2c::Operation::Read(buf) => { + self.do_read(address, buf)?; + self.cmd_stop(); + } + i2c::Operation::Write(bytes) => { + self.do_write(address, bytes)?; + self.cmd_stop(); + } + } + } + + Ok(()) + } + + fn write(&mut self, address: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.do_write(address, bytes)?; + self.cmd_stop(); + Ok(()) + } + + fn read(&mut self, address: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { + self.do_read(address, buffer)?; + self.cmd_stop(); + Ok(()) + } + + fn write_read( + &mut self, + address: u8, + bytes: &[u8], + buffer: &mut [u8], + ) -> Result<(), Self::Error> { + self.do_write_read(address, bytes, buffer)?; + self.cmd_stop(); + Ok(()) + } +} + +impl crate::ehal_02::blocking::i2c::Write for I2c { type Error = Error; fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { @@ -13,7 +75,7 @@ impl Write for I2c { } } -impl Read for I2c { +impl crate::ehal_02::blocking::i2c::Read for I2c { type Error = Error; fn read(&mut self, addr: u8, buffer: &mut [u8]) -> Result<(), Self::Error> { @@ -23,7 +85,7 @@ impl Read for I2c { } } -impl WriteRead for I2c { +impl crate::ehal_02::blocking::i2c::WriteRead for I2c { type Error = Error; fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { diff --git a/hal/src/sercom/spi.rs b/hal/src/sercom/spi.rs index 2a479a044800..356cff25f54b 100644 --- a/hal/src/sercom/spi.rs +++ b/hal/src/sercom/spi.rs @@ -242,16 +242,16 @@ //! //! Only `Spi` structs can actually perform transactions. To do so, use the //! various embedded HAL traits, like -//! [`spi::FullDuplex`](embedded_hal::spi::FullDuplex), -//! [`serial::Read`](embedded_hal::serial::Read) or -//! [`serial::Write`](embedded_hal::serial::Write). +//! [`spi::FullDuplex`](crate::ehal_02::spi::FullDuplex), +//! [`serial::Read`](crate::ehal_02::serial::Read) or +//! [`serial::Write`](crate::ehal_02::serial::Write). //! See the [`impl_ehal`] module documentation for more details about the //! specific trait implementations, which vary based on [`Size`] and //! [`Capability`]. //! //! ``` //! use nb::block; -//! use embedded_hal::spi::FullDuplex; +//! use crate::ehal_02::spi::FullDuplex; //! //! block!(spi.send(0xAA55)); //! let rcvd: u16 = block!(spi.read()); @@ -304,9 +304,10 @@ use atsamd_hal_macros::{hal_cfg, hal_docs, hal_macro_helper, hal_module}; use core::marker::PhantomData; use bitflags::bitflags; -use embedded_hal::spi; -pub use embedded_hal::spi::{Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +use num_traits::AsPrimitive; +use crate::ehal; +pub use crate::ehal::spi::{Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use crate::sercom::{pad::SomePad, Sercom, APB_CLK_CTRL}; use crate::time::Hertz; use crate::typelevel::{Is, NoneT, Sealed}; @@ -347,11 +348,7 @@ pub mod lengths { }); } -#[hal_module( - any("sercom0-d11", "sercom0-d21") => "spi/impl_ehal_thumbv6m.rs", - "sercom0-d5x" => "spi/impl_ehal_thumbv7em.rs", -)] -pub mod impl_ehal {} +pub mod impl_ehal; //============================================================================= // BitOrder @@ -628,6 +625,7 @@ where mode: PhantomData, size: PhantomData, freq: Hertz, + nop_word: DataWidth, } impl Config

{ @@ -649,6 +647,7 @@ impl Config

{ mode: PhantomData, size: PhantomData, freq: freq.into(), + nop_word: 0x00.as_(), } } @@ -715,6 +714,7 @@ where mode: PhantomData, size: PhantomData, freq: self.freq, + nop_word: self.nop_word, } } @@ -819,19 +819,19 @@ where /// Get the SPI mode (clock polarity & phase) #[inline] - pub fn get_spi_mode(&self) -> spi::Mode { + pub fn get_spi_mode(&self) -> ehal::spi::Mode { self.regs.get_spi_mode() } /// Set the SPI mode (clock polarity & phase) #[inline] - pub fn set_spi_mode(&mut self, mode: spi::Mode) { + pub fn set_spi_mode(&mut self, mode: ehal::spi::Mode) { self.regs.set_spi_mode(mode); } /// Set the SPI mode (clock polarity & phase) using the builder pattern #[inline] - pub fn spi_mode(mut self, mode: spi::Mode) -> Self { + pub fn spi_mode(mut self, mode: ehal::spi::Mode) -> Self { self.set_spi_mode(mode); self } @@ -866,6 +866,31 @@ where self } + /// Get the NOP word + /// + /// This word is used when reading in Duplex mode, since an equal number of + /// words must be sent in order to avoid overflow errors. + pub fn get_nop_word(&self) -> DataWidth { + self.nop_word + } + + /// Set the NOP word + /// + /// This word is used when reading in Duplex mode, since an equal number of + /// words must be sent in order to avoid overflow errors. + pub fn set_nop_word(&mut self, nop_word: DataWidth) { + self.nop_word = nop_word; + } + + /// Set the NOP word using the builder pattern + /// + /// This word is used when reading in Duplex mode, since an equal number of + /// words must be sent in order to avoid overflow errors. + pub fn nop_word(mut self, nop_word: DataWidth) -> Self { + self.nop_word = nop_word; + self + } + /// Get the baud rate /// /// The returned baud rate may not exactly match what was set. @@ -1271,6 +1296,19 @@ where self.config.as_mut().regs.disable(); self.config } + + /// Block until at least one of the flags specified in `flags`, or `ERROR`, + /// is set. + /// + /// # Returns `Err(Error)` if an error is detected. + fn block_on_flags(&mut self, flags: Flags) -> Result<(), Error> { + while !self.read_flags().intersects(flags | Flags::ERROR) { + core::hint::spin_loop(); + } + + self.read_flags_errors()?; + Ok(()) + } } #[hal_cfg("sercom0-d5x")] diff --git a/hal/src/sercom/spi/char_size.rs b/hal/src/sercom/spi/char_size.rs index 19945a6d4465..49e4c729ca89 100644 --- a/hal/src/sercom/spi/char_size.rs +++ b/hal/src/sercom/spi/char_size.rs @@ -24,7 +24,7 @@ use crate::typelevel::Sealed; /// [type-level function]: crate::typelevel#type-level-functions pub trait CharSize: Sealed { /// Word size for the character size - type Word: 'static; + type Word: 'static + Copy; /// Register bit pattern for the corresponding `CharSize` const BITS: u8; diff --git a/hal/src/sercom/spi/impl_ehal.rs b/hal/src/sercom/spi/impl_ehal.rs new file mode 100644 index 000000000000..5f396f9cd24f --- /dev/null +++ b/hal/src/sercom/spi/impl_ehal.rs @@ -0,0 +1,121 @@ +use super::*; +use crate::ehal::spi::{self, ErrorType, SpiBus}; +#[allow(unused_imports)] +use crate::ehal_02::{blocking, serial}; +use num_traits::PrimInt; + +#[hal_module( + any("sercom0-d11", "sercom0-d21") => "impl_ehal_thumbv6m.rs", + "sercom0-d5x" => "impl_ehal_thumbv7em.rs" +)] +pub mod impl_ehal_02 {} + +impl spi::Error for Error { + fn kind(&self) -> crate::ehal::spi::ErrorKind { + match self { + Error::Overflow => crate::ehal::spi::ErrorKind::Overrun, + Error::LengthError => crate::ehal::spi::ErrorKind::Other, + } + } +} + +impl ErrorType for Spi +where + C: ValidConfig, + D: Capability, +{ + type Error = Error; +} + +impl Spi, Duplex> +where + Config: ValidConfig, + P: ValidPads, + M: MasterMode, + C: Size + 'static, + C::Word: PrimInt + AsPrimitive, + DataWidth: AsPrimitive, +{ + /// Read and write a single word to the bus simultaneously. + fn transfer_word_in_place(&mut self, word: C::Word) -> Result { + self.block_on_flags(Flags::DRE)?; + + unsafe { + self.write_data(word.as_()); + } + + self.block_on_flags(Flags::TXC | Flags::RXC)?; + let word = unsafe { self.read_data().as_() }; + Ok(word) + } + + /// Perform a transfer, word by word. + /// + /// No-op words will be written if `read` is longer than `write`. Extra + /// words are ignored if `write` is longer than `read`. + fn transfer_word_by_word( + &mut self, + read: &mut [C::Word], + write: &[C::Word], + ) -> Result<(), Error> { + let nop_word = self.config.nop_word; + for (r, w) in read + .iter_mut() + .zip(write.iter().chain(core::iter::repeat(&nop_word.as_()))) + { + *r = self.transfer_word_in_place(*w)?; + } + + Ok(()) + } +} + +impl SpiBus> for Spi, Duplex> +where + Config: ValidConfig, + P: ValidPads, + M: MasterMode, + C: Size + 'static, + C::Word: PrimInt + AsPrimitive + Copy, + DataWidth: AsPrimitive, +{ + fn read(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { + for word in words.iter_mut() { + *word = self.transfer_word_in_place(self.config.nop_word.as_())?; + } + + Ok(()) + } + + #[inline] + fn write(&mut self, words: &[Word]) -> Result<(), Self::Error> { + // We are `Duplex`, so we must receive as many words as we send, + // otherwise we could trigger an overflow + for word in words { + let _ = self.transfer_word_in_place(*word)?; + } + Ok(()) + } + + #[inline] + fn transfer(&mut self, read: &mut [Word], write: &[Word]) -> Result<(), Self::Error> { + self.transfer_word_by_word(read, write) + } + + #[inline] + fn transfer_in_place<'w>(&mut self, words: &mut [Word]) -> Result<(), Self::Error> { + for word in words { + let read = self.transfer_word_in_place(*word)?; + *word = read; + } + + Ok(()) + } + + #[inline] + fn flush(&mut self) -> Result<(), Error> { + // Ignore buffer overflow errors + let _ = self.block_on_flags(Flags::TXC); + Ok(()) + } +} diff --git a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs index ebf502ac5fc1..b212651d92cb 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv6m.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv6m.rs @@ -68,33 +68,63 @@ //! These traits are implemented following all of the rules outlined above for //! the different [`Size`] and [`Capability`] options. -use embedded_hal::{blocking, serial, spi}; +use super::*; +use crate::ehal_nb; use nb::Error::WouldBlock; use num_traits::{AsPrimitive, PrimInt}; -use super::*; +impl ehal_nb::serial::Error for Error { + fn kind(&self) -> ehal_nb::serial::ErrorKind { + match self { + Error::Overflow => ehal_nb::serial::ErrorKind::Overrun, + Error::LengthError => ehal_nb::serial::ErrorKind::Other, + } + } +} + +impl ehal_nb::serial::ErrorType for Spi +where + C: ValidConfig, + D: Capability, +{ + type Error = Error; +} + +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl embedded_io::ErrorType for Spi +where + C: ValidConfig, + D: Capability, +{ + type Error = Error; +} //============================================================================= // serial::Read //============================================================================= -/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] +/// Implement [`Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] /// -/// `serial::Read` is only implemented for `Spi` structs with `Rx` +/// [`Read`] is only implemented for `Spi` structs with `Rx` /// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so /// it keeps track of the transaction state. If a transaction is in progress, /// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`. -impl serial::Read for Spi, Rx> +/// +/// [`Read`]: ehal_nb::serial::Read +impl ehal_nb::serial::Read for Spi, Rx> where Config: ValidConfig, P: ValidPads, M: MasterMode, C: CharSize, C::Word: PrimInt, - u16: AsPrimitive, + DataWidth: AsPrimitive, { - type Error = Error; - #[inline] fn read(&mut self) -> nb::Result { let in_progress = self.capability.in_progress; @@ -112,23 +142,48 @@ where } } -/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`] +/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] +/// +/// [`Read`] is only implemented for `Spi` structs with `Rx` +/// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so +/// it keeps track of the transaction state. If a transaction is in progress, +/// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`. +/// +/// [`Read`]: crate::ehal_02::serial::Read +impl serial::Read for Spi, Rx> +where + Config: ValidConfig, + P: ValidPads, + M: MasterMode, + C: CharSize, + C::Word: PrimInt, + DataWidth: AsPrimitive, +{ + type Error = Error; + + #[inline] + fn read(&mut self) -> nb::Result { + >::read(self) + } +} + +/// Implement [`Read`] for [`Rx`] [`Spi`] structs in [`Slave`] /// [`OpMode`] /// -/// `serial::Read` is only implemented for `Spi` structs with `Rx` +/// [`Read`] is only implemented for `Spi` structs with `Rx` /// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate /// transactions, so it does not have to store any internal state. It only has /// to wait on `RXC`. -impl serial::Read for Spi, Rx> +/// +/// [`Read`]: ehal_nb::serial::Read +impl ehal_nb::serial::Read for Spi, Rx> where Config: ValidConfig, P: ValidPads, C: CharSize, C::Word: PrimInt, - u16: AsPrimitive, + DataWidth: AsPrimitive, { - type Error = Error; - /// Wait for an `RXC` flag, then read the word #[inline] fn read(&mut self) -> nb::Result { @@ -141,22 +196,87 @@ where } } +/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`] +/// [`OpMode`] +/// +/// [`serial::Read`] is only implemented for `Spi` structs with `Rx` +/// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate +/// transactions, so it does not have to store any internal state. It only has +/// to wait on `RXC`. +impl serial::Read for Spi, Rx> +where + Config: ValidConfig, + P: ValidPads, + C: CharSize, + C::Word: PrimInt, + DataWidth: AsPrimitive, +{ + type Error = Error; + + /// Wait for an `RXC` flag, then read the word + #[inline] + fn read(&mut self) -> nb::Result { + >::read(self) + } +} + +//============================================================================= +// embedded_io::Read +//============================================================================= +impl embedded_io::Read for Spi, Rx> +where + Config: ValidConfig, + P: ValidPads, + M: MasterMode, +{ + fn read(&mut self, buf: &mut [u8]) -> Result { + for byte in buf.iter_mut() { + let w = nb::block!(::read(self))?; + *byte = w; + } + + Ok(buf.len()) + } +} + +impl

embedded_io::Read for Spi, Rx> +where + Config: ValidConfig, + P: ValidPads, +{ + fn read(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); + }; + + for byte in buf.iter_mut() { + let w = nb::block!(::read(self))?; + *byte = w; + } + + Ok(buf.len()) + } +} + //============================================================================= // serial::Write //============================================================================= -/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs +/// Implement [`Write`] for [`Tx`] [`Spi`] structs /// -/// `serial::Write` is only implemented for `Spi` structs with `Tx` +/// [`Write`] is only implemented for `Spi` structs with `Tx` /// [`Capability`]. Because the `Capability` is `Tx`, this implementation never /// reads the DATA register and ignores all buffer overflow errors. -impl serial::Write for Spi +/// +/// [`Write`]: ehal_nb::serial::Write +impl ehal_nb::serial::Write for Spi, Tx> where - C: ValidConfig, - C::Word: PrimInt + AsPrimitive, + Config: ValidConfig, + P: ValidPads, + M: OpMode, + C: CharSize, + C::Word: PrimInt + AsPrimitive, { - type Error = Error; - #[inline] fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { // Ignore buffer overflow errors @@ -179,6 +299,32 @@ where } } +/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs +/// +/// `serial::Write` is only implemented for `Spi` structs with `Tx` +/// [`Capability`]. Because the `Capability` is `Tx`, this implementation never +/// reads the DATA register and ignores all buffer overflow errors. +impl serial::Write for Spi, Tx> +where + Config: ValidConfig, + P: ValidPads, + M: OpMode, + C: CharSize, + C::Word: PrimInt + AsPrimitive, +{ + type Error = Error; + + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { + >::write(self, word) + } + + #[inline] + fn flush(&mut self) -> nb::Result<(), Error> { + >::flush(self) + } +} + //============================================================================= // blocking::serial::Write //============================================================================= @@ -190,6 +336,28 @@ where { } +//============================================================================= +// embedded_io::Write +//============================================================================= +impl embedded_io::Write for Spi, Tx> +where + Config: ValidConfig, + P: ValidPads, + M: OpMode, +{ + fn write(&mut self, buf: &[u8]) -> Result { + for byte in buf { + nb::block!(::write(self, *byte))?; + } + + Ok(buf.len()) + } + + fn flush(&mut self) -> Result<(), Self::Error> { + nb::block!(::flush(self)) + } +} + //============================================================================= // spi::FullDuplex //============================================================================= @@ -199,7 +367,40 @@ where /// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`] /// [`Capability`]. The [`Word`] size used in the implementation depends on the /// corresponding [`CharSize`]. -impl spi::FullDuplex for Spi +impl ehal_nb::spi::FullDuplex for Spi +where + C: ValidConfig, + C::Word: PrimInt + AsPrimitive, + u16: AsPrimitive, +{ + #[inline] + fn read(&mut self) -> nb::Result { + let flags = self.read_flags_errors()?; + if flags.contains(Flags::RXC) { + unsafe { Ok(self.read_data().as_()) } + } else { + Err(WouldBlock) + } + } + + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Self::Error> { + let flags = self.read_flags_errors()?; + if flags.contains(Flags::DRE) { + unsafe { self.write_data(word.as_()) }; + Ok(()) + } else { + Err(WouldBlock) + } + } +} + +/// Implement [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`] +/// +/// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`] +/// [`Capability`]. The [`Word`] size used in the implementation depends on the +/// corresponding [`CharSize`]. +impl crate::ehal_02::spi::FullDuplex for Spi where C: ValidConfig, C::Word: PrimInt + AsPrimitive, @@ -383,7 +584,6 @@ impl_blocking_spi_write!(EightBit, NineBit); // blocking::spi::WriteIter //============================================================================= -#[cfg(feature = "unproven")] macro_rules! impl_blocking_spi_write_iter { ( $($CharSize:ident),+ ) => { $( @@ -473,5 +673,4 @@ macro_rules! impl_blocking_spi_write_iter { }; } -#[cfg(feature = "unproven")] impl_blocking_spi_write_iter!(EightBit, NineBit); diff --git a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs index dfa8f321ca45..8b106e637086 100644 --- a/hal/src/sercom/spi/impl_ehal_thumbv7em.rs +++ b/hal/src/sercom/spi/impl_ehal_thumbv7em.rs @@ -90,38 +90,69 @@ //! These traits are implemented following all of the rules outlined above for //! the different [`Size`] and [`Capability`] options. -use embedded_hal::{blocking, serial, spi}; +use crate::ehal_02; +use crate::ehal_nb; +use crate::sercom::spi::{ + AtomicSize, Capability, Config, DataWidth, Duplex, DynLength, Error, Flags, GreaterThan4, + Length, MasterMode, OpMode, Receive, Rx, Slave, Spi, Status, Tx, ValidConfig, ValidPads, Word, +}; use nb::Error::WouldBlock; use num_traits::{AsPrimitive, PrimInt}; use typenum::{U1, U2, U3, U4}; use crate::pac::sercom0::RegisterBlock; -use super::*; +impl ehal_nb::serial::Error for Error { + fn kind(&self) -> ehal_nb::serial::ErrorKind { + match self { + Error::Overflow => ehal_nb::serial::ErrorKind::Overrun, + Error::LengthError => ehal_nb::serial::ErrorKind::Other, + } + } +} + +impl ehal_nb::serial::ErrorType for Spi +where + C: ValidConfig, + D: Capability, +{ + type Error = Error; +} + +impl embedded_io::Error for Error { + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl embedded_io::ErrorType for Spi +where + C: ValidConfig, + D: Capability, +{ + type Error = Error; +} //============================================================================= // serial::Read //============================================================================= -/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] +/// Implement [`ehal_nb::serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] /// /// `serial::Read` is only implemented for `Spi` structs with `Rx` /// [`Capability`]. In a `MasterMode`, `Read` has to initiate transactions, so /// it keeps track of the transaction state. If a transaction is in progress, /// it will wait on `RXC`. If not, it will wait on `DRE`, and then send `0`. -impl serial::Read for Spi, Rx> +impl ehal_nb::serial::Read for Spi, Rx> where Config: ValidConfig, P: ValidPads, M: MasterMode, L: Length, L::Word: PrimInt, - u32: AsPrimitive, + DataWidth: AsPrimitive, { - type Error = Error; - - #[inline] - fn read(&mut self) -> nb::Result { + fn read(&mut self) -> nb::Result { let in_progress = self.capability.in_progress; let flags = self.read_flags_errors()?; if !in_progress && flags.contains(Flags::DRE) { @@ -137,6 +168,26 @@ where } } +/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in a [`MasterMode`] +/// +/// Refer to the [`ehal_nb::serial::Read`] implementation of [`Spi`] for more details. +impl ehal_02::serial::Read for Spi, Rx> +where + Config: ValidConfig, + P: ValidPads, + M: MasterMode, + L: Length, + L::Word: PrimInt, + DataWidth: AsPrimitive, +{ + type Error = Error; + + #[inline] + fn read(&mut self) -> nb::Result { + >::read(self) + } +} + /// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`] /// [`OpMode`] /// @@ -144,16 +195,14 @@ where /// [`Capability`]. In `Slave` `OpMode`, `Read` does not have to initiate /// transactions, so it does not have to store any internal state. It only has /// to wait on `RXC`. -impl serial::Read for Spi, Rx> +impl ehal_nb::serial::Read for Spi, Rx> where Config: ValidConfig, P: ValidPads, L: Length, L::Word: PrimInt, - u32: AsPrimitive, + DataWidth: AsPrimitive, { - type Error = Error; - #[inline] fn read(&mut self) -> nb::Result { let flags = self.read_flags_errors()?; @@ -165,23 +214,41 @@ where } } +/// Implement [`serial::Read`] for [`Rx`] [`Spi`] structs in [`Slave`] +/// [`OpMode`] +/// +/// Refer to the [`ehal_nb::serial::Read`] implementation of [`Spi`] for more details. +impl ehal_02::serial::Read for Spi, Rx> +where + Config: ValidConfig, + P: ValidPads, + L: Length, + L::Word: PrimInt, + DataWidth: AsPrimitive, +{ + type Error = Error; + + #[inline] + fn read(&mut self) -> nb::Result { + >::read(self) + } +} + //============================================================================= // serial::Write //============================================================================= -/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs +/// Implement [`ehal_nb::serial::Write`] for [`Tx`] [`Spi`] structs /// /// `serial::Write` is only implemented for `Spi` structs with `Tx` /// [`Capability`]. Because the `Capability` is `Tx`, this implementation never /// reads the DATA register and ignores all buffer overflow errors. -impl serial::Write for Spi +impl ehal_nb::serial::Write for Spi where C: ValidConfig, C::Size: AtomicSize, - C::Word: PrimInt + AsPrimitive, + C::Word: PrimInt + AsPrimitive, { - type Error = Error; - #[inline] fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { // Ignore buffer overflow errors @@ -208,14 +275,34 @@ where } } +/// Implement [`serial::Write`] for [`Tx`] [`Spi`] structs +impl ehal_02::serial::Write for Spi +where + C: ValidConfig, + C::Size: AtomicSize, + C::Word: PrimInt + AsPrimitive, +{ + type Error = Error; + + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { + >::write(self, word) + } + + #[inline] + fn flush(&mut self) -> nb::Result<(), Error> { + >::flush(self) + } +} + //============================================================================= // blocking::serial::Write //============================================================================= -impl blocking::serial::write::Default for Spi +impl ehal_02::blocking::serial::write::Default for Spi where C: ValidConfig, - Spi: serial::Write, + Spi: ehal_02::serial::Write, { } @@ -223,18 +310,53 @@ where // spi::FullDuplex //============================================================================= +// Implement [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`] +/// +/// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`] +/// [`Capability`] and the transaction [`Length`] is `<= 4` bytes. When the +/// [`Length`] is `<= 4`, the [`Word`] is a primitive integer, with a size that +/// depends on the [`Length`] (`u8`, `u16` or `u32`). +impl ehal_nb::spi::FullDuplex for Spi +where + C: ValidConfig, + C::Size: AtomicSize, + C::Word: PrimInt + AsPrimitive, + DataWidth: AsPrimitive, +{ + #[inline] + fn read(&mut self) -> nb::Result { + let flags = self.read_flags_errors()?; + if flags.contains(Flags::RXC) { + Ok(self.config.as_mut().regs.read_data().as_()) + } else { + Err(WouldBlock) + } + } + + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Error> { + let flags = self.read_flags_errors()?; + if flags.contains(Flags::DRE) { + self.config.as_mut().regs.write_data(word.as_()); + Ok(()) + } else { + Err(WouldBlock) + } + } +} + /// Implement [`spi::FullDuplex`] for [`Spi`] structs with [`AtomicSize`] /// /// `spi::FullDuplex` is only implemented when the `Spi` struct has [`Duplex`] /// [`Capability`] and the transaction [`Length`] is `<= 4` bytes. When the /// [`Length`] is `<= 4`, the [`Word`] is a primitive integer, with a size that /// depends on the [`Length`] (`u8`, `u16` or `u32`). -impl spi::FullDuplex for Spi +impl ehal_02::spi::FullDuplex for Spi where C: ValidConfig, C::Size: AtomicSize, - C::Word: PrimInt + AsPrimitive, - u32: AsPrimitive, + C::Word: PrimInt + AsPrimitive, + DataWidth: AsPrimitive, { type Error = Error; @@ -276,7 +398,7 @@ macro_rules! impl_blocking_spi_transfer { /// (`u8`, `u16` or `u32`). /// /// [`Transfer`]: blocking::spi::Transfer - impl blocking::spi::Transfer> for Spi, A> + impl $crate::ehal_02::blocking::spi::Transfer> for Spi, A> where Config: ValidConfig, P: ValidPads, @@ -297,7 +419,7 @@ macro_rules! impl_blocking_spi_transfer { Some(cell) => cell.get(), None => unreachable!(), }; - self.config.as_mut().regs.write_data(word as u32); + self.config.as_mut().regs.write_data(word as DataWidth); } if to_recv.len() > to_send.len() && flags.contains(Flags::RXC) { let word = self.config.as_mut().regs.read_data() as Word<$Length>; @@ -324,7 +446,7 @@ impl_blocking_spi_transfer!(U1, U2, U3, U4); /// is incorrect, it will panic. /// /// [`Transfer`]: blocking::spi::Transfer -impl blocking::spi::Transfer for Spi, A> +impl ehal_02::blocking::spi::Transfer for Spi, A> where Config: ValidConfig, P: ValidPads, @@ -350,7 +472,7 @@ where /// of [`Spi::get_dyn_length`], it will panic. /// /// [`Transfer`]: blocking::spi::Transfer -impl blocking::spi::Transfer for Spi, A> +impl ehal_02::blocking::spi::Transfer for Spi, A> where Config: ValidConfig, P: ValidPads, @@ -383,7 +505,7 @@ macro_rules! impl_blocking_spi_write { /// (`u8`, `u16` or `u32`). /// /// [`Write`]: blocking::spi::Write - impl blocking::spi::Write> for Spi, Duplex> + impl $crate::ehal_02::blocking::spi::Write> for Spi, Duplex> where Config: ValidConfig, P: ValidPads, @@ -404,7 +526,7 @@ macro_rules! impl_blocking_spi_write { Some(word) => *word, None => unreachable!(), }; - self.config.as_mut().regs.write_data(word as u32); + self.config.as_mut().regs.write_data(word as DataWidth); } if to_recv > to_send.len() && flags.contains(Flags::RXC) { self.config.as_mut().regs.read_data() as Word<$Length>; @@ -426,7 +548,7 @@ macro_rules! impl_blocking_spi_write { /// reads the DATA register and ignores all buffer overflow errors. /// /// [`Write`]: blocking::spi::Write - impl blocking::spi::Write> for Spi, Tx> + impl $crate::ehal_02::blocking::spi::Write> for Spi, Tx> where Config: ValidConfig, P: ValidPads, @@ -443,7 +565,7 @@ macro_rules! impl_blocking_spi_write { if self.read_status().contains(Status::LENERR) { return Err(Error::LengthError) } else if self.read_flags().contains(Flags::DRE) { - self.config.as_mut().regs.write_data(*word as u32); + self.config.as_mut().regs.write_data(*word as DataWidth); break } } @@ -465,7 +587,7 @@ impl_blocking_spi_write!(U1, U2, U3, U4); /// it will panic. /// /// [`Write`]: blocking::spi::Write -impl blocking::spi::Write for Spi, Duplex> +impl ehal_02::blocking::spi::Write for Spi, Duplex> where Config: ValidConfig, P: ValidPads, @@ -495,7 +617,7 @@ where /// register and ignores all buffer overflow errors. /// /// [`Write`]: blocking::spi::Write -impl blocking::spi::Write for Spi, Tx> +impl ehal_02::blocking::spi::Write for Spi, Tx> where Config: ValidConfig, P: ValidPads, @@ -522,7 +644,7 @@ where /// [`Spi::get_dyn_length`], it will panic. /// /// [`Write`]: blocking::spi::Write -impl blocking::spi::Write for Spi, Duplex> +impl ehal_02::blocking::spi::Write for Spi, Duplex> where Config: ValidConfig, P: ValidPads, @@ -551,7 +673,7 @@ where /// register and ignores all buffer overflow errors. /// /// [`Write`]: blocking::spi::Write -impl blocking::spi::Write for Spi, Tx> +impl ehal_02::blocking::spi::Write for Spi, Tx> where Config: ValidConfig, P: ValidPads, @@ -585,8 +707,7 @@ macro_rules! impl_blocking_spi_write_iter { /// (`u8`, `u16` or `u32`). /// /// [`WriteIter`]: blocking::spi::WriteIter - #[cfg(feature = "unproven")] - impl blocking::spi::WriteIter> for Spi, Duplex> + impl $crate::ehal_02::blocking::spi::WriteIter> for Spi, Duplex> where Config: ValidConfig, P: ValidPads, @@ -607,7 +728,7 @@ macro_rules! impl_blocking_spi_write_iter { loop { let flags = self.read_flags_errors()?; if flags.contains(Flags::DRE) { - unsafe { self.write_data(word as u32) }; + unsafe { self.write_data(word as DataWidth) }; break } } @@ -633,8 +754,7 @@ macro_rules! impl_blocking_spi_write_iter { /// reads the DATA register and ignores all buffer overflow errors. /// /// [`WriteIter`]: blocking::spi::WriteIter - #[cfg(feature = "unproven")] - impl blocking::spi::WriteIter> for Spi, Tx> + impl $crate::ehal_02::blocking::spi::WriteIter> for Spi, Tx> where Config: ValidConfig, P: ValidPads, @@ -654,7 +774,7 @@ macro_rules! impl_blocking_spi_write_iter { if self.read_status().contains(Status::LENERR) { return Err(Error::LengthError) } else if self.read_flags().contains(Flags::DRE) { - unsafe { self.write_data(word as u32) }; + unsafe { self.write_data(word as DataWidth) }; break } } diff --git a/hal/src/sercom/spi/reg.rs b/hal/src/sercom/spi/reg.rs index d5cd15a6ca6d..f8dcf0f0f487 100644 --- a/hal/src/sercom/spi/reg.rs +++ b/hal/src/sercom/spi/reg.rs @@ -1,6 +1,6 @@ use atsamd_hal_macros::{hal_cfg, hal_macro_helper}; -use embedded_hal::spi; +use crate::ehal; #[hal_cfg(any("sercom0-d11", "sercom0-d21"))] use crate::pac::sercom0::SPI; @@ -160,7 +160,7 @@ impl Registers { /// Get the SPI mode (clock polarity & phase) #[inline] - pub fn get_spi_mode(&self) -> spi::Mode { + pub fn get_spi_mode(&self) -> ehal::spi::Mode { let reg = self.spi().ctrla.read(); let cpol = reg.cpol().bit(); let cpha = reg.cpha().bit(); @@ -172,12 +172,12 @@ impl Registers { false => Phase::CaptureOnFirstTransition, true => Phase::CaptureOnSecondTransition, }; - spi::Mode { polarity, phase } + ehal::spi::Mode { polarity, phase } } /// Set the SPI mode (clock polarity & phase) #[inline] - pub fn set_spi_mode(&mut self, mode: spi::Mode) { + pub fn set_spi_mode(&mut self, mode: ehal::spi::Mode) { let cpol = match mode.polarity { Polarity::IdleLow => false, Polarity::IdleHigh => true, diff --git a/hal/src/sercom/spi_future.rs b/hal/src/sercom/spi_future.rs index b7158f6ae94b..582dee590686 100644 --- a/hal/src/sercom/spi_future.rs +++ b/hal/src/sercom/spi_future.rs @@ -177,7 +177,7 @@ use atsamd_hal_macros::hal_cfg; use core::convert::Infallible; use core::task::Poll; -use embedded_hal::digital::v2::OutputPin; +use crate::ehal_02::digital::v2::OutputPin; use crate::gpio::pin::{OptionalPin, SomePin}; use crate::typelevel::NoneT; diff --git a/hal/src/sercom/uart/charsize.rs b/hal/src/sercom/uart/charsize.rs index b334373ade5e..187c3ea95c60 100644 --- a/hal/src/sercom/uart/charsize.rs +++ b/hal/src/sercom/uart/charsize.rs @@ -11,7 +11,7 @@ use num_traits::{AsPrimitive, PrimInt}; /// use a `u16` word. pub trait CharSize: Sealed { /// Word size for the character size - type Word: 'static + PrimInt + AsPrimitive; + type Word: 'static + PrimInt + AsPrimitive + Copy; } /// Type-level `enum` indicating a [`CharSize`] that is not dynamic diff --git a/hal/src/sercom/uart/impl_ehal.rs b/hal/src/sercom/uart/impl_ehal.rs index 67626fff51b8..f2bbf41a87c3 100644 --- a/hal/src/sercom/uart/impl_ehal.rs +++ b/hal/src/sercom/uart/impl_ehal.rs @@ -1,7 +1,10 @@ //! `embedded-hal` trait implementations for [`Uart`]s -use super::{DataReg, Error, Flags, Receive, Transmit, Uart, ValidConfig}; -use embedded_hal::{ +use super::{ + Capability, Config, DataReg, EightBit, Error, Error as UartError, Flags, Receive, Transmit, + Uart, ValidConfig, ValidPads, +}; +use crate::ehal_02::{ blocking, serial::{Read, Write}, }; @@ -19,6 +22,129 @@ where /// Wait for an `RXC` flag, then read the word #[inline] fn read(&mut self) -> nb::Result { + >::read(self) + } +} + +impl Write for Uart +where + C: ValidConfig, + D: Transmit, +{ + type Error = UartError; + + /// Wait for a `DRE` flag, then write a word + #[inline] + fn write(&mut self, word: C::Word) -> nb::Result<(), Self::Error> { + >::write(self, word) + } + + /// Wait for a `TXC` flag + #[inline] + fn flush(&mut self) -> nb::Result<(), Self::Error> { + >::flush(self) + } +} + +impl blocking::serial::write::Default for Uart +where + C: ValidConfig, + D: Transmit, + Uart: Write, +{ +} + +impl embedded_io::Error for UartError { + #[inline] + fn kind(&self) -> embedded_io::ErrorKind { + embedded_io::ErrorKind::Other + } +} + +impl embedded_io::ErrorType for Uart +where + C: ValidConfig, + D: Capability, +{ + type Error = UartError; +} + +impl embedded_io::Write for Uart, D> +where + P: ValidPads, + D: Transmit, +{ + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + for word in buf { + nb::block!(>::write( + self, *word + ))?; + } + + Ok(buf.len()) + } + + /// Wait for a `TXC` flag + #[inline] + fn flush(&mut self) -> Result<(), Self::Error> { + nb::block!(>::flush(self))?; + Ok(()) + } +} + +impl embedded_io::Read for Uart, D> +where + P: ValidPads, + D: Receive, +{ + #[inline] + fn read(&mut self, buf: &mut [u8]) -> Result { + if buf.is_empty() { + return Ok(0); + } + + for byte in buf.iter_mut() { + let w = nb::block!(>::read(self))?; + *byte = w; + } + + Ok(buf.len()) + } +} + +impl embedded_hal_nb::serial::Error for UartError { + #[inline] + fn kind(&self) -> embedded_hal_nb::serial::ErrorKind { + use embedded_hal_nb::serial::ErrorKind; + + match self { + Self::ParityError => ErrorKind::Parity, + Self::FrameError => ErrorKind::FrameFormat, + Self::Overflow => ErrorKind::Overrun, + _ => ErrorKind::Other, + } + } +} + +impl embedded_hal_nb::serial::ErrorType for Uart +where + C: ValidConfig, + W: Copy, + D: Capability, +{ + type Error = UartError; +} + +impl embedded_hal_nb::serial::Read for Uart +where + C: ValidConfig, + D: Receive, + DataReg: AsPrimitive, +{ + #[inline] + fn read(&mut self) -> nb::Result { + // Wait for an `RXC` flag, then read the word let flags = self.read_flags_errors()?; if flags.contains(Flags::RXC) { unsafe { Ok(self.read_data().as_()) } @@ -28,13 +154,11 @@ where } } -impl Write for Uart +impl embedded_hal_nb::serial::Write for Uart where C: ValidConfig, D: Transmit, { - type Error = core::convert::Infallible; - /// Wait for a `DRE` flag, then write a word #[inline] fn write(&mut self, word: C::Word) -> nb::Result<(), Self::Error> { @@ -57,11 +181,3 @@ where } } } - -impl blocking::serial::write::Default for Uart -where - C: ValidConfig, - D: Transmit, - Uart: Write, -{ -} diff --git a/hal/src/sleeping_delay.rs b/hal/src/sleeping_delay.rs index fb27b220fc53..515c6749dfb1 100644 --- a/hal/src/sleeping_delay.rs +++ b/hal/src/sleeping_delay.rs @@ -3,10 +3,11 @@ use core::sync::atomic; use cortex_m::asm; use fugit::ExtU32; -use crate::ehal::blocking::delay::{DelayMs, DelayUs}; +use crate::ehal::delay::DelayNs; +use crate::ehal_02; use crate::timer_traits::InterruptDrivenTimer; -const NUM_US_IN_S: u32 = 1_000_000; +const NUM_NS_IN_S: u32 = 1_000_000_000; /// Delay and sleep while we do (WFI) using a timer pub struct SleepingDelay { @@ -35,28 +36,42 @@ where } } -impl DelayUs for SleepingDelay +impl ehal_02::blocking::delay::DelayUs for SleepingDelay where TIM: InterruptDrivenTimer, TYPE: Into, { fn delay_us(&mut self, us: TYPE) { - let us: u32 = us.into(); + ::delay_us(self, us.into()); + } +} + +impl ehal_02::blocking::delay::DelayMs for SleepingDelay +where + TIM: InterruptDrivenTimer, + TYPE: Into, +{ + fn delay_ms(&mut self, ms: TYPE) { + ::delay_ms(self, ms.into()); + } +} +impl DelayNs for SleepingDelay { + fn delay_ns(&mut self, ns: u32) { // Determine how many cycles we need to run for this delay, if any // Avoid timers that run longer than a second because for 48 MHz-based timers, // there is no valid divisor + cycle count greater than ~1.3s, so we'd panic. - let mut count: u32 = 1 + (us / NUM_US_IN_S); + let mut loop_counter: u32 = 1 + (ns / NUM_NS_IN_S); // Start the timer and sleep! - self.timer.start((us / count).nanos()); + self.timer.start((ns / loop_counter).nanos()); self.timer.enable_interrupt(); loop { asm::wfi(); if self.timer.wait().is_ok() || self.interrupt_fired.load(atomic::Ordering::Relaxed) { self.interrupt_fired.store(false, atomic::Ordering::Relaxed); - count -= 1; - if count == 0 { + loop_counter -= 1; + if loop_counter == 0 { break; } } @@ -64,13 +79,3 @@ where self.timer.disable_interrupt(); } } - -impl DelayMs for SleepingDelay -where - TIM: InterruptDrivenTimer, - TYPE: Into, -{ - fn delay_ms(&mut self, ms: TYPE) { - self.delay_us(ms.into() * 1_000_u32); - } -} diff --git a/hal/src/timer_params.rs b/hal/src/timer_params.rs index 359c0e27bfa8..33d7d225f293 100644 --- a/hal/src/timer_params.rs +++ b/hal/src/timer_params.rs @@ -16,7 +16,7 @@ impl TimerParams { } /// calculates TimerParams from a given period based timeout. - pub fn new_us(timeout: Nanoseconds, src_freq: Hertz) -> Self { + pub fn new_ns(timeout: Nanoseconds, src_freq: Hertz) -> Self { let ticks: u32 = (timeout.to_nanos() as u64 * src_freq.to_Hz() as u64 / 1_000_000_000_u64) as u32; Self::new_from_ticks(ticks) @@ -38,7 +38,7 @@ impl TimerParams { let cycles: u32 = ticks / divider; - if cycles > u16::max_value() as u32 { + if cycles > u16::MAX as u32 { panic!("cycles {} is out of range for a 16 bit counter", cycles); } @@ -51,13 +51,13 @@ impl TimerParams { #[cfg(test)] mod tests { - use crate::prelude::*; + use crate::fugit::{ExtU32, RateExtU32}; use crate::timer_params::TimerParams; #[test] fn timer_params_hz_and_us_same_1hz() { let tp_from_hz = TimerParams::new(1.Hz(), 48.MHz()); - let tp_from_us = TimerParams::new_us(1_000_000.micros(), 48.MHz()); + let tp_from_us = TimerParams::new_ns(1_000_000.micros(), 48.MHz()); assert_eq!(tp_from_hz.divider, tp_from_us.divider); assert_eq!(tp_from_hz.cycles, tp_from_us.cycles); @@ -66,7 +66,7 @@ mod tests { #[test] fn timer_params_hz_and_us_same_3hz() { let tp_from_hz = TimerParams::new(3.Hz(), 48.MHz()); - let tp_from_us = TimerParams::new_us(333_333.micros(), 48.MHz()); + let tp_from_us = TimerParams::new_ns(333_333.micros(), 48.MHz()); // There's some rounding error here, but it is extremely small (1 cycle // difference) diff --git a/hal/src/timer_traits.rs b/hal/src/timer_traits.rs index 335e73049600..a2bc858ce750 100644 --- a/hal/src/timer_traits.rs +++ b/hal/src/timer_traits.rs @@ -1,12 +1,19 @@ -use crate::ehal::timer::{CountDown, Periodic}; -use crate::time; +use core::convert::Infallible; -/// Trait for timers that can enable & disable an interrupt that fires +use fugit::NanosDurationU32; + +/// Specifies a timer that can enable & disable an interrupt that fires /// when the timer expires -pub trait InterruptDrivenTimer: CountDown