diff --git a/src/main.rs b/src/main.rs index 919ed8c..952059b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,9 @@ use embassy_futures::join::{join3, join4}; use embassy_nrf::gpio::{AnyPin, Input, OutputDrive, Pull}; use embassy_nrf::interrupt::Priority; use embassy_nrf::pwm::{DutyCycle, Prescaler, SimplePwm}; -use embassy_nrf::Peri; +use embassy_nrf::{bind_interrupts, saadc, Peri}; +use embassy_nrf::peripherals::SAADC; +use embassy_nrf::saadc::{ChannelConfig, Gain, Reference, Saadc}; use embassy_sync::blocking_mutex::raw::ThreadModeRawMutex; use embassy_sync::mutex::Mutex; use embassy_sync::signal::Signal; @@ -96,12 +98,16 @@ struct Server { light: AnimationService, } +bind_interrupts!(struct AdcIrqs { + SAADC => saadc::InterruptHandler; +}); + #[embassy_executor::main] async fn main(spawner: Spawner) { let mut config = embassy_nrf::config::Config::default(); config.gpiote_interrupt_priority = Priority::P2; config.time_interrupt_priority = Priority::P2; - let p = embassy_nrf::init(config); + let mut p = embassy_nrf::init(config); let config = nrf_softdevice::Config { clock: Some(raw::nrf_clock_lf_cfg_t { @@ -138,16 +144,23 @@ async fn main(spawner: Spawner) { let sd = Softdevice::enable(&config); let server = Server::new(sd).expect("failed to enable softdevice"); - let pwm_text = SimplePwm::new_3ch(p.PWM0, p.P1_15, p.P1_13, p.P1_11, &Default::default()); - let pwm_heart = SimplePwm::new_3ch(p.PWM2, p.P0_31, p.P0_29, p.P0_02, &Default::default()); + let mut channel_config = ChannelConfig::single_ended(p.P0_31.reborrow()); + channel_config.gain = Gain::GAIN1_6; + channel_config.reference = Reference::INTERNAL; + let saadc = Saadc::new(p.SAADC, AdcIrqs, saadc::Config::default(), [channel_config]); + + let pwm_text = SimplePwm::new_3ch(p.PWM0, p.P1_00, p.P1_04, p.P1_06, &Default::default()); + let pwm_heart = SimplePwm::new_3ch(p.PWM2, p.P0_17, p.P0_20, p.P0_22, &Default::default()); spawner.spawn(radar_task()).expect("failed to spawn radar task"); - spawner.spawn(touch_button(p.P0_20.into())).expect("failed to spawn touch task"); + spawner.spawn(touch_button(p.P0_08.into())).expect("failed to spawn touch task"); spawner.spawn(actions_task()).expect("failed to spawn actions task"); spawner.spawn(softdevice_task(sd)).expect("failed to spawn softdevice task"); + spawner.spawn(battery_task(saadc)).expect("failed to spawn softdevice task"); - join4(gatt_task(server, sd), moving_radar(p.P0_22.into()), heartbeat_task(pwm_heart), light_task(pwm_text)).await; + join4(gatt_task(server, sd), moving_radar(p.P0_06.into()), heartbeat_task(pwm_heart), light_task(pwm_text)).await; } + async fn gatt_task(server: Server, sd: &'static Softdevice) { static ADV_DATA: LegacyAdvertisementPayload = LegacyAdvertisementBuilder::new() .flags(&[Flag::GeneralDiscovery, Flag::LE_Only]) @@ -317,6 +330,40 @@ async fn touch_button(pin: Peri<'static, AnyPin>) { } } +#[embassy_executor::task] +async fn battery_task(mut saadc: Saadc<'static, 1>) { + const REFERENCE: f32 = 3.6; + let mut measurements = [0i16; 4]; + let mut index = 0; + + loop { + let mut buf = [0; 1]; + saadc.sample(&mut buf).await; + let voltage = ((buf[0] as f32 * REFERENCE) / 2.03f32) as i16; + measurements[index] = voltage; + index = (index + 1) % measurements.len(); + if measurements.iter().any(|v| *v == 0) { + Timer::after_millis(1000).await; + } else { + let total = (measurements.iter().sum::() / measurements.len() as i16) as u16; + let percent = battery_mv_to_percent(total); + info!("Battery: {=i16}, {=u16}, {}%", voltage, total, percent); + Timer::after_millis(2000).await; + } + } +} + +fn battery_mv_to_percent(mv: u16) -> u8 { + match mv { + mv if mv >= 4150 => 100, + mv if mv <= 3000 => 0, + _ => { + let percent = (mv as u32 - 3000) * 100 / (4150 - 3000); + percent as u8 + } + } +} + #[embassy_executor::task] async fn actions_task() { loop {