Skip to content

Commit

Permalink
examples(pygamer): Restore neopixel examples using SPI driver
Browse files Browse the repository at this point in the history
  • Loading branch information
jbeaurivage committed Dec 9, 2024
1 parent 8243da6 commit 275d0e8
Show file tree
Hide file tree
Showing 7 changed files with 547 additions and 1 deletion.
26 changes: 26 additions & 0 deletions boards/pygamer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ version = "0.20.0"
optional = true
version = "0.3.2"

[dependencies.ws2812-spi]
version = "0.5.0"
features = ["mosi_idle_high"]
optional = true

[dev-dependencies]
embedded-graphics = "0.8.1"
embedded-sdmmc = "0.8.0"
Expand All @@ -52,6 +57,7 @@ max-channels = ["dma", "atsamd-hal/max-channels"]
panic_led = []
rt = ["cortex-m-rt", "atsamd-hal/samd51j-rt"]
usb = ["atsamd-hal/usb", "usb-device"]
neopixel-spi = ["dep:ws2812-spi"]
# Enable async support from atsamd-hal
async = ["atsamd-hal/async"]

Expand Down Expand Up @@ -89,3 +95,23 @@ name = "timer"
[[example]]
name = "usb_poll"
required-features = ["usb"]

[[example]]
name = "neopixel_adc_battery"
required-features = ["neopixel-spi"]

[[example]]
name = "neopixel_adc_light"
required-features = ["neopixel-spi"]

[[example]]
name = "neopixel_button"
required-features = ["neopixel-spi"]

[[example]]
name = "neopixel_easing"
required-features = ["neopixel-spi"]

[[example]]
name = "neopixel_rainbow"
required-features = ["neopixel-spi"]
89 changes: 89 additions & 0 deletions boards/pygamer/examples/neopixel_adc_battery.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//! Display battery percentage on the neopixels.
//!
//! Note leds may appear white during debug. Either build for release or add
//! opt-level = 2 to profile.dev in Cargo.toml
#![no_std]
#![no_main]

#[cfg(not(feature = "panic_led"))]
use panic_halt as _;
use pygamer::{entry, hal, pac, Pins};

use hal::adc::Adc;
use hal::{clock::GenericClockController, delay::Delay};

use pac::gclk::pchctrl::Genselect::Gclk11;

use hal::ehal::delay::DelayNs;

use pac::{CorePeripherals, Peripherals};
use smart_leds::{brightness, SmartLedsWrite, RGB8};

#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
let core = CorePeripherals::take().unwrap();
let mut clocks = GenericClockController::with_internal_32kosc(
peripherals.gclk,
&mut peripherals.mclk,
&mut peripherals.osc32kctrl,
&mut peripherals.oscctrl,
&mut peripherals.nvmctrl,
);
let pins = Pins::new(peripherals.port).split();

let mut adc0 = Adc::adc0(peripherals.adc0, &mut peripherals.mclk, &mut clocks, Gclk11);
let mut battery = pins.battery.init();

// neopixels
let mut neopixel = pins.neopixel.init_spi(
&mut clocks,
// Unfortunately, the SPI driver requires a clock pin, even though it's not used by the
// neopixels.
pins.i2c.scl,
peripherals.sercom2,
&mut peripherals.mclk,
);

let mut delay = Delay::new(core.SYST, &mut clocks);

//todo put this on a .. 10minute, 30min, update timer
loop {
let battery_data = battery.read(&mut adc0);

let mut colors = [
RGB8::default(),
RGB8::default(),
RGB8::default(),
RGB8::default(),
RGB8::default(),
];

if battery_data < 3.6 {
enable_leds(1, &mut colors);
} else if (3.6..3.8).contains(&battery_data) {
enable_leds(2, &mut colors);
} else if (3.8..3.9).contains(&battery_data) {
enable_leds(3, &mut colors);
} else if (3.9..4.0).contains(&battery_data) {
enable_leds(4, &mut colors);
} else {
enable_leds(5, &mut colors);
};

neopixel
.write(brightness(colors.iter().cloned(), 1))
.unwrap();

// Reset the LEDs
delay.delay_ms(10);
}
}

/// Turn on the specified number of LEDs and set the color to red.
fn enable_leds(num_leds: usize, colors: &mut [RGB8]) {
for color in colors.iter_mut().take(num_leds) {
*color = RGB8::from((255, 0, 0));
}
}
88 changes: 88 additions & 0 deletions boards/pygamer/examples/neopixel_adc_light.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! Display light sensor reading on the neopixels.
//!
//! Note leds may appear white during debug. Either build for release or add
//! opt-level = 2 to profile.dev in Cargo.toml
#![no_std]
#![no_main]

#[cfg(not(feature = "panic_led"))]
use panic_halt as _;
use pygamer::{entry, hal, pac, Pins};

use hal::adc::Adc;
use hal::prelude::*;
use hal::{clock::GenericClockController, delay::Delay};
use pac::gclk::pchctrl::Genselect::Gclk11;
use pac::{CorePeripherals, Peripherals};
use smart_leds::SmartLedsWrite;
use smart_leds::{
hsv::{hsv2rgb, Hsv},
RGB8,
};

#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
let core = CorePeripherals::take().unwrap();
let mut clocks = GenericClockController::with_internal_32kosc(
peripherals.gclk,
&mut peripherals.mclk,
&mut peripherals.osc32kctrl,
&mut peripherals.oscctrl,
&mut peripherals.nvmctrl,
);
let pins = Pins::new(peripherals.port).split();

let mut adc1 = Adc::adc1(peripherals.adc1, &mut peripherals.mclk, &mut clocks, Gclk11);
let mut light = pins.light_pin.into_alternate();

// neopixels
let mut neopixel = pins.neopixel.init_spi(
&mut clocks,
// Unfortunately, the SPI driver requires a clock pin, even though it's not used by the
// neopixels.
pins.i2c.scl,
peripherals.sercom2,
&mut peripherals.mclk,
);

let mut delay = Delay::new(core.SYST, &mut clocks);

const NUM_LEDS: usize = 5;
let mut j: u8 = 0;

loop {
let light_data: u16 = adc1.read(&mut light).unwrap();

let pos: usize = if light_data < 100 {
0
} else if (147..1048).contains(&light_data) {
1
} else if (1048..3048).contains(&light_data) {
2
} else if (3048..3948).contains(&light_data) {
3
} else {
4
};

//finally paint the one led wherever the position is
let _ = neopixel.write((0..NUM_LEDS).map(|i| {
if i == pos {
hsv2rgb(Hsv {
hue: j,
sat: 255,
val: 32,
})
} else {
RGB8::default()
}
}));

//incremement the hue easing
j = j.wrapping_add(1);

delay.delay_ms(10u8);
}
}
115 changes: 115 additions & 0 deletions boards/pygamer/examples/neopixel_button.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
//! Joystick y controls the color of a neopixel while Joystick x moves it
//! left and right around the center neopixel
//! Select and Start control a second neopixel left and right while it is
//! automatically rotating through the color wheel
//! When they overlap, joystick takes precedence
//!
//! Note leds may appear white during debug. Either build for release or add
//! opt-level = 2 to profile.dev in Cargo.toml
#![no_std]
#![no_main]

#[cfg(not(feature = "panic_led"))]
use panic_halt as _;
use pygamer::{self as bsp, entry, hal, pac, pins::Keys, Pins};

use bsp::util::map_from;
use hal::adc::Adc;
use hal::{clock::GenericClockController, delay::Delay};

use pac::gclk::pchctrl::Genselect::Gclk11;
use pac::{CorePeripherals, Peripherals};

use hal::ehal::delay::DelayNs;

use smart_leds::SmartLedsWrite;
use smart_leds::{
hsv::{hsv2rgb, Hsv},
RGB8,
};

#[entry]
fn main() -> ! {
let mut peripherals = Peripherals::take().unwrap();
let core_peripherals = CorePeripherals::take().unwrap();

let mut clocks = GenericClockController::with_internal_32kosc(
peripherals.gclk,
&mut peripherals.mclk,
&mut peripherals.osc32kctrl,
&mut peripherals.oscctrl,
&mut peripherals.nvmctrl,
);

let mut delay = Delay::new(core_peripherals.SYST, &mut clocks);
let pins = Pins::new(peripherals.port).split();

let mut buttons = pins.buttons.init();

let mut adc1 = Adc::adc1(peripherals.adc1, &mut peripherals.mclk, &mut clocks, Gclk11);
let mut joystick = pins.joystick.init();

// neopixels
let mut neopixel = pins.neopixel.init_spi(
&mut clocks,
// Unfortunately, the SPI driver requires a clock pin, even though it's not used by the
// neopixels.
pins.i2c.scl,
peripherals.sercom2,
&mut peripherals.mclk,
);

const NUM_LEDS: usize = 5;
let mut pos_button: usize = 2;
let mut color_button: u8 = 0;
loop {
let (x, y) = joystick.read(&mut adc1);

// map up/down to control rainbow color 0-255
let color_joy = map_from(y as i16, (0, 4095), (0, 255)) as u8;

// map left/right to neopixel position 0-4
// joystick is not quite linear, rests at second pixel
// shifting up by 500 seems to help
let pos_joy = map_from(x as i16 + 500, (0, 4595), (0, 4)) as usize;

for event in buttons.events() {
match event {
Keys::SelectDown => {
pos_button = pos_button.saturating_sub(1);
}
Keys::StartDown => {
if pos_button < 4 {
pos_button += 1;
}
}
_ => {}
}
}

//finally paint the two leds at position, accel priority
let _ = neopixel.write((0..NUM_LEDS).map(|i| {
if i == pos_joy {
hsv2rgb(Hsv {
hue: color_joy,
sat: 255,
val: 32,
})
} else if i == pos_button {
hsv2rgb(Hsv {
hue: color_button,
sat: 255,
val: 32,
})
} else {
RGB8::default()
}
}));

//incremement the hue easing
color_button = color_button.wrapping_add(1);

delay.delay_ms(5);
}
}
Loading

0 comments on commit 275d0e8

Please sign in to comment.