tasks: render: switch to using the new figments DMA driver
This commit is contained in:
@@ -83,10 +83,7 @@ async fn main(spawner: Spawner) {
|
||||
wdt.enable();
|
||||
|
||||
// Spawn the rendering task as soon as possible so it can start pushing pixels
|
||||
spawner.must_spawn(renderbug_embassy::tasks::render::render(peripherals.RMT, peripherals.GPIO5.degrade(), surfaces, safety_surfaces, display_controls, wdt));
|
||||
|
||||
// Wait one scheduler tick for the rendering task to get initialized
|
||||
Timer::after_ticks(1).await;
|
||||
spawner.must_spawn(renderbug_bike::tasks::render::render(peripherals.SPI2.degrade(), peripherals.DMA_CH2.degrade(), peripherals.GPIO5.degrade(), surfaces, safety_surfaces, display_controls, wdt));
|
||||
|
||||
#[cfg(feature="motion")]
|
||||
{
|
||||
|
||||
@@ -1,34 +1,38 @@
|
||||
use embassy_time::{Duration, Instant, Timer};
|
||||
use esp_hal::{gpio::AnyPin, rmt::Rmt, time::Rate, timer::timg::Wdt};
|
||||
use esp_hal_smartled::{buffer_size_async, SmartLedsAdapterAsync};
|
||||
use esp_hal::spi::Mode;
|
||||
use esp_hal::spi::master::{AnySpi, Config, Spi};
|
||||
use esp_hal::{gpio::AnyPin, time::Rate, timer::timg::Wdt};
|
||||
use esp_hal::dma::{AnyGdmaChannel, DmaTxBuf};
|
||||
use figments::prelude::*;
|
||||
use figments_esp32_ws2812_dma::{DmaBuffers, Esp32Ws2812SpiDmaWriter};
|
||||
use figments_render::gamma::GammaCurve;
|
||||
use figments_render::output::{GammaCorrected, OutputAsync};
|
||||
use log::{info, warn};
|
||||
use log::*;
|
||||
|
||||
use crate::graphics::display::NUM_PIXELS;
|
||||
use crate::{graphics::display::{BikeOutput, DisplayControls, Uniforms}, tasks::ui::UiSurfacePool};
|
||||
|
||||
const POWER_MA : u32 = 300;
|
||||
const POWER_VOLTS : u32 = 5;
|
||||
const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA;
|
||||
static SPI_BUFFERS: static_cell::ConstStaticCell<DmaBuffers<u8, {NUM_PIXELS * 12 + 140}>> = static_cell::ConstStaticCell::new(DmaBuffers::new(0));
|
||||
|
||||
#[embassy_executor::task]
|
||||
pub async fn render(rmt: esp_hal::peripherals::RMT<'static>, gpio: AnyPin<'static>, mut surfaces: UiSurfacePool, mut safety_surfaces: UiSurfacePool, mut controls: DisplayControls, mut wdt: Wdt<esp_hal::peripherals::TIMG0<'static>>) {
|
||||
let frequency: Rate = Rate::from_mhz(80);
|
||||
let rmt = Rmt::new(rmt, frequency)
|
||||
.expect("Failed to initialize RMT").into_async();
|
||||
let rmt_channel = rmt.channel0;
|
||||
pub async fn render(spi: AnySpi<'static>, dma: AnyGdmaChannel<'static>, gpio: AnyPin<'static>, mut surfaces: UiSurfacePool, mut safety_surfaces: UiSurfacePool, mut controls: DisplayControls, mut wdt: Wdt<esp_hal::peripherals::TIMG0<'static>>) {
|
||||
info!("Starting rendering task");
|
||||
|
||||
// FIXME: I don't know why we need to add an extra bunch of pixels, but otherwise the buffer is too small?
|
||||
let mut rmt_buffer = esp_hal_smartled::smart_led_buffer!(NUM_PIXELS + 25);
|
||||
let buffers = SPI_BUFFERS.take();
|
||||
|
||||
// FIXME: The strip is GRB, we need to fix the pixel swizzling deep within the traits
|
||||
let target = SmartLedsAdapterAsync::new_with_color(rmt_channel, gpio, &mut rmt_buffer);
|
||||
let tx_buf = DmaTxBuf::new(&mut buffers.tx_descriptors, &mut buffers.tx_buffer).unwrap();
|
||||
let conf = Config::default()
|
||||
.with_frequency(Rate::from_khz(3_800))
|
||||
.with_mode(Mode::_0);
|
||||
|
||||
// Change this to adjust the power available; the USB spec says 500ma is the standard limit, but sometimes you can draw more from a power brick
|
||||
const POWER_MA : u32 = 500;
|
||||
let driver = Spi::new(spi, conf).unwrap()
|
||||
.with_mosi(gpio)
|
||||
.with_dma(dma).into_async();
|
||||
|
||||
// You probably don't need to change these values, unless your LED strip is somehow not 5 volts
|
||||
const POWER_VOLTS : u32 = 5;
|
||||
|
||||
const MAX_POWER_MW : u32 = if cfg!(feature="max-usb-power") { u32::MAX } else { POWER_VOLTS * POWER_MA };
|
||||
let target = Esp32Ws2812SpiDmaWriter::new(driver, tx_buf);
|
||||
|
||||
// This value is used as the 'seed' for rendering each frame, allowing us to do things like run the animation backwards, frames for double FPS, or even use system uptime for more human-paced animations
|
||||
let mut uniforms = Uniforms {
|
||||
@@ -43,7 +47,7 @@ pub async fn render(rmt: esp_hal::peripherals::RMT<'static>, gpio: AnyPin<'stati
|
||||
controls.notify_render_is_running(true);
|
||||
|
||||
// TODO: The prediction engine should be able to scale the display FPS down for power saving sometimes
|
||||
const FPS: u64 = 80;
|
||||
const FPS: u64 = 30;
|
||||
const RENDER_BUDGET: Duration = Duration::from_millis(1000 / FPS);
|
||||
|
||||
const ANIMATION_TPS: u64 = 120;
|
||||
@@ -59,7 +63,6 @@ pub async fn render(rmt: esp_hal::peripherals::RMT<'static>, gpio: AnyPin<'stati
|
||||
surfaces.commit();
|
||||
safety_surfaces.commit();
|
||||
surfaces.render_to(&mut output, &uniforms);
|
||||
// TODO: We should split up the safety layers so they always have full power
|
||||
safety_surfaces.render_to(&mut output, &uniforms);
|
||||
|
||||
// Finally, write out the rendered frame
|
||||
@@ -88,6 +91,8 @@ pub async fn render(rmt: esp_hal::peripherals::RMT<'static>, gpio: AnyPin<'stati
|
||||
// Otherwise, we have a problem
|
||||
// TODO: Automatically scale FPS back when this happens
|
||||
warn!("Render stall! Frame took {}ms", render_duration.as_millis());
|
||||
// Kick the scheduler since it took so long
|
||||
Timer::after_ticks(1).await;
|
||||
}
|
||||
|
||||
// TODO: Need a way to let the UI layers configure this
|
||||
|
||||
Reference in New Issue
Block a user