Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

examples(pygamer): Restore neopixel examples using SPI driver #802

Merged
merged 1 commit into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading