led and backlight
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
[build]
|
||||||
|
target = "riscv32imac-unknown-none-elf"
|
||||||
|
|
||||||
|
[target.riscv32imac-unknown-none-elf]
|
||||||
|
runner = "espflash flash --monitor"
|
||||||
|
rustflags = ["-C", "link-arg=-Tlinkall.x"]
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
/target
|
||||||
Generated
+1463
File diff suppressed because it is too large
Load Diff
+20
@@ -0,0 +1,20 @@
|
|||||||
|
[package]
|
||||||
|
name = "espboard"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
esp-backtrace = { version = "0.20.0", features = ["esp32c6", "println", "panic-handler"] }
|
||||||
|
esp-bootloader-esp-idf = { version = "0.6.0", features = ["esp32c6"] }
|
||||||
|
esp-hal = { version = "1.2.0", features = ["esp32c6", "unstable"] }
|
||||||
|
esp-hal-smartled = { version = "0.18", default-features = false, features = ["esp32c6"] }
|
||||||
|
esp-println = { version = "0.18.0", default-features = false, features = ["esp32c6", "jtag-serial"] }
|
||||||
|
smart-leds = "0.4"
|
||||||
|
smart-leds-trait = "0.3"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
codegen-units = 1
|
||||||
|
incremental = false
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
codegen-units = 1
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
use esp_hal::gpio::interconnect::PeripheralOutput;
|
||||||
|
use esp_hal::gpio::DriveMode;
|
||||||
|
use esp_hal::ledc::channel::{self, Channel, ChannelIFace};
|
||||||
|
use esp_hal::ledc::timer::TimerIFace;
|
||||||
|
use esp_hal::ledc::LowSpeed;
|
||||||
|
|
||||||
|
/// Maximum duty cycle percentage. The board documentation warns against
|
||||||
|
/// running the display above 50% brightness, so `level = 1.0` maps to this.
|
||||||
|
const MAX_DUTY_PCT: u8 = 50;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
Channel(channel::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<channel::Error> for Error {
|
||||||
|
fn from(e: channel::Error) -> Self {
|
||||||
|
Error::Channel(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Backlight PWM driver. The channel holds a reference to the caller-owned
|
||||||
|
/// timer, so this type's lifetime is bounded by the timer's lifetime.
|
||||||
|
pub struct LcdBacklight<'a> {
|
||||||
|
channel: Channel<'a, LowSpeed>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> LcdBacklight<'a> {
|
||||||
|
pub fn new(
|
||||||
|
timer: &'a dyn TimerIFace<LowSpeed>,
|
||||||
|
pin: impl PeripheralOutput<'a>,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let mut channel = Channel::new(channel::Number::Channel0, pin);
|
||||||
|
channel.configure(channel::config::Config {
|
||||||
|
timer,
|
||||||
|
duty_pct: 0,
|
||||||
|
drive_mode: DriveMode::PushPull,
|
||||||
|
})?;
|
||||||
|
Ok(Self { channel })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the backlight level from `0.0` (off) to `1.0` (maximum).
|
||||||
|
///
|
||||||
|
/// `1.0` is scaled to a 50% duty cycle, the maximum brightness the board
|
||||||
|
/// documentation recommends.
|
||||||
|
pub fn set_level(&mut self, level: f32) -> Result<(), Error> {
|
||||||
|
let duty_pct = ((level.clamp(0.0, 1.0) * MAX_DUTY_PCT as f32) + 0.5) as u8;
|
||||||
|
self.channel.set_duty(duty_pct).map_err(Error::Channel)
|
||||||
|
}
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
use esp_hal::gpio::interconnect::PeripheralOutput;
|
||||||
|
use esp_hal::rmt::TxChannelCreator;
|
||||||
|
use esp_hal::time::Rate;
|
||||||
|
use esp_hal::Blocking;
|
||||||
|
use esp_hal_smartled::{RmtSmartLeds, WS2812_TIMING, buffer_size, color_order};
|
||||||
|
use smart_leds_trait::{RGB8, SmartLedsWrite};
|
||||||
|
|
||||||
|
const RMT_FREQ: Rate = Rate::from_mhz(80);
|
||||||
|
|
||||||
|
type SmartLed = RmtSmartLeds<'static, { buffer_size::<RGB8>(1) }, Blocking, RGB8, color_order::Grb>;
|
||||||
|
|
||||||
|
pub struct RgbLed {
|
||||||
|
led: SmartLed,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RgbLed {
|
||||||
|
pub fn new(
|
||||||
|
channel: impl TxChannelCreator<'static, Blocking>,
|
||||||
|
pin: impl PeripheralOutput<'static>,
|
||||||
|
) -> Result<Self, esp_hal_smartled::Error> {
|
||||||
|
Ok(Self {
|
||||||
|
led: SmartLed::new_with_memsize(WS2812_TIMING, channel, pin, 2, RMT_FREQ)?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_color(
|
||||||
|
&mut self,
|
||||||
|
r: u8,
|
||||||
|
g: u8,
|
||||||
|
b: u8,
|
||||||
|
) -> Result<(), esp_hal_smartled::AdapterError> {
|
||||||
|
self.led.write([RGB8 { r, g, b }])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_rgb(&mut self, rgb: RGB8) -> Result<(), esp_hal_smartled::AdapterError> {
|
||||||
|
self.led.write([rgb])
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn off(&mut self) -> Result<(), esp_hal_smartled::AdapterError> {
|
||||||
|
self.set_color(0, 0, 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
mod backlight;
|
||||||
|
mod led;
|
||||||
|
|
||||||
|
use esp_backtrace as _;
|
||||||
|
use esp_bootloader_esp_idf::esp_app_desc;
|
||||||
|
use esp_hal::ledc::timer::{self, TimerIFace};
|
||||||
|
use esp_hal::ledc::{LSGlobalClkSource, Ledc, LowSpeed};
|
||||||
|
use esp_hal::{init, rmt::Rmt, time::Rate, Config};
|
||||||
|
use esp_println::println;
|
||||||
|
use smart_leds::hsv::{hsv2rgb, Hsv};
|
||||||
|
use smart_leds::{brightness, gamma};
|
||||||
|
|
||||||
|
esp_app_desc!();
|
||||||
|
|
||||||
|
#[esp_hal::main]
|
||||||
|
fn main() -> ! {
|
||||||
|
let peripherals = init(Config::default());
|
||||||
|
|
||||||
|
let mut led = {
|
||||||
|
let rmt = Rmt::new(peripherals.RMT, Rate::from_mhz(80)).expect("Failed to init RMT");
|
||||||
|
led::RgbLed::new(rmt.channel0, peripherals.GPIO8).expect("Failed to init RGB LED")
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut ledc = Ledc::new(peripherals.LEDC);
|
||||||
|
ledc.set_global_slow_clock(LSGlobalClkSource::APBClk);
|
||||||
|
let mut timer = ledc.timer::<LowSpeed>(timer::Number::Timer0);
|
||||||
|
timer
|
||||||
|
.configure(timer::config::Config {
|
||||||
|
duty: timer::config::Duty::Duty8Bit,
|
||||||
|
clock_source: timer::LSClockSource::APBClk,
|
||||||
|
frequency: Rate::from_khz(5),
|
||||||
|
})
|
||||||
|
.expect("Failed to configure backlight timer");
|
||||||
|
let mut backlight =
|
||||||
|
backlight::LcdBacklight::new(&timer, peripherals.GPIO22).expect("Failed to init backlight");
|
||||||
|
|
||||||
|
let delay = esp_hal::delay::Delay::new();
|
||||||
|
|
||||||
|
let levels = [1.0f32, 0.75, 0.5, 0.25, 0.0, 0.5];
|
||||||
|
let mut level_idx = 0;
|
||||||
|
|
||||||
|
loop {
|
||||||
|
for hue in 0..=255 {
|
||||||
|
let rgb = hsv2rgb(Hsv {
|
||||||
|
hue,
|
||||||
|
sat: 255,
|
||||||
|
val: 255,
|
||||||
|
});
|
||||||
|
let lit = brightness(gamma(core::iter::once(rgb)), 40)
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
led.set_rgb(lit).unwrap();
|
||||||
|
|
||||||
|
if hue % 32 == 0 {
|
||||||
|
println!("hue {hue}: ({}, {}, {})", lit.r, lit.g, lit.b);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay.delay_millis(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
let level = levels[level_idx % levels.len()];
|
||||||
|
backlight.set_level(level).unwrap();
|
||||||
|
println!("backlight level: {level}");
|
||||||
|
level_idx += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user