diff --git a/boards/feather_m4_can/.cargo/config.toml b/boards/feather_m4_can/.cargo/config.toml
new file mode 100644
index 000000000000..eb96b4c41105
--- /dev/null
+++ b/boards/feather_m4_can/.cargo/config.toml
@@ -0,0 +1,15 @@
+# vim:ft=toml:
+[target.thumbv7em-none-eabihf]
+runner = 'arm-none-eabi-gdb'
+# runner = 'probe-run --chip ATSAMD51J19A'
+
+[build]
+target = "thumbv7em-none-eabihf"
+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/feather_m4_can/CHANGELOG.md b/boards/feather_m4_can/CHANGELOG.md
new file mode 100644
index 000000000000..24393864da82
--- /dev/null
+++ b/boards/feather_m4_can/CHANGELOG.md
@@ -0,0 +1,27 @@
+# Unreleased
+
+# v0.10.1
+
+- Update to `atsamd-hal` version `0.15.1`
+- Make use of `bsp_peripherals` macro
+
+# v0.10.0
+
+- Update `lib.rs` and examples to reflect removal of `v1` APIs and promotion of `v2` APIs
+- Add an `i2c` example
+- Update `i2c_master` convenience function to use the new `sercom::v2::i2c` API
+- Updated to 2021 edition, updated dependencies, removed unused dependencies (#562)
+
+# v0.9.0
+
+- replace deprecated `SpinTimer` with `TimerCounter` in the `neopixel_rainbow` example
+- remove extraneous `embedded-hal` dependencies from BSPs
+- cleanup `cortex_m` dependency
+- move `usbd-x` crates used only in examples to `[dev-dependencies]`
+- removed unnecessary dependency on `nb` (#510)
+- add Public Key Cryptography Controller (PUKCC) example (#486)
+- Update to use refactored SPI module (#467)
+
+---
+
+Changelog tracking started at v0.8.0
diff --git a/boards/feather_m4_can/Cargo.toml b/boards/feather_m4_can/Cargo.toml
new file mode 100644
index 000000000000..e3c70be87ed5
--- /dev/null
+++ b/boards/feather_m4_can/Cargo.toml
@@ -0,0 +1,59 @@
+[package]
+name = "feather_m4_can"
+version = "0.10.1"
+edition = "2021"
+authors = ["Theodore DeRego <tderego94@gmail.com>"]
+description = "Board Support crate for the Adafruit Feather M4 CAN"
+keywords = ["no-std", "arm", "cortex-m", "embedded-hal"]
+categories = ["embedded", "hardware-support", "no-std"]
+license = "MIT OR Apache-2.0"
+repository = "https://github.com/atsamd-rs/atsamd"
+readme = "README.md"
+documentation = "https://atsamd-rs.github.io/atsamd/atsamd51j/feather_m4/"
+
+# for cargo flash
+[package.metadata]
+chip = "ATSAMD51J19A"
+
+[dependencies.cortex-m-rt]
+version = "0.7"
+optional = true
+
+[dependencies.atsamd-hal]
+path = "../../hal"
+version = "0.15.1"
+default-features = false
+
+[dependencies.usb-device]
+version = "0.2"
+optional = true
+
+[dev-dependencies]
+cortex-m = "0.7"
+usbd-serial = "0.1"
+panic-halt = "0.2"
+panic-semihosting = "0.5"
+smart-leds = "0.3"
+ws2812-timer-delay = "0.3"
+heapless = "0.7"
+
+[features]
+# ask the HAL to enable atsamd51j support
+default = ["rt", "atsamd-hal/samd51j", "atsamd-hal/samd51"]
+rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"]
+unproven = ["atsamd-hal/unproven"]
+usb = ["atsamd-hal/usb", "usb-device"]
+dma = ["atsamd-hal/dma", "unproven"]
+max-channels = ["dma", "atsamd-hal/dma"]
+
+
+[profile.dev]
+incremental = false
+codegen-units = 1
+debug = true
+lto = true
+
+[profile.release]
+debug = true
+lto = true
+opt-level = "s"
diff --git a/boards/feather_m4_can/README.md b/boards/feather_m4_can/README.md
new file mode 100644
index 000000000000..87548bba6ebe
--- /dev/null
+++ b/boards/feather_m4_can/README.md
@@ -0,0 +1,26 @@
+# Adafruit Feather M4 CAN Board Support Crate
+
+This crate provides a type-safe API for working with the [Adafruit Feather M4 CAN
+board](https://www.adafruit.com/product/4759).
+
+## Prerequisites
+* Install the cross compile toolchain `rustup target add thumbv7em-none-eabihf`
+* Install [cargo-hf2 the hf2 bootloader flasher tool](https://crates.io/crates/cargo-hf2) however your platform requires
+
+## Uploading an example
+Check out the repository for examples:
+
+https://github.com/atsamd-rs/atsamd/tree/master/boards/feather_m4_can/examples
+
+* Be in this directory `cd boards/feather_m4`
+* Put your device in bootloader mode usually by hitting the reset button twice.
+* Build and upload in one step
+```
+$ cargo hf2 --release --example blinky_basic
+    Finished release [optimized + debuginfo] target(s) in 0.19s
+    Searching for a connected device with known vid/pid pair.
+    Trying  Ok(Some("Adafruit Industries")) Ok(Some("PyBadge"))
+    Flashing "/Users/User/atsamd/boards/feather_m4/target/thumbv7em-none-eabihf/release/examples/blinky_basic"
+    Finished in 0.079s
+$
+```
diff --git a/boards/feather_m4_can/build.rs b/boards/feather_m4_can/build.rs
new file mode 100644
index 000000000000..4bed4688f2c0
--- /dev/null
+++ b/boards/feather_m4_can/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/feather_m4_can/examples/blinky_basic.rs b/boards/feather_m4_can/examples/blinky_basic.rs
new file mode 100644
index 000000000000..26d182ed1306
--- /dev/null
+++ b/boards/feather_m4_can/examples/blinky_basic.rs
@@ -0,0 +1,37 @@
+#![no_std]
+#![no_main]
+
+use feather_m4_can as bsp;
+#[cfg(not(feature = "use_semihosting"))]
+use panic_halt as _;
+#[cfg(feature = "use_semihosting")]
+use panic_semihosting as _;
+
+use bsp::entry;
+use bsp::hal;
+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_external_32kosc(
+        peripherals.GCLK,
+        &mut peripherals.MCLK,
+        &mut peripherals.OSC32KCTRL,
+        &mut peripherals.OSCCTRL,
+        &mut peripherals.NVMCTRL,
+    );
+    let pins = bsp::Pins::new(peripherals.PORT);
+    let mut red_led = pins.d13.into_push_pull_output();
+    let mut delay = Delay::new(core.SYST, &mut clocks);
+    loop {
+        delay.delay_ms(2000u16);
+        red_led.set_high().unwrap();
+        delay.delay_ms(2000u16);
+        red_led.set_low().unwrap();
+    }
+}
diff --git a/boards/feather_m4_can/examples/neopixel_rainbow.rs b/boards/feather_m4_can/examples/neopixel_rainbow.rs
new file mode 100644
index 000000000000..656afbc7b058
--- /dev/null
+++ b/boards/feather_m4_can/examples/neopixel_rainbow.rs
@@ -0,0 +1,67 @@
+#![no_std]
+#![no_main]
+
+// Neopixel Rainbow
+// This only functions when the --release version is compiled. Using the debug
+// version leads to slow pulse durations which results in a straight white LED
+// output.
+//
+// // Needs to be compiled with --release for the timing to be correct
+
+use bsp::hal;
+use feather_m4_can as bsp;
+
+#[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::timer::*;
+
+use smart_leds::{
+    hsv::{hsv2rgb, Hsv},
+    SmartLedsWrite,
+};
+use ws2812_timer_delay::Ws2812;
+
+#[entry]
+fn main() -> ! {
+    let mut peripherals = Peripherals::take().unwrap();
+    let core = CorePeripherals::take().unwrap();
+    let mut clocks = GenericClockController::with_external_32kosc(
+        peripherals.GCLK,
+        &mut peripherals.MCLK,
+        &mut peripherals.OSC32KCTRL,
+        &mut peripherals.OSCCTRL,
+        &mut peripherals.NVMCTRL,
+    );
+    let pins = bsp::Pins::new(peripherals.PORT);
+    let mut delay = Delay::new(core.SYST, &mut clocks);
+
+    let gclk0 = clocks.gclk0();
+    let timer_clock = clocks.tc2_tc3(&gclk0).unwrap();
+    let mut timer = TimerCounter::tc3_(&timer_clock, peripherals.TC3, &mut peripherals.MCLK);
+    timer.start(3.mhz());
+
+    let neopixel_pin = pins.neopixel.into_push_pull_output();
+    let mut neopixel_power_pin = pins.neopixel_pwr.into_push_pull_output();
+    neopixel_power_pin.set_high().unwrap();
+    let mut neopixel = Ws2812::new(timer, neopixel_pin);
+
+    loop {
+        for j in 0..255u8 {
+            let colors = [hsv2rgb(Hsv {
+                hue: j,
+                sat: 255,
+                val: 2,
+            })];
+            neopixel.write(colors.iter().cloned()).unwrap();
+            delay.delay_ms(5u8);
+        }
+    }
+}
diff --git a/boards/feather_m4_can/memory.x b/boards/feather_m4_can/memory.x
new file mode 100644
index 000000000000..073403cecc8e
--- /dev/null
+++ b/boards/feather_m4_can/memory.x
@@ -0,0 +1,8 @@
+MEMORY
+{
+  /* Leave 16k for the default bootloader on the Feather M4 */
+  FLASH (rx) : ORIGIN = 0x00000000 + 16K, LENGTH = 512K - 16K
+  RAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 192K
+}
+_stack_start = ORIGIN(RAM) + LENGTH(RAM);
+
diff --git a/boards/feather_m4_can/src/lib.rs b/boards/feather_m4_can/src/lib.rs
new file mode 100644
index 000000000000..3cfa9d3662ca
--- /dev/null
+++ b/boards/feather_m4_can/src/lib.rs
@@ -0,0 +1,297 @@
+#![no_std]
+#![deny(missing_docs)]
+
+//! Board support crate for Adafruit's Feather M4 Express,
+//! an ATSAMD51-based board in Feather form factor.
+
+#[cfg(feature = "rt")]
+pub use cortex_m_rt::entry;
+
+pub use atsamd_hal as hal;
+pub use hal::ehal;
+pub use hal::pac;
+
+use hal::clock::GenericClockController;
+use hal::sercom::{
+    i2c, spi,
+    uart::{self, BaudMode, Oversampling},
+    IoSet1, UndocIoSet1,
+};
+use hal::time::Hertz;
+
+#[cfg(feature = "usb")]
+use hal::usb::usb_device::bus::UsbBusAllocator;
+#[cfg(feature = "usb")]
+pub use hal::usb::UsbBus;
+
+hal::bsp_peripherals!(
+    SERCOM1 { SpiSercom }
+    SERCOM2 { I2cSercom }
+    SERCOM5 { UartSercom }
+);
+
+hal::bsp_pins!(
+    PA02 {
+        /// Analog pin 0.  Can act as a true analog output
+        /// as it has a DAC (which is not currently supported
+        /// by this hal) as well as input.
+        name: a0,
+    }
+    PA05 {
+        /// Analog Pin 1
+        name: a1,
+    }
+    PB08 {
+        /// Analog Pin 2
+        name: a2,
+    }
+    PB09 {
+        /// Analog Pin 3
+        name: a3,
+    }
+    PA04 {
+        /// Analog Pin 4
+        name: a4,
+    }
+    PA06 {
+        /// Analog Pin 5
+        name: a5,
+    }
+    PB01 {
+        /// Analog Vdiv (1/2 resistor divider for monitoring the battery)
+        name: battery,
+    }
+
+    PB17 {
+        /// Pin 0, UART rx
+        name: d0,
+        aliases: {
+            AlternateC: UartRx
+        }
+    }
+    PB16 {
+        /// Pin 1, UART tx
+        name: d1,
+        aliases: {
+            AlternateC: UartTx
+        }
+    }
+    PA14 {
+        /// Pin 4, PWM capable
+        name: d4,
+    }
+    PA16 {
+        /// Pin 5, PWM capable
+        name: d5,
+    }
+    PA18 {
+        /// Pin 6, PWM capable
+        name: d6,
+    }
+    PB02 {
+        /// Neopixel Pin
+        name: neopixel,
+    }
+    PB03 {
+        /// Neopixel Pin
+        name: neopixel_pwr,
+    }
+    PA19 {
+        /// Pin 9, PWM capable.  Also analog input (A7)
+        name: d9,
+    }
+    PA20 {
+        /// Pin 10, PWM capable
+        name: d10,
+    }
+    PA21 {
+        /// Pin 11, PWM capable
+        name: d11,
+    }
+    PA22 {
+        /// Pin 12, PWM capable
+        name: d12,
+    }
+    PA23 {
+        /// Pin 13, which is also attached to the red LED. PWM capable.
+        name: d13,
+        aliases: {
+            PushPullOutput: RedLed,
+            AlternateE: RedLedPwm
+        }
+    }
+    PA12 {
+        /// The I2C data line
+        name: sda,
+        aliases: {
+            AlternateC: Sda
+        }
+    }
+    PA13 {
+        /// The I2C clock line
+        name: scl,
+        aliases: {
+            AlternateC: Scl
+        }
+    }
+    PA17 {
+        /// The SPI SCK
+        name: sck,
+        aliases: {
+            AlternateC: Sclk
+        }
+    }
+    PB23 {
+        /// The SPI MOSI
+        name: mosi,
+        aliases: {
+            AlternateC: Mosi
+        }
+    }
+    PB22 {
+        /// The SPI MISO
+        name: miso,
+        aliases: {
+            AlternateC: Miso
+        }
+    }
+    PA24 {
+        /// The USB D- pad
+        name: usb_dm,
+        aliases: {
+            AlternateG: UsbDm
+        }
+    }
+    PA25 {
+        /// The USB D+ pad
+        name: usb_dp,
+        aliases: {
+            AlternateG: UsbDp
+        }
+    }
+    PB12 {
+        /// CAN1_S
+        name: can1_s,
+    }
+    PB13 {
+        /// BOOST Enable
+        name: boost_en,
+    }
+    PB14 {
+        /// CAN1_TX
+        name: can1_tx,
+    }
+    PB15 {
+        /// CAN1_RX
+        name: can1_rx,
+    }
+);
+
+/// SPI pads for the labelled SPI peripheral
+///
+/// You can use these pads with other, user-defined [`spi::Config`]urations.
+pub type SpiPads = spi::Pads<SpiSercom, UndocIoSet1, Miso, Mosi, Sclk>;
+
+/// SPI master for the labelled SPI peripheral
+///
+/// This type implements [`FullDuplex<u8>`](ehal::spi::FullDuplex).
+pub type Spi = spi::Spi<spi::Config<SpiPads>, 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<Hertz>,
+    sercom: SpiSercom,
+    mclk: &mut pac::MCLK,
+    sclk: impl Into<Sclk>,
+    mosi: impl Into<Mosi>,
+    miso: impl Into<Miso>,
+) -> Spi {
+    let gclk0 = clocks.gclk0();
+    let clock = clocks.sercom1_core(&gclk0).unwrap();
+    let freq = clock.freq();
+    let (miso, mosi, sclk) = (miso.into(), mosi.into(), sclk.into());
+    let pads = spi::Pads::default().data_in(miso).data_out(mosi).sclk(sclk);
+    spi::Config::new(mclk, sercom, pads, freq)
+        .baud(baud)
+        .spi_mode(spi::MODE_0)
+        .enable()
+}
+
+/// I2C pads for the labelled I2C peripheral
+///
+/// You can use these pads with other, user-defined [`i2c::Config`]urations.
+pub type I2cPads = i2c::Pads<I2cSercom, IoSet1, Sda, Scl>;
+
+/// 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<i2c::Config<I2cPads>>;
+
+/// 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,
+    baud: impl Into<Hertz>,
+    sercom: I2cSercom,
+    mclk: &mut pac::MCLK,
+    sda: impl Into<Sda>,
+    scl: impl Into<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(mclk, sercom, pads, freq)
+        .baud(baud)
+        .enable()
+}
+
+/// UART pads for the labelled RX & TX pins
+pub type UartPads = uart::Pads<UartSercom, IoSet1, UartRx, UartTx>;
+
+/// UART device for the labelled RX & TX pins
+pub type Uart = uart::Uart<uart::Config<UartPads>, 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<Hertz>,
+    sercom: UartSercom,
+    mclk: &mut pac::MCLK,
+    rx: impl Into<UartRx>,
+    tx: impl Into<UartTx>,
+) -> 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(mclk, sercom, pads, clock.freq())
+        .baud(baud, BaudMode::Fractional(Oversampling::Bits16))
+        .enable()
+}
+
+#[cfg(feature = "usb")]
+/// Convenience function for setting up USB
+pub fn usb_allocator(
+    dm: impl Into<UsbDm>,
+    dp: impl Into<UsbDp>,
+    usb: pac::USB,
+    clocks: &mut GenericClockController,
+    mclk: &mut pac::MCLK,
+) -> UsbBusAllocator<UsbBus> {
+    use pac::gclk::{genctrl::SRC_A, pchctrl::GEN_A};
+
+    clocks.configure_gclk_divider_and_source(GEN_A::GCLK2, 1, SRC_A::DFLL, false);
+    let usb_gclk = clocks.get_gclk(GEN_A::GCLK2).unwrap();
+    let usb_clock = &clocks.usb(&usb_gclk).unwrap();
+    let (dm, dp) = (dm.into(), dp.into());
+    UsbBusAllocator::new(UsbBus::new(usb_clock, mclk, dm, dp, usb))
+}
diff --git a/crates.json b/crates.json
index 609d87809bfd..c0c232494043 100644
--- a/crates.json
+++ b/crates.json
@@ -36,6 +36,10 @@
       "tier": 1,
       "build": "cargo build --examples --all-features"
     },
+    "feather_m4_can": {
+      "tier": 1,
+      "build": "cargo build --examples --all-features"
+    },
     "gemma_m0": {
       "tier": 2,
       "build": "cargo build --examples --features=unproven"