#![no_std] extern crate cortex_m; extern crate embedded_hal; extern crate itsybitsy_m0 as hal; extern crate panic_halt; pub use cortex_m::asm::delay; pub use hal::entry; use atsamd21g18a::{ Peripherals }; use core::u8; use core::fmt::Debug; pub use embedded_hal::digital::v2::OutputPin; use hal::{ clock::GenericClockController, }; use lights::{ HardwareRgb, Lights }; pub fn boot() -> NeopixelLights, impl OutputPin, impl OutputPin> { let mut peripherals = Peripherals::take().unwrap(); let _clock = GenericClockController::with_internal_32kosc( peripherals.GCLK, &mut peripherals.PM, &mut peripherals.SYSCTRL, &mut peripherals.NVMCTRL ); let mut pins = hal::Pins::new(peripherals.PORT); NeopixelLights { out: pins.d7.into_push_pull_output(&mut pins.port), high_out: pins.d5.into_push_pull_output(&mut pins.port), red_led: pins.d13.into_open_drain_output(&mut pins.port), debug_light: false, } } // WS2815 lighting times // approx. 20ns per clock cycle; // const ZERO_HIGH_CYCLES: u32 = 11; // about 220ns // const ONE_HIGH_CYCLES: u32 = 29; // about 580ns // const ZERO_LOW_CYCLES: u32 = 29; // about 580ns // const ONE_LOW_CYCLES: u32 = 11; // about 220ns // experimentally, there is some unknown overhead // but these timings appear to work for me: const ZERO_HIGH_CYCLES: u32 = 11-8; const ONE_HIGH_CYCLES: u32 = 29-8; const ZERO_LOW_CYCLES: u32 = 29-8; const ONE_LOW_CYCLES: u32 = 11-8; const LATCH_CYCLES: u32 = 15000; // about 300us pub struct NeopixelLights { pub out: T, pub high_out: U, pub red_led: V, pub debug_light: bool } impl NeopixelLights where T::Error: Debug, U::Error: Debug, V::Error: Debug, { #[inline] pub fn write(&mut self, bit: bool) { self.high_out.set_high().unwrap(); delay(if bit { ONE_HIGH_CYCLES } else { ZERO_HIGH_CYCLES }); self.high_out.set_low().unwrap(); delay(if bit { ONE_LOW_CYCLES } else { ZERO_LOW_CYCLES }); } #[inline] pub fn byte(&mut self, byte: u8) { self.write(byte & 0x80 != 0); self.write(byte & 0x40 != 0); self.write(byte & 0x20 != 0); self.write(byte & 0x10 != 0); self.write(byte & 0x08 != 0); self.write(byte & 0x04 != 0); self.write(byte & 0x02 != 0); self.write(byte & 0x01 != 0); } /// Blink light, probably to indicate a loop is still running pub fn heartbeat(&mut self) { if self.debug_light { self.red_led.set_low().unwrap(); } else { self.red_led.set_high().unwrap(); } self.debug_light = !self.debug_light; } } impl Lights for NeopixelLights where T::Error: Debug, U::Error: Debug, V::Error: Debug, { type Pixel = HardwareRgb; #[inline] fn render(&mut self, rgb: &HardwareRgb) { // GRB pixel order self.byte(rgb.1); self.byte(rgb.0); self.byte(rgb.2); } #[inline] fn latch(&mut self) { delay(LATCH_CYCLES); } }