Skip to content

Commit 5c66bb1

Browse files
committed
First version. It blinks!
0 parents  commit 5c66bb1

9 files changed

+302
-0
lines changed

.cargo/config

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
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 openocd.gdb"
5+
# runner = "gdb-multiarch -q -x openocd.gdb"
6+
# runner = "gdb -q -x openocd.gdb"
7+
8+
rustflags = [
9+
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
10+
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
11+
"-C", "link-arg=--nmagic",
12+
13+
# LLD (shipped with the Rust toolchain) is used as the default linker
14+
"-C", "link-arg=-Tlink.x",
15+
16+
# if you run into problems with LLD switch to the GNU linker by commenting out
17+
# this line
18+
# "-C", "linker=arm-none-eabi-ld",
19+
20+
# if you need to link to pre-compiled C libraries provided by a C toolchain
21+
# use GCC as the linker by commenting out both lines above and then
22+
# uncommenting the three lines below
23+
# "-C", "linker=arm-none-eabi-gcc",
24+
# "-C", "link-arg=-Wl,-Tlink.x",
25+
# "-C", "link-arg=-nostartfiles",
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)
34+
# target = "thumbv8m.base-none-eabi" # Cortex-M23
35+
# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU)
36+
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

Cargo.toml

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "pico-blink-rs"
3+
version = "0.1.0"
4+
authors = ["Jonathan 'theJPster' Pallant <[email protected]>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
cortex-m = "0.7"
11+
cortex-m-rt = "0.6.13"
12+
rp2040-pac = { path = "../rp2040-pac" }
13+
panic-halt = "0.2.0"
14+
15+
# this lets you use `cargo fix`!
16+
[[bin]]
17+
name = "pico-blink-rs"
18+
test = false
19+
bench = false
20+
21+
[profile.release]
22+
codegen-units = 1 # better optimizations
23+
debug = true # symbols are nice and they don't increase the size on Flash
24+
lto = true # better optimizations

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# pico-blink-rs
2+
3+
Running Rust code on the Raspberry Pi Pico
4+
5+
## Booting
6+
7+
The RP2040 has external QSPI flash. There is an internal mask-ROM bootloader which can read the first 256 bytes of external flash and copy it to the top of SRAM (`0x2004_1f00`). This 256 byte block is the 'second stage bootloader'. Its job is to reconfigure the XIP_SSI interface to the right values for the attached QSPI flash chip (the mask ROM has some very conservative defaults which should work with all chips), and configure the XIP so that the QSPI flash appears at address `0x1000_0000` upwards.
8+
9+
The second stage bootloader then loads the user application once the XIP_SSI configuration is complete. It does this by jumping to `0x1000_0100`, which is 256 bytes into the QSPI flash contents (or immediately after the 256 byte second stage bootloader).
10+
11+
## Licence
12+
13+
This work is licenced under CC0.

build.rs

+31
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+
}

memory.x

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
MEMORY
2+
{
3+
/* NOTE 1 K = 1 KiBi = 1024 bytes */
4+
/* To suit Raspberry Pi RP2040 SoC */
5+
BOOT_LOADER : ORIGIN = 0x10000000, LENGTH = 512
6+
FLASH : ORIGIN = 0x10000200, LENGTH = 2048K - 512
7+
RAM : ORIGIN = 0x20000000, LENGTH = 256K
8+
}
9+
10+
SECTIONS {
11+
12+
/* ### Boot loader */
13+
.boot_loader ORIGIN(BOOT_LOADER) :
14+
{
15+
KEEP(*(.boot_loader*));
16+
} > BOOT_LOADER
17+
18+
} INSERT BEFORE .text;

src/boot2.bin

256 Bytes
Binary file not shown.

src/boot2_and_reset.bin

512 Bytes
Binary file not shown.

src/main.rs

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#![no_std]
2+
#![no_main]
3+
4+
use cortex_m_rt::{entry, pre_init};
5+
use panic_halt as _;
6+
7+
#[link_section = ".boot_loader"]
8+
#[no_mangle]
9+
pub static BOOT_LOADER: [u8; 512] = *include_bytes!("boot2_and_reset.bin");
10+
11+
#[pre_init]
12+
unsafe fn pre_init() {
13+
let sio = &*rp2040_pac::SIO::ptr();
14+
15+
// If we are core 1, then stop dead and let core 0 do all the work.
16+
if sio.cpuid.read() != 0u32 {
17+
loop {
18+
cortex_m::asm::nop();
19+
}
20+
}
21+
}
22+
23+
unsafe fn setup_chip(p: &mut rp2040_pac::Peripherals) {
24+
// Now reset all the peripherals, except QSPI and XIP (we're using those
25+
// to execute from external flash!)
26+
27+
p.RESETS.reset.write(|w| {
28+
w.adc().set_bit();
29+
w.busctrl().set_bit();
30+
w.dma().set_bit();
31+
w.i2c0().set_bit();
32+
w.i2c1().set_bit();
33+
w.io_bank0().set_bit();
34+
w.io_qspi().clear_bit();
35+
w.jtag().set_bit();
36+
w.pads_bank0().set_bit();
37+
w.pads_qspi().clear_bit();
38+
w.pio0().set_bit();
39+
w.pio1().set_bit();
40+
w.pll_sys().clear_bit();
41+
w.pll_usb().clear_bit();
42+
w.pwm().set_bit();
43+
w.rtc().set_bit();
44+
w.spi0().set_bit();
45+
w.spi1().set_bit();
46+
w.syscfg().set_bit();
47+
w.sysinfo().set_bit();
48+
w.tbman().set_bit();
49+
w.timer().set_bit();
50+
w.uart0().set_bit();
51+
w.uart1().set_bit();
52+
w.usbctrl().set_bit();
53+
w
54+
});
55+
56+
// unreset_block_wait(RESETS_RESET_BITS /* 01ff_ffff */ & ~(
57+
// RESETS_RESET_ADC_BITS |
58+
// RESETS_RESET_RTC_BITS |
59+
// RESETS_RESET_SPI0_BITS |
60+
// RESETS_RESET_SPI1_BITS |
61+
// RESETS_RESET_UART0_BITS |
62+
// RESETS_RESET_UART1_BITS |
63+
// RESETS_RESET_USBCTRL_BITS
64+
// ));
65+
66+
const RESETS_RESET_BITS: u32 = 0x01ffffff;
67+
const RESETS_RESET_USBCTRL_BITS: u32 = 0x01000000;
68+
const RESETS_RESET_UART1_BITS: u32 = 0x00800000;
69+
const RESETS_RESET_UART0_BITS: u32 = 0x00400000;
70+
const RESETS_RESET_SPI1_BITS: u32 = 0x00020000;
71+
const RESETS_RESET_SPI0_BITS: u32 = 0x00010000;
72+
const RESETS_RESET_RTC_BITS: u32 = 0x00008000;
73+
const RESETS_RESET_ADC_BITS: u32 = 0x00000001;
74+
75+
const PERIPHERALS_TO_UNRESET: u32 = RESETS_RESET_BITS
76+
& !(RESETS_RESET_ADC_BITS
77+
| RESETS_RESET_RTC_BITS
78+
| RESETS_RESET_SPI0_BITS
79+
| RESETS_RESET_SPI1_BITS
80+
| RESETS_RESET_UART0_BITS
81+
| RESETS_RESET_UART1_BITS
82+
| RESETS_RESET_USBCTRL_BITS);
83+
84+
p.RESETS.reset.modify(|_r, w| {
85+
// w.adc().clear_bit();
86+
w.busctrl().clear_bit();
87+
w.dma().clear_bit();
88+
w.i2c0().clear_bit();
89+
w.i2c1().clear_bit();
90+
w.io_bank0().clear_bit();
91+
w.io_qspi().clear_bit();
92+
w.jtag().clear_bit();
93+
w.pads_bank0().clear_bit();
94+
w.pads_qspi().clear_bit();
95+
w.pio0().clear_bit();
96+
w.pio1().clear_bit();
97+
w.pll_sys().clear_bit();
98+
w.pll_usb().clear_bit();
99+
w.pwm().clear_bit();
100+
// w.rtc().clear_bit();
101+
// w.spi0().clear_bit();
102+
// w.spi1().clear_bit();
103+
w.syscfg().clear_bit();
104+
w.sysinfo().clear_bit();
105+
w.tbman().clear_bit();
106+
w.timer().clear_bit();
107+
// w.uart0().clear_bit();
108+
// w.uart1().clear_bit();
109+
// w.usbctrl().clear_bit();
110+
w
111+
});
112+
113+
while (!p.RESETS.reset_done.read().bits() & PERIPHERALS_TO_UNRESET) != 0 {
114+
cortex_m::asm::nop();
115+
}
116+
}
117+
118+
#[entry]
119+
fn main() -> ! {
120+
let mut p = rp2040_pac::Peripherals::take().unwrap();
121+
122+
unsafe {
123+
setup_chip(&mut p);
124+
}
125+
126+
// Set GPIO25 to be an input (output enable is cleared)
127+
p.SIO.gpio_oe_clr.write(|w| unsafe {
128+
w.bits(1 << 25);
129+
w
130+
});
131+
132+
// Set GPIO25 to be an output low (output is cleared)
133+
p.SIO.gpio_out_clr.write(|w| unsafe {
134+
w.bits(1 << 25);
135+
w
136+
});
137+
138+
// Configure pin 25 for GPIO
139+
p.PADS_BANK0.gpio25.write(|w| {
140+
// Output Disable off
141+
w.od().clear_bit();
142+
// Input Enable on
143+
w.ie().set_bit();
144+
w
145+
});
146+
p.IO_BANK0.gpio25_ctrl.write(|w| {
147+
// Map pin 25 to SIO
148+
w.funcsel().sio_25();
149+
w
150+
});
151+
152+
// Set GPIO25 to be an output (output enable is set)
153+
p.SIO.gpio_oe_set.write(|w| unsafe {
154+
w.bits(1 << 25);
155+
w
156+
});
157+
158+
loop {
159+
for _i in 0..1000000 {
160+
cortex_m::asm::nop();
161+
}
162+
163+
// Set GPIO25 to be low
164+
p.SIO.gpio_out_clr.write(|w| unsafe {
165+
w.bits(1 << 25);
166+
w
167+
});
168+
169+
for _i in 0..1000000 {
170+
cortex_m::asm::nop();
171+
}
172+
173+
// Set GPIO25 to be high
174+
p.SIO.gpio_out_set.write(|w| unsafe {
175+
w.bits(1 << 25);
176+
w
177+
});
178+
}
179+
}

0 commit comments

Comments
 (0)