Skip to content

Commit 4011af3

Browse files
committed
Merge branch 'release/v0.2.0'
2 parents c5d0305 + 06ce002 commit 4011af3

File tree

5 files changed

+130
-68
lines changed

5 files changed

+130
-68
lines changed

.github/workflows/release.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
on:
2+
push:
3+
tags:
4+
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
5+
6+
name: Upload Release
7+
8+
jobs:
9+
build:
10+
name: Upload Release
11+
runs-on: ubuntu-latest
12+
steps:
13+
- name: Checkout
14+
uses: actions/checkout@v1
15+
with:
16+
submodules: true
17+
- name: Add Target
18+
run: rustup target add thumbv6m-none-eabi
19+
- name: Install flip-link
20+
run: cd / && cargo install flip-link
21+
- name: Build
22+
run: cargo build --release --target=thumbv6m-none-eabi
23+
- name: Get Branch Name
24+
id: branch_name
25+
run: |
26+
echo ::set-output name=SOURCE_TAG::${GITHUB_REF#refs/tags/}
27+
- name: Create Release
28+
id: create_release
29+
uses: actions/create-release@v1
30+
env:
31+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32+
with:
33+
tag_name: ${{ github.ref }}
34+
release_name: Release ${{ steps.branch_name.outputs.SOURCE_TAG }}
35+
draft: true
36+
prerelease: false
37+
- name: Upload files to Release
38+
uses: softprops/action-gh-release@v1
39+
with:
40+
files: |
41+
target/thumbv6m-none-eabi/release/neotron-bmc
42+
env:
43+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
# Changelog
22

3-
## Unrelease Changes
3+
## Unreleased Changes
44

5+
* None
6+
7+
## v0.2.0
8+
* Change to blink power LED when in standby
9+
* Actually controls DC power and reset (but doesn't check the voltage rails yet)
10+
11+
## v0.1.0
512
* Skeleton application using knurling template
613
* Started work on command protocol definition
714
* LED Blinking Modes defined

Cargo.toml

Lines changed: 2 additions & 2 deletions
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"
44
edition = "2018"
5-
version = "0.1.0"
5+
version = "0.2.0"
66

77
[workspace]
88
members = ["testsuite"]
@@ -76,4 +76,4 @@ overflow-checks = false # <-
7676
# defmt = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" }
7777
# defmt-rtt = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" }
7878
# defmt-test = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" }
79-
# panic-probe = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" }
79+
# panic-probe = { git = "https://github.com/knurling-rs/defmt", rev = "use defmt version reported by `probe-run --version`" }

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The NBMC firmware is designed to run on an ST Micro STM32F0 (STM32F031K6T6) micr
3232
| Pin | Name | Signal | Function |
3333
| :--- | :--- | :---------- | :------------------------------------------- |
3434
| 02 | PF0 | BUTTON_nPWR | Power Button Input (active low) |
35-
| 03 | PF1 | HOST_nRST | Reset Output to reset the rest of the system |
35+
| 03 | PF1 | BUTTON_nRST | Reset Button Input (active low) |
3636
| 06 | PA0 | MON_3V3 | 3.3V rail monitor Input (1.65V nominal) |
3737
| 07 | PA1 | MON_5V | 5.0V rail monitor Input (1.65V nominal) |
3838
| 08 | PA2 | nSYS_RESET | System Reset Output (active low) |

src/main.rs

Lines changed: 76 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use cortex_m::interrupt::free as disable_interrupts;
1212
use rtic::app;
1313
use stm32f0xx_hal::{
14-
gpio::gpioa::{PA10, PA11, PA12, PA9},
14+
gpio::gpioa::{PA10, PA11, PA12, PA2, PA3, PA9},
1515
gpio::gpiob::{PB0, PB1},
1616
gpio::gpiof::{PF0, PF1},
1717
gpio::{Alternate, Input, Output, PullUp, PushPull, AF1},
@@ -54,28 +54,33 @@ const APP: () = {
5454
/// The FTDI UART header (J105)
5555
serial: serial::Serial<pac::USART1, PA9<Alternate<AF1>>, PA10<Alternate<AF1>>>,
5656
/// The Clear-To-Send line on the FTDI UART header (which the serial object can't handle)
57-
uart_cts: PA11<Alternate<AF1>>,
57+
pin_uart_cts: PA11<Alternate<AF1>>,
5858
/// The Ready-To-Receive line on the FTDI UART header (which the serial object can't handle)
59-
uart_rts: PA12<Alternate<AF1>>,
59+
pin_uart_rts: PA12<Alternate<AF1>>,
6060
/// The power button
6161
button_power: PF0<Input<PullUp>>,
6262
/// The reset button
6363
button_reset: PF1<Input<PullUp>>,
6464
/// Tracks power button state for short presses. 75ms x 2 = 150ms is a short press
65-
button_power_short_press: debouncr::Debouncer<u8, debouncr::Repeat2>,
65+
press_button_power_short: debouncr::Debouncer<u8, debouncr::Repeat2>,
6666
/// Tracks power button state for long presses. 75ms x 16 = 1200ms is a long press
67-
button_power_long_press: debouncr::Debouncer<u16, debouncr::Repeat16>,
67+
press_button_power_long: debouncr::Debouncer<u16, debouncr::Repeat16>,
6868
/// Tracks DC power state
69-
dc_power_enabled: DcPowerState,
69+
state_dc_power_enabled: DcPowerState,
70+
/// Controls the DC-DC PSU
71+
pin_dc_on: PA3<Output<PushPull>>,
72+
/// Controls the Reset signal across the main board, putting all the
73+
/// chips (except this BMC!) in reset when pulled low.
74+
pin_sys_reset: PA2<Output<PushPull>>,
7075
}
7176

7277
/// The entry point to our application.
7378
///
7479
/// Sets up the hardware and spawns the regular tasks.
7580
///
76-
/// * Task `led_status_blink` - blinks the LED
81+
/// * Task `led_power_blink` - blinks the LED
7782
/// * Task `button_poll` - checks the power and reset buttons
78-
#[init(spawn = [led_status_blink, button_poll])]
83+
#[init(spawn = [led_power_blink, button_poll])]
7984
fn init(ctx: init::Context) -> init::LateResources {
8085
defmt::info!("Neotron BMC version {:?} booting", VERSION);
8186

@@ -100,12 +105,14 @@ const APP: () = {
100105
let (
101106
uart_tx,
102107
uart_rx,
103-
uart_cts,
104-
uart_rts,
108+
pin_uart_cts,
109+
pin_uart_rts,
105110
mut led_power,
106111
led_status,
107112
button_power,
108113
button_reset,
114+
mut pin_dc_on,
115+
mut pin_sys_reset,
109116
) = disable_interrupts(|cs| {
110117
(
111118
gpioa.pa9.into_alternate_af1(cs),
@@ -116,17 +123,22 @@ const APP: () = {
116123
gpiob.pb1.into_push_pull_output(cs),
117124
gpiof.pf0.into_pull_up_input(cs),
118125
gpiof.pf1.into_pull_up_input(cs),
126+
gpioa.pa3.into_push_pull_output(cs),
127+
gpioa.pa2.into_push_pull_output(cs),
119128
)
120129
});
121130

131+
pin_sys_reset.set_low().unwrap();
132+
pin_dc_on.set_low().unwrap();
133+
122134
defmt::info!("Creating UART...");
123135

124136
let mut serial =
125137
serial::Serial::usart1(dp.USART1, (uart_tx, uart_rx), 115_200.bps(), &mut rcc);
126138

127139
serial.listen(serial::Event::Rxne);
128140

129-
ctx.spawn.led_status_blink().unwrap();
141+
ctx.spawn.led_power_blink().unwrap();
130142

131143
ctx.spawn.button_poll().unwrap();
132144

@@ -136,15 +148,17 @@ const APP: () = {
136148

137149
init::LateResources {
138150
serial,
139-
uart_cts,
140-
uart_rts,
151+
pin_uart_cts,
152+
pin_uart_rts,
141153
led_power,
142154
led_status,
143155
button_power,
144156
button_reset,
145-
button_power_short_press: debouncr::debounce_2(false),
146-
button_power_long_press: debouncr::debounce_16(false),
147-
dc_power_enabled: DcPowerState::Off,
157+
press_button_power_short: debouncr::debounce_2(false),
158+
press_button_power_long: debouncr::debounce_16(false),
159+
state_dc_power_enabled: DcPowerState::Off,
160+
pin_dc_on,
161+
pin_sys_reset,
148162
}
149163
}
150164

@@ -182,78 +196,76 @@ const APP: () = {
182196
///
183197
/// This task is called periodically. We check whether the status LED is currently on or off,
184198
/// and set it to the opposite. This makes the LED blink.
185-
#[task(schedule = [led_status_blink], resources = [led_status])]
186-
fn led_status_blink(ctx: led_status_blink::Context) {
199+
#[task(schedule = [led_power_blink], resources = [led_power, state_dc_power_enabled])]
200+
fn led_power_blink(ctx: led_power_blink::Context) {
187201
// Use the safe local `static mut` of RTIC
188202
static mut LED_STATE: bool = false;
189203

190-
defmt::trace!("blink time {}", ctx.scheduled.counts());
191-
192-
if *LED_STATE {
193-
ctx.resources.led_status.set_low().unwrap();
194-
*LED_STATE = false;
195-
} else {
196-
ctx.resources.led_status.set_high().unwrap();
197-
*LED_STATE = true;
204+
if *ctx.resources.state_dc_power_enabled == DcPowerState::Off {
205+
defmt::trace!("blink time {}", ctx.scheduled.counts());
206+
if *LED_STATE {
207+
ctx.resources.led_power.set_low().unwrap();
208+
*LED_STATE = false;
209+
} else {
210+
ctx.resources.led_power.set_high().unwrap();
211+
*LED_STATE = true;
212+
}
213+
let next = ctx.scheduled + LED_PERIOD_MS.millis();
214+
defmt::trace!("Next blink at {}", next.counts());
215+
ctx.schedule.led_power_blink(next).unwrap();
198216
}
199-
let next = ctx.scheduled + LED_PERIOD_MS.millis();
200-
defmt::trace!("Next blink at {}", next.counts());
201-
ctx.schedule.led_status_blink(next).unwrap();
202217
}
203218

204219
/// This task polls our power and reset buttons.
205220
///
206221
/// We poll them rather than setting up an interrupt as we need to debounce them, which involves waiting a short period and checking them again. Given that we have to do that, we might as well not bother with the interrupt.
207-
#[task(schedule = [button_poll], resources = [led_power, button_power, button_power_short_press, button_power_long_press, dc_power_enabled])]
222+
#[task(
223+
schedule = [button_poll],
224+
spawn = [led_power_blink],
225+
resources = [
226+
led_power, button_power, press_button_power_short, press_button_power_long, state_dc_power_enabled,
227+
pin_sys_reset, pin_dc_on
228+
]
229+
)]
208230
fn button_poll(ctx: button_poll::Context) {
209231
// Poll button
210232
let pressed: bool = ctx.resources.button_power.is_low().unwrap();
211233

212234
// Update state
213-
let short_edge = ctx.resources.button_power_short_press.update(pressed);
214-
let long_edge = ctx.resources.button_power_long_press.update(pressed);
235+
let short_edge = ctx.resources.press_button_power_short.update(pressed);
236+
let long_edge = ctx.resources.press_button_power_long.update(pressed);
215237

216238
// Dispatch event
217-
if short_edge == Some(debouncr::Edge::Rising) {
218-
defmt::trace!(
219-
"Power short press in! {}",
220-
*ctx.resources.dc_power_enabled as u8
221-
);
222-
if *ctx.resources.dc_power_enabled == DcPowerState::Off {
223-
*ctx.resources.dc_power_enabled = DcPowerState::Starting;
239+
match (long_edge, short_edge, *ctx.resources.state_dc_power_enabled) {
240+
(None, Some(debouncr::Edge::Rising), DcPowerState::Off) => {
241+
defmt::info!("Power button pressed whilst off.");
242+
// Button pressed - power on system
243+
*ctx.resources.state_dc_power_enabled = DcPowerState::Starting;
224244
ctx.resources.led_power.set_high().unwrap();
225245
defmt::info!("Power on!");
226-
// TODO: Enable DC PSU here
246+
ctx.resources.pin_dc_on.set_high().unwrap();
227247
// TODO: Start monitoring 3.3V and 5.0V rails here
228248
// TODO: Take system out of reset when 3.3V and 5.0V are good
249+
ctx.resources.pin_sys_reset.set_high().unwrap();
229250
}
230-
} else if short_edge == Some(debouncr::Edge::Falling) {
231-
defmt::trace!(
232-
"Power short press out! {}",
233-
*ctx.resources.dc_power_enabled as u8
234-
);
235-
match *ctx.resources.dc_power_enabled {
236-
DcPowerState::Starting => {
237-
*ctx.resources.dc_power_enabled = DcPowerState::On;
238-
}
239-
DcPowerState::On => {
240-
// TODO: Tell host that power off was requested
241-
}
242-
DcPowerState::Off => {
243-
// Ignore
244-
}
251+
(None, Some(debouncr::Edge::Falling), DcPowerState::Starting) => {
252+
defmt::info!("Power button released.");
253+
// Button released after power on
254+
*ctx.resources.state_dc_power_enabled = DcPowerState::On;
245255
}
246-
}
247-
248-
if long_edge == Some(debouncr::Edge::Rising) {
249-
defmt::trace!(
250-
"Power long press in! {}",
251-
*ctx.resources.dc_power_enabled as u8
252-
);
253-
if *ctx.resources.dc_power_enabled == DcPowerState::On {
254-
*ctx.resources.dc_power_enabled = DcPowerState::Off;
256+
(Some(debouncr::Edge::Rising), None, DcPowerState::On) => {
257+
defmt::info!("Power button held whilst on.");
258+
*ctx.resources.state_dc_power_enabled = DcPowerState::Off;
255259
ctx.resources.led_power.set_low().unwrap();
256260
defmt::info!("Power off!");
261+
ctx.resources.pin_sys_reset.set_low().unwrap();
262+
// TODO: Wait for 100ms for chips to stop?
263+
ctx.resources.pin_dc_on.set_low().unwrap();
264+
// Start LED blinking again
265+
ctx.spawn.led_power_blink().unwrap();
266+
}
267+
_ => {
268+
// Do nothing
257269
// TODO: Put system in reset here
258270
// TODO: Disable DC PSU here
259271
}

0 commit comments

Comments
 (0)