diff --git a/src/bin/main.rs b/src/bin/main.rs index 50488b6..46be582 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -7,8 +7,6 @@ )] -use core::{num::{self, Wrapping}, ptr::addr_of_mut}; - use alloc::{string::String, sync::Arc}; use embassy_executor::Spawner; use embassy_time::{Duration, Instant, Timer, WithTimeout}; @@ -16,7 +14,7 @@ use embassy_time::{Duration, Instant, Timer, WithTimeout}; use enum_map::EnumMap; use esp_hal::{gpio::{Output, OutputConfig, Pin}, time::Rate}; use esp_hal::{ - clock::CpuClock, system::{AppCoreGuard, CpuControl, Stack}, timer::{systimer::SystemTimer, timg::{TimerGroup, Wdt}} + clock::CpuClock, timer::{systimer::SystemTimer, timg::{TimerGroup, Wdt}} }; use embassy_sync::{ @@ -28,13 +26,10 @@ use renderbug_bike::{events::{Prediction, SensorSource, SensorState}, graphics:: use renderbug_bike::events::Measurement; use static_cell::StaticCell; use esp_backtrace as _; -use esp_rtos::embassy::{Executor, InterruptExecutor}; -use esp_hal::interrupt::software::SoftwareInterruptControl; +use esp_hal::spi::master::any::Degrade; -use renderbug_embassy::tasks::{ - motion::motion_task, - ui::{Ui, ui_main} -}; +use renderbug_bike::tasks::ui::{Ui, ui_main}; +use esp_hal::dma::DmaChannelConvert; use embassy_sync::{blocking_mutex::raw::CriticalSectionRawMutex, pubsub::DynSubscriber}; use embassy_sync::channel::Channel; @@ -48,14 +43,25 @@ esp_bootloader_esp_idf::esp_app_desc!(); #[cfg(feature="radio")] static WIFI_INIT: StaticCell> = StaticCell::new(); +rtos_trace::global_trace!(Tracer); + #[esp_rtos::main] async fn main(spawner: Spawner) { - esp_alloc::heap_allocator!(size: 128 * 1024); + // If we aren't using the second CPU, we can use the bootloader space for the heap instead + if cfg!(not(feature="dual-core")) { + esp_alloc::heap_allocator!(#[esp_hal::ram(reclaimed)] size: 73744); + esp_alloc::heap_allocator!(size: 32 * 1024); + } else { + esp_alloc::heap_allocator!(size: 100000); + } + RenderbugLogger::init_logger(); let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); let peripherals = esp_hal::init(config); + info!("Boot memory stats: {}", esp_alloc::HEAP.stats()); + let sys_timer = SystemTimer::new(peripherals.SYSTIMER); esp_rtos::start(sys_timer.alarm0); info!("Embassy initialized!"); @@ -102,15 +108,15 @@ async fn main(spawner: Spawner) { let i2c = I2c::new(peripherals.I2C1, Config::default()).unwrap().with_scl(scl).with_sda(sda).into_async(); let i2c_bus = I2C_BUS.init(Mutex::new(i2c)); #[cfg(feature="mpu")] - spawner.must_spawn(renderbug_embassy::tasks::mpu::mpu_task(motion_bus.dyn_sender(), I2cDevice::new(i2c_bus))); + spawner.must_spawn(renderbug_bike::tasks::mpu::mpu_task(motion_bus.dyn_sender(), I2cDevice::new(i2c_bus))); #[cfg(feature="gps")] - spawner.must_spawn(renderbug_embassy::tasks::gps::gps_task(motion_bus.dyn_sender(), I2cDevice::new(i2c_bus))); + spawner.must_spawn(renderbug_bike::tasks::gps::gps_task(motion_bus.dyn_sender(), I2cDevice::new(i2c_bus))); } #[cfg(feature="oled")] { use esp_hal::i2c::master::{Config, I2c}; - use renderbug_embassy::graphics::ssd1306::SsdOutput; + use renderbug_bike::graphics::ssd1306::SsdOutput; let rst = Output::new(peripherals.GPIO21, esp_hal::gpio::Level::Low, OutputConfig::default()); let i2c = I2c::new( @@ -118,7 +124,7 @@ async fn main(spawner: Spawner) { Config::default().with_frequency(Rate::from_khz(400)) ).unwrap().with_scl(peripherals.GPIO18).with_sda(peripherals.GPIO17).into_async(); let output = SsdOutput::new(i2c, rst, oled_controls).await; - spawner.must_spawn(renderbug_embassy::tasks::oled_render::oled_render(output, oled_surfaces, oled_uniforms)); + spawner.must_spawn(renderbug_bike::tasks::oled_render::oled_render(output, oled_surfaces, oled_uniforms)); } let mut storage = renderbug_bike::storage::SharedFlash::new(esp_storage::FlashStorage::new()); @@ -179,13 +185,13 @@ async fn main(spawner: Spawner) { #[cfg(not(feature="demo"))] { info!("Launching motion engine"); - spawner.must_spawn(motion_task(motion_bus.dyn_receiver(), predictions.dyn_publisher().unwrap())); + spawner.must_spawn(renderbug_bike::tasks::motion::motion_task(motion_bus.dyn_receiver(), predictions.dyn_publisher().unwrap(), recording_bus.dyn_publisher().unwrap())); } #[cfg(feature="demo")] { warn!("Launching with demo sequencer"); - spawner.must_spawn(renderbug_embassy::tasks::demo::demo_task(predictions.dyn_publisher().unwrap())); + spawner.must_spawn(renderbug_bike::tasks::demo::demo_task(predictions.dyn_publisher().unwrap())); } info!("Launching Safety UI"); @@ -224,22 +230,31 @@ async fn main(spawner: Spawner) { info!("Launching core 2 watchdog"); let timer1 = TimerGroup::new(peripherals.TIMG1); let mut ui_wdt = timer1.wdt; - ui_wdt.set_timeout(esp_hal::timer::timg::MwdtStage::Stage0, esp_hal::time::Duration::from_secs(10)); - #[cfg(feature="dual-core")] + ui_wdt.set_timeout(esp_hal::timer::timg::MwdtStage::Stage0, esp_hal::time::Duration::from_secs(60)); ui_wdt.enable(); spawner.must_spawn(wdt_task(ui_wdt)); } spawner.must_spawn(print_sensor_status(predictions.dyn_subscriber().unwrap())); - info!("System is ready in {}ms", Instant::now().as_millis()); + info!("Ready to rock and roll in {}ms", Instant::now().as_millis()); }; + #[allow(static_mut_refs)] #[cfg(feature="dual-core")] { - static mut CORE2_STACK: Stack<16384> = Stack::new(); + use core::mem::MaybeUninit; + + use esp_hal::interrupt::software::SoftwareInterruptControl; + use esp_hal::system::Stack; + use esp_rtos::embassy::Executor; + + // We can be sneaky and stick the stack for the second core into the bootloader ram + #[esp_hal::ram(reclaimed)] + static mut CORE2_STACK: MaybeUninit> = MaybeUninit::uninit(); let swi = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); - esp_rtos::start_second_core(peripherals.CPU_CTRL, swi.software_interrupt0, swi.software_interrupt1, unsafe { &mut *addr_of_mut!(CORE2_STACK) }, || { + // SAFETY: The internal implementation of Stack is itself MaybeUninit + esp_rtos::start_second_core(peripherals.CPU_CTRL, swi.software_interrupt0, swi.software_interrupt1, unsafe { CORE2_STACK.assume_init_mut() }, || { info!("Second CPU core started"); static CORE2_EXEC: StaticCell = StaticCell::new(); let exec = CORE2_EXEC.init_with(|| { Executor::new() }); @@ -250,7 +265,10 @@ async fn main(spawner: Spawner) { #[cfg(not(feature="dual-core"))] core2_main(spawner); - info!("Ready to rock and roll"); + loop { + //info!("Memory stats: {}", esp_alloc::HEAP.stats()); + Timer::after_secs(1).await; + } } #[embassy_executor::task] @@ -304,7 +322,7 @@ async fn print_sensor_readings(mut events: DynSubscriber<'static, Measurement>) async fn print_sensor_status(mut events: DynSubscriber<'static, Prediction>) { info!("telemetry ready"); - let mut num_events = Wrapping(0usize); + let mut sensor_states: EnumMap = EnumMap::default(); loop { let next = events.next_message_pure().with_timeout(Duration::from_secs(5)).await; match next {