diff --git a/boards/arduino_mkrzero/CHANGELOG.md b/boards/arduino_mkrzero/CHANGELOG.md index 3a0d6e25265d..5a8779b9bc62 100644 --- a/boards/arduino_mkrzero/CHANGELOG.md +++ b/boards/arduino_mkrzero/CHANGELOG.md @@ -1,5 +1,10 @@ # Unreleased +# v0.12.1 + +- update to `atsamd-hal-0.16`, along with redefining pins using the bsp_pins! macro +- split up library into pin definitions and peripheral & USB setup function definitions + # v0.12.0 - update to `atsamd-hal-0.14` and other latest dependencies (#564) diff --git a/boards/arduino_mkrzero/Cargo.toml b/boards/arduino_mkrzero/Cargo.toml index c67938212410..80c78dcb9b98 100644 --- a/boards/arduino_mkrzero/Cargo.toml +++ b/boards/arduino_mkrzero/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arduino_mkrzero" -version = "0.12.0" +version = "0.12.1" authors = ["Wez Furlong ", "David McGillicuddy "] description = "Board Support crate for the Arduino MKRZERO" keywords = ["no-std", "arm", "cortex-m", "embedded-hal", "arduino"] @@ -15,18 +15,23 @@ version = "0.7" optional = true [dependencies.atsamd-hal] -version = "0.14" +version = "0.16" default-features = false [dependencies.usb-device] version = "0.2" optional = true +[dependencies.embedded-sdmmc] +version = "0.3" +optional = true + [dev-dependencies] cortex-m = "0.7" usbd-serial = "0.1" panic-halt = "0.2" panic-semihosting = "0.5" +cortex-m-rtic = "1.0" [features] # ask the HAL to enable atsamd21g support @@ -35,14 +40,22 @@ rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"] usb = ["atsamd-hal/usb", "usb-device"] unproven = ["atsamd-hal/unproven"] use_semihosting = [] +rtic = ["atsamd-hal/rtic"] # for cargo flash [package.metadata] chip = "ATSAMD21G18A" +[dependencies] +embedded-hal = "0.2.7" + [[example]] name = "blinky_basic" +[[example]] +name = "blinky_rtic" +required-features = ["rtic", "unproven"] + [[example]] name = "usb_logging" required-features = ["usb"] diff --git a/boards/arduino_mkrzero/examples/blinky_basic.rs b/boards/arduino_mkrzero/examples/blinky_basic.rs index a443cf2f376d..f74bec8dcddd 100644 --- a/boards/arduino_mkrzero/examples/blinky_basic.rs +++ b/boards/arduino_mkrzero/examples/blinky_basic.rs @@ -25,8 +25,8 @@ fn main() -> ! { &mut peripherals.SYSCTRL, &mut peripherals.NVMCTRL, ); - let mut pins = bsp::Pins::new(peripherals.PORT); - let mut led = pins.led_builtin.into_open_drain_output(&mut pins.port); + let pins = bsp::pins::Pins::new(peripherals.PORT); + let mut led = bsp::pin_alias!(pins.led).into_push_pull_output(); let mut delay = Delay::new(core.SYST, &mut clocks); loop { diff --git a/boards/arduino_mkrzero/examples/blinky_rtic.rs b/boards/arduino_mkrzero/examples/blinky_rtic.rs new file mode 100644 index 000000000000..73edc4d9ae79 --- /dev/null +++ b/boards/arduino_mkrzero/examples/blinky_rtic.rs @@ -0,0 +1,73 @@ +//! Uses RTIC with the RTC as time source to blink an LED. +//! +//! The idle task is sleeping the CPU, so in practice this gives similar power +//! figure as the "sleeping_timer_rtc" example. +#![no_std] +#![no_main] + +use arduino_mkrzero as bsp; + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; +use rtic::app; + +#[app(device = bsp::pac, peripherals = true, dispatchers = [EVSYS])] +mod app { + use super::*; + use bsp::hal; + use hal::clock::{ClockGenId, ClockSource, GenericClockController}; + use hal::pac::Peripherals; + use hal::prelude::*; + use hal::rtc::{Count32Mode, Duration, Rtc}; + + #[local] + struct Local {} + + #[shared] + struct Shared { + // The LED could be a local resource, since it is only used in one task + // But we want to showcase shared resources and locking + led: bsp::pins::Led, + } + + #[monotonic(binds = RTC, default = true)] + type RtcMonotonic = Rtc; + + #[init] + fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) { + let mut peripherals: Peripherals = cx.device; + let pins = bsp::pins::Pins::new(peripherals.PORT); + let mut core: rtic::export::Peripherals = cx.core; + let mut clocks = GenericClockController::with_external_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let _gclk = clocks.gclk0(); + let rtc_clock_src = clocks + .configure_gclk_divider_and_source(ClockGenId::GCLK2, 1, ClockSource::XOSC32K, false) + .unwrap(); + clocks.configure_standby(ClockGenId::GCLK2, true); + let rtc_clock = clocks.rtc(&rtc_clock_src).unwrap(); + let rtc = Rtc::count32_mode(peripherals.RTC, rtc_clock.freq(), &mut peripherals.PM); + let led = bsp::pin_alias!(pins.led).into(); + + // We can use the RTC in standby for maximum power savings + core.SCB.set_sleepdeep(); + + // Start the blink task + blink::spawn().unwrap(); + + (Shared { led }, Local {}, init::Monotonics(rtc)) + } + + #[task(shared = [led])] + fn blink(mut cx: blink::Context) { + // If the LED were a local resource, the lock would not be necessary + let _ = cx.shared.led.lock(|led| led.toggle()); + blink::spawn_after(Duration::secs(3)).ok(); + } +} diff --git a/boards/arduino_mkrzero/examples/pwm.rs b/boards/arduino_mkrzero/examples/pwm.rs index d73c3e8508d3..d98635981459 100644 --- a/boards/arduino_mkrzero/examples/pwm.rs +++ b/boards/arduino_mkrzero/examples/pwm.rs @@ -12,6 +12,7 @@ use panic_semihosting as _; use bsp::entry; use hal::clock::{GenericClockController, Tcc0Tcc1Clock}; use hal::delay::Delay; +use hal::gpio::AlternateE; use hal::pac::{CorePeripherals, Peripherals}; use hal::prelude::*; use hal::pwm::{Channel, Pwm0}; @@ -27,18 +28,18 @@ fn main() -> ! { &mut peripherals.NVMCTRL, ); let mut delay = Delay::new(core.SYST, &mut clocks); - let mut pins = bsp::Pins::new(peripherals.PORT); + let pins = bsp::pins::Pins::new(peripherals.PORT); // PWM0_CH1 is A4 on the board - pin 19 or PA05 // see: https://github.com/arduino/ArduinoCore-samd/blob/master/variants/mkrzero/variant.cpp - let _a4 = pins.a4.into_function_e(&mut pins.port); + let _a4 = pins.pa04.into_mode::(); let gclk0 = clocks.gclk0(); let tcc0_tcc1_clock: &Tcc0Tcc1Clock = &clocks.tcc0_tcc1(&gclk0).unwrap(); let mut pwm0 = Pwm0::new( &tcc0_tcc1_clock, - 1.khz(), + 1u32.kHz(), peripherals.TCC0, &mut peripherals.PM, ); diff --git a/boards/arduino_mkrzero/examples/usb_logging.rs b/boards/arduino_mkrzero/examples/usb_logging.rs index d105ce44ddb0..2a777ae801eb 100644 --- a/boards/arduino_mkrzero/examples/usb_logging.rs +++ b/boards/arduino_mkrzero/examples/usb_logging.rs @@ -3,8 +3,6 @@ use arduino_mkrzero as bsp; use bsp::hal; -use usb_device; -use usbd_serial; #[cfg(not(feature = "use_semihosting"))] use panic_halt as _; @@ -38,25 +36,28 @@ fn main() -> ! { &mut peripherals.SYSCTRL, &mut peripherals.NVMCTRL, ); - let mut pins = bsp::Pins::new(peripherals.PORT); - let mut led = pins.led_builtin.into_open_drain_output(&mut pins.port); + let pins = bsp::pins::Pins::new(peripherals.PORT); + let mut led = bsp::pin_alias!(pins.led).into_push_pull_output(); let mut delay = Delay::new(core.SYST, &mut clocks); + let usb_n = bsp::pin_alias!(pins.usb_n); + let usb_p = bsp::pin_alias!(pins.usb_p); + let bus_allocator = unsafe { - USB_ALLOCATOR = Some(bsp::usb_allocator( + USB_ALLOCATOR = Some(bsp::usb::usb_allocator( peripherals.USB, &mut clocks, &mut peripherals.PM, - pins.usb_n, // PA24, also usb_dm - pins.usb_p, // PA24 also usb_dp + usb_n.into(), + usb_p.into(), )); USB_ALLOCATOR.as_ref().unwrap() }; unsafe { - USB_SERIAL = Some(SerialPort::new(&bus_allocator)); + USB_SERIAL = Some(SerialPort::new(bus_allocator)); USB_BUS = Some( - UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x2222, 0x3333)) + UsbDeviceBuilder::new(bus_allocator, UsbVidPid(0x2222, 0x3333)) .manufacturer("Fake company") .product("Serial port") .serial_number("TEST") @@ -78,27 +79,23 @@ fn main() -> ! { // Turn off interrupts so we don't fight with the interrupt cortex_m::interrupt::free(|_| unsafe { - USB_BUS.as_mut().map(|_| { - USB_SERIAL.as_mut().map(|serial| { - // Skip errors so we can continue the program - let _ = serial.write("log line\r\n".as_bytes()); - }); - }) + if let Some(serial) = USB_SERIAL.as_mut() { + let _ = serial.write("log line\r\n".as_bytes()); + } }); } } fn poll_usb() { unsafe { - USB_BUS.as_mut().map(|usb_dev| { - USB_SERIAL.as_mut().map(|serial| { + if let Some(usb_dev) = USB_BUS.as_mut() { + if let Some(serial) = USB_SERIAL.as_mut() { usb_dev.poll(&mut [serial]); - // Make the other side happy let mut buf = [0u8; 16]; let _ = serial.read(&mut buf); - }); - }); + } + } }; } diff --git a/boards/arduino_mkrzero/src/lib.rs b/boards/arduino_mkrzero/src/lib.rs index d3cae6503ac6..20c457cfac68 100644 --- a/boards/arduino_mkrzero/src/lib.rs +++ b/boards/arduino_mkrzero/src/lib.rs @@ -7,126 +7,9 @@ extern crate cortex_m_rt; #[cfg(feature = "rt")] pub use cortex_m_rt::entry; -#[cfg(feature = "usb")] -use gpio::v2::{AnyPin, PA24, PA25}; -#[cfg(feature = "usb")] -use hal::clock::GenericClockController; -#[cfg(feature = "usb")] -use hal::usb::usb_device::bus::UsbBusAllocator; -#[cfg(feature = "usb")] -pub use hal::usb::UsbBus; - -use hal::prelude::*; -use hal::*; - -pub use hal::common::*; - pub use hal::pac; -use gpio::{Floating, Input, Port}; - -// The docs could be further improved with details of the specific channels etc -define_pins!( - /// Maps the pins to their arduino names and the numbers printed on the board. - /// Information from: - struct Pins, - pac: pac, - - /// Digital 0: PWM, TC - pin d0 = a22, - - /// Digital 1: PWM, TC - pin d1 = a23, - - /// Digital 2: PWM, TCC, ADC - pin d2 = a10, - - /// Digital 3: PWM, TCC, ADC - pin d3 = a11, - - /// Digital 4: PWM, TC - pin d4 = b10, - - /// Digital 5: PWM, TC - pin d5 = b11, - - /// Digital 6: PWM, TCC - pin d6 = a20, - - /// Digital 7: PWM, TCC - pin d7 = a21, - - /// SPI MOSI: PWM, TCC - pin mosi = a16, - - /// SPI SCK - pin sck = a17, - - /// SPI MISO: PWM, TC - pin miso = a19, - - /// SDA - pin sda = a8, - - /// SCL - pin scl = a9, - - /// RX - pin rx = b23, - - /// TX - pin tx = b22, - - /// Analog 0: DAC - pin a0 = a2, - - /// Analog 1 - pin a1 = b2, - - /// Analog 2 - pin a2 = b3, - - /// Analog 3: PWM, TCC - pin a3 = a4, - - /// Analog 4: PWM, TCC - pin a4 = a5, - - /// Analog 5 - pin a5 = a6, - - /// Analog 6 - pin a6 = a7, - - pin usb_n = a24, - pin usb_p = a25, - pin usb_id = a18, - pin aref = a3, - pin sd_sck = a12, - pin sd_mosi = a13, - pin sd_ss = a14, - pin sd_miso = a15, - pin sd_cd = a27, - - /// LED built into the board - pin led_builtin = b8, - - pin bottom_pad = a28, - pin adc_battery = b9, - pin xin32 = a0, - pin xout32 = a1, -); - +pub mod pins; +pub mod sercom; #[cfg(feature = "usb")] -pub fn usb_allocator( - usb: pac::USB, - clocks: &mut GenericClockController, - pm: &mut pac::PM, - dm: impl AnyPin, - dp: impl AnyPin, -) -> UsbBusAllocator { - let gclk0 = clocks.gclk0(); - let usb_clock = &clocks.usb(&gclk0).unwrap(); - - UsbBusAllocator::new(UsbBus::new(usb_clock, pm, dm, dp, usb)) -} +pub mod usb; diff --git a/boards/arduino_mkrzero/src/pins.rs b/boards/arduino_mkrzero/src/pins.rs new file mode 100644 index 000000000000..12363a292d21 --- /dev/null +++ b/boards/arduino_mkrzero/src/pins.rs @@ -0,0 +1,220 @@ +//! Pin definitions for the Arduino MkrZero board +//! +//! Built-in pin definitions are defined here for each pin, +//! and additional pin capabilities, such as the timer/counter or waveform +//! output, and alternate sercom pad definitsions must be defined separately. + +use super::hal; + +hal::bsp_pins! { + PA02 { + /// PA02: Analog DAC output / ADC input 0, digital pin 15. + aliases: { + PushPullOutput: D15 + AlternateB: Dac0 + AlternateB: A0 + } + } + PA03 { + /// PA03: ADC/DAC reference voltage. + aliases: { + AlternateB: ARef + } + } + PA04 { + /// PA04: Analog input 3, digital pin 18. + aliases: { + PushPullOutput: D18 + AlternateB: A3 + } + } + PA05 { + /// PA05: Analog input 4, digital pin 19. + aliases: { + PushPullOutput: D19 + AlternateB: A4 + } + } + PA06 { + /// PA06: Analog input 5, digital pin 20. + aliases: { + PushPullOutput: D20 + AlternateB: A5 + } + } + PA07 { + /// PA07: Analog input 6, digital pin 21. + aliases: { + PushPullOutput: D21 + AlternateB: A6 + } + } + PA08 { + /// PA08: Sercom 2 SDA, digital pin 11. + aliases: { + PushPullOutput: D11 + AlternateD: I2cSda + } + } + PA09 { + /// PA09: Sercom 2 SCL, digital pin 12. + aliases: { + PushPullOutput: D12 + AlternateD: I2cScl + } + } + PA10 { + /// PA10: Digital pin 2. + aliases: { + PushPullOutput: D2 + } + } + PA11 { + /// PA11: Digital pin 3. + aliases: { + PushPullOutput: D3 + } + } + PA12 { + /// PA12: SD Card COPI. + aliases: { + AlternateD: SdCopi + } + } + PA13 { + /// PA13: SD Card SCK. + aliases: { + AlternateD: SdSck + } + } + PA14 { + /// PA14: SD Card SS. Operated either by the peripheral or by an output GPIO pin. + aliases: { + PushPullOutput: SdSsGpio + AlternateD: SdSs + } + } + PA15 { + /// PA15: SD Card CIPO. + aliases: { + AlternateD: SdCipo + } + } + PA16 { + /// PA16: Sercom 1 SPI COPI, digital pin 8. + aliases: { + PushPullOutput: D8 + AlternateC: SpiCopi + } + } + PA17 { + /// PA17: Sercom 1 SPI SCK, digital pin 9 + aliases: { + PushPullOutput: D9 + AlternateC: SpiSck + } + } + PA18 { + /// PA18: USB Input Detection + aliases: { + FloatingDisabled: UsbId + } + } + PA19 { + /// PA19: Main SPI CIPO, digital pin 10 + aliases: { + PushPullOutput: D10 + AlternateC: SpiCipo + } + } + PA20 { + /// PA20: Digital pin 6 + aliases: { + PushPullOutput: D6 + } + } + PA21 { + /// PA21: Digital pin 7 + aliases: { + PushPullOutput: D7 + } + } + PA22 { + /// PA22: Digital pin 0 + aliases: { + PushPullOutput: D0 + } + } + PA23 { + /// PA23: Digital pin 1 + aliases: { + PushPullOutput: D1 + } + } + PA24 { + /// PA24: USB Negative + aliases: { + AlternateG: UsbN + } + } + PA25 { + /// PA25: USB Positive + aliases: { + AlternateG: UsbP + } + } + PA27 { + /// PA27: SD Card Detect + // FloatingInput: SdCd + } + PB02 { + /// PB02: Analog input 1, digital pin 16 + aliases: { + AlternateB: A1 + PushPullOutput: D16 + } + } + PB03 { + /// PB03: Analog input 2, digital pin 17 + aliases: { + AlternateB: A2 + PushPullOutput: D17 + } + } + PB08 { + /// PB08: LED + aliases: { + PushPullOutput: Led + } + } + PB09 { + /// PB09: Battery voltage sensor + aliases: { + AlternateB: VBatt + } + } + PB10 { + /// PB10: Digital pin 4 + aliases: { + PushPullOutput: D4 + } + } + PB11 { + /// PB11: Digital pin 5 + aliases: { + PushPullOutput: D5 + } + } + PB22 { + /// PB22: UART Tx + aliases: { + AlternateD: UartTx + } + } + PB23 { + /// PB22: UART Rx + aliases: { + AlternateD: UartRx + } + } +} diff --git a/boards/arduino_mkrzero/src/sercom.rs b/boards/arduino_mkrzero/src/sercom.rs new file mode 100644 index 000000000000..659714d361d9 --- /dev/null +++ b/boards/arduino_mkrzero/src/sercom.rs @@ -0,0 +1,121 @@ +use crate::hal; +use hal::pac; + +use embedded_hal; + +use hal::clock::GenericClockController; +use hal::sercom::{i2c, spi, uart}; +use hal::time::Hertz; +use uart::{BaudMode, Oversampling}; + +use crate::pins::*; + +hal::bsp_peripherals!( + SERCOM1 { SpiSercom } + SERCOM2 { I2cSercom } + SERCOM4 { SdSercom } + SERCOM5 { UartSercom } +); + +/// SPI pads +pub type SpiPads = spi::Pads; + +/// SPI peripheral type +pub type Spi = spi::Spi, spi::Duplex>; + +/// Set up the SPI peripheral +#[allow(clippy::too_many_arguments)] +pub fn setup_spi( + clocks: &mut GenericClockController, + baud: Hertz, + spi_sercom: SpiSercom, + pm: &pac::PM, + cipo: impl Into, + copi: impl Into, + sck: impl Into, + mode: embedded_hal::spi::Mode, +) -> Spi { + let gclk0 = clocks.gclk0(); + let clock = clocks.sercom1_core(&gclk0).unwrap(); + let freq = clock.freq(); + let (cipo, copi, sck) = (cipo.into(), copi.into(), sck.into()); + let pads = spi::Pads::default().data_in(cipo).data_out(copi).sclk(sck); + spi::Config::new(pm, spi_sercom, pads, freq) + .baud(baud) + .spi_mode(mode) + .enable() +} + +/// I2C pads +pub type I2cPads = i2c::Pads; + +/// Extension 2 I2C device +pub type I2c = i2c::I2c>; + +/// Set up the extension 1 I2C device +pub fn setup_i2c( + clocks: &mut GenericClockController, + baud: Hertz, + ext2_i2c_sercom: I2cSercom, + pm: &pac::PM, + sda: impl Into, + scl: impl Into, +) -> I2c { + let gclk0 = clocks.gclk0(); + let clock = &clocks.sercom2_core(&gclk0).unwrap(); + let freq = clock.freq(); + let pads = i2c::Pads::new(sda.into(), scl.into()); + i2c::Config::new(pm, ext2_i2c_sercom, pads, freq) + .baud(baud) + .enable() +} + +/// SD Card pads +pub type SdPads = spi::Pads; + +/// SD Card peripheral type +pub type Sd = spi::Spi, spi::Duplex>; + +/// Set up the SD Card SPI peripheral +pub fn setup_sd( + clocks: &mut GenericClockController, + baud: Hertz, + spi_sercom: SdSercom, + pm: &pac::PM, + cipo: impl Into, + copi: impl Into, + sck: impl Into, +) -> Sd { + let gclk0 = clocks.gclk0(); + let clock = clocks.sercom4_core(&gclk0).unwrap(); + let freq = clock.freq(); + let (cipo, copi, sck) = (cipo.into(), copi.into(), sck.into()); + let pads = spi::Pads::default().data_in(cipo).data_out(copi).sclk(sck); + spi::Config::new(pm, spi_sercom, pads, freq) + .baud(baud) + .spi_mode(spi::MODE_0) + .enable() +} + +/// UART pads +pub type UartPads = uart::Pads; + +/// UART device +pub type Uart = uart::Uart, uart::Duplex>; + +/// Set up the UART peripheral +pub fn setup_uart( + clocks: &mut GenericClockController, + baud: Hertz, + uart_sercom: UartSercom, + pm: &pac::PM, + uart_rx: impl Into, + uart_tx: impl Into, +) -> Uart { + let gclk0 = clocks.gclk0(); + let clock = clocks.sercom5_core(&gclk0).unwrap(); + let pads = uart::Pads::default().rx(uart_rx.into()).tx(uart_tx.into()); + uart::Config::new(pm, uart_sercom, pads, clock.freq()) + .baud(baud, BaudMode::Fractional(Oversampling::Bits16)) + .enable() +} diff --git a/boards/arduino_mkrzero/src/usb.rs b/boards/arduino_mkrzero/src/usb.rs new file mode 100644 index 000000000000..1a5c9d944a49 --- /dev/null +++ b/boards/arduino_mkrzero/src/usb.rs @@ -0,0 +1,19 @@ +use crate::hal; +use crate::pins::{UsbN, UsbP}; +use hal::pac; + +use hal::clock::GenericClockController; +use hal::usb::{usb_device::bus::UsbBusAllocator, UsbBus}; + +pub fn usb_allocator( + usb: pac::USB, + clocks: &mut GenericClockController, + pm: &mut pac::PM, + dm: UsbN, + dp: UsbP, +) -> UsbBusAllocator { + let gclk0 = clocks.gclk0(); + let usb_clock = &clocks.usb(&gclk0).unwrap(); + + UsbBusAllocator::new(UsbBus::new(usb_clock, pm, dm, dp, usb)) +}