Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add board support for Arduino MKR WiFi 1010. #606

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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] |
Expand All @@ -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/
Expand Down
17 changes: 17 additions & 0 deletions boards/arduino_mkrwifi1010/.cargo/config
Original file line number Diff line number Diff line change
@@ -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",
]
11 changes: 11 additions & 0 deletions boards/arduino_mkrwifi1010/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Changelog

## Unreleased

# v0.1.0

- initial add

---

Changelog began tracking from 0.1.0
67 changes: 67 additions & 0 deletions boards/arduino_mkrwifi1010/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
[package]
name = "arduino_mkrwifi1010"
version = "0.1.0"
authors = ["Osvald Ivarsson <[email protected]>"]
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.15"
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"] }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you managed to get your changes upstreamed? I don't really like depending on someone's personal branch. That feels very hacky. Plus, I don't think you can even publish to crates.io if you have a Git dependency.

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"]
45 changes: 45 additions & 0 deletions boards/arduino_mkrwifi1010/README.md
Original file line number Diff line number Diff line change
@@ -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`
16 changes: 16 additions & 0 deletions boards/arduino_mkrwifi1010/build.rs
Original file line number Diff line number Diff line change
@@ -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");
}
38 changes: 38 additions & 0 deletions boards/arduino_mkrwifi1010/examples/blinky_basic.rs
Original file line number Diff line number Diff line change
@@ -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.d6.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();
}
}
118 changes: 118 additions & 0 deletions boards/arduino_mkrwifi1010/examples/onboard_rgb_led.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// 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.SERCOM4,
&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
}
}
Loading