From d63e9e964d6e9fd122a8e9bed65e4ae8b18c76d6 Mon Sep 17 00:00:00 2001 From: Djeeberjr Date: Mon, 27 Oct 2025 15:15:01 +0100 Subject: [PATCH] improved hardware init --- Cargo.lock | 1 + Cargo.toml | 1 + src/feedback.rs | 4 +- src/init/hardware.rs | 184 ++++++++++++++++++++++--------------------- src/main.rs | 31 +++++--- 5 files changed, 116 insertions(+), 105 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e55fb72..0331bf7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1156,6 +1156,7 @@ dependencies = [ "smart-leds", "smoltcp", "static_cell", + "thiserror", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index fe87538..97d05d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ smart-leds = "0.4.0" embedded-sdmmc = "0.8.0" embedded-hal-bus = "0.3.0" +thiserror = { version = "2.0.17", default-features = false } [profile.dev] # Rust debug is too slow. diff --git a/src/feedback.rs b/src/feedback.rs index 0081f29..5daa892 100644 --- a/src/feedback.rs +++ b/src/feedback.rs @@ -1,4 +1,5 @@ use embassy_time::{Duration, Timer}; +use esp_hal::gpio::{AnyPin, Output}; use esp_hal::peripherals; use esp_hal_smartled::SmartLedsAdapterAsync; use log::debug; @@ -26,10 +27,9 @@ const LED_LEVEL: u8 = 255; #[embassy_executor::task] pub async fn feedback_task( mut led: SmartLedsAdapterAsync<'static, { hardware::LED_BUFFER_SIZE }>, - buzzer: peripherals::GPIO21<'static>, + mut buzzer: Output<'static>, ) { debug!("Starting feedback task"); - let mut buzzer = init::hardware::setup_buzzer(buzzer); loop { let feedback_state = FEEDBACK_STATE.wait().await; match feedback_state { diff --git a/src/init/hardware.rs b/src/init/hardware.rs index 3b57d85..aa9542b 100644 --- a/src/init/hardware.rs +++ b/src/init/hardware.rs @@ -1,14 +1,12 @@ -use core::cell::RefCell; -use critical_section::Mutex; use embassy_executor::Spawner; use embassy_net::Stack; use embassy_time::{Duration, Timer}; use esp_hal::Blocking; use esp_hal::delay::Delay; -use esp_hal::gpio::Input; +use esp_hal::gpio::{AnyPin}; use esp_hal::i2c::master::Config; use esp_hal::peripherals::{ - GPIO0, GPIO1, GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23, I2C0, RMT, SPI2, + GPIO1, GPIO16, GPIO17, GPIO18, GPIO19, GPIO20, GPIO21, GPIO22, GPIO23, I2C0, RMT, SPI2, UART1, }; use esp_hal::rmt::Rmt; @@ -21,12 +19,12 @@ use esp_hal::{ clock::CpuClock, gpio::{Output, OutputConfig}, i2c::master::I2c, - timer::systimer::SystemTimer, uart::Uart, }; use esp_hal_smartled::{SmartLedsAdapterAsync, buffer_size_async}; use esp_println::logger::init_logger; use log::{debug, error}; +use thiserror::Error; use crate::init::network; use crate::init::sd_card::{SDCardPersistence, setup_sdcard}; @@ -52,8 +50,6 @@ use crate::init::wifi; pub const NUM_LEDS: usize = 1; pub const LED_BUFFER_SIZE: usize = buffer_size_async(NUM_LEDS); -static SD_DET: Mutex>> = Mutex::new(RefCell::new(None)); - #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { let delay = Delay::new(); @@ -64,109 +60,116 @@ fn panic(info: &core::panic::PanicInfo) -> ! { esp_bootloader_esp_idf::esp_app_desc!(); -pub async fn hardware_init( - spawner: Spawner, -) -> ( - Uart<'static, Async>, - Stack<'static>, - I2c<'static, Async>, - GPIO21<'static>, - GPIO0<'static>, - SmartLedsAdapterAsync<'static, LED_BUFFER_SIZE>, - SDCardPersistence, -) { - let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); - let peripherals = esp_hal::init(config); +#[derive(Error, Debug)] +pub enum HardwareInitError { + #[error("Failed to etup UART")] + Uart(#[from] esp_hal::uart::ConfigError), - esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 65536); + #[error("Failed to setup I2C")] + I2C(#[from] esp_hal::i2c::master::ConfigError), - let timg0 = TimerGroup::new(peripherals.TIMG0); - let sw_interrupt = - esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); - esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0); + #[error("Failed to setup SPI")] + Spi(#[from] esp_hal::spi::master::ConfigError), - init_logger(log::LevelFilter::Debug); + #[error("Failed to setuo LED")] + Led(#[from] esp_hal::rmt::Error), +} - let rng = esp_hal::rng::Rng::new(); - let network_seed = (rng.random() as u64) << 32 | rng.random() as u64; +pub struct AppHardware { + pub uart: Uart<'static, Async>, + pub network_stack: Stack<'static>, + pub i2c: I2c<'static, Async>, + pub buzzer: Output<'static>, + pub sd_present: AnyPin<'static>, + pub led: SmartLedsAdapterAsync<'static, LED_BUFFER_SIZE>, + pub sdcard: SDCardPersistence, +} - wifi::set_antenna_mode(peripherals.GPIO3, peripherals.GPIO14).await; - let interfaces = wifi::setup_wifi(peripherals.WIFI, spawner); - let stack = network::setup_network(network_seed, interfaces.ap, spawner); +impl AppHardware { + pub async fn init(spawner: Spawner) -> Result { + let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max()); + let peripherals = esp_hal::init(config); - Timer::after(Duration::from_millis(1)).await; + esp_alloc::heap_allocator!(#[unsafe(link_section = ".dram2_uninit")] size: 65536); - let uart_device = setup_uart(peripherals.UART1, peripherals.GPIO16, peripherals.GPIO17); + let timg0 = TimerGroup::new(peripherals.TIMG0); + let sw_interrupt = + esp_hal::interrupt::software::SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); + esp_rtos::start(timg0.timer0, sw_interrupt.software_interrupt0); - let i2c_device = setup_i2c(peripherals.I2C0, peripherals.GPIO22, peripherals.GPIO23); + init_logger(log::LevelFilter::Debug); - let sd_det_gpio = peripherals.GPIO0; + let rng = esp_hal::rng::Rng::new(); + let network_seed = (rng.random() as u64) << 32 | rng.random() as u64; - let spi_bus = setup_spi( - peripherals.SPI2, - peripherals.GPIO19, - peripherals.GPIO20, - peripherals.GPIO18, - ); + wifi::set_antenna_mode(peripherals.GPIO3, peripherals.GPIO14).await; + let interfaces = wifi::setup_wifi(peripherals.WIFI, spawner); + let network_stack = network::setup_network(network_seed, interfaces.ap, spawner); - let sd_cs_pin = Output::new( - peripherals.GPIO2, - esp_hal::gpio::Level::High, - OutputConfig::default(), - ); + Timer::after(Duration::from_millis(1)).await; - let vol_mgr = setup_sdcard(spi_bus, sd_cs_pin); + let uart_device = setup_uart(peripherals.UART1, peripherals.GPIO16, peripherals.GPIO17)?; - let buzzer_gpio = peripherals.GPIO21; + let i2c_device = setup_i2c(peripherals.I2C0, peripherals.GPIO22, peripherals.GPIO23)?; - let led = setup_led(peripherals.RMT, peripherals.GPIO1); + let sd_det_gpio = peripherals.GPIO0; - Timer::after(Duration::from_millis(500)).await; + let spi_bus = setup_spi( + peripherals.SPI2, + peripherals.GPIO19, + peripherals.GPIO20, + peripherals.GPIO18, + )?; - debug!("hardware init done"); + let sd_cs_pin = Output::new( + peripherals.GPIO2, + esp_hal::gpio::Level::High, + OutputConfig::default(), + ); - ( - uart_device, - stack, - i2c_device, - buzzer_gpio, - sd_det_gpio, - led, - vol_mgr, - ) + let vol_mgr = setup_sdcard(spi_bus, sd_cs_pin); + + let buzzer_gpio = peripherals.GPIO21; + let buzzer = setup_buzzer(buzzer_gpio); + + let led = setup_led(peripherals.RMT, peripherals.GPIO1)?; + + Timer::after(Duration::from_millis(500)).await; + + debug!("hardware init done"); + + Ok(Self { + uart: uart_device, + network_stack, + i2c: i2c_device, + buzzer, + sd_present: sd_det_gpio.into(), + led, + sdcard: vol_mgr, + }) + } } fn setup_uart( uart1: UART1<'static>, uart_tx: GPIO16<'static>, uart_rx: GPIO17<'static>, -) -> Uart<'static, Async> { - let uard_device = Uart::new(uart1, esp_hal::uart::Config::default().with_baudrate(9600)); - - match uard_device { - Ok(block) => block.with_rx(uart_rx).with_tx(uart_tx).into_async(), - Err(e) => { - error!("Failed to initialize UART: {e}"); - panic!(); //TODO panic! - } - } +) -> Result, esp_hal::uart::ConfigError> { + let uart_device = Uart::new(uart1, esp_hal::uart::Config::default().with_baudrate(9600))?; + Ok(uart_device.with_rx(uart_rx).with_tx(uart_tx).into_async()) } fn setup_i2c( i2c0: I2C0<'static>, sda: GPIO22<'static>, scl: GPIO23<'static>, -) -> I2c<'static, Async> { +) -> Result, esp_hal::i2c::master::ConfigError> { debug!("init I2C"); let config = Config::default().with_frequency(Rate::from_khz(400)); - let i2c = match I2c::new(i2c0, config) { - Ok(i2c) => i2c.with_sda(sda).with_scl(scl).into_async(), - Err(e) => { - error!("Failed to initialize I2C: {:?}", e); - panic!(); //TODO panic! - } - }; - i2c + + let i2c = I2c::new(i2c0, config)?; + + Ok(i2c.with_sda(sda).with_scl(scl).into_async()) } fn setup_spi( @@ -174,35 +177,34 @@ fn setup_spi( sck: GPIO19<'static>, miso: GPIO20<'static>, mosi: GPIO18<'static>, -) -> Spi<'static, Blocking> { - let spi = match Spi::new(spi2, Spi_config::default()) { - Ok(spi) => spi.with_sck(sck).with_miso(miso).with_mosi(mosi), - Err(e) => panic!("Failed to initialize SPI: {:?}", e), - }; - spi +) -> Result, esp_hal::spi::master::ConfigError> { + let spi = Spi::new(spi2, Spi_config::default())?; + Ok(spi.with_sck(sck).with_miso(miso).with_mosi(mosi)) } pub fn setup_buzzer(buzzer_gpio: GPIO21<'static>) -> Output<'static> { let config = esp_hal::gpio::OutputConfig::default() .with_drive_strength(esp_hal::gpio::DriveStrength::_40mA); - let buzzer = Output::new(buzzer_gpio, esp_hal::gpio::Level::Low, config); - buzzer + Output::new(buzzer_gpio, esp_hal::gpio::Level::Low, config) } fn setup_led<'a>( rmt: RMT<'a>, led_gpio: GPIO1<'a>, -) -> esp_hal_smartled::SmartLedsAdapterAsync<'a, LED_BUFFER_SIZE> { +) -> Result, esp_hal::rmt::Error> { let rmt: Rmt<'_, esp_hal::Async> = { let frequency: Rate = Rate::from_mhz(80); Rmt::new(rmt, frequency) - } - .expect("Failed to initialize RMT") + }? .into_async(); let rmt_channel = rmt.channel0; let rmt_buffer = [esp_hal::rmt::PulseCode::default(); LED_BUFFER_SIZE]; - SmartLedsAdapterAsync::new(rmt_channel, led_gpio, rmt_buffer) + Ok(SmartLedsAdapterAsync::new( + rmt_channel, + led_gpio, + rmt_buffer, + )) } diff --git a/src/main.rs b/src/main.rs index 78b35a7..ddaf721 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,7 +17,7 @@ use embassy_sync::{ signal::Signal, }; use embassy_time::{Duration, Timer}; -use esp_hal::gpio::Input; +use esp_hal::gpio::{AnyPin, Input}; use esp_hal::{gpio::InputConfig, peripherals}; use log::{debug, info}; use static_cell::StaticCell; @@ -25,7 +25,7 @@ use static_cell::StaticCell; extern crate alloc; use crate::{ - init::sd_card::SDCardPersistence, + init::{hardware::AppHardware, sd_card::SDCardPersistence}, store::{IDStore, day::Day, tally_id::TallyID}, webserver::start_webserver, }; @@ -47,36 +47,43 @@ static CHAN: StaticCell = StaticCell::new(); #[esp_rtos::main] async fn main(spawner: Spawner) -> ! { - let (uart_device, stack, i2c, buzzer_gpio, sd_det_gpio, led, persistence_layer) = - init::hardware::hardware_init(spawner).await; + let app_hardware = AppHardware::init(spawner).await.unwrap(); info!("Starting up..."); - let mut rtc = drivers::rtc::RTCClock::new(i2c).await; + let mut rtc = drivers::rtc::RTCClock::new(app_hardware.i2c).await; - let store: UsedStore = IDStore::new_from_storage(persistence_layer).await; + let store: UsedStore = IDStore::new_from_storage(app_hardware.sdcard).await; let shared_store = Rc::new(Mutex::new(store)); let chan: &'static mut TallyChannel = CHAN.init(PubSubChannel::new()); let publisher: TallyPublisher = chan.publisher().unwrap(); let mut sub: TallySubscriber = chan.subscriber().unwrap(); - wait_for_stack_up(stack).await; + wait_for_stack_up(app_hardware.network_stack).await; - start_webserver(spawner, stack, shared_store.clone(), chan); + start_webserver( + spawner, + app_hardware.network_stack, + shared_store.clone(), + chan, + ); /****************************** Spawning tasks ***********************************/ debug!("spawing NFC reader task..."); spawner.must_spawn(drivers::nfc_reader::rfid_reader_task( - uart_device, + app_hardware.uart, publisher, )); debug!("spawing feedback task.."); - spawner.must_spawn(feedback::feedback_task(led, buzzer_gpio)); + spawner.must_spawn(feedback::feedback_task( + app_hardware.led, + app_hardware.buzzer, + )); debug!("spawn sd detect task"); - spawner.must_spawn(sd_detect_task(sd_det_gpio)); + spawner.must_spawn(sd_detect_task(app_hardware.sd_present)); /******************************************************************************/ debug!("everything spawned"); @@ -101,7 +108,7 @@ async fn main(spawner: Spawner) -> ! { } #[embassy_executor::task] -async fn sd_detect_task(sd_det_gpio: peripherals::GPIO0<'static>) { +async fn sd_detect_task(sd_det_gpio: AnyPin<'static>) { let mut sd_det = Input::new(sd_det_gpio, InputConfig::default()); sd_det.wait_for(esp_hal::gpio::Event::AnyEdge).await;