platform: esp32: first attempt at an i2s implementation, and fix rmt flickering with thread magic
This commit is contained in:
parent
ea75d7a2ee
commit
b20c562b27
@ -1,3 +1,4 @@
|
||||
use core::borrow::BorrowMut;
|
||||
use std::sync::Arc;
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Mutex;
|
||||
@ -8,30 +9,81 @@ use chrono::Utc;
|
||||
use esp_idf_svc::eventloop::{EspSubscription, EspSystemEventLoop, System};
|
||||
use esp_idf_svc::hal::modem::Modem;
|
||||
use esp_idf_svc::hal::prelude::Peripherals;
|
||||
use esp_idf_svc::hal::task::thread::ThreadSpawnConfiguration;
|
||||
use esp_idf_svc::netif::IpEvent;
|
||||
use esp_idf_svc::nvs::{EspDefaultNvsPartition, EspNvsPartition, NvsDefault};
|
||||
use esp_idf_svc::sntp::EspSntp;
|
||||
use esp_idf_svc::sys::esp_efuse_mac_get_default;
|
||||
use esp_idf_svc::wifi::{AuthMethod, ClientConfiguration, Configuration, EspWifi, WifiEvent};
|
||||
|
||||
use rgb::Rgb;
|
||||
|
||||
use super::smart_leds_lib::rmt::FastWs2812Esp32Rmt;
|
||||
use super::smart_leds_lib::StrideOutput;
|
||||
use super::Board;
|
||||
|
||||
use crate::buffers::BufferedSurfacePool;
|
||||
use crate::task::FixedSizeScheduler;
|
||||
use crate::task::Task;
|
||||
use crate::buffers::Pixbuf;
|
||||
use crate::mappings::StrideMapping;
|
||||
use crate::platform::smart_leds_lib::StrideOutput;
|
||||
use crate::platform::smart_leds_lib::rmt::FastWs2812Esp32Rmt;
|
||||
use crate::task::FixedSizeScheduler;
|
||||
use crate::task::Task;
|
||||
use crate::time::Periodically;
|
||||
|
||||
pub mod i2s {
|
||||
use esp_idf_svc::hal::i2s::*;
|
||||
use rgb::ComponentBytes;
|
||||
use rgb::Rgb;
|
||||
|
||||
use crate::mappings::*;
|
||||
use crate::buffers::Pixbuf;
|
||||
use crate::render::Output;
|
||||
use crate::render::Sample;
|
||||
|
||||
pub struct I2SOutput<'d> {
|
||||
driver: I2sDriver<'d, I2sTx>,
|
||||
pixbuf: [Rgb<u8>; 310],
|
||||
pixmap: StrideMapping,
|
||||
}
|
||||
|
||||
impl<'d> I2SOutput<'d> {
|
||||
fn new(driver: I2sDriver<'d, I2sTx>) -> Self {
|
||||
I2SOutput {
|
||||
driver,
|
||||
pixbuf: Pixbuf::new(),
|
||||
pixmap: StrideMapping::new_jar()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Output for I2SOutput<'d> {
|
||||
fn blank(&mut self) {
|
||||
self.pixbuf.blank();
|
||||
}
|
||||
|
||||
fn commit(&mut self) {
|
||||
let bytes = self.pixbuf.as_bytes();
|
||||
let mut written = self.driver.preload_data(bytes).unwrap();
|
||||
self.driver.tx_enable().unwrap();
|
||||
while written < bytes.len() {
|
||||
let next = &bytes[written..];
|
||||
written += self.driver.write(next, 0).unwrap();
|
||||
}
|
||||
self.driver.tx_disable().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Sample for I2SOutput<'d> {
|
||||
type Pixel = Rgb<u8>;
|
||||
fn sample(&mut self, rect: &crate::geometry::Rectangle<crate::geometry::Virtual>) -> impl crate::render::PixelView<Pixel = Self::Pixel> {
|
||||
StrideSampler::new(&mut self.pixbuf, self.pixmap.select(rect))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Esp32Board {
|
||||
output: Option<<Self as Board>::Output>,
|
||||
sys_loop: EspSystemEventLoop,
|
||||
modem: Option<Modem>,
|
||||
surfaces: BufferedSurfacePool
|
||||
surfaces: BufferedSurfacePool,
|
||||
output: Option<<Self as Board>::Output>
|
||||
}
|
||||
|
||||
impl Board for Esp32Board {
|
||||
@ -50,43 +102,61 @@ impl Board for Esp32Board {
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
let sys_loop = EspSystemEventLoop::take().unwrap();
|
||||
|
||||
let channel = peripherals.rmt.channel0;
|
||||
let pins = peripherals.pins;
|
||||
let mut chip_id: [u8; 8] = [0; 8];
|
||||
unsafe {
|
||||
esp_efuse_mac_get_default(&mut chip_id as *mut u8);
|
||||
}
|
||||
|
||||
log::info!("Setting up for chip ID {:?}", chip_id);
|
||||
|
||||
let (pixmap, target) = match chip_id {
|
||||
[72, 202, 67, 89, 145, 204, 0, 0] => {
|
||||
(StrideMapping::new_panel(), FastWs2812Esp32Rmt::new(channel, pins.gpio5).unwrap())
|
||||
},
|
||||
[140, 170, 181, 131, 95, 116, 0, 0] => {
|
||||
(StrideMapping::new_jar(), FastWs2812Esp32Rmt::new(channel, pins.gpio14).unwrap())
|
||||
},
|
||||
_ => {
|
||||
(StrideMapping::new(), FastWs2812Esp32Rmt::new(channel, pins.gpio5).unwrap())
|
||||
}
|
||||
};
|
||||
log::info!("Setting up output for chip ID {:x?}", chip_id);
|
||||
|
||||
const POWER_VOLTS : u32 = 5;
|
||||
const POWER_MA : u32 = 500;
|
||||
const MAX_POWER_MW : u32 = POWER_VOLTS * POWER_MA;
|
||||
let pins = peripherals.pins;
|
||||
|
||||
let output = StrideOutput::new(
|
||||
Pixbuf::new(),
|
||||
pixmap,
|
||||
target,
|
||||
MAX_POWER_MW
|
||||
);
|
||||
ThreadSpawnConfiguration {
|
||||
pin_to_core: Some(esp_idf_svc::hal::cpu::Core::Core1),
|
||||
..Default::default()
|
||||
}.set().unwrap();
|
||||
// Wifi driver creates too many interrupts on core0, so we need to use RMT on core1.
|
||||
// But the implementation spawns a thread based on the core the driver was created in,
|
||||
// so we create the driver in another thread briefly.
|
||||
// Fun stuff.
|
||||
let output = match chip_id {
|
||||
[72, 202, 67, 89, 145, 204, 0, 0] => {
|
||||
StrideOutput::new(
|
||||
Pixbuf::new(),
|
||||
StrideMapping::new_panel(),
|
||||
std::thread::spawn(move || { FastWs2812Esp32Rmt::new(peripherals.rmt.channel0, pins.gpio5).unwrap() }).join().unwrap(),
|
||||
MAX_POWER_MW
|
||||
)
|
||||
},
|
||||
[0x8C, 0xAA, 0xB5, 0x83, 0x5f, 0x74, 0x0, 0x0] => {
|
||||
StrideOutput::new(
|
||||
Pixbuf::new(),
|
||||
StrideMapping::new_jar(),
|
||||
std::thread::spawn(move || { FastWs2812Esp32Rmt::new(peripherals.rmt.channel0, pins.gpio14).unwrap() }).join().unwrap(),
|
||||
MAX_POWER_MW
|
||||
)
|
||||
},
|
||||
_ => {
|
||||
StrideOutput::new(
|
||||
Pixbuf::new(),
|
||||
StrideMapping::new(),
|
||||
std::thread::spawn(move || { FastWs2812Esp32Rmt::new(peripherals.rmt.channel0, pins.gpio5).unwrap() }).join().unwrap(),
|
||||
MAX_POWER_MW
|
||||
)
|
||||
}
|
||||
};
|
||||
ThreadSpawnConfiguration {
|
||||
..Default::default()
|
||||
}.set().unwrap();
|
||||
|
||||
Esp32Board {
|
||||
output: Some(output),
|
||||
modem: Some(peripherals.modem),
|
||||
sys_loop: sys_loop.clone(),
|
||||
surfaces: BufferedSurfacePool::new()
|
||||
surfaces: BufferedSurfacePool::new(),
|
||||
output: Some(output)
|
||||
}
|
||||
}
|
||||
|
||||
@ -134,6 +204,7 @@ struct WifiTask {
|
||||
|
||||
impl WifiTask {
|
||||
fn new(modem: Modem, sys_loop: EspSystemEventLoop, nvs: &EspNvsPartition<NvsDefault>) -> Self {
|
||||
log::info!("Installing wifi driver");
|
||||
let mut wifi = EspWifi::new(
|
||||
modem,
|
||||
sys_loop.clone(),
|
||||
@ -178,8 +249,6 @@ impl Task for WifiTask {
|
||||
fn start(&mut self) {
|
||||
log::info!("Starting wifi!");
|
||||
|
||||
log::info!("waiting for loop");
|
||||
|
||||
let wifi_state = self.state.clone();
|
||||
self.wifi_sub = Some(self.sys_loop.subscribe::<WifiEvent, _>( move |evt| {
|
||||
log::warn!("wifi event {:?}", evt);
|
||||
|
Loading…
x
Reference in New Issue
Block a user