Skip to content

Commit 262d1ab

Browse files
committed
Merge branch 'release/v0.4.2'
2 parents 58c03ae + 733f11b commit 262d1ab

File tree

4 files changed

+166
-107
lines changed

4 files changed

+166
-107
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## Unreleased Changes
44

5+
## v0.4.2
6+
7+
* Improvements to SPI communications link
8+
* Move some processing out of interrupts and into the main loop, to improve reliability
9+
510
## v0.4.1
611

712
* Update dependencies (moves away from yanked critical-section 0.2.x)

neotron-bmc-pico/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
authors = ["Jonathan 'theJPster' Pallant <github@thejpster.org.uk>"]
33
name = "neotron-bmc-pico"
44
edition = "2018"
5-
version = "0.4.0"
5+
version = "0.4.2"
66

77
[dependencies]
88
cortex-m = { version = "0.7.5", features = ["inline-asm", "critical-section-single-core"] }

neotron-bmc-pico/src/main.rs

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use stm32f0xx_hal::{
2222
gpio::{Alternate, Floating, Input, Output, PullDown, PullUp, PushPull, AF1},
2323
pac,
2424
prelude::*,
25-
serial,
25+
rcc, serial,
2626
};
2727

2828
use neotron_bmc_commands::Command;
@@ -80,6 +80,10 @@ mod app {
8080
Ps2Data1(u16),
8181
/// Message from SPI bus
8282
SpiRequest(neotron_bmc_protocol::Request),
83+
/// SPI CS went low (active)
84+
SpiEnable,
85+
/// SPI CS went high (inactive)
86+
SpiDisable,
8387
/// The power button was given a press
8488
PowerButtonShortPress,
8589
/// The power button was held down
@@ -159,6 +163,8 @@ mod app {
159163
press_button_power_long: debouncr::Debouncer<u16, debouncr::Repeat16>,
160164
/// Tracks reset button state for short presses. 75ms x 2 = 150ms is a long press
161165
press_button_reset_short: debouncr::Debouncer<u8, debouncr::Repeat2>,
166+
/// Run-time Clock Control (required for resetting peripheral blocks)
167+
rcc: Option<rcc::Rcc>,
162168
}
163169

164170
#[monotonic(binds = SysTick, default = true)]
@@ -281,7 +287,6 @@ mod app {
281287
let spi = neotron_bmc_pico::spi::SpiPeripheral::new(
282288
dp.SPI1,
283289
(pin_sck, pin_cipo, pin_copi),
284-
2_000_000,
285290
&mut rcc,
286291
);
287292

@@ -339,6 +344,7 @@ mod app {
339344
press_button_power_short: debouncr::debounce_2(false),
340345
press_button_power_long: debouncr::debounce_16(false),
341346
press_button_reset_short: debouncr::debounce_2(false),
347+
rcc: Some(rcc),
342348
};
343349
let init = init::Monotonics(mono);
344350
(shared_resources, local_resources, init)
@@ -347,14 +353,15 @@ mod app {
347353
/// Our idle task.
348354
///
349355
/// This task is called when there is nothing else to do.
350-
#[idle(shared = [msg_q_out, msg_q_in, spi, state_dc_power_enabled, pin_dc_on, pin_sys_reset, pin_cs])]
356+
#[idle(shared = [msg_q_out, msg_q_in, spi, state_dc_power_enabled, pin_dc_on, pin_sys_reset], local = [rcc])]
351357
fn idle(mut ctx: idle::Context) -> ! {
352358
// TODO: Get this from the VERSION static variable or from PKG_VERSION
353359
let mut register_state = RegisterState {
354360
firmware_version: *b"Neotron BMC v0.4.1-alpha\x00\x00\x00\x00\x00\x00\x00\x00",
355361
..Default::default()
356362
};
357-
363+
// Take this out of the `local` object to avoid sharing issues.
364+
let mut rcc = ctx.local.rcc.take().unwrap();
358365
defmt::info!("Idle is running...");
359366
loop {
360367
match ctx.shared.msg_q_out.dequeue() {
@@ -377,36 +384,46 @@ mod app {
377384
}
378385
Some(Message::PowerButtonLongPress) => {
379386
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::On {
380-
defmt::info!("Power button held whilst on.");
387+
defmt::info!("Power off requested!");
381388
ctx.shared
382389
.state_dc_power_enabled
383390
.lock(|r| *r = DcPowerState::Off);
384-
defmt::info!("Power off!");
391+
// Stop any SPI stuff that's currently going on (the host is about to be powered off)
392+
ctx.shared.spi.lock(|s| s.stop());
393+
// Put the host into reset
385394
ctx.shared.pin_sys_reset.lock(|pin| pin.set_low().unwrap());
395+
// Shut off the 5V power
386396
ctx.shared.pin_dc_on.set_low().unwrap();
387-
ctx.shared.spi.lock(|s| s.disable());
388397
// Start LED blinking again
389398
led_power_blink::spawn().unwrap();
390399
}
391400
}
392401
Some(Message::PowerButtonShortPress) => {
393402
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::Off {
394-
defmt::info!("Power button pressed whilst off. Powering up.");
395-
// Button pressed - power on system
403+
defmt::info!("Power up requested!");
404+
// Button pressed - power on system.
405+
// Step 1 - Note our new power state
396406
ctx.shared
397407
.state_dc_power_enabled
398408
.lock(|r| *r = DcPowerState::Starting);
409+
// Step 2 - Hold reset line (active) low
410+
ctx.shared.pin_sys_reset.lock(|pin| pin.set_low().unwrap());
411+
// Step 3 - Turn on PSU
399412
ctx.shared.pin_dc_on.set_high().unwrap();
413+
// Step 4 - Leave it in reset for a while.
400414
// TODO: Start monitoring 3.3V and 5.0V rails here
401415
// TODO: Take system out of reset when 3.3V and 5.0V are good
402-
ctx.shared.pin_sys_reset.lock(|pin| pin.set_high().unwrap());
403-
ctx.shared.spi.lock(|s| s.enable());
416+
// Returns an error if it's already scheduled (but we don't care)
417+
let _ = exit_reset::spawn_after(RESET_DURATION_MS.millis());
404418
}
405419
}
406420
Some(Message::PowerButtonRelease) => {
407421
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::Starting {
408422
defmt::info!("Power button released.");
409-
// Button released after power on
423+
// Button released after power on. Change the power
424+
// state machine t "On". We were in 'Starting' to ignore
425+
// any further button events until the button had been
426+
// released.
410427
ctx.shared
411428
.state_dc_power_enabled
412429
.lock(|r| *r = DcPowerState::On);
@@ -417,10 +434,25 @@ mod app {
417434
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::On {
418435
defmt::info!("Reset!");
419436
ctx.shared.pin_sys_reset.lock(|pin| pin.set_low().unwrap());
420-
// Returns an error if it's already scheduled
437+
ctx.shared.spi.lock(|s| s.reset(&mut rcc));
438+
// Returns an error if it's already scheduled (but we don't care)
421439
let _ = exit_reset::spawn_after(RESET_DURATION_MS.millis());
422440
}
423441
}
442+
Some(Message::SpiEnable) => {
443+
if ctx.shared.state_dc_power_enabled.lock(|r| *r) != DcPowerState::Off {
444+
// Turn on the SPI peripheral
445+
ctx.shared.spi.lock(|s| s.start());
446+
} else {
447+
// Ignore message - it'll be the CS line being pulled low when the host is powered off
448+
defmt::info!("Ignoring spurious CS low");
449+
}
450+
}
451+
Some(Message::SpiDisable) => {
452+
// Turn off the SPI peripheral. Don't need to check power state for this.
453+
ctx.shared.spi.lock(|s| s.stop());
454+
defmt::trace!("SPI Disable");
455+
}
424456
Some(Message::SpiRequest(req)) => {
425457
process_command(req, &mut register_state, |rsp| {
426458
ctx.shared.spi.lock(|spi| {
@@ -487,7 +519,7 @@ mod app {
487519
#[task(
488520
binds = EXTI4_15,
489521
priority = 4,
490-
shared = [ps2_clk0, msg_q_in, ps2_dat0, exti, spi, pin_cs, kb_decoder],
522+
shared = [ps2_clk0, msg_q_in, ps2_dat0, exti, pin_cs, kb_decoder],
491523
)]
492524
fn exti4_15_interrupt(mut ctx: exti4_15_interrupt::Context) {
493525
let pr = ctx.shared.exti.pr.read();
@@ -511,12 +543,15 @@ mod app {
511543
}
512544

513545
if pr.pr4().bit_is_set() {
514-
if ctx.shared.pin_cs.lock(|pin| pin.is_low().unwrap()) {
515-
// If incoming Chip Select is low, turn on the SPI engine
516-
ctx.shared.spi.lock(|s| s.start());
546+
let msg = if ctx.shared.pin_cs.lock(|pin| pin.is_low().unwrap()) {
547+
// If incoming Chip Select is low, tell the main thread to turn on the SPI engine
548+
Message::SpiEnable
517549
} else {
518-
// If incoming Chip Select is high, turn off the SPI engine
519-
ctx.shared.spi.lock(|s| s.stop());
550+
// If incoming Chip Select is high, tell the main thread to turn off the SPI engine
551+
Message::SpiDisable
552+
};
553+
if ctx.shared.msg_q_in.lock(|q| q.enqueue(msg)).is_err() {
554+
panic!("queue full");
520555
}
521556
// Clear the pending flag for this pin
522557
ctx.shared.exti.pr.write(|w| w.pr4().set_bit());
@@ -663,7 +698,8 @@ mod app {
663698
#[task(shared = [pin_sys_reset, state_dc_power_enabled])]
664699
fn exit_reset(mut ctx: exit_reset::Context) {
665700
defmt::debug!("End reset");
666-
if ctx.shared.state_dc_power_enabled.lock(|r| *r) == DcPowerState::On {
701+
if ctx.shared.state_dc_power_enabled.lock(|r| *r) != DcPowerState::Off {
702+
// Raising the reset line takes the rest of the system out of reset
667703
ctx.shared.pin_sys_reset.lock(|pin| pin.set_high().unwrap());
668704
}
669705
}

0 commit comments

Comments
 (0)