holiday_lights/itsybitsy_m0_lights/src/lib.rs

157 lines
4.2 KiB
Rust
Raw Normal View History

2019-03-22 04:53:09 +00:00
#![no_std]
#![feature(asm)]
2019-03-22 04:53:09 +00:00
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 core::fmt::Debug;
use core::sync::atomic::{compiler_fence, Ordering};
2021-07-05 00:30:13 +00:00
use core::u8;
pub use embedded_hal::digital::v2::OutputPin;
2021-07-05 00:30:13 +00:00
use hal::{clock::GenericClockController, pac::Peripherals};
use lights::{HardwareRgb, Lights};
2019-03-22 04:53:09 +00:00
2021-07-05 00:30:13 +00:00
pub fn boot() -> NeopixelLights<
impl OutputPin<Error = ()>,
impl OutputPin<Error = ()>,
impl OutputPin<Error = ()>,
> {
2019-03-22 04:53:09 +00:00
let mut peripherals = Peripherals::take().unwrap();
let _clock = GenericClockController::with_internal_32kosc(
peripherals.GCLK,
&mut peripherals.PM,
&mut peripherals.SYSCTRL,
2021-07-05 00:30:13 +00:00
&mut peripherals.NVMCTRL,
2019-03-22 04:53:09 +00:00
);
let mut pins = hal::Pins::new(peripherals.PORT);
NeopixelLights {
2019-06-14 00:23:35 +00:00
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,
2019-03-22 04:53:09 +00:00
}
}
2021-07-05 05:22:59 +00:00
// WS2815 ideal lighting times
2019-03-22 04:53:09 +00:00
// approx. 20ns per clock cycle;
2019-10-27 05:20:30 +00:00
// 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
2019-06-14 00:23:35 +00:00
const LATCH_CYCLES: u32 = 15000; // about 300us
2019-03-22 04:53:09 +00:00
pub struct NeopixelLights<T: OutputPin, U: OutputPin, V: OutputPin> {
pub out: T,
pub high_out: U,
pub red_led: V,
2021-07-05 00:30:13 +00:00
pub debug_light: bool,
2019-03-22 04:53:09 +00:00
}
impl<T: OutputPin, U: OutputPin, V: OutputPin> NeopixelLights<T, U, V>
where
T::Error: Debug,
U::Error: Debug,
V::Error: Debug,
{
2019-03-22 04:53:09 +00:00
#[inline]
pub fn write(&mut self, bit: bool) {
// go high
self.high_out.set_high().unwrap();
2021-07-05 05:22:59 +00:00
// experimentally, there is some unknown overhead
// but these timings appear to work for me
unsafe {
compiler_fence(Ordering::SeqCst);
asm!(
2021-07-05 05:22:59 +00:00
// 8 nops
"nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;",
);
compiler_fence(Ordering::SeqCst);
}
if bit {
unsafe {
compiler_fence(Ordering::SeqCst);
asm!(
2021-07-05 05:22:59 +00:00
// 14 nops
"nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;",
"nop;", "nop;", "nop;", "nop;",
);
compiler_fence(Ordering::SeqCst);
}
}
// go low
self.high_out.set_low().unwrap();
unsafe {
compiler_fence(Ordering::SeqCst);
asm!(
2021-07-05 05:22:59 +00:00
// 15 nops
"nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;", "nop;",
"nop;", "nop;", "nop;", "nop;", "nop;",
);
compiler_fence(Ordering::SeqCst);
}
2019-03-22 04:53:09 +00:00
}
#[inline]
pub fn byte(&mut self, byte: u8) {
2019-03-22 04:53:09 +00:00
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);
unsafe {
compiler_fence(Ordering::SeqCst);
asm!(
// 5 nops
"nop;", "nop;", "nop;", "nop;", "nop;",
);
compiler_fence(Ordering::SeqCst);
}
2019-03-22 04:53:09 +00:00
}
/// 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;
}
2019-03-22 04:53:09 +00:00
}
impl<T: OutputPin, U: OutputPin, V: OutputPin> Lights for NeopixelLights<T, U, V>
where
T::Error: Debug,
U::Error: Debug,
V::Error: Debug,
{
2019-03-22 04:53:09 +00:00
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]
2019-03-22 04:53:09 +00:00
fn latch(&mut self) {
delay(LATCH_CYCLES);
}
}