Skip to content

Commit 584a773

Browse files
committed
Add board support package/crate
Move demo firmware to an example.
1 parent b1a391e commit 584a773

File tree

17 files changed

+495
-1775
lines changed

17 files changed

+495
-1775
lines changed

.github/workflows/ci.yml

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ jobs:
2727
shell: devenv shell bash -- -e {0}
2828
run: treefmt --fail-on-change
2929

30-
demo-firmware:
31-
name: Demo firmware
30+
bsp:
31+
name: BSP
3232
needs:
3333
- formatting
3434
runs-on: ubuntu-latest
@@ -45,23 +45,55 @@ jobs:
4545
- name: Add Rust target
4646
shell: devenv shell bash -- -e {0}
4747
run: |
48-
cd ./demo-firmware
48+
cd ./bsp
4949
rustup target add thumbv6m-none-eabi
5050
5151
- name: Clippy
5252
shell: devenv shell bash -- -e {0}
5353
run: |
54-
cd ./demo-firmware
54+
cd ./bsp
5555
cargo clippy -- -D warnings
5656
5757
- name: Build
5858
shell: devenv shell bash -- -e {0}
5959
run: |
60-
cd ./demo-firmware
60+
cd ./bsp
6161
cargo build
6262
63-
- name: Build (with panic_probe)
63+
examples:
64+
name: Examples
65+
needs:
66+
- bsp
67+
runs-on: ubuntu-latest
68+
69+
strategy:
70+
matrix:
71+
example:
72+
- "kitchen-sink"
73+
74+
steps:
75+
- uses: actions/checkout@v4
76+
- uses: cachix/install-nix-action@v30
77+
- uses: cachix/cachix-action@v15
78+
with:
79+
name: devenv
80+
- name: Install devenv.sh
81+
run: nix profile install nixpkgs#devenv
82+
83+
- name: Add Rust target
84+
shell: devenv shell bash -- -e {0}
85+
run: |
86+
cd ./bsp/examples/${{ matrix.example }}
87+
rustup target add thumbv6m-none-eabi
88+
89+
- name: Clippy
6490
shell: devenv shell bash -- -e {0}
6591
run: |
66-
cd ./demo-firmware
67-
cargo build -F panic-probe
92+
cd ./bsp/examples/${{ matrix.example }}
93+
cargo clippy -- -D warnings
94+
95+
- name: Build
96+
shell: devenv shell bash -- -e {0}
97+
run: |
98+
cd ./bsp/examples/${{ matrix.example }}
99+
cargo build
File renamed without changes.

bsp/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target
2+
Cargo.lock

bsp/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[package]
2+
name = "pico-plc-bsp"
3+
version = "0.1.0"
4+
edition = "2021"
5+
authors = ["Dan Nixon <[email protected]>"]
6+
license = "MIT"
7+
8+
[dependencies]
9+
embassy-rp = { version = "0.3.1", features = ["rp2040"] }
10+
one-wire-bus = "0.1.1"

bsp/examples/kitchen-sink/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target
2+
Cargo.lock

demo-firmware/Cargo.toml renamed to bsp/examples/kitchen-sink/Cargo.toml

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,24 @@
11
[package]
2-
name = "pico-plc-demo-firmware"
2+
name = "pico-plc-kitchen-sink-example"
33
version = "0.1.0"
4-
authors = ["Dan Nixon <[email protected]>"]
54
edition = "2021"
5+
authors = ["Dan Nixon <[email protected]>"]
66
license = "MIT"
77

8-
[features]
9-
panic-probe = ["dep:panic-probe"]
10-
118
[dependencies]
129
cortex-m-rt = "0.7.5"
1310
embassy-rp = { version = "0.3.1", features = ["defmt", "unstable-pac", "time-driver", "critical-section-impl", "rp2040"] }
11+
pico-plc-bsp = { path = "../../" }
12+
assign-resources = "0.4.1"
13+
portable-atomic = { version = "1.10.0", features = ["critical-section"] }
1414

1515
embassy-executor = { version = "0.7.0", features = ["task-arena-size-98304", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] }
1616
embassy-time = "0.4.0"
1717

1818
defmt = "0.3.10"
1919
defmt-rtt = "0.4.1"
20-
panic-probe = { version = "0.3.2", features = ["print-defmt"], optional = true }
21-
22-
embassy-sync = "0.6.2"
23-
portable-atomic = { version = "1.10.0", features = ["critical-section"] }
24-
static_cell = "2.1.0"
20+
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
2521

26-
one-wire-bus = "0.1.1"
2722
ds18b20 = "0.1.1"
2823

2924
[profile.release]
File renamed without changes.
File renamed without changes.

bsp/examples/kitchen-sink/src/main.rs

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use assign_resources::assign_resources;
5+
use defmt::{debug, info, unwrap};
6+
use defmt_rtt as _;
7+
use embassy_executor::Spawner;
8+
use embassy_rp::gpio::{Input, Level, Output, Pull};
9+
use embassy_time::{Delay, Duration, Ticker, Timer};
10+
use panic_probe as _;
11+
use pico_plc_bsp::peripherals;
12+
use portable_atomic as _;
13+
14+
assign_resources! {
15+
io: IoPinResources {
16+
io0: IO_0,
17+
io1: IO_1,
18+
io2: IO_2,
19+
io3: IO_3,
20+
io4: IO_4,
21+
io5: IO_5,
22+
},
23+
inputs: InputPinResources {
24+
in0: IN_0,
25+
in1: IN_1,
26+
in2: IN_2,
27+
in3: IN_3,
28+
in4: IN_4,
29+
in5: IN_5,
30+
in6: IN_6,
31+
in7: IN_7,
32+
},
33+
relays: RelayResources {
34+
relay0: RELAY_0,
35+
relay1: RELAY_1,
36+
relay2: RELAY_2,
37+
relay3: RELAY_3,
38+
relay4: RELAY_4,
39+
relay5: RELAY_5,
40+
relay6: RELAY_6,
41+
relay7: RELAY_7,
42+
},
43+
onewire: OnewireResources {
44+
pin: ONEWIRE,
45+
},
46+
}
47+
48+
#[embassy_executor::main]
49+
async fn main(spawner: Spawner) {
50+
let p = pico_plc_bsp::peripherals::PicoPlc::default();
51+
let r = split_resources!(p);
52+
53+
let led = Output::new(p.PIN_25, Level::Low);
54+
55+
let io0 = Input::new(r.io.io0, Pull::Up);
56+
let io1 = Input::new(r.io.io1, Pull::Up);
57+
let io2 = Input::new(r.io.io2, Pull::Up);
58+
let io3 = Input::new(r.io.io3, Pull::Up);
59+
let io4 = Input::new(r.io.io4, Pull::Up);
60+
let io5 = Input::new(r.io.io5, Pull::Up);
61+
62+
let in0 = Input::new(r.inputs.in0, Pull::Down);
63+
let in1 = Input::new(r.inputs.in1, Pull::Down);
64+
let in2 = Input::new(r.inputs.in2, Pull::Down);
65+
let in3 = Input::new(r.inputs.in3, Pull::Down);
66+
let in4 = Input::new(r.inputs.in4, Pull::Down);
67+
let in5 = Input::new(r.inputs.in5, Pull::Down);
68+
let in6 = Input::new(r.inputs.in6, Pull::Down);
69+
let in7 = Input::new(r.inputs.in7, Pull::Down);
70+
71+
unwrap!(spawner.spawn(read_isolated_input(in0, 0)));
72+
unwrap!(spawner.spawn(read_isolated_input(in1, 1)));
73+
unwrap!(spawner.spawn(read_isolated_input(in2, 2)));
74+
unwrap!(spawner.spawn(read_isolated_input(in3, 3)));
75+
unwrap!(spawner.spawn(read_isolated_input(in4, 4)));
76+
unwrap!(spawner.spawn(read_isolated_input(in5, 5)));
77+
unwrap!(spawner.spawn(read_isolated_input(in6, 6)));
78+
unwrap!(spawner.spawn(read_isolated_input(in7, 7)));
79+
80+
unwrap!(spawner.spawn(read_io(io0, 0)));
81+
unwrap!(spawner.spawn(read_io(io1, 1)));
82+
unwrap!(spawner.spawn(read_io(io2, 2)));
83+
unwrap!(spawner.spawn(read_io(io3, 3)));
84+
unwrap!(spawner.spawn(read_io(io4, 4)));
85+
unwrap!(spawner.spawn(read_io(io5, 5)));
86+
87+
unwrap!(spawner.spawn(relay_output(r.relays)));
88+
89+
unwrap!(spawner.spawn(blink_led(led)));
90+
91+
unwrap!(spawner.spawn(read_temperature_sensors(r.onewire)));
92+
}
93+
94+
#[derive(Default)]
95+
struct PinChangeDetector {
96+
last: Option<Level>,
97+
}
98+
99+
impl PinChangeDetector {
100+
fn update(&mut self, new: Level) -> Option<Level> {
101+
let changed = self.last != Some(new);
102+
self.last = Some(new);
103+
104+
if changed {
105+
self.last
106+
} else {
107+
None
108+
}
109+
}
110+
}
111+
112+
fn level_as_str(level: Level) -> &'static str {
113+
match level {
114+
Level::Low => "low",
115+
Level::High => "high",
116+
}
117+
}
118+
119+
#[embassy_executor::task(pool_size = 8)]
120+
async fn read_isolated_input(input: Input<'static>, num: usize) {
121+
let mut detector = PinChangeDetector::default();
122+
123+
loop {
124+
Timer::after_micros(10).await;
125+
126+
if let Some(level) = detector.update(input.get_level()) {
127+
info!("Input {} is {}", num, level_as_str(level));
128+
}
129+
}
130+
}
131+
132+
#[embassy_executor::task(pool_size = 6)]
133+
async fn read_io(input: Input<'static>, num: usize) {
134+
let mut detector = PinChangeDetector::default();
135+
136+
loop {
137+
Timer::after_micros(10).await;
138+
139+
if let Some(level) = detector.update(input.get_level()) {
140+
info!("IO {} is {}", num, level_as_str(level));
141+
}
142+
}
143+
}
144+
145+
#[embassy_executor::task]
146+
async fn blink_led(mut led: Output<'static>) {
147+
loop {
148+
led.toggle();
149+
Timer::after_millis(500).await;
150+
}
151+
}
152+
153+
#[embassy_executor::task]
154+
async fn relay_output(r: RelayResources) {
155+
let mut relays = [
156+
Output::new(r.relay0, Level::Low),
157+
Output::new(r.relay1, Level::Low),
158+
Output::new(r.relay2, Level::Low),
159+
Output::new(r.relay3, Level::Low),
160+
Output::new(r.relay4, Level::Low),
161+
Output::new(r.relay5, Level::Low),
162+
Output::new(r.relay6, Level::Low),
163+
Output::new(r.relay7, Level::Low),
164+
];
165+
166+
let mut ticker = Ticker::every(Duration::from_secs(1));
167+
168+
loop {
169+
for (i, relay) in relays.iter_mut().enumerate() {
170+
info!("Turning relay {} on", i);
171+
relay.set_high();
172+
173+
ticker.next().await;
174+
175+
info!("Turning relay {} off", i);
176+
relay.set_low();
177+
178+
ticker.next().await;
179+
}
180+
}
181+
}
182+
183+
#[embassy_executor::task]
184+
async fn read_temperature_sensors(r: OnewireResources) {
185+
let mut bus = pico_plc_bsp::onewire::new(r.pin).unwrap();
186+
187+
for device_address in bus.devices(false, &mut Delay) {
188+
let device_address = device_address.unwrap();
189+
info!("Found one wire device at address: {}", device_address.0);
190+
}
191+
192+
let mut ticker = Ticker::every(Duration::from_secs(5));
193+
194+
loop {
195+
ds18b20::start_simultaneous_temp_measurement(&mut bus, &mut Delay).unwrap();
196+
197+
Timer::after_millis(ds18b20::Resolution::Bits12.max_measurement_time_millis() as u64).await;
198+
199+
let mut search_state = None;
200+
while let Some((device_address, state)) = bus
201+
.device_search(search_state.as_ref(), false, &mut Delay)
202+
.unwrap()
203+
{
204+
search_state = Some(state);
205+
206+
if device_address.family_code() == ds18b20::FAMILY_CODE {
207+
debug!("Found DS18B20 at address: {}", device_address.0);
208+
209+
let sensor = ds18b20::Ds18b20::new::<()>(device_address).unwrap();
210+
let sensor_data = sensor.read_data(&mut bus, &mut Delay).unwrap();
211+
info!(
212+
"DS18B20 {} is {}°C",
213+
device_address.0, sensor_data.temperature
214+
);
215+
} else {
216+
info!(
217+
"Found unknown one wire device at address: {}",
218+
device_address.0
219+
);
220+
}
221+
}
222+
223+
ticker.next().await;
224+
}
225+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[toolchain]
2-
channel = "1.84"
2+
channel = "1.85"
33
components = ["rust-src", "clippy", "rust-analyzer"]
44
profile = "minimal"

0 commit comments

Comments
 (0)