From 5c3a37ec0e22675bf5759de13b2bb2e86fff29fd Mon Sep 17 00:00:00 2001 From: Osvald Ivarsson Date: Wed, 4 May 2022 22:28:17 +0200 Subject: [PATCH 1/3] Add board support for Arduino MKR WiFI 1010. --- README.md | 3 +- boards/arduino_mkrwifi1010/.cargo/config | 17 + boards/arduino_mkrwifi1010/CHANGELOG.md | 11 + boards/arduino_mkrwifi1010/Cargo.toml | 67 ++++ boards/arduino_mkrwifi1010/README.md | 45 +++ boards/arduino_mkrwifi1010/build.rs | 16 + .../examples/blinky_basic.rs | 38 +++ .../examples/onboard_rgb_led.rs | 117 +++++++ boards/arduino_mkrwifi1010/examples/uart.rs | 64 ++++ .../examples/usb_logging.rs | 104 ++++++ .../arduino_mkrwifi1010/examples/usb_poll.rs | 89 +++++ boards/arduino_mkrwifi1010/examples/wifi.rs | 234 +++++++++++++ boards/arduino_mkrwifi1010/memory.x | 5 + boards/arduino_mkrwifi1010/src/lib.rs | 317 ++++++++++++++++++ crates.json | 4 + 15 files changed, 1130 insertions(+), 1 deletion(-) create mode 100644 boards/arduino_mkrwifi1010/.cargo/config create mode 100644 boards/arduino_mkrwifi1010/CHANGELOG.md create mode 100644 boards/arduino_mkrwifi1010/Cargo.toml create mode 100644 boards/arduino_mkrwifi1010/README.md create mode 100644 boards/arduino_mkrwifi1010/build.rs create mode 100644 boards/arduino_mkrwifi1010/examples/blinky_basic.rs create mode 100644 boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs create mode 100644 boards/arduino_mkrwifi1010/examples/uart.rs create mode 100644 boards/arduino_mkrwifi1010/examples/usb_logging.rs create mode 100644 boards/arduino_mkrwifi1010/examples/usb_poll.rs create mode 100644 boards/arduino_mkrwifi1010/examples/wifi.rs create mode 100644 boards/arduino_mkrwifi1010/memory.x create mode 100644 boards/arduino_mkrwifi1010/src/lib.rs diff --git a/README.md b/README.md index 90fad5e83d71..3d058f6851a2 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ In addition to the PACs and HAL, there numerous **B**oard **S**upport **P**ackag |:------|:--------|:-----------------------| | [atsamd11c](https://docs.rs/atsamd11c/) | [![Crates.io](https://img.shields.io/crates/v/atsamd11c.svg)](https://crates.io/crates/atsamd11c) | | | [atsamd21e](https://docs.rs/atsamd21e/) | [![Crates.io](https://img.shields.io/crates/v/atsamd21e.svg)](https://crates.io/crates/atsamd21e) | [Gemma M0][gemma_m0], [Serpente][serpente], [Trinket M0][trinket_m0] | -| [atsamd21g](https://docs.rs/atsamd21g/) | [![Crates.io](https://img.shields.io/crates/v/atsamd21g.svg)](https://crates.io/crates/atsamd21g) | [Arduino Nano 33 IOT][arduino_nano33_iot], [Circuit Playground Express][circuit_playground_express], [Feather M0][feather_m0], [ItsyBitsy M0][itsybitsy_m0], [Metro M0][metro_m0], [MKR1000][arduino_mkr1000], [MKR Vidor 4000][arduino_mkr_vidor_4000], [MKR ZERO][arduino_mkrzero], [SAMD21 Mini][samd21_mini], [SODAQ ONE][sodaq_one], [Wio Lite MG126][wio_lite_mg126], [Xiao M0][xiao_m0] | +| [atsamd21g](https://docs.rs/atsamd21g/) | [![Crates.io](https://img.shields.io/crates/v/atsamd21g.svg)](https://crates.io/crates/atsamd21g) | [Arduino Nano 33 IOT][arduino_nano33_iot], [Circuit Playground Express][circuit_playground_express], [Feather M0][feather_m0], [ItsyBitsy M0][itsybitsy_m0], [Metro M0][metro_m0], [MKR1000][arduino_mkr1000], [MKR Vidor 4000][arduino_mkr_vidor_4000], [MKR WiFi 1010][arduino_mkrwifi1010], [MKR ZERO][arduino_mkrzero], [SAMD21 Mini][samd21_mini], [SODAQ ONE][sodaq_one], [Wio Lite MG126][wio_lite_mg126], [Xiao M0][xiao_m0] | | [atsamd21j](https://docs.rs/atsamd21j/) | [![Crates.io](https://img.shields.io/crates/v/atsamd21j.svg)](https://crates.io/crates/atsamd21j) | [SODAQ SARA AFF][sodaq_sara_aff] | | [atsamd51g](https://docs.rs/atsamd51g/) | [![Crates.io](https://img.shields.io/crates/v/atsamd51g.svg)](https://crates.io/crates/atsamd51g) | [ItsyBitsy M4][itsybitsy_m4], [Trellis M4][trellis_m4] | | [atsamd51j](https://docs.rs/atsamd51j/) | [![Crates.io](https://img.shields.io/crates/v/atsamd51j.svg)](https://crates.io/crates/atsamd51j) | [EdgeBadge][edgebadge], [Feather M4][feather_m4], [Metro M4][metro_m4], [PyPortal][pyportal] | @@ -31,6 +31,7 @@ In addition to the PACs and HAL, there numerous **B**oard **S**upport **P**ackag [arduino_mkr1000]: https://github.com/atsamd-rs/atsamd/tree/master/boards/arduino_mkr1000 [arduino_mkr_vidor_4000]: https://github.com/atsamd-rs/atsamd/tree/master/boards/arduino_mkrvidor4000 +[arduino_mkrwifi1010]: https://github.com/atsamd-rs/atsamd/tree/master/boards/arduino_mkrwifi1010 [arduino_mkrzero]: https://github.com/atsamd-rs/atsamd/tree/master/boards/arduino_mkrzero/ [arduino_nano33_iot]: https://github.com/atsamd-rs/atsamd/tree/master/boards/arduino_nano33iot [atsame54_xpro]: https://github.com/atsamd-rs/atsamd/tree/master/boards/atsame54_xpro/ diff --git a/boards/arduino_mkrwifi1010/.cargo/config b/boards/arduino_mkrwifi1010/.cargo/config new file mode 100644 index 000000000000..f3fab0fca64a --- /dev/null +++ b/boards/arduino_mkrwifi1010/.cargo/config @@ -0,0 +1,17 @@ +# samd21 is a Cortex-M0 and thus thumbv6m + +[build] +target = "thumbv6m-none-eabi" + +[target.thumbv6m-none-eabi] +runner = 'arm-none-eabi-gdb' +#runner = 'probe-run --chip ATSAMD21G18A' + +rustflags = [ + + # This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x + # See https://github.com/rust-embedded/cortex-m-quickstart/pull/95 + "-C", "link-arg=--nmagic", + + "-C", "link-arg=-Tlink.x", +] diff --git a/boards/arduino_mkrwifi1010/CHANGELOG.md b/boards/arduino_mkrwifi1010/CHANGELOG.md new file mode 100644 index 000000000000..8037cfa49c9b --- /dev/null +++ b/boards/arduino_mkrwifi1010/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +## Unreleased + +# v0.1.0 + +- initial add + +--- + +Changelog began tracking from 0.1.0 diff --git a/boards/arduino_mkrwifi1010/Cargo.toml b/boards/arduino_mkrwifi1010/Cargo.toml new file mode 100644 index 000000000000..bba9c5008604 --- /dev/null +++ b/boards/arduino_mkrwifi1010/Cargo.toml @@ -0,0 +1,67 @@ +[package] +name = "arduino_mkrwifi1010" +version = "0.1.0" +authors = ["Osvald Ivarsson "] +description = "Board Support crate for the Arduino MKR WiFi 1010" +keywords = ["no-std", "arm", "cortex-m", "embedded-hal", "arduino"] +categories = ["embedded", "hardware-support", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/atsamd-rs/atsamd" +readme = "README.md" +edition = "2021" + +[dependencies.cortex-m-rt] +version = "0.7" +optional = true + +[dependencies.atsamd-hal] +version = "0.14" +default-features = false + +[dependencies.usb-device] +version = "0.2" +optional = true + +[dev-dependencies] +cortex-m = "0.7" +panic-halt = "0.2" +panic-semihosting = "0.5" +usbd-serial = "0.1" +wifi-nina = { git = "https://github.com/Foosvald/wifi-nina", branch = "invert-reset-logic-with-feature", features = ["reset-high"] } +no-std-net = { version = "0.5.0", default-features = false } +heapless = "0.7" + + +[features] +# ask the HAL to enable atsamd21g support +default = ["rt", "atsamd-hal/samd21g"] +rt = ["cortex-m-rt", "atsamd-hal/samd21g-rt"] +usb = ["atsamd-hal/usb", "usb-device"] +unproven = ["atsamd-hal/unproven"] +use_semihosting = [] + +# for cargo flash +[package.metadata] +chip = "ATSAMD21G18A" + +[[example]] +name = "blinky_basic" + +[[example]] +name = "uart" + +[[example]] +name = "usb_logging" +required-features = ["usb", "unproven"] + +[[example]] +name = "usb_poll" +required-features = ["usb", "unproven"] + +[[example]] +name = "onboard_rgb_led" +required-features = ["usb", "unproven"] + +[[example]] +name = "wifi" +required-features = ["usb", "unproven"] diff --git a/boards/arduino_mkrwifi1010/README.md b/boards/arduino_mkrwifi1010/README.md new file mode 100644 index 000000000000..65420c202ba8 --- /dev/null +++ b/boards/arduino_mkrwifi1010/README.md @@ -0,0 +1,45 @@ +# Arduino MKR WiFi 1010 Board Support Crate + +This crate provides a type-safe API for working with the [Arduino MKR WiFi 1010](https://store.arduino.cc/products/arduino-mkr-wifi-1010). + +## Requirements + +1. Arduino IDE or [arduino CLI](https://github.com/arduino/arduino-cli) installed. +2. `samd` package installed. You can do this by going to Tools->Board->BoardManager and then searching for `samd` or run `arduino-cli core install arduino:samd`. +3. Now the arduino distribution contains bossac.exe in `ArduinoData/packages/arduino/tools/bossac/1.7.0[-arduino3]/` add it to your path + - **linux**: `ArduinoData` is likely something like `~/.arduino15/` + - **OSX**: `ArduinoData` is likely something like `~/Library/Arduino15` +4. Probably best to install an example sketch via the IDE just to make sure everything is working. +5. `arm-none-eabi` tools installed, you need `gcc` and `objcopy`. + - **Note**: Alternatively, you can use [cargo-binutils](https://github.com/rust-embedded/cargo-binutils), which is likely easier to install on OSX and also easier to use, as it will automatically detect the target +6. `thumbv6m-none-eabi` rust target installed via `rustup target add thumbv6m-none-eabi`. Some features may also require nightly rust. + +## Steps +### Build and copy elf file to binary +```bash +cargo build --release --example blinky_basic +# If using cargo-binutils, you can `rust-objcopy` with the same flags, or combine these 2 steps with `cargo objcopy` +arm-none-eabi-objcopy -O binary target/thumbv6m-none-eabi/release/examples/blinky_basic target/blinky_basic.bin +```` +or if using cargo-binutils you can combine these 2 steps into one: +```bash + cargo objcopy --release --example blinky_basic -- -O binary target/blinky_basic.bin +```` + +### Flash to device +```bash +# If using bossac +bossac -i -d -U true -i -e -w -v target/blinky_basic.bin -R +```` +or +```bash +# If using arduino-cli +arduino-cli upload -i target/blinky_basic.bin -b arduino:samd:mkrwifi1010 -p /dev/ttyACM0 +``` + +(You may need to use `--port` with something like `/dev/ttyACM0`/`/dev/ttyACM1`, or `/dev/tty.usbmodemNNNNN` on OSX) + +## Notes + - It may help to double-press the center button to reset when re-flashing the device. This sets the device in a bootloader mode. + - For the usb example, `picocom` is a good simple terminal serial emulator, installable with your os's package manager or `brew` + - On OSX, after flashing the tty for serial communication may be different, for example `/dev/tty.usbmodemTEST1` diff --git a/boards/arduino_mkrwifi1010/build.rs b/boards/arduino_mkrwifi1010/build.rs new file mode 100644 index 000000000000..4bed4688f2c0 --- /dev/null +++ b/boards/arduino_mkrwifi1010/build.rs @@ -0,0 +1,16 @@ +use std::env; +use std::fs::File; +use std::io::Write; +use std::path::PathBuf; +fn main() { + if env::var_os("CARGO_FEATURE_RT").is_some() { + let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); + File::create(out.join("memory.x")) + .unwrap() + .write_all(include_bytes!("memory.x")) + .unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); + } + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/boards/arduino_mkrwifi1010/examples/blinky_basic.rs b/boards/arduino_mkrwifi1010/examples/blinky_basic.rs new file mode 100644 index 000000000000..81514a50ac4d --- /dev/null +++ b/boards/arduino_mkrwifi1010/examples/blinky_basic.rs @@ -0,0 +1,38 @@ +#![no_std] +#![no_main] + +use arduino_mkrwifi1010 as bsp; +use bsp::hal; + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::entry; +use hal::clock::GenericClockController; +use hal::delay::Delay; +use hal::pac::{CorePeripherals, Peripherals}; +use hal::prelude::*; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + let mut led: bsp::Led = pins.led.into(); + let mut delay = Delay::new(core.SYST, &mut clocks); + + loop { + delay.delay_ms(1000u32); + led.set_high().unwrap(); + delay.delay_ms(1000u32); + led.set_low().unwrap(); + } +} diff --git a/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs b/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs new file mode 100644 index 000000000000..38f5ccdbcce1 --- /dev/null +++ b/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs @@ -0,0 +1,117 @@ +// This blinks the onboard RGB led through SPI to the NINA-W102 Wi-Fi module where the RGB led sits +// The example uses the wifi_nina library to control the WiFi on the NINA-W102 when it +// runs the Arduino nina-fw firmware which is installed by default on all Arduino MKR 1010s: https://github.com/arduino/nina-fw + +#![no_std] +#![no_main] + +use arduino_mkrwifi1010 as bsp; +use atsamd_hal::thumbv6m::clock::GClock; +use bsp::hal; +use core::time::Duration; + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::entry; +use hal::clock::GenericClockController; +use hal::delay::Delay; +use hal::pac::{CorePeripherals, Peripherals}; +use hal::prelude::*; +use hal::time::MegaHertz; +use hal::timer::{TimerCounter, TimerCounter5}; +use wifi_nina::transport::SpiTransport; + +const BOOT_DELAY_MS: u16 = 100; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + let mut delay = Delay::new(core.SYST, &mut clocks); + + delay.delay_ms(BOOT_DELAY_MS); + + let spi = bsp::nina_spi_master( + &mut clocks, + MegaHertz(8), + peripherals.SERCOM2, + &mut peripherals.PM, + pins.nina_sck, + pins.nina_mosi, + pins.nina_miso, + ); + + let gclk0 = clocks.gclk0(); + let mut timer = Timer::new(peripherals.TC5, &mut clocks, &gclk0, &mut peripherals.PM); + + let spi_transport = SpiTransport::start( + spi, + pins.nina_ack.into_floating_input(), + pins.nina_resetn.into_push_pull_output(), + pins.nina_cs.into_push_pull_output(), + |d: Duration| delay.delay_ms(d.as_millis() as u32), + ) + .unwrap(); + let mut wifi = wifi_nina::Wifi::new(spi_transport); + + // Full power is too strong to look at :) + // let rgb = [[255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 255], [0, 0, 0]]; + let rgb = [[64, 0, 0], [0, 64, 0], [0, 0, 64], [64, 64, 64], [0, 0, 0]]; + let mut current = 0; + + let mut led_last_toggled = timer.millis(); + wifi.set_led(rgb[current][0], rgb[current][1], rgb[current][2]) + .unwrap(); + + loop { + timer.tick(); + let now = timer.millis(); + if (now - led_last_toggled) > 1000 { + wifi.set_led(rgb[current][0], rgb[current][1], rgb[current][2]) + .unwrap(); + current = (current + 1) % rgb.len(); + led_last_toggled = now; + } + } +} + +pub struct Timer { + tc: TimerCounter5, + millis: u64, +} + +impl Timer { + pub fn new( + tc5: bsp::pac::TC5, + clocks: &mut GenericClockController, + gclk0: &GClock, + pm: &mut bsp::pac::PM, + ) -> Self { + let timer_clock = clocks.tc4_tc5(gclk0).unwrap(); + let mut timer = TimerCounter::tc5_(&timer_clock, tc5, pm); + timer.start(1.khz()); + Timer { + tc: timer, + millis: 0, + } + } + + pub fn tick(&mut self) { + nb::block!(self.tc.wait()).ok(); + self.millis += 1; + } + + pub fn millis(&self) -> u64 { + self.millis + } +} diff --git a/boards/arduino_mkrwifi1010/examples/uart.rs b/boards/arduino_mkrwifi1010/examples/uart.rs new file mode 100644 index 000000000000..08ae39307f71 --- /dev/null +++ b/boards/arduino_mkrwifi1010/examples/uart.rs @@ -0,0 +1,64 @@ +#![no_std] +#![no_main] + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use arduino_mkrwifi1010 as bsp; +use bsp::hal; +use bsp::pac; + +use bsp::entry; +use hal::clock::GenericClockController; +use hal::prelude::*; + +use pac::{CorePeripherals, Peripherals}; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + + let pins = bsp::Pins::new(peripherals.PORT); + let mut delay = hal::delay::Delay::new(core.SYST, &mut clocks); + + let mut red_led = pins.led.into_push_pull_output(); + + // Setup UART peripheral. + let mut uart = bsp::uart( + &mut clocks, + 9600.hz(), + peripherals.SERCOM5, + &mut peripherals.PM, + pins.rx, + pins.tx, + ); + + // Write out a message on start up. + for byte in b"Hello world!\r\n" { + nb::block!(uart.write(*byte)).unwrap(); + } + + loop { + match uart.read() { + Ok(byte) => { + // Echo all received characters. + nb::block!(uart.write(byte)).unwrap(); + + // Blink the red led to show that a character has arrived. + red_led.set_high().unwrap(); + delay.delay_ms(2u16); + red_led.set_low().unwrap(); + } + Err(_) => delay.delay_ms(5u16), + }; + } +} diff --git a/boards/arduino_mkrwifi1010/examples/usb_logging.rs b/boards/arduino_mkrwifi1010/examples/usb_logging.rs new file mode 100644 index 000000000000..5ac2b2a522d9 --- /dev/null +++ b/boards/arduino_mkrwifi1010/examples/usb_logging.rs @@ -0,0 +1,104 @@ +#![no_std] +#![no_main] + +use arduino_mkrwifi1010 as bsp; +use bsp::hal; +use bsp::hal::prelude::*; + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::entry; +use hal::clock::GenericClockController; +use hal::pac::{interrupt, CorePeripherals, Peripherals}; + +use hal::usb::UsbBus; +use usb_device::bus::UsbBusAllocator; +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +use cortex_m::asm::delay as cycle_delay; +use cortex_m::peripheral::NVIC; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + let mut led: bsp::Led = pins.led.into(); + + let bus_allocator = unsafe { + USB_ALLOCATOR = Some(bsp::usb_allocator( + peripherals.USB, + &mut clocks, + &mut peripherals.PM, + pins.usb_dm, + pins.usb_dp, + )); + USB_ALLOCATOR.as_ref().unwrap() + }; + + unsafe { + USB_SERIAL = Some(SerialPort::new(bus_allocator)); + USB_BUS = Some( + UsbDeviceBuilder::new(bus_allocator, UsbVidPid(0x2222, 0x3333)) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST") + .device_class(USB_CLASS_CDC) + .build(), + ); + } + + unsafe { + core.NVIC.set_priority(interrupt::USB, 1); + NVIC::unmask(interrupt::USB); + } + + // Flash the LED in a spin loop to demonstrate that USB is + // entirely interrupt driven. + loop { + cycle_delay(5 * 1024 * 1024); + led.toggle().unwrap(); + + // Turn off interrupts so we don't fight with the interrupt + cortex_m::interrupt::free(|_| unsafe { + if USB_BUS.as_mut().is_some() { + if let Some(serial) = USB_SERIAL.as_mut() { + let _ = serial.write("log line\r\n".as_bytes()); + } + } + }); + } +} + +static mut USB_ALLOCATOR: Option> = None; +static mut USB_BUS: Option> = None; +static mut USB_SERIAL: Option> = None; + +fn poll_usb() { + unsafe { + 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); + } + } + }; +} + +#[interrupt] +fn USB() { + poll_usb(); +} diff --git a/boards/arduino_mkrwifi1010/examples/usb_poll.rs b/boards/arduino_mkrwifi1010/examples/usb_poll.rs new file mode 100644 index 000000000000..af4e7695f1e6 --- /dev/null +++ b/boards/arduino_mkrwifi1010/examples/usb_poll.rs @@ -0,0 +1,89 @@ +//! Makes the device appear as a USB serial port loop back device. +//! Repeats back all characters sent to it, but in upper case. + +#![no_std] +#![no_main] + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use arduino_mkrwifi1010 as bsp; +use bsp::hal; +use bsp::pac; +use panic_halt as _; + +use bsp::entry; +use hal::clock::GenericClockController; +use hal::prelude::*; + +use pac::Peripherals; + +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + + let pins = bsp::Pins::new(peripherals.PORT); + + let usb_bus = bsp::usb_allocator( + peripherals.USB, + &mut clocks, + &mut peripherals.PM, + pins.usb_dm, + pins.usb_dp, + ); + + let mut serial = SerialPort::new(&usb_bus); + let mut led = pins.led.into_push_pull_output(); + + let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x2222, 0x3333)) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST") + .device_class(USB_CLASS_CDC) + .build(); + + loop { + if !usb_dev.poll(&mut [&mut serial]) { + continue; + } + + let mut buf = [0u8; 64]; + + match serial.read(&mut buf) { + Ok(count) if count > 0 => { + led.set_high().unwrap(); // Turn on + + // Echo back in upper case + for c in buf[0..count].iter_mut() { + if 0x61 <= *c && *c <= 0x7a { + *c &= !0x20; + } + } + + let mut write_offset = 0; + while write_offset < count { + match serial.write(&buf[write_offset..count]) { + Ok(len) if len > 0 => { + write_offset += len; + } + _ => {} + } + } + } + _ => {} + } + + led.set_low().unwrap(); // Turn off + } +} diff --git a/boards/arduino_mkrwifi1010/examples/wifi.rs b/boards/arduino_mkrwifi1010/examples/wifi.rs new file mode 100644 index 000000000000..202fb4edb7de --- /dev/null +++ b/boards/arduino_mkrwifi1010/examples/wifi.rs @@ -0,0 +1,234 @@ +// This connects to WiFI through SPI to the NINA-W102 Wi-Fi module using the wifi_nina library. +// This works when the NINA-W102 runs the Arduino nina-fw firmware which is installed by default +// on all Arduino MKR 1010s: https://github.com/arduino/nina-fw +// The example then prints out various debug messages to the USB serial + +#![no_std] +#![no_main] + +use arduino_mkrwifi1010 as bsp; +use atsamd_hal::thumbv6m::usb::UsbBus; +use bsp::hal; +use core::time::Duration; + +#[cfg(not(feature = "use_semihosting"))] +use panic_halt as _; +#[cfg(feature = "use_semihosting")] +use panic_semihosting as _; + +use bsp::entry; +use hal::clock::GenericClockController; +use hal::delay::Delay; +use hal::pac::{interrupt, CorePeripherals, Peripherals}; +use hal::prelude::*; +use hal::time::MegaHertz; + +use core::fmt::Write; +use cortex_m::asm::delay as cycle_delay; +use cortex_m::interrupt::free as disable_interrupts; +use cortex_m::peripheral::NVIC; +use heapless::String; +use usb_device::bus::UsbBusAllocator; +use usb_device::prelude::*; +use usbd_serial::{SerialPort, USB_CLASS_CDC}; +use wifi_nina::transport::SpiTransport; +use wifi_nina::types::{ + Config, ConnectionState, NetworkConfig, ProtocolMode, StationConfig, TcpState, +}; + +const BOOT_DELAY_MS: u16 = 100; + +static mut USB_ALLOCATOR: Option> = None; +static mut USB_BUS: Option> = None; +static mut USB_SERIAL: Option> = None; + +const WIFI_SSID: &[u8] = b"CHANGE-ME"; +const WIFI_PASSWORD: &[u8] = b"CHANGE-ME"; + +#[entry] +fn main() -> ! { + let mut peripherals = Peripherals::take().unwrap(); + let mut core = CorePeripherals::take().unwrap(); + let mut clocks = GenericClockController::with_internal_32kosc( + peripherals.GCLK, + &mut peripherals.PM, + &mut peripherals.SYSCTRL, + &mut peripherals.NVMCTRL, + ); + let pins = bsp::Pins::new(peripherals.PORT); + let mut delay = Delay::new(core.SYST, &mut clocks); + + // Setup USB + let bus_allocator = unsafe { + USB_ALLOCATOR = Some(bsp::usb_allocator( + peripherals.USB, + &mut clocks, + &mut peripherals.PM, + pins.usb_dm, + pins.usb_dp, + )); + USB_ALLOCATOR.as_ref().unwrap() + }; + + unsafe { + USB_SERIAL = Some(SerialPort::new(bus_allocator)); + USB_BUS = Some( + UsbDeviceBuilder::new(bus_allocator, UsbVidPid(0x2222, 0x3333)) + .manufacturer("Fake company") + .product("Serial port") + .serial_number("TEST") + .device_class(USB_CLASS_CDC) + .build(), + ); + } + + unsafe { + core.NVIC.set_priority(interrupt::USB, 1); + NVIC::unmask(interrupt::USB); + } + + delay.delay_ms(BOOT_DELAY_MS); + + // Setup Wifi module + let spi = bsp::nina_spi_master( + &mut clocks, + MegaHertz(8), + peripherals.SERCOM2, + &mut peripherals.PM, + pins.nina_sck, + pins.nina_mosi, + pins.nina_miso, + ); + + let spi_transport = SpiTransport::start( + spi, + pins.nina_ack.into_floating_input(), + pins.nina_resetn.into_push_pull_output(), + pins.nina_cs.into_push_pull_output(), + |d: Duration| delay.delay_ms(d.as_millis() as u32), + ) + .unwrap(); + let mut wifi = wifi_nina::Wifi::new(spi_transport); + + // Try to connect to WiFi and then make raw HTTP request towards an IP address of http://ifconfig.co + usbserial_write!("Connecting to WiFi\r\n"); + let configure_result = wifi.configure( + Config::Station(StationConfig { + network: NetworkConfig::Password { + ssid: WIFI_SSID, + password: WIFI_PASSWORD, + }, + }), + Some(Duration::from_secs(5)), + ); + usbserial_write!( + "Result after trying to connect for at maximum 30 seconds: {:?}\r\n", + &configure_result + ); + if configure_result.is_err() { + usbserial_write!("Make sure that you specified the right SSID and password for the WiFi and that it's 2.4GHz and not 5GHz since the NINA-W102 WiFi module only supports 2.4GHz."); + } + + let mut client_result = wifi.new_client(); + if let Ok(client) = &mut client_result { + // We'll make a request directly to an IP of http://ifconfig.co/country (IP found by doing nslookup ifconfig.co on 2022-05-04, hopefully it continues to work.) + // An alternative is to add DNS functionality to wifi_nina which has partial support for it implemented, but I haven't tried that + let connection_result = client.connect_ipv4( + &mut wifi, + no_std_net::Ipv4Addr::new(188, 114, 96, 2), + 80, + ProtocolMode::Tcp, + ); + usbserial_write!("Tcp connection result: {:?}\r\n", connection_result); + + let send_result = client.send( + &mut wifi, + b"GET /country HTTP/1.1\nHost: ifconfig.co\nConnection: close\n\n", + ); + usbserial_write!("Send result: {:?}\r\n", send_result); + usbserial_write!("You are (maybe) in country (look after the headers down below):\r\n"); + + while let Ok(state) = client.state(&mut wifi) { + let mut buf = [0u8; 2048]; + + let recv_result = client.recv(&mut wifi, &mut buf); + match recv_result { + Ok(received_bytes) => { + cortex_m::interrupt::free(|_| unsafe { + if USB_BUS.as_mut().is_some() { + if let Some(serial) = USB_SERIAL.as_mut() { + let mut write_offset = 0; + while write_offset < received_bytes { + match serial.write(&buf[write_offset..received_bytes]) { + Ok(len) if len > 0 => { + write_offset += len; + } + _ => {} + } + } + } + } + }); + } + Err(e) => { + usbserial_write!("Error trying to receive data: {:?}\r\n", e); + } + } + if state == TcpState::Closed { + usbserial_write!("\r\nBreaking since TcpState is Closed.\r\n"); + break; + } + } + } + + usbserial_write!("Connection status of WiFi (after HTTP connection closed above):\r\n"); + + loop { + // Since our other delay moved into SpiTransport cycle_delay was the easiest way to slow down the loop a bit + cycle_delay(30 * 1024 * 1024); + + let connection_state = + wifi.await_connection_state(ConnectionState::Connected, Duration::from_millis(0)); + usbserial_write!("WiFi connection state: {:?}\r\n", connection_state); + } +} + +fn poll_usb() { + unsafe { + 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); + } + } + }; +} + +#[interrupt] +fn USB() { + poll_usb(); +} + +#[macro_export] +macro_rules! usbserial_write { + ($($tt:tt)*) => {{ + let mut s: String<1024> = String::new(); + write!(s, $($tt)*).unwrap(); + let message_bytes = s.as_bytes(); + let mut total_written = 0; + while total_written < message_bytes.len() { + let bytes_written = disable_interrupts(|_| unsafe { + match USB_SERIAL.as_mut().unwrap().write( + &message_bytes[total_written..] + ) { + Ok(count) => count, + Err(_) => 0, + } + }); + total_written += bytes_written; + } + }}; +} diff --git a/boards/arduino_mkrwifi1010/memory.x b/boards/arduino_mkrwifi1010/memory.x new file mode 100644 index 000000000000..5d4acb9e0f69 --- /dev/null +++ b/boards/arduino_mkrwifi1010/memory.x @@ -0,0 +1,5 @@ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x00000000+0x2000, LENGTH = 0x00040000-0x2000 /* First 8KB used by bootloader */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000 +} \ No newline at end of file diff --git a/boards/arduino_mkrwifi1010/src/lib.rs b/boards/arduino_mkrwifi1010/src/lib.rs new file mode 100644 index 000000000000..7a8d21509026 --- /dev/null +++ b/boards/arduino_mkrwifi1010/src/lib.rs @@ -0,0 +1,317 @@ +#![no_std] + +#[cfg(feature = "rt")] +pub use cortex_m_rt::entry; + +pub use atsamd_hal as hal; +use atsamd_hal::sercom::I2CMaster2; +pub use hal::ehal; +pub use hal::pac; + +use hal::clock::GenericClockController; +use hal::sercom::v2::{spi, uart, Sercom1, Sercom2, Sercom5}; +use hal::time::Hertz; + +#[cfg(feature = "usb")] +use hal::usb::{usb_device::bus::UsbBusAllocator, UsbBus}; + +// The docs could be further improved with details of the specific channels etc +// Maps the pins to their arduino names and the numbers printed on the board. +// Information from: +hal::bsp_pins!( + PB23 { + /// RX + name: rx + aliases: { + AlternateD: Rx + } + } + PB22 { + /// TX + name: tx + aliases: { + AlternateD: Tx + } + } + PA22 { + /// Digital 0: PWM, TC + name: d0 + } + PA23 { + /// Digital 1: PWM, TC + name: d1 + } + PA10 { + /// Digital 2: ADC, PWM, TCC + name: d2 + } + PA11 { + /// Digital 3: ADC, PWM, TCC + name: d3 + } + PB10 { + /// Digital 4: PWM, TC + name: d4 + } + PB11 { + /// Digital 5: PWM, TC + name: d5 + } + PA20 { + /// Digital 6: PWM, TCC, LED_BUILTIN + name: led + aliases: { + PushPullOutput: Led, + } + } + PA21 { + /// Digital 7: PWM, TC + name: d7 + } + PA16 { + /// Digital 8/SPI MOSI: PWM, TCC + name: mosi + aliases: { + AlternateC: Mosi + } + } + PA17 { + /// Digital 9/SPI SCK + name: sck, + aliases: { + AlternateC: Sck + } + } + PA19 { + /// Digital 10/SPI MISO: PWM, TC + name: miso + aliases: { + AlternateC: Miso + } + } + PA08 { + /// Digital 11/SC2 SDA: ADC + name: sda + aliases: { + AlternateD: Sda + } + } + PA09 { + /// Digital 12/SC2 SCL: ADC + name: scl + aliases: { + AlternateD: Scl + } + } + PA02 { + /// Analog 0: DAC0, ADC + name: a0 + } + PB02 { + /// Analog 1: ADC + name: a1 + } + PB03 { + /// Analog 2: ADC + name: a2 + } + PA04 { + /// Analog 3: ADC, PWM, TCC + name: a3 + } + PA05 { + /// Analog 4: ADC, PWM, TCC + name: a4 + } + PA06 { + /// Analog 5: ADC + name: a5 + } + PA07 { + /// Analog 5: ADC + name: a6 + } + PA24 { + /// USB D- Pad + name: usb_dm + aliases: { + AlternateG: UsbDm + } + } + PA25 { + /// USB D+ Pad + name: usb_dp + aliases: { + AlternateG: UsbDp + } + } + PA18 { + /// USB ID Pad + name: usb_id + } + PA03 { + /// AREF + name: aref + } + PA12 { + /// NINA MOSI + name: nina_mosi + aliases: { + AlternateC: NinaMosi + } + } + PA13 { + /// NINA MISO + name: nina_miso + aliases: { + AlternateC: NinaMiso + } + } + PA14 { + /// NINA CS + name: nina_cs + } + PA15 { + /// NINA SCK + name: nina_sck + aliases: { + AlternateC: NinaSck + } + } + PA27 { + /// NINA GPIO0 + name: nina_gpio0 + } + PB08 { + /// NINA RESETN: ADC + name: nina_resetn + } + PB09 { + /// ADC VBAT: ADC, PWM, TC + name: adc_vbat + } + PA00 { + /// 32768Hz Crystal XIN32 + name: xin32 + } + PA01 { + /// 32768Hz Crystal XOUT32 + name: xout32 + } + PA28 { + /// NINA ACK + name: nina_ack + } +); + +#[cfg(feature = "usb")] +pub fn usb_allocator( + usb: pac::USB, + clocks: &mut GenericClockController, + pm: &mut pac::PM, + dm: impl Into, + dp: impl Into, +) -> UsbBusAllocator { + let gclk0 = clocks.gclk0(); + let usb_clock = &clocks.usb(&gclk0).unwrap(); + let (dm, dp) = (dm.into(), dp.into()); + UsbBusAllocator::new(UsbBus::new(usb_clock, pm, dm, dp, usb)) +} + +/// Convenience for setting up the labelled SDA, SCL pins to +/// operate as an I2C master running at the specified frequency. +pub fn i2c_master( + clocks: &mut GenericClockController, + bus_speed: impl Into, + sercom2: pac::SERCOM2, + pm: &mut pac::PM, + sda: impl Into, + scl: impl Into, +) -> I2CMaster2 { + let gclk0 = &clocks.gclk0(); + let clock = &clocks.sercom2_core(gclk0).unwrap(); + let (bus_speed, sda, scl) = (bus_speed.into(), sda.into(), scl.into()); + + I2CMaster2::new(clock, bus_speed, sercom2, pm, sda, scl) +} + +/// UART pads +pub type UartPads = uart::Pads; +/// UART device for the labelled RX & TX pins +pub type Uart = uart::Uart, uart::Duplex>; + +/// Convenience for setting up the labelled RX, TX pins to +/// operate as a UART device running at the specified baud. +pub fn uart( + clocks: &mut GenericClockController, + baud: impl Into, + sercom5: pac::SERCOM5, + pm: &mut pac::PM, + rx: impl Into, + tx: impl Into, +) -> Uart { + let gclk0 = clocks.gclk0(); + let clock = &clocks.sercom5_core(&gclk0).unwrap(); + let baud = baud.into(); + let pads = uart::Pads::default().rx(rx.into()).tx(tx.into()); + + uart::Config::new(pm, sercom5, pads, clock.freq()) + .baud(baud, uart::BaudMode::Fractional(uart::Oversampling::Bits16)) + .enable() +} + +// SPI pads for the labelled SPI peripheral +/// +/// You can use these pads with other, user-defined [`spi::Config`]urations. +pub type SpiPads = spi::Pads; + +/// SPI master for the labelled SPI peripheral +/// +/// This type implements [`FullDuplex`](ehal::spi::FullDuplex). +pub type Spi = spi::Spi, spi::Duplex>; + +/// Convenience for setting up the labelled SPI peripheral. +/// This powers up SERCOM1 and configures it for use as an +/// SPI Master in SPI Mode 0. +pub fn spi_master( + clocks: &mut GenericClockController, + baud: impl Into, + sercom1: pac::SERCOM1, + pm: &mut pac::PM, + sck: impl Into, + mosi: impl Into, + miso: impl Into, +) -> Spi { + let gclk0 = clocks.gclk0(); + let clock = clocks.sercom1_core(&gclk0).unwrap(); + let (miso, mosi, sclk) = (miso.into(), mosi.into(), sck.into()); + let pads = spi::Pads::default().data_in(miso).data_out(mosi).sclk(sclk); + + spi::Config::new(pm, sercom1, pads, clock.freq()) + .baud(baud) + .spi_mode(spi::MODE_0) + .enable() +} + +pub type NinaSpiPads = spi::Pads; +pub type NinaSpi = spi::Spi, spi::Duplex>; + +pub fn nina_spi_master( + clocks: &mut GenericClockController, + baud: impl Into, + sercom2: pac::SERCOM2, + pm: &mut pac::PM, + sck: impl Into, + mosi: impl Into, + miso: impl Into, +) -> NinaSpi { + let gclk0 = clocks.gclk0(); + let clock = clocks.sercom2_core(&gclk0).unwrap(); + let (miso, mosi, sclk) = (miso.into(), mosi.into(), sck.into()); + let pads = spi::Pads::default().data_in(miso).data_out(mosi).sclk(sclk); + + spi::Config::new(pm, sercom2, pads, clock.freq()) + .baud(baud) + .spi_mode(spi::MODE_0) + .enable() +} diff --git a/crates.json b/crates.json index 609d87809bfd..a77b85519f68 100644 --- a/crates.json +++ b/crates.json @@ -8,6 +8,10 @@ "tier": 2, "build": "cargo build --examples --features=unproven,usb" }, + "arduino_mkrwifi1010": { + "tier": 2, + "build": "cargo build --examples --features=unproven,usb" + }, "arduino_mkrzero": { "tier": 2, "build": "cargo build --examples --features=unproven,usb" From 7b7bcc49aab4f763b5f81df09bfd9e59dd17bcf8 Mon Sep 17 00:00:00 2001 From: Osvald Ivarsson Date: Wed, 4 May 2022 23:43:06 +0200 Subject: [PATCH 2/3] Fix formatting in arduino_mkrwifi1010 examples. --- .../arduino_mkrwifi1010/examples/onboard_rgb_led.rs | 9 +++++---- boards/arduino_mkrwifi1010/examples/wifi.rs | 12 +++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs b/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs index 38f5ccdbcce1..05ffcc914177 100644 --- a/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs +++ b/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs @@ -1,6 +1,6 @@ -// This blinks the onboard RGB led through SPI to the NINA-W102 Wi-Fi module where the RGB led sits -// The example uses the wifi_nina library to control the WiFi on the NINA-W102 when it -// runs the Arduino nina-fw firmware which is installed by default on all Arduino MKR 1010s: https://github.com/arduino/nina-fw +// This blinks the onboard RGB led through SPI to the NINA-W102 Wi-Fi module +// where the RGB led sits The example uses the wifi_nina library to control the +// WiFi on the NINA-W102 when it runs the Arduino nina-fw firmware which is installed by default on all Arduino MKR 1010s: https://github.com/arduino/nina-fw #![no_std] #![no_main] @@ -65,7 +65,8 @@ fn main() -> ! { let mut wifi = wifi_nina::Wifi::new(spi_transport); // Full power is too strong to look at :) - // let rgb = [[255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 255], [0, 0, 0]]; + // let rgb = [[255, 0, 0], [0, 255, 0], [0, 0, 255], [255, 255, 255], [0, 0, + // 0]]; let rgb = [[64, 0, 0], [0, 64, 0], [0, 0, 64], [64, 64, 64], [0, 0, 0]]; let mut current = 0; diff --git a/boards/arduino_mkrwifi1010/examples/wifi.rs b/boards/arduino_mkrwifi1010/examples/wifi.rs index 202fb4edb7de..dfd0f4eb38c4 100644 --- a/boards/arduino_mkrwifi1010/examples/wifi.rs +++ b/boards/arduino_mkrwifi1010/examples/wifi.rs @@ -1,6 +1,6 @@ -// This connects to WiFI through SPI to the NINA-W102 Wi-Fi module using the wifi_nina library. -// This works when the NINA-W102 runs the Arduino nina-fw firmware which is installed by default -// on all Arduino MKR 1010s: https://github.com/arduino/nina-fw +// This connects to WiFI through SPI to the NINA-W102 Wi-Fi module using the +// wifi_nina library. This works when the NINA-W102 runs the Arduino nina-fw +// firmware which is installed by default on all Arduino MKR 1010s: https://github.com/arduino/nina-fw // The example then prints out various debug messages to the USB serial #![no_std] @@ -132,7 +132,8 @@ fn main() -> ! { let mut client_result = wifi.new_client(); if let Ok(client) = &mut client_result { // We'll make a request directly to an IP of http://ifconfig.co/country (IP found by doing nslookup ifconfig.co on 2022-05-04, hopefully it continues to work.) - // An alternative is to add DNS functionality to wifi_nina which has partial support for it implemented, but I haven't tried that + // An alternative is to add DNS functionality to wifi_nina which has partial + // support for it implemented, but I haven't tried that let connection_result = client.connect_ipv4( &mut wifi, no_std_net::Ipv4Addr::new(188, 114, 96, 2), @@ -184,7 +185,8 @@ fn main() -> ! { usbserial_write!("Connection status of WiFi (after HTTP connection closed above):\r\n"); loop { - // Since our other delay moved into SpiTransport cycle_delay was the easiest way to slow down the loop a bit + // Since our other delay moved into SpiTransport cycle_delay was the easiest way + // to slow down the loop a bit cycle_delay(30 * 1024 * 1024); let connection_state = From ecf2fccda48ff0c9d6f26c90db94beac0199eeea Mon Sep 17 00:00:00 2001 From: Osvald Ivarsson Date: Thu, 5 May 2022 22:45:29 +0200 Subject: [PATCH 3/3] Update atsamd-hal to 0.15, rename led to d6 and use SERCOM4 for Nina module. --- boards/arduino_mkrwifi1010/Cargo.toml | 2 +- .../examples/blinky_basic.rs | 2 +- .../examples/onboard_rgb_led.rs | 2 +- boards/arduino_mkrwifi1010/examples/uart.rs | 2 +- .../examples/usb_logging.rs | 2 +- .../arduino_mkrwifi1010/examples/usb_poll.rs | 2 +- boards/arduino_mkrwifi1010/examples/wifi.rs | 2 +- boards/arduino_mkrwifi1010/src/lib.rs | 446 +++++++++--------- 8 files changed, 242 insertions(+), 218 deletions(-) diff --git a/boards/arduino_mkrwifi1010/Cargo.toml b/boards/arduino_mkrwifi1010/Cargo.toml index bba9c5008604..4a5261a55605 100644 --- a/boards/arduino_mkrwifi1010/Cargo.toml +++ b/boards/arduino_mkrwifi1010/Cargo.toml @@ -15,7 +15,7 @@ version = "0.7" optional = true [dependencies.atsamd-hal] -version = "0.14" +version = "0.15" default-features = false [dependencies.usb-device] diff --git a/boards/arduino_mkrwifi1010/examples/blinky_basic.rs b/boards/arduino_mkrwifi1010/examples/blinky_basic.rs index 81514a50ac4d..3e426af9f870 100644 --- a/boards/arduino_mkrwifi1010/examples/blinky_basic.rs +++ b/boards/arduino_mkrwifi1010/examples/blinky_basic.rs @@ -26,7 +26,7 @@ fn main() -> ! { &mut peripherals.NVMCTRL, ); let pins = bsp::Pins::new(peripherals.PORT); - let mut led: bsp::Led = pins.led.into(); + let mut led: bsp::Led = pins.d6.into(); let mut delay = Delay::new(core.SYST, &mut clocks); loop { diff --git a/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs b/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs index 05ffcc914177..a6bbcb116c0c 100644 --- a/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs +++ b/boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs @@ -44,7 +44,7 @@ fn main() -> ! { let spi = bsp::nina_spi_master( &mut clocks, MegaHertz(8), - peripherals.SERCOM2, + peripherals.SERCOM4, &mut peripherals.PM, pins.nina_sck, pins.nina_mosi, diff --git a/boards/arduino_mkrwifi1010/examples/uart.rs b/boards/arduino_mkrwifi1010/examples/uart.rs index 08ae39307f71..8f22c59117a7 100644 --- a/boards/arduino_mkrwifi1010/examples/uart.rs +++ b/boards/arduino_mkrwifi1010/examples/uart.rs @@ -30,7 +30,7 @@ fn main() -> ! { let pins = bsp::Pins::new(peripherals.PORT); let mut delay = hal::delay::Delay::new(core.SYST, &mut clocks); - let mut red_led = pins.led.into_push_pull_output(); + let mut red_led: bsp::Led = pins.d6.into_push_pull_output(); // Setup UART peripheral. let mut uart = bsp::uart( diff --git a/boards/arduino_mkrwifi1010/examples/usb_logging.rs b/boards/arduino_mkrwifi1010/examples/usb_logging.rs index 5ac2b2a522d9..ab1c3cfcd617 100644 --- a/boards/arduino_mkrwifi1010/examples/usb_logging.rs +++ b/boards/arduino_mkrwifi1010/examples/usb_logging.rs @@ -33,7 +33,7 @@ fn main() -> ! { &mut peripherals.NVMCTRL, ); let pins = bsp::Pins::new(peripherals.PORT); - let mut led: bsp::Led = pins.led.into(); + let mut led: bsp::Led = pins.d6.into(); let bus_allocator = unsafe { USB_ALLOCATOR = Some(bsp::usb_allocator( diff --git a/boards/arduino_mkrwifi1010/examples/usb_poll.rs b/boards/arduino_mkrwifi1010/examples/usb_poll.rs index af4e7695f1e6..5bc911ca6ba0 100644 --- a/boards/arduino_mkrwifi1010/examples/usb_poll.rs +++ b/boards/arduino_mkrwifi1010/examples/usb_poll.rs @@ -44,7 +44,7 @@ fn main() -> ! { ); let mut serial = SerialPort::new(&usb_bus); - let mut led = pins.led.into_push_pull_output(); + let mut led: bsp::Led = pins.d6.into(); let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x2222, 0x3333)) .manufacturer("Fake company") diff --git a/boards/arduino_mkrwifi1010/examples/wifi.rs b/boards/arduino_mkrwifi1010/examples/wifi.rs index dfd0f4eb38c4..492318157e0c 100644 --- a/boards/arduino_mkrwifi1010/examples/wifi.rs +++ b/boards/arduino_mkrwifi1010/examples/wifi.rs @@ -93,7 +93,7 @@ fn main() -> ! { let spi = bsp::nina_spi_master( &mut clocks, MegaHertz(8), - peripherals.SERCOM2, + peripherals.SERCOM4, &mut peripherals.PM, pins.nina_sck, pins.nina_mosi, diff --git a/boards/arduino_mkrwifi1010/src/lib.rs b/boards/arduino_mkrwifi1010/src/lib.rs index 7a8d21509026..72e84aaa9844 100644 --- a/boards/arduino_mkrwifi1010/src/lib.rs +++ b/boards/arduino_mkrwifi1010/src/lib.rs @@ -4,206 +4,218 @@ pub use cortex_m_rt::entry; pub use atsamd_hal as hal; -use atsamd_hal::sercom::I2CMaster2; pub use hal::ehal; pub use hal::pac; +use hal::sercom::{ + i2c, spi, + uart::{self}, +}; use hal::clock::GenericClockController; -use hal::sercom::v2::{spi, uart, Sercom1, Sercom2, Sercom5}; use hal::time::Hertz; #[cfg(feature = "usb")] use hal::usb::{usb_device::bus::UsbBusAllocator, UsbBus}; -// The docs could be further improved with details of the specific channels etc -// Maps the pins to their arduino names and the numbers printed on the board. -// Information from: -hal::bsp_pins!( - PB23 { - /// RX - name: rx - aliases: { - AlternateD: Rx - } - } - PB22 { - /// TX - name: tx - aliases: { - AlternateD: Tx - } - } - PA22 { - /// Digital 0: PWM, TC - name: d0 - } - PA23 { - /// Digital 1: PWM, TC - name: d1 - } - PA10 { - /// Digital 2: ADC, PWM, TCC - name: d2 - } - PA11 { - /// Digital 3: ADC, PWM, TCC - name: d3 - } - PB10 { - /// Digital 4: PWM, TC - name: d4 - } - PB11 { - /// Digital 5: PWM, TC - name: d5 - } - PA20 { - /// Digital 6: PWM, TCC, LED_BUILTIN - name: led - aliases: { - PushPullOutput: Led, - } - } - PA21 { - /// Digital 7: PWM, TC - name: d7 - } - PA16 { - /// Digital 8/SPI MOSI: PWM, TCC - name: mosi - aliases: { - AlternateC: Mosi - } - } - PA17 { - /// Digital 9/SPI SCK - name: sck, - aliases: { - AlternateC: Sck - } - } - PA19 { - /// Digital 10/SPI MISO: PWM, TC - name: miso - aliases: { - AlternateC: Miso - } - } - PA08 { - /// Digital 11/SC2 SDA: ADC - name: sda - aliases: { - AlternateD: Sda - } - } - PA09 { - /// Digital 12/SC2 SCL: ADC - name: scl - aliases: { - AlternateD: Scl - } - } - PA02 { - /// Analog 0: DAC0, ADC - name: a0 - } - PB02 { - /// Analog 1: ADC - name: a1 - } - PB03 { - /// Analog 2: ADC - name: a2 - } - PA04 { - /// Analog 3: ADC, PWM, TCC - name: a3 - } - PA05 { - /// Analog 4: ADC, PWM, TCC - name: a4 - } - PA06 { - /// Analog 5: ADC - name: a5 - } - PA07 { - /// Analog 5: ADC - name: a6 - } - PA24 { - /// USB D- Pad - name: usb_dm - aliases: { - AlternateG: UsbDm - } - } - PA25 { - /// USB D+ Pad - name: usb_dp - aliases: { - AlternateG: UsbDp - } - } - PA18 { - /// USB ID Pad - name: usb_id - } - PA03 { - /// AREF - name: aref - } - PA12 { - /// NINA MOSI - name: nina_mosi - aliases: { - AlternateC: NinaMosi - } - } - PA13 { - /// NINA MISO - name: nina_miso - aliases: { - AlternateC: NinaMiso - } - } - PA14 { - /// NINA CS - name: nina_cs - } - PA15 { - /// NINA SCK - name: nina_sck - aliases: { - AlternateC: NinaSck - } - } - PA27 { - /// NINA GPIO0 - name: nina_gpio0 - } - PB08 { - /// NINA RESETN: ADC - name: nina_resetn - } - PB09 { - /// ADC VBAT: ADC, PWM, TC - name: adc_vbat - } - PA00 { - /// 32768Hz Crystal XIN32 - name: xin32 - } - PA01 { - /// 32768Hz Crystal XOUT32 - name: xout32 - } - PA28 { - /// NINA ACK - name: nina_ack - } +hal::bsp_peripherals!( + SERCOM1 { SpiSercom } + SERCOM2 { I2cSercom } + SERCOM4 { NinaSercom } + SERCOM5 { UartSercom } ); +/// Definitions related to pins and pin aliases +// Information from: +pub mod pins { + use super::hal; + hal::bsp_pins!( + PB23 { + /// RX + name: rx + aliases: { + AlternateD: Rx + } + } + PB22 { + /// TX + name: tx + aliases: { + AlternateD: Tx + } + } + PA22 { + /// Digital 0: PWM, TC + name: d0 + } + PA23 { + /// Digital 1: PWM, TC + name: d1 + } + PA10 { + /// Digital 2: ADC, PWM, TCC + name: d2 + } + PA11 { + /// Digital 3: ADC, PWM, TCC + name: d3 + } + PB10 { + /// Digital 4: PWM, TC + name: d4 + } + PB11 { + /// Digital 5: PWM, TC + name: d5 + } + PA20 { + /// Digital 6: PWM, TCC, LED_BUILTIN + name: d6 + aliases: { + PushPullOutput: Led, + } + } + PA21 { + /// Digital 7: PWM, TC + name: d7 + } + PA16 { + /// Digital 8/SPI MOSI: PWM, TCC + name: mosi + aliases: { + AlternateC: Mosi + } + } + PA17 { + /// Digital 9/SPI SCK + name: sck, + aliases: { + AlternateC: Sck + } + } + PA19 { + /// Digital 10/SPI MISO: PWM, TC + name: miso + aliases: { + AlternateC: Miso + } + } + PA08 { + /// Digital 11/SC2 SDA: ADC + name: sda + aliases: { + AlternateD: Sda + } + } + PA09 { + /// Digital 12/SC2 SCL: ADC + name: scl + aliases: { + AlternateD: Scl + } + } + PA02 { + /// Analog 0: DAC0, ADC + name: a0 + } + PB02 { + /// Analog 1: ADC + name: a1 + } + PB03 { + /// Analog 2: ADC + name: a2 + } + PA04 { + /// Analog 3: ADC, PWM, TCC + name: a3 + } + PA05 { + /// Analog 4: ADC, PWM, TCC + name: a4 + } + PA06 { + /// Analog 5: ADC + name: a5 + } + PA07 { + /// Analog 5: ADC + name: a6 + } + PA24 { + /// USB D- Pad + name: usb_dm + aliases: { + AlternateG: UsbDm + } + } + PA25 { + /// USB D+ Pad + name: usb_dp + aliases: { + AlternateG: UsbDp + } + } + PA18 { + /// USB ID Pad + name: usb_id + } + PA03 { + /// AREF + name: aref + } + PA12 { + /// NINA MOSI + name: nina_mosi + aliases: { + AlternateD: NinaMosi + } + } + PA13 { + /// NINA MISO + name: nina_miso + aliases: { + AlternateD: NinaMiso + } + } + PA14 { + /// NINA CS + name: nina_cs + } + PA15 { + /// NINA SCK + name: nina_sck + aliases: { + AlternateD: NinaSck + } + } + PA27 { + /// NINA GPIO0 + name: nina_gpio0 + } + PB08 { + /// NINA RESETN: ADC + name: nina_resetn + } + PB09 { + /// ADC VBAT: ADC, PWM, TC + name: adc_vbat + } + PA00 { + /// 32768Hz Crystal XIN32 + name: xin32 + } + PA01 { + /// 32768Hz Crystal XOUT32 + name: xout32 + } + PA28 { + /// NINA ACK + name: nina_ack + } + ); +} +pub use pins::*; + #[cfg(feature = "usb")] pub fn usb_allocator( usb: pac::USB, @@ -218,25 +230,38 @@ pub fn usb_allocator( UsbBusAllocator::new(UsbBus::new(usb_clock, pm, dm, dp, usb)) } +/// I2C pads for the labelled I2C peripheral +/// +/// You can use these pads with other, user-defined [`i2c::Config`]urations. +pub type I2cPads = i2c::Pads; + +/// I2C master for the labelled I2C peripheral +/// +/// This type implements [`Read`](ehal::blocking::i2c::Read), +/// [`Write`](ehal::blocking::i2c::Write) and +/// [`WriteRead`](ehal::blocking::i2c::WriteRead). +pub type I2c = i2c::I2c>; /// Convenience for setting up the labelled SDA, SCL pins to /// operate as an I2C master running at the specified frequency. pub fn i2c_master( clocks: &mut GenericClockController, - bus_speed: impl Into, - sercom2: pac::SERCOM2, + baud: impl Into, + sercom: I2cSercom, pm: &mut pac::PM, sda: impl Into, scl: impl Into, -) -> I2CMaster2 { - let gclk0 = &clocks.gclk0(); - let clock = &clocks.sercom2_core(gclk0).unwrap(); - let (bus_speed, sda, scl) = (bus_speed.into(), sda.into(), scl.into()); - - I2CMaster2::new(clock, bus_speed, sercom2, pm, sda, scl) +) -> I2c { + let gclk0 = clocks.gclk0(); + let clock = &clocks.sercom2_core(&gclk0).unwrap(); + let freq = clock.freq(); + let baud = baud.into(); + let pads = i2c::Pads::new(sda.into(), scl.into()); + i2c::Config::new(pm, sercom, pads, freq).baud(baud).enable() } -/// UART pads -pub type UartPads = uart::Pads; +/// UART pads for the labelled RX & TX pins +pub type UartPads = uart::Pads; + /// UART device for the labelled RX & TX pins pub type Uart = uart::Uart, uart::Duplex>; @@ -245,7 +270,7 @@ pub type Uart = uart::Uart, uart::Duplex>; pub fn uart( clocks: &mut GenericClockController, baud: impl Into, - sercom5: pac::SERCOM5, + sercom: UartSercom, pm: &mut pac::PM, rx: impl Into, tx: impl Into, @@ -255,15 +280,15 @@ pub fn uart( let baud = baud.into(); let pads = uart::Pads::default().rx(rx.into()).tx(tx.into()); - uart::Config::new(pm, sercom5, pads, clock.freq()) + uart::Config::new(pm, sercom, pads, clock.freq()) .baud(baud, uart::BaudMode::Fractional(uart::Oversampling::Bits16)) .enable() } -// SPI pads for the labelled SPI peripheral +/// SPI pads for the labelled SPI peripheral /// /// You can use these pads with other, user-defined [`spi::Config`]urations. -pub type SpiPads = spi::Pads; +pub type SpiPads = spi::Pads; /// SPI master for the labelled SPI peripheral /// @@ -271,12 +296,12 @@ pub type SpiPads = spi::Pads; pub type Spi = spi::Spi, spi::Duplex>; /// Convenience for setting up the labelled SPI peripheral. -/// This powers up SERCOM1 and configures it for use as an +/// This powers up the SPI SERCOM and configures it for use as an /// SPI Master in SPI Mode 0. pub fn spi_master( clocks: &mut GenericClockController, baud: impl Into, - sercom1: pac::SERCOM1, + sercom: SpiSercom, pm: &mut pac::PM, sck: impl Into, mosi: impl Into, @@ -286,31 +311,30 @@ pub fn spi_master( let clock = clocks.sercom1_core(&gclk0).unwrap(); let (miso, mosi, sclk) = (miso.into(), mosi.into(), sck.into()); let pads = spi::Pads::default().data_in(miso).data_out(mosi).sclk(sclk); - - spi::Config::new(pm, sercom1, pads, clock.freq()) + spi::Config::new(pm, sercom, pads, clock.freq()) .baud(baud) .spi_mode(spi::MODE_0) .enable() } -pub type NinaSpiPads = spi::Pads; +pub type NinaSpiPads = spi::Pads; pub type NinaSpi = spi::Spi, spi::Duplex>; pub fn nina_spi_master( clocks: &mut GenericClockController, baud: impl Into, - sercom2: pac::SERCOM2, + sercom: NinaSercom, pm: &mut pac::PM, sck: impl Into, mosi: impl Into, miso: impl Into, ) -> NinaSpi { let gclk0 = clocks.gclk0(); - let clock = clocks.sercom2_core(&gclk0).unwrap(); + let clock = clocks.sercom4_core(&gclk0).unwrap(); let (miso, mosi, sclk) = (miso.into(), mosi.into(), sck.into()); let pads = spi::Pads::default().data_in(miso).data_out(mosi).sclk(sclk); - spi::Config::new(pm, sercom2, pads, clock.freq()) + spi::Config::new(pm, sercom, pads, clock.freq()) .baud(baud) .spi_mode(spi::MODE_0) .enable()