Last active
January 21, 2020 15:06
-
-
Save BenBergman/161432bde25f633d1cb4c61027f790a7 to your computer and use it in GitHub Desktop.
Trying to get M0 USB working, starting with the Circuit Python Express
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
[package] | |
name = "circuit_playground_express" | |
version = "0.5.0" | |
authors = ["Paul Sajna <paulsajna@gmail.com>"] | |
description = "Board Support crate for the Adafruit Circuit Playground Express" | |
keywords = ["no-std", "arm", "cortex-m", "embedded-hal"] | |
license = "MIT OR Apache-2.0" | |
repository = "https://github.com/atsamd-rs/atsamd" | |
readme = "README.md" | |
documentation = "https://atsamd-rs.github.io/atsamd/atsamd21g18a/circuit_playground_express/" | |
edition = "2018" | |
[dependencies] | |
cortex-m = "~0.6" | |
embedded-hal = "~0.2" | |
nb = "~0.1" | |
[dependencies.cortex-m-rt] | |
version = "^0.6.10" | |
optional = true | |
[dependencies.atsamd-hal] | |
path = "../../hal" | |
version = "~0.7" | |
default-features = false | |
[dev-dependencies] | |
panic-halt = "~0.2" | |
panic_rtt = "~0.2" | |
[dependencies.usb-device] | |
version = "~0.2" | |
optional = true | |
[dependencies.usbd-serial] | |
version = "~0.1" | |
optional = true | |
[features] | |
# ask the HAL to enable atsamd21g18a support | |
default = ["rt", "atsamd-hal/samd21g18a"] | |
rt = ["cortex-m-rt", "atsamd-hal/samd21g18a-rt"] | |
unproven = ["atsamd-hal/unproven"] | |
use_semihosting = [] | |
use_rtt = ["atsamd-hal/use_rtt"] | |
usb = ["atsamd-hal/usb", "usb-device", "usbd-serial"] | |
[profile.dev] | |
incremental = false | |
codegen-units = 1 | |
debug = true | |
lto = false | |
[profile.release] | |
debug = true | |
lto = true | |
opt-level = "s" | |
[[example]] | |
name = "usb_serial" | |
required-features = ["usb"] | |
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
#![no_std] | |
extern crate atsamd_hal as hal; | |
#[cfg(feature = "rt")] | |
pub use cortex_m_rt::entry; | |
use hal::prelude::*; | |
use hal::*; | |
pub use hal::target_device as pac; | |
pub use hal::common::*; | |
pub use hal::samd21::*; | |
use gpio::{Floating, Input, Output, Port, PushPull}; | |
use hal::clock::GenericClockController; | |
#[cfg(feature = "usb")] | |
use hal::gpio::IntoFunction; | |
#[cfg(feature = "usb")] | |
use crate::pac::gclk::{genctrl::SRC_A, clkctrl::GEN_A}; | |
#[cfg(feature = "usb")] | |
use usb_device::bus::UsbBusAllocator; | |
#[cfg(feature = "usb")] | |
use hal::usb::UsbBus; | |
use hal::sercom::{I2CMaster5, PadPin, SPIMaster3}; | |
use hal::time::Hertz; | |
define_pins!( | |
/// Maps the pins to their arduino names and | |
/// the numbers printed on the board. | |
struct Pins, | |
target_device: target_device, | |
/// Pin 0, rx. Also analog input (A6) | |
pin rx = b9, | |
/// Pin 1, tx. Also analog input (A7) | |
pin tx = b8, | |
/// Pin 4, button A. | |
pin d4 = a28, | |
/// Pin 5, button B. | |
pin d5 = a14, | |
/// Pin 7, slide switch. | |
pin d7 = a15, | |
/// Pin 11, speaker enable. | |
pin d11 = a30, | |
/// Digital pin number 13, which is also attached to the red LED. PWM capable. | |
pin d13 = a17, | |
/// The I2C SDA. Also D2 and A5. | |
pin sda = b2, | |
/// The I2C SCL. Also D3 and A4 | |
pin scl = b3, | |
/// The data line attached to the neopixel. Also D8. | |
pin neopixel = b23, | |
/// The line attached to the speaker. Also D12 and A0. | |
pin speaker = a2, | |
/// The SPI SCK. Also D6 and A1 | |
pin sck = a5, | |
/// The SPI MOSI. Also D10 and A3 | |
pin mosi = a7, | |
/// The SPI MISO. Also D9 and A2 | |
pin miso = a6, | |
/// The SCK pin attached to the on-board SPI flash | |
pin flash_sck = a21, | |
/// The MOSI pin attached to the on-board SPI flash | |
pin flash_mosi = a20, | |
/// The MISO pin attached to the on-board SPI flash | |
pin flash_miso = a16, | |
/// The CS pin attached to the on-board SPI flash | |
pin flash_cs = b22, | |
pin accel_sda = a0, | |
pin accel_scl = a1, | |
/// The USB D- pad | |
pin usb_dm = a24, | |
/// The USB D+ pad | |
pin usb_dp = a25, | |
); | |
/// Convenience for accessing the on-board SPI Flash device. | |
/// This powers up SERCOM5 and configures it for use as an | |
/// SPI Master. | |
pub fn flash_spi_master( | |
clocks: &mut GenericClockController, | |
sercom3: pac::SERCOM3, | |
pm: &mut pac::PM, | |
sck: gpio::Pa21<Input<Floating>>, | |
mosi: gpio::Pa20<Input<Floating>>, | |
miso: gpio::Pa16<Input<Floating>>, | |
cs: gpio::Pb22<Input<Floating>>, | |
port: &mut Port, | |
) -> (SPIMaster3< | |
hal::sercom::Sercom3Pad0<gpio::Pa16<gpio::PfD>>, | |
hal::sercom::Sercom3Pad2<gpio::Pa20<gpio::PfD>>, | |
hal::sercom::Sercom3Pad3<gpio::Pa21<gpio::PfD>>, | |
>, gpio::Pb22<Output<PushPull>>) { | |
let gclk0 = clocks.gclk0(); | |
let flash = SPIMaster3::new( | |
&clocks.sercom3_core(&gclk0).unwrap(), | |
48.mhz(), | |
hal::hal::spi::Mode { | |
phase: hal::hal::spi::Phase::CaptureOnFirstTransition, | |
polarity: hal::hal::spi::Polarity::IdleLow, | |
}, | |
sercom3, | |
pm, | |
(miso.into_pad(port), mosi.into_pad(port), sck.into_pad(port)), | |
); | |
let mut cs = cs.into_push_pull_output(port); | |
// We’re confident that set_high won’t error here because on-board | |
// GPIO pins don’t error. | |
cs.set_high().unwrap(); | |
(flash, cs) | |
} | |
/// Convenience for setting up the labelled SDA, SCL pins to | |
/// operate as an I2C master running at the specified frequency. | |
pub fn i2c_master<F: Into<Hertz>>( | |
clocks: &mut GenericClockController, | |
bus_speed: F, | |
sercom5: pac::SERCOM5, | |
pm: &mut pac::PM, | |
sda: gpio::Pb2<Input<Floating>>, | |
scl: gpio::Pb3<Input<Floating>>, | |
port: &mut Port, | |
) -> I2CMaster5< | |
hal::sercom::Sercom5Pad0<gpio::Pb2<gpio::PfD>>, | |
hal::sercom::Sercom5Pad1<gpio::Pb3<gpio::PfD>>, | |
> { | |
let gclk0 = clocks.gclk0(); | |
I2CMaster5::new( | |
&clocks.sercom5_core(&gclk0).unwrap(), | |
bus_speed.into(), | |
sercom5, | |
pm, | |
sda.into_pad(port), | |
scl.into_pad(port), | |
) | |
} | |
#[cfg(feature = "usb")] | |
pub fn usb_allocator( | |
usb: pac::USB, | |
clocks: &mut GenericClockController, | |
pm: &mut pac::PM, | |
usb_dm: gpio::Pa24<Input<Floating>>, | |
usb_dp: gpio::Pa25<Input<Floating>>, | |
port: &mut Port, | |
) -> UsbBusAllocator<UsbBus> { | |
clocks.configure_gclk_divider_and_source(GEN_A::GCLK0, 1, SRC_A::DFLL48M, false); | |
let usb_gclk = clocks.get_gclk(GEN_A::GCLK0).unwrap(); | |
let usb_clock = &clocks.usb(&usb_gclk).unwrap(); | |
UsbBusAllocator::new(UsbBus::new( | |
usb_clock, | |
pm, | |
usb_dm.into_function(port), | |
usb_dp.into_function(port), | |
usb, | |
)) | |
} |
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
#![no_std] | |
#![no_main] | |
extern crate circuit_playground_express as hal; | |
extern crate panic_rtt; | |
use cortex_m_rt::{exception, ExceptionFrame}; | |
use hal::clock::GenericClockController; | |
use hal::prelude::*; | |
use hal::{entry}; | |
use hal::delay::Delay; | |
use hal::pac::{interrupt, Interrupt, CorePeripherals, Peripherals}; | |
use hal::usb::UsbBus; | |
use hal::usb_allocator; | |
use usb_device::bus::UsbBusAllocator; | |
use usb_device::prelude::*; | |
use usbd_serial::{SerialPort, USB_CLASS_CDC}; | |
static mut USB_ALLOCATOR: Option<UsbBusAllocator<UsbBus>> = None; | |
static mut USB_BUS: Option<UsbDevice<UsbBus>> = None; | |
static mut USB_SERIAL: Option<SerialPort<UsbBus>> = None; | |
#[entry] | |
fn main() -> ! { | |
//dbgprint!("main entered"); | |
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 mut pins = hal::Pins::new(peripherals.PORT); | |
let mut core = CorePeripherals::take().unwrap(); | |
let mut delay = Delay::new(core.SYST, &mut clocks); | |
let mut red_led = pins.d13.into_open_drain_output(&mut pins.port); | |
red_led.set_high().unwrap(); | |
red_led.set_low().unwrap(); | |
delay.delay_ms(1000u16); | |
//dbgprint!("make usb_bus"); | |
for _ in 1..2 { | |
delay.delay_ms(100u8); | |
red_led.set_high().unwrap(); | |
delay.delay_ms(100u8); | |
red_led.set_low().unwrap(); | |
} | |
delay.delay_ms(1000u16); | |
let bus_allocator = unsafe { | |
USB_ALLOCATOR = Some(usb_allocator( | |
peripherals.USB, | |
&mut clocks, | |
&mut peripherals.PM, | |
pins.usb_dm, | |
pins.usb_dp, | |
&mut pins.port, | |
)); | |
USB_ALLOCATOR.as_ref().unwrap() | |
}; | |
for _ in 1..3 { | |
delay.delay_ms(100u8); | |
red_led.set_high().unwrap(); | |
delay.delay_ms(100u8); | |
red_led.set_low().unwrap(); | |
} | |
delay.delay_ms(1000u16); | |
unsafe { | |
USB_BUS = Some( | |
UsbDeviceBuilder::new(&bus_allocator, UsbVidPid(0x16c0, 0x27dd)) | |
.manufacturer("Fake company") | |
.product("Serial port") | |
.serial_number("TEST") | |
.device_class(USB_CLASS_CDC) | |
.build(), | |
); | |
}; | |
for _ in 1..4 { | |
delay.delay_ms(100u8); | |
red_led.set_high().unwrap(); | |
delay.delay_ms(100u8); | |
red_led.set_low().unwrap(); | |
} | |
delay.delay_ms(1000u16); | |
//dbgprint!("make serial"); | |
unsafe { | |
USB_SERIAL = Some(SerialPort::new(&bus_allocator)); | |
}; | |
for _ in 1..5 { | |
delay.delay_ms(100u8); | |
red_led.set_high().unwrap(); | |
delay.delay_ms(100u8); | |
red_led.set_low().unwrap(); | |
} | |
delay.delay_ms(1000u16); | |
unsafe { | |
core.NVIC.set_priority(Interrupt::USB, 0); | |
} | |
core.NVIC.enable(Interrupt::USB); | |
//dbgprint!("do loop"); | |
loop { | |
delay.delay_ms(200u8); | |
red_led.set_low().unwrap(); | |
delay.delay_ms(100u8); | |
red_led.set_high().unwrap(); | |
} | |
} | |
fn poll_usb() { | |
unsafe { | |
match (USB_BUS.as_mut(), USB_SERIAL.as_mut()) { | |
(Some(usb_dev), Some(serial)) => { | |
usb_dev.poll(&mut [serial]); | |
let mut buf = [0u8; 8]; | |
match serial.read(&mut buf) { | |
Ok(count) if count > 0 => { | |
// Echo back in upper case | |
for c in buf[0..count].iter_mut() { | |
if 0x61 <= *c && *c <= 0x7a { | |
*c &= !0x20; | |
} | |
} | |
serial.write(&buf[0..count]).ok(); | |
} | |
_ => {} | |
} | |
}, | |
_ => {} | |
}; | |
}; | |
} | |
#[exception] | |
fn HardFault(ef: &ExceptionFrame) -> ! { | |
//dbgprint!("hard_fault"); | |
panic!("{:#?}", ef); | |
} | |
#[interrupt] | |
fn USB() { | |
poll_usb(); | |
} | |
#[exception] | |
fn DefaultHandler(irqn: i16) { | |
//dbgprint!("default_handler"); | |
panic!("Unhandled exception (IRQn = {})", irqn); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment