Skip to content

Instantly share code, notes, and snippets.

@BenBergman
Last active January 21, 2020 15:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BenBergman/161432bde25f633d1cb4c61027f790a7 to your computer and use it in GitHub Desktop.
Save BenBergman/161432bde25f633d1cb4c61027f790a7 to your computer and use it in GitHub Desktop.
Trying to get M0 USB working, starting with the Circuit Python Express
[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"]
#![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,
))
}
#![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