Skip to content

Commit 68bf181

Browse files
jannicthejpster
authored andcommitted
Check for 3.3V supply before raising IRQ and continuing boot process
1 parent 6cee4f5 commit 68bf181

File tree

1 file changed

+59
-24
lines changed

1 file changed

+59
-24
lines changed

neotron-bmc-pico/src/main.rs

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ use core::convert::TryFrom;
1616
use heapless::spsc::{Consumer, Producer, Queue};
1717
use rtic::app;
1818
use stm32f0xx_hal::{
19-
gpio::gpioa::{PA10, PA11, PA12, PA15, PA2, PA3, PA4, PA8, PA9},
19+
adc,
20+
adc::Adc,
21+
gpio::gpioa::{PA0, PA10, PA11, PA12, PA15, PA2, PA3, PA4, PA8, PA9},
2022
gpio::gpiob::{PB0, PB3, PB4, PB5},
2123
gpio::gpiof::{PF0, PF1},
22-
gpio::{Alternate, Floating, Input, Output, PullDown, PullUp, PushPull, AF1},
24+
gpio::{Alternate, Analog, Floating, Input, Output, PullDown, PullUp, PushPull, AF1},
2325
pac,
2426
prelude::*,
2527
rcc, serial,
@@ -170,6 +172,10 @@ mod app {
170172
rcc: Option<rcc::Rcc>,
171173
/// IRQ pin
172174
pin_irq: PA8<Output<PushPull>>,
175+
/// 3.3V monitor pin
176+
pin_3v3_monitor: PA0<Analog>,
177+
/// ADC
178+
adc: Adc,
173179
}
174180

175181
#[monotonic(binds = SysTick, default = true)]
@@ -204,6 +210,10 @@ mod app {
204210
// Initialize the monotonic timer using the Cortex-M SysTick peripheral
205211
let mono = Systick::new(cp.SYST, rcc.clocks.sysclk().0);
206212

213+
let mut adc = Adc::new(dp.ADC, &mut rcc);
214+
adc.set_sample_time(adc::AdcSampleTime::T_1);
215+
adc.set_precision(adc::AdcPrecision::B_6);
216+
207217
defmt::info!("Creating pins...");
208218
let gpioa = dp.GPIOA.split(&mut rcc);
209219
let gpiob = dp.GPIOB.split(&mut rcc);
@@ -236,6 +246,8 @@ mod app {
236246
pin_cipo,
237247
pin_copi,
238248
mut pin_irq,
249+
pin_3v3_monitor,
250+
adc,
239251
) = cortex_m::interrupt::free(|cs| {
240252
(
241253
// uart_tx,
@@ -281,6 +293,10 @@ mod app {
281293
gpioa.pa7.into_alternate_af0(cs),
282294
// pin_irq
283295
gpioa.pa8.into_push_pull_output(cs),
296+
// pin_3v3_monitor
297+
gpioa.pa0.into_analog(cs),
298+
// ADC
299+
adc,
284300
)
285301
});
286302

@@ -364,6 +380,8 @@ mod app {
364380
press_button_reset_short: debouncr::debounce_2(false),
365381
rcc: Some(rcc),
366382
pin_irq,
383+
pin_3v3_monitor,
384+
adc,
367385
};
368386
let init = init::Monotonics(mono);
369387
(shared_resources, local_resources, init)
@@ -372,7 +390,7 @@ mod app {
372390
/// Our idle task.
373391
///
374392
/// This task is called when there is nothing else to do.
375-
#[idle(shared = [msg_q_out, msg_q_in, spi, state_dc_power_enabled, pin_dc_on, pin_sys_reset, speaker], local = [pin_irq, rcc, speaker_task_handle: Option<speaker_pwm_stop::MyMono::SpawnHandle> = None])]
393+
#[idle(shared = [msg_q_out, msg_q_in, spi, state_dc_power_enabled, pin_dc_on, pin_sys_reset, speaker], local = [pin_irq, rcc, speaker_task_handle: Option<speaker_pwm_stop::MyMono::SpawnHandle> = None, adc, pin_3v3_monitor])]
376394
fn idle(mut ctx: idle::Context) -> ! {
377395
// TODO: Get this from the VERSION static variable or from PKG_VERSION
378396
let mut register_state = RegisterState {
@@ -420,7 +438,8 @@ mod app {
420438
}
421439
}
422440
Some(Message::PowerButtonLongPress) => {
423-
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::On {
441+
let power_state = ctx.shared.state_dc_power_enabled.lock(|r| *r);
442+
if power_state == DcPowerState::On || power_state == DcPowerState::Starting {
424443
defmt::info!("Power off requested!");
425444
ctx.shared
426445
.state_dc_power_enabled
@@ -452,26 +471,12 @@ mod app {
452471
ctx.shared.pin_sys_reset.lock(|pin| pin.set_low().unwrap());
453472
// Step 4 - Turn on PSU
454473
ctx.shared.pin_dc_on.set_high().unwrap();
455-
// Step 5 - Leave it in reset for a while.
456-
// TODO: Start monitoring 3.3V and 5.0V rails here
457-
// TODO: Take system out of reset when 3.3V and 5.0V are good
458-
// Returns an error if it's already scheduled (but we don't care)
459-
let _ = exit_reset::spawn_after(RESET_DURATION_MS.millis());
460-
// Set 6 - unmask the IRQ
461-
irq_forced_low = false;
474+
// Step 5 happens below when power is good
475+
defmt::info!("Waiting for power-good");
462476
}
463477
}
464478
Some(Message::PowerButtonRelease) => {
465-
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::Starting {
466-
defmt::info!("Power button released.");
467-
// Button released after power on. Change the power
468-
// state machine t "On". We were in 'Starting' to ignore
469-
// any further button events until the button had been
470-
// released.
471-
ctx.shared
472-
.state_dc_power_enabled
473-
.lock(|r| *r = DcPowerState::On);
474-
}
479+
defmt::info!("Power button released.");
475480
}
476481
Some(Message::ResetButtonShortPress) => {
477482
// Is the board powered on? Don't do a reset if it's powered off.
@@ -493,7 +498,7 @@ mod app {
493498
}
494499
}
495500
Some(Message::SpiEnable) => {
496-
if ctx.shared.state_dc_power_enabled.lock(|r| *r) != DcPowerState::Off {
501+
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::On {
497502
// Turn on the SPI peripheral and expect four bytes (the
498503
// length of a Request).
499504
ctx.shared.spi.lock(|s| s.start(4));
@@ -583,7 +588,37 @@ mod app {
583588
);
584589
}
585590
}
586-
// TODO: Read ADC for 3.3V and 5.0V rails and check good
591+
// TODO: Also monitor 5.0V rail
592+
593+
// Wait for power good
594+
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::Starting {
595+
let mon_3v3 = ctx.local.adc.read_abs_mv(ctx.local.pin_3v3_monitor);
596+
defmt::trace!("3v3 reading: {}", mon_3v3);
597+
if mon_3v3 < 1600 {
598+
defmt::info!("3v3 below threshold: {} mv", mon_3v3);
599+
} else {
600+
defmt::info!(
601+
"Power good. 3v3 at {} mV. Continue with startup sequence.",
602+
mon_3v3
603+
);
604+
// Change the power state machine to "On". We were in 'Starting' to ignore
605+
// any further button events until the button had been
606+
// released and to wait for power good.
607+
ctx.shared
608+
.state_dc_power_enabled
609+
.lock(|r| *r = DcPowerState::On);
610+
// Steps 1 - 4 happened above, in the button press handler
611+
// Step 5 - Leave it in reset for a while.
612+
// TODO: Start monitoring 3.3V and 5.0V rails here
613+
// TODO: Take system out of reset when 3.3V and 5.0V are good
614+
// Returns an error if it's already scheduled (but we don't care)
615+
let _ = exit_reset::spawn_after(RESET_DURATION_MS.millis());
616+
// Set 6 - unmask the IRQ
617+
irq_forced_low = false;
618+
}
619+
}
620+
// TODO: Shutdown system if mon_3v3 falls below threshold
621+
// TODO: Maybe report voltages to CPU?
587622
}
588623
}
589624

@@ -797,7 +832,7 @@ mod app {
797832
#[task(shared = [pin_sys_reset, state_dc_power_enabled])]
798833
fn exit_reset(mut ctx: exit_reset::Context) {
799834
defmt::debug!("End reset");
800-
if ctx.shared.state_dc_power_enabled.lock(|r| *r) != DcPowerState::Off {
835+
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::On {
801836
// Raising the reset line takes the rest of the system out of reset
802837
ctx.shared.pin_sys_reset.lock(|pin| pin.set_high().unwrap());
803838
}

0 commit comments

Comments
 (0)