Skip to content

Commit 22aa576

Browse files
barafaelAfoHT
authored andcommitted
Add v1.0 L4 heartbeat example
1 parent 964a3f3 commit 22aa576

File tree

6 files changed

+191
-0
lines changed

6 files changed

+191
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2+
# uncomment ONE of these three option to make `cargo run` start a GDB session
3+
# which option to pick depends on your system
4+
# runner = "arm-none-eabi-gdb -q -x jlink.gdb"
5+
# runner = "arm-none-eabi-gdb -q -x openocd.gdb"
6+
runner = "gdb-multiarch -q -x openocd.gdb"
7+
# runner = "gdb -q -x openocd.gdb"
8+
9+
rustflags = [
10+
# LLD (shipped with the Rust toolchain) is used as the default linker
11+
"-C", "link-arg=-Tlink.x",
12+
13+
# if you run into problems with LLD switch to the GNU linker by commenting out
14+
# this line
15+
# "-C", "linker=arm-none-eabi-ld",
16+
17+
# if you need to link to pre-compiled C libraries provided by a C toolchain
18+
# use GCC as the linker by commenting out both lines above and then
19+
# uncommenting the three lines below
20+
# "-C", "linker=arm-none-eabi-gcc",
21+
# "-C", "link-arg=-Wl,-Tlink.x",
22+
# "-C", "link-arg=-nostartfiles",
23+
24+
# uncomment for unchecked wrapping arithmetics also in dev mode
25+
# "-Z", "force-overflow-checks=off",
26+
]
27+
28+
[build]
29+
# Pick ONE of these compilation targets
30+
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
31+
# target = "thumbv7m-none-eabi" # Cortex-M3
32+
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
33+
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Refer to https://github.com/probe-rs/cargo-embed/blob/master/src/config/default.toml
2+
# for the comprehensive list of options
3+
4+
[default.general]
5+
chip = "STM32L412"
6+
7+
[default.rtt]
8+
enabled = true
9+
show_timestamps = true
10+
11+
[default.gdb]
12+
# Whether or not a GDB server should be opened after flashing.
13+
# This is exclusive and cannot be used with RTT at the moment.
14+
enabled = false
15+
# The connection string in host:port format wher the GDB server will open a socket.
16+
# gdb_connection_string
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/target
2+
**/*.rs.bk
3+
Cargo.lock
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
[package]
2+
name = "stm32l4_heartbeat"
3+
categories = ["embedded", "no-std"]
4+
authors = [
5+
"arrowcircle",
6+
"Emil Fresk <emil.fresk@gmail.com>",
7+
"Domenico Andreoli <domenico.andreoli@linux.com>",
8+
]
9+
description = "Heartbeat for stm32l4xx"
10+
keywords = ["arm", "cortex-m"]
11+
license = "MIT OR Apache-2.0"
12+
version = "0.1.0"
13+
edition = "2021"
14+
15+
[dependencies]
16+
embedded-hal = "0.2.6"
17+
cortex-m-rtic = "1.0.0"
18+
stm32l4xx-hal = { version = "0.6.0", features = ["rt", "stm32l4x2"] }
19+
heapless = "0.7.10"
20+
systick-monotonic = "1.0.0"
21+
panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] }
22+
rtt-target = { version = "0.3.1", features = ["cortex-m"] }
23+
24+
# this lets you use `cargo fix`!
25+
[[bin]]
26+
name = "stm32l4_heartbeat"
27+
test = false
28+
bench = false
29+
30+
[profile.dev]
31+
opt-level = 1
32+
codegen-units = 16
33+
debug = true
34+
lto = false
35+
36+
[profile.release]
37+
opt-level = "s" # optimize for size
38+
codegen-units = 1 # better optimizations
39+
debug = true # symbols are nice and they don't increase the size on Flash
40+
lto = true # better optimizations

rtic_v1/stm32l4_heartbeat/memory.x

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
MEMORY
2+
{
3+
/* NOTE 1 K = 1 KiBi = 1024 bytes */
4+
/* TODO Adjust these memory regions to match your device memory layout */
5+
/* These values correspond to the LM3S6965, one of the few devices QEMU can emulate */
6+
FLASH : ORIGIN = 0x08000000, LENGTH = 64K
7+
RAM : ORIGIN = 0x20000000, LENGTH = 20K
8+
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
#![deny(unsafe_code)]
2+
#![deny(warnings)]
3+
#![no_main]
4+
#![no_std]
5+
6+
use heapless::Vec;
7+
use panic_rtt_target as _;
8+
use rtic::app;
9+
use rtt_target::{rprintln, rtt_init_print};
10+
use stm32l4xx_hal::gpio::{gpiob::PB3, Output, PushPull, State};
11+
use stm32l4xx_hal::prelude::*;
12+
use systick_monotonic::{fugit::Duration, Systick};
13+
14+
#[app(device = stm32l4xx_hal::pac, dispatchers = [SPI3])]
15+
mod app {
16+
use super::*;
17+
18+
#[shared]
19+
struct Shared {}
20+
21+
#[local]
22+
struct Local {
23+
led: PB3<Output<PushPull>>,
24+
intervals: Vec<u32, 6>,
25+
}
26+
27+
#[monotonic(binds = SysTick, default = true)]
28+
type MonoTimer = Systick<1000>;
29+
30+
#[init]
31+
fn init(cx: init::Context) -> (Shared, Local, init::Monotonics) {
32+
// Setup clocks
33+
let mut flash = cx.device.FLASH.constrain();
34+
let mut rcc = cx.device.RCC.constrain();
35+
let mut pwr = cx.device.PWR.constrain(&mut rcc.apb1r1);
36+
let mono = Systick::new(cx.core.SYST, 72_000_000);
37+
38+
rtt_init_print!();
39+
rprintln!("init");
40+
41+
let _clocks = rcc.cfgr.sysclk(72.mhz()).freeze(&mut flash.acr, &mut pwr);
42+
43+
// Setup LED
44+
let mut gpiob = cx.device.GPIOB.split(&mut rcc.ahb2);
45+
let led = gpiob.pb3.into_push_pull_output_with_state(
46+
&mut gpiob.moder,
47+
&mut gpiob.otyper,
48+
State::Low,
49+
);
50+
51+
// Simple heart beat LED on/off sequence
52+
let mut intervals: Vec<u32, 6> = Vec::new();
53+
intervals.push(30).unwrap(); // P Wave
54+
intervals.push(40).unwrap(); // PR Segment
55+
intervals.push(120).unwrap(); // QRS Complex
56+
intervals.push(30).unwrap(); // ST Segment
57+
intervals.push(60).unwrap(); // T Wave
58+
intervals.push(720).unwrap(); // Rest
59+
60+
// Schedule the blinking task
61+
blink::spawn(0).unwrap();
62+
63+
(Shared {}, Local { led, intervals }, init::Monotonics(mono))
64+
}
65+
66+
#[idle]
67+
fn idle(_: idle::Context) -> ! {
68+
loop {
69+
core::hint::spin_loop();
70+
}
71+
}
72+
73+
#[task(local = [led, intervals])]
74+
fn blink(cx: blink::Context, state: usize) {
75+
rprintln!("blink");
76+
let duration = cx.local.intervals[state];
77+
let next_state = (state + 1) % cx.local.intervals.len();
78+
79+
if state % 2 == 0 {
80+
cx.local.led.set_high().unwrap();
81+
} else {
82+
cx.local.led.set_low().unwrap();
83+
}
84+
85+
blink::spawn_after(
86+
Duration::<u64, 1, 1000>::from_ticks(duration as u64),
87+
next_state,
88+
)
89+
.unwrap();
90+
}
91+
}

0 commit comments

Comments
 (0)