-
Notifications
You must be signed in to change notification settings - Fork 201
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
feather_m4_can
board, add mcan
example
- the new `feather_m4_can` board is added as a clone of `feather_m4` with just the chip changed ATSAM(D->E)51J - adapt pinmux: alternate function pins for CAN1 connecting to TCAN1051 transceiver - adapt `mcan` example from `xplain` board replacing button triggering by a periodic task
- Loading branch information
Showing
25 changed files
with
3,313 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
# vim:ft=toml: | ||
[target.thumbv7em-none-eabihf] | ||
runner = 'arm-none-eabi-gdb' | ||
#runner = 'probe-run --chip ATSAME51J19A' | ||
|
||
[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", | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# v0.1.0 | ||
|
||
- The board is added as a clone of `feather_m4` with chip changed ATSAM(D->E)51J | ||
- adapt pinmux: alternate function pins for CAN1 connecting to TCAN1051 transceiver | ||
- clone `mcan` example from `atsame54_xpro` board (using periodic task instead of button) | ||
|
||
--- | ||
|
||
Changelog tracking started at v0.1.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
[package] | ||
name = "feather_m4_can" | ||
version = "0.1.0" | ||
edition = "2021" | ||
authors = ["Theodore DeRego <[email protected]>"] | ||
description = "Board Support crate for the Adafruit Feather M4 CAN" | ||
keywords = ["no-std", "arm", "cortex-m", "embedded-hal", "can"] | ||
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_can/" | ||
|
||
# for cargo flash | ||
[package.metadata] | ||
chip = "ATSAME51J19A" | ||
|
||
[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] | ||
mcan = "0.2" | ||
dwt-systick-monotonic = "1.1" | ||
panic-rtt-target = { version = "0.1", features = ["cortex-m"] } | ||
rtt-target = { version = "0.3", features = ["cortex-m"] } | ||
cortex-m = "0.7" | ||
usbd-serial = "0.1" | ||
cortex-m-rtic = "1.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 atsame51j support | ||
default = ["rt", "atsamd-hal/same51j", "atsamd-hal/same51"] | ||
rt = ["cortex-m-rt", "atsamd-hal/same51j-rt"] | ||
unproven = ["atsamd-hal/unproven"] | ||
usb = ["atsamd-hal/usb", "usb-device"] | ||
can = ["atsamd-hal/can"] | ||
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" | ||
|
||
[[example]] | ||
name = "pwm" | ||
required-features = ["unproven"] | ||
|
||
[[example]] | ||
name = "usb_echo" | ||
required-features = ["usb"] | ||
|
||
[[example]] | ||
name = "dmac" | ||
required-features = ["dma"] | ||
|
||
[[example]] | ||
name = "uart" | ||
required-features = ["dma"] | ||
|
||
[[example]] | ||
name = "pukcc_test" | ||
required-features = ["unproven", "usb"] | ||
|
||
[[example]] | ||
name = "nvm_dsu" | ||
required-features = ["unproven", "usb"] | ||
|
||
[[example]] | ||
name = "smart_eeprom" | ||
required-features = ["unproven", "usb"] | ||
|
||
[[example]] | ||
name = "i2c" | ||
required-features = ["atsamd-hal/dma"] | ||
|
||
[[example]] | ||
name = "mcan" | ||
required-features = ["can"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Adafruit Feather M4 Board Support Crate | ||
|
||
This crate provides a type-safe API for working with the [Adafruit Feather M4 | ||
board](https://www.adafruit.com/product/3857). | ||
|
||
## 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_can` | ||
* 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_can/target/thumbv7em-none-eabihf/release/examples/blinky_basic" | ||
Finished in 0.079s | ||
$ | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
#![no_main] | ||
#![no_std] | ||
|
||
use panic_halt as _; | ||
|
||
use core::fmt::Write as _; | ||
|
||
use atsamd_hal::{ | ||
clock::v2::{ | ||
self as clock, | ||
dpll::Dpll, | ||
gclk::{Gclk, GclkDiv16, GclkDiv8}, | ||
osculp32k::OscUlp32k, | ||
pclk::Pclk, | ||
rtcosc::RtcOsc, | ||
xosc32k::{ControlGainMode, Xosc1k, Xosc32k, Xosc32kBase}, | ||
}, | ||
ehal::serial::Read as _, | ||
ehal::serial::Write, | ||
gpio::{Pins, PA04, PA05}, | ||
rtc::{ClockMode, Rtc}, | ||
sercom::{ | ||
uart::{self, BaudMode, Flags, Oversampling}, | ||
IoSet3, Sercom0, | ||
}, | ||
time::U32Ext, | ||
}; | ||
|
||
use rtic::app; | ||
|
||
type Pads = uart::PadsFromIds<Sercom0, IoSet3, PA05, PA04>; | ||
type Uart = uart::Uart<uart::Config<Pads>, uart::Duplex>; | ||
|
||
#[app(device = atsamd_hal::pac, peripherals = true)] | ||
mod app { | ||
use super::*; | ||
|
||
#[shared] | ||
struct SharedResources { | ||
uart: Uart, | ||
rtc: Rtc<ClockMode>, | ||
} | ||
|
||
#[local] | ||
struct LocalResources {} | ||
|
||
#[init] | ||
fn init(cx: init::Context) -> (SharedResources, LocalResources, init::Monotonics()) { | ||
let mut device = cx.device; | ||
|
||
// Get the clocks & tokens | ||
let (_buses, clocks, tokens) = clock::clock_system_at_reset( | ||
device.OSCCTRL, | ||
device.OSC32KCTRL, | ||
device.GCLK, | ||
device.MCLK, | ||
&mut device.NVMCTRL, | ||
); | ||
|
||
// This is required because the `sercom` and `rtc` modules have not yet | ||
// been update to use `clock::v2` | ||
let (_, _, _, mut mclk) = unsafe { clocks.pac.steal() }; | ||
|
||
// Get the pins | ||
let pins = Pins::new(device.PORT); | ||
|
||
// Take `Dfll` 48 MHz, divide down to `2 MHz` through `Gclk1` | ||
let (gclk1, dfll) = Gclk::from_source(tokens.gclks.gclk1, clocks.dfll); | ||
let gclk1 = gclk1.div(GclkDiv16::Div(24)).enable(); | ||
|
||
// Output `Gclk1` on PB15 pin | ||
let (gclk1, _gclk1_out) = gclk1.enable_gclk_out(pins.pb15); | ||
|
||
// Setup a peripheral channel to power up `Dpll0` from `Gclk1` | ||
let (pclk_dpll0, gclk1) = Pclk::enable(tokens.pclks.dpll0, gclk1); | ||
|
||
// Configure `Dpll0` with `2 * 60 + 0/32 = 120 MHz` frequency | ||
let dpll0 = Dpll::from_pclk(tokens.dpll0, pclk_dpll0) | ||
.loop_div(60, 0) | ||
.enable(); | ||
|
||
// Swap source of `Gclk0` from Dfll to Dpll0, `48 Mhz -> 120 MHz` | ||
let (gclk0, _dfll, _dpll0) = clocks.gclk0.swap_sources(dfll, dpll0); | ||
|
||
// Output `Gclk0` on pin PB14 | ||
let (gclk0, _gclk0_out) = gclk0.enable_gclk_out(pins.pb14); | ||
|
||
// Setup a peripheral channel to power up `Dpll1` from `Gclk1` | ||
let (pclk_dpll1, _gclk1) = Pclk::enable(tokens.pclks.dpll1, gclk1); | ||
|
||
// Configure `Dpll1` with `2 * 50 + 0/32 = 100 MHz` frequency | ||
let dpll1 = Dpll::from_pclk(tokens.dpll1, pclk_dpll1) | ||
.loop_div(50, 0) | ||
.enable(); | ||
|
||
// Output `Dpll1` on PB20 pin via `Gclk6`, divided by 200 resulting in 0.5 MHz | ||
// output frequency | ||
let (gclk6, _dpll1) = Gclk::from_source(tokens.gclks.gclk6, dpll1); | ||
let gclk6 = gclk6.div(GclkDiv8::Div(200)).enable(); | ||
let (_gclk6, _gclk6_out) = gclk6.enable_gclk_out(pins.pb12); | ||
|
||
// Configure `Xosc32k` with both outputs (1kHz, 32kHz) activated | ||
let xosc32k_base = Xosc32kBase::from_crystal(tokens.xosc32k.base, pins.pa00, pins.pa01) | ||
.control_gain_mode(ControlGainMode::HighSpeed) | ||
.on_demand(false) | ||
.run_standby(true) | ||
.enable(); | ||
let (xosc1k, xosc32k_base) = Xosc1k::enable(tokens.xosc32k.xosc1k, xosc32k_base); | ||
let (xosc32k, _xosc32k_base) = Xosc32k::enable(tokens.xosc32k.xosc32k, xosc32k_base); | ||
|
||
// Output `Xosc32k` on PB16 pin via `Gclk2`, divided by 2 resulting in 16 kHz | ||
// output frequency | ||
let (gclk2, _xosc32k) = Gclk::from_source(tokens.gclks.gclk2, xosc32k); | ||
let gclk2 = gclk2.div(GclkDiv8::Div(2)).enable(); | ||
let (_gclk2, _gclk2_out) = gclk2.enable_gclk_out(pins.pb16); | ||
|
||
// Output `OscUlp32k` on PB11 pin via `Gclk5`, without any division resulting in | ||
// 32 kHz output frequency | ||
let (osculp32k, _osculp_base) = | ||
OscUlp32k::enable(tokens.osculp32k.osculp32k, clocks.osculp32k_base); | ||
let (gclk5, _osculp32k) = Gclk::from_source(tokens.gclks.gclk5, osculp32k); | ||
let gclk5 = gclk5.enable(); | ||
let (_gclk5, _gclk5_out) = gclk5.enable_gclk_out(pins.pb11); | ||
|
||
// Setup a peripheral channel to power up `Uart` from `Gclk0` | ||
let (pclk_sercom0, _gclk0) = Pclk::enable(tokens.pclks.sercom0, gclk0); | ||
|
||
use atsamd_hal::sercom::uart; | ||
|
||
let pads = uart::Pads::default().rx(pins.pa05).tx(pins.pa04); | ||
// In the future, the `Uart` will take ownership of the `Pclk` and will | ||
// take an `ApbClk` instead of `&MCLK` | ||
let mut uart = uart::Config::new(&mclk, device.SERCOM0, pads, pclk_sercom0.freq()) | ||
.baud(115_200.hz(), BaudMode::Arithmetic(Oversampling::Bits16)) | ||
.enable(); | ||
uart.enable_interrupts(Flags::RXC); | ||
|
||
// Initialize the RTC oscillator from the 1 kHz output of XOSC32K | ||
let (rtc_osc, _xosc1k) = RtcOsc::enable(tokens.rtcosc, xosc1k); | ||
|
||
// Setup an `Rtc` in `ClockMode` | ||
// In the future, the `Rtc` will take ownership of the `RtcOsc` | ||
let rtc = Rtc::clock_mode(device.RTC, rtc_osc.freq(), &mut mclk); | ||
|
||
writeln!(&mut uart as &mut dyn Write<_, Error = _>, "RTIC booted!").unwrap(); | ||
|
||
( | ||
SharedResources { uart, rtc }, | ||
LocalResources {}, | ||
init::Monotonics(), | ||
) | ||
} | ||
|
||
#[task(binds = SERCOM0_2, shared = [uart, rtc])] | ||
fn uart(cx: uart::Context) { | ||
let mut uart = cx.shared.uart; | ||
let mut rtc = cx.shared.rtc; | ||
// Read from `Uart` to clean interrupt flag | ||
let _ = uart.lock(|u| u.read().unwrap()); | ||
|
||
// Print out `DateTime` coming from `Rtc` | ||
uart.lock(|u| { | ||
writeln!( | ||
u as &mut dyn Write<_, Error = _>, | ||
"{:#?}", | ||
rtc.lock(|r| r.current_time()) | ||
) | ||
.unwrap() | ||
}); | ||
} | ||
} |
Oops, something went wrong.