Skip to content

Commit 4c59abf

Browse files
committed
rp2040 local resource example for rtic v2
1 parent 47b2774 commit 4c59abf

File tree

5 files changed

+227
-0
lines changed

5 files changed

+227
-0
lines changed
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
[package]
2+
name = "rp2040_local_i2c_init"
3+
categories = ["embedded", "no-std"]
4+
description = "Example task local initialized resources for Raspberry Pi Pico"
5+
license = "MIT OR Apache-2.0"
6+
version = "0.1.0"
7+
edition = "2021"
8+
9+
[dependencies]
10+
cortex-m = "0.7"
11+
rtic = { git = "https://github.com/rtic-rs/rtic", features = ["thumbv6-backend"] }
12+
rtic-monotonics = { git = "https://github.com/rtic-rs/rtic", features = ["cortex-m-systick", "rp2040"] }
13+
embedded-hal = { version = "0.2.7", features = ["unproven"] }
14+
fugit = "0.3"
15+
rp-pico = "0.7.0"
16+
panic-probe = "0.3"
17+
18+
[profile.dev]
19+
opt-level = 1
20+
codegen-units = 16
21+
debug = true
22+
lto = false
23+
24+
[profile.release]
25+
opt-level = "s" # optimize for size
26+
codegen-units = 1 # better optimizations
27+
debug = true # symbols are nice and they don't increase the size on Flash
28+
lto = true # better optimzations
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[default.probe]
2+
protocol = "Swd"
3+
speed = 20000
4+
# If you only have one probe cargo embed will pick automatically
5+
# Otherwise: add your probe's VID/PID/serial to filter
6+
7+
## rust-dap
8+
# usb_vid = "6666"
9+
# usb_pid = "4444"
10+
# serial = "test"
11+
12+
13+
[default.flashing]
14+
enabled = true
15+
16+
[default.reset]
17+
enabled = true
18+
halt_afterwards = false
19+
20+
[default.general]
21+
chip = "RP2040"
22+
log_level = "WARN"
23+
# RP2040 does not support connect_under_reset
24+
connect_under_reset = false
25+
26+
[default.rtt]
27+
enabled = true
28+
up_mode = "NoBlockSkip"
29+
channels = [
30+
{ up = 0, down = 0, name = "name", up_mode = "NoBlockSkip", format = "Defmt" },
31+
]
32+
timeout = 3000
33+
show_timestamps = true
34+
log_enabled = false
35+
log_path = "./logs"
36+
37+
[default.gdb]
38+
enabled = true
39+
gdb_connection_string = "127.0.0.1:2345"
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//! This build script copies the `memory.x` file from the crate root into
2+
//! a directory where the linker can always find it at build time.
3+
//! For many projects this is optional, as the linker always searches the
4+
//! project root directory -- wherever `Cargo.toml` is. However, if you
5+
//! are using a workspace or have a more complicated build setup, this
6+
//! build script becomes required. Additionally, by requesting that
7+
//! Cargo re-run the build script whenever `memory.x` is changed,
8+
//! updating `memory.x` ensures a rebuild of the application with the
9+
//! new memory settings.
10+
11+
use std::env;
12+
use std::fs::File;
13+
use std::io::Write;
14+
use std::path::PathBuf;
15+
16+
fn main() {
17+
// Put `memory.x` in our output directory and ensure it's
18+
// on the linker search path.
19+
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
20+
File::create(out.join("memory.x"))
21+
.unwrap()
22+
.write_all(include_bytes!("memory.x"))
23+
.unwrap();
24+
println!("cargo:rustc-link-search={}", out.display());
25+
26+
// By default, Cargo will re-run a build script whenever
27+
// any file in the project changes. By specifying `memory.x`
28+
// here, we ensure the build script is only re-run when
29+
// `memory.x` is changed.
30+
println!("cargo:rerun-if-changed=memory.x");
31+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
MEMORY {
2+
BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100
3+
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
4+
RAM : ORIGIN = 0x20000000, LENGTH = 256K
5+
}
6+
7+
EXTERN(BOOT2_FIRMWARE)
8+
9+
SECTIONS {
10+
/* ### Boot loader */
11+
.boot2 ORIGIN(BOOT2) :
12+
{
13+
KEEP(*(.boot2));
14+
} > BOOT2
15+
} INSERT BEFORE .text;
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#![no_std]
2+
#![no_main]
3+
#![feature(type_alias_impl_trait)]
4+
5+
#[rtic::app(
6+
device = rp_pico::hal::pac,
7+
dispatchers = [TIMER_IRQ_1]
8+
)]
9+
mod app {
10+
use rp_pico::hal::{
11+
clocks, gpio,
12+
gpio::pin::bank0::{Gpio2, Gpio25, Gpio3},
13+
gpio::pin::PushPullOutput,
14+
pac,
15+
sio::Sio,
16+
watchdog::Watchdog,
17+
I2C,
18+
};
19+
use rp_pico::XOSC_CRYSTAL_FREQ;
20+
21+
use core::mem::MaybeUninit;
22+
use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
23+
use fugit::RateExtU32;
24+
use rtic_monotonics::systick::*;
25+
26+
use panic_probe as _;
27+
28+
rtic_monotonics::make_systick_handler!();
29+
30+
type I2CBus = I2C<
31+
pac::I2C1,
32+
(
33+
gpio::Pin<Gpio2, gpio::FunctionI2C>,
34+
gpio::Pin<Gpio3, gpio::FunctionI2C>,
35+
),
36+
>;
37+
38+
#[shared]
39+
struct Shared {}
40+
41+
#[local]
42+
struct Local {
43+
led: gpio::Pin<Gpio25, PushPullOutput>,
44+
i2c: &'static mut I2CBus,
45+
}
46+
47+
#[init(local=[
48+
// Task local initialized resources are static
49+
// Here we use MaybeUninit to allow for initialization in init()
50+
// This enables its usage in driver initialization
51+
i2c_ctx: MaybeUninit<I2CBus> = MaybeUninit::uninit()
52+
])]
53+
fn init(mut ctx: init::Context) -> (Shared, Local) {
54+
// Configure the clocks, watchdog - The default is to generate a 125 MHz system clock
55+
Systick::start(ctx.core.SYST, 125_000_000); // default rp2040 clock-rate is 125MHz
56+
let mut watchdog = Watchdog::new(ctx.device.WATCHDOG);
57+
let clocks = clocks::init_clocks_and_plls(
58+
XOSC_CRYSTAL_FREQ,
59+
ctx.device.XOSC,
60+
ctx.device.CLOCKS,
61+
ctx.device.PLL_SYS,
62+
ctx.device.PLL_USB,
63+
&mut ctx.device.RESETS,
64+
&mut watchdog,
65+
)
66+
.ok()
67+
.unwrap();
68+
69+
// Init LED pin
70+
let sio = Sio::new(ctx.device.SIO);
71+
let gpioa = rp_pico::Pins::new(
72+
ctx.device.IO_BANK0,
73+
ctx.device.PADS_BANK0,
74+
sio.gpio_bank0,
75+
&mut ctx.device.RESETS,
76+
);
77+
let mut led = gpioa.led.into_push_pull_output();
78+
led.set_low().unwrap();
79+
80+
// Init I2C pins
81+
let sda_pin = gpioa.gpio2.into_mode::<gpio::FunctionI2C>();
82+
let scl_pin = gpioa.gpio3.into_mode::<gpio::FunctionI2C>();
83+
84+
// Init I2C itself, using MaybeUninit to overwrite the previously
85+
// uninitialized i2c_ctx variable without dropping its value
86+
// (i2c_ctx definined in init local resources above)
87+
let i2c_tmp: &'static mut _ = ctx.local.i2c_ctx.write(I2C::i2c1(
88+
ctx.device.I2C1,
89+
sda_pin,
90+
scl_pin,
91+
100.kHz(),
92+
&mut ctx.device.RESETS,
93+
&clocks.system_clock,
94+
));
95+
96+
// Spawn heartbeat task
97+
heartbeat::spawn().ok();
98+
99+
// Return resources and timer
100+
(Shared {}, Local { led, i2c: i2c_tmp })
101+
}
102+
103+
#[task(local = [i2c, led])]
104+
async fn heartbeat(ctx: heartbeat::Context) {
105+
// Flicker the built-in LED
106+
_ = ctx.local.led.toggle();
107+
108+
// Congrats, you can use your i2c and have access to it here,
109+
// now to do something with it!
110+
111+
// Re-spawn this task after 1 second
112+
Systick::delay(1000.millis()).await;
113+
}
114+
}

0 commit comments

Comments
 (0)