Skip to content

Commit 3e34713

Browse files
committed
Merge branch 'release/v0.2.0' into main
2 parents 47e4be6 + f5a0e4c commit 3e34713

7 files changed

+49
-45
lines changed

CHANGELOG.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Changelog
2+
3+
## Unreleased Changes
4+
5+
## v0.2.0
6+
7+
Uses `rp2040_boot2` crate for the bootloader.
8+
9+
## v0.1.0
10+
11+
As released in the twitch.tv stream.
12+
13+

Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
[package]
22
name = "pico-blink-rs"
3-
version = "0.1.0"
3+
version = "0.2.0"
44
authors = ["Jonathan 'theJPster' Pallant <[email protected]>"]
55
edition = "2018"
6+
license = "CC0"
7+
description = "Basic blinky program for the Raspberry Pi Pico"
68

79
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
810

@@ -11,6 +13,7 @@ cortex-m = "0.7"
1113
cortex-m-rt = "0.6.13"
1214
rp2040-pac = { git = "https://github.com/rp-rs/rp2040-pac", branch="main" }
1315
panic-halt = "0.2.0"
16+
rp2040-boot2 = "0.1.0"
1417

1518
# this lets you use `cargo fix`!
1619
[[bin]]

README.md

+12-7
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ Running Rust code on the Raspberry Pi Pico
44

55
## Booting
66

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.
7+
The RP2040 has external QSPI flash. There is an internal mask-ROM bootloader which can read the first 256 bytes of
8+
external flash and copy it to the top of SRAM (`0x2004_1f00`). This 256 byte block is the 'second stage bootloader'.
9+
Its job is to reconfigure the XIP_SSI interface to the right values for the attached QSPI flash chip (the mask ROM has
10+
some very conservative defaults which should work with all chips), and configure the XIP so that the QSPI flash appears
11+
at address `0x1000_0000` upwards.
812

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). We emulate this by storing the second stage bootloader in a static array at the start of our application.
13+
The second stage bootloader then loads the user application once the XIP_SSI configuration is complete. It does this by
14+
reading a vector table at `0x1000_0100`, which is 256 bytes into the QSPI flash contents (or immediately after the 256
15+
byte second stage bootloader), and jumping to the reset vector.
1016

11-
The application needs to relocate the vector table using VTOR, then set the stack pointer
12-
and call the reset function manually. Rather than do that in Rust, currently we copy the first 256 bytes of the "blink" pico-sdk example, which does this for us. Yes, this is ugly. The bootloader should be trimmed back to 256 bytes and some Rust code written which sets up VTOR correctly. Or, we can ask Raspberry Pi Trading to change boot2 to expect a Vector Table at 0x100 instead of a function: see https://github.com/raspberrypi/pico-sdk/pull/10.
13-
14-
We should also write a BSP for the pico, and a HAL for the RP2040. Basically, don't do any of what I did here. But hey, it blinks!
17+
We should also write a BSP for the pico, and a HAL for the RP2040. Basically, don't do any of what I did here. But hey,
18+
it blinks!
1519

1620
## Licence
1721

18-
This work is licenced under CC0. The bootrom binaries are Copyright Raspberry Pi Trading and build from pico-sdk v1.0.0.
22+
This work is licenced under CC0. Binaries may include material Copyright Raspberry Pi Trading - see other crates for
23+
details.

memory.x

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ MEMORY
22
{
33
/* NOTE 1 K = 1 KiBi = 1024 bytes */
44
/* To suit Raspberry Pi RP2040 SoC */
5-
BOOT_LOADER : ORIGIN = 0x10000000, LENGTH = 512
6-
FLASH : ORIGIN = 0x10000200, LENGTH = 2048K - 512
5+
BOOT_LOADER : ORIGIN = 0x10000000, LENGTH = 0x100
6+
FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100
77
RAM : ORIGIN = 0x20000000, LENGTH = 256K
88
}
99

src/boot2.bin

-256 Bytes
Binary file not shown.

src/boot2_and_reset.bin

-512 Bytes
Binary file not shown.

src/main.rs

+18-35
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,17 @@
11
#![no_std]
22
#![no_main]
33

4-
use cortex_m_rt::{entry, pre_init};
4+
use cortex_m_rt::entry;
55
use panic_halt as _;
66

77
#[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().bits() != 0u32 {
17-
loop {
18-
cortex_m::asm::nop();
19-
}
20-
}
21-
}
8+
#[used]
9+
pub static BOOT_LOADER: [u8; 256] = rp2040_boot2::BOOT_LOADER;
2210

11+
/// Handle peripheral resets so the chip is usable.
2312
unsafe fn setup_chip(p: &mut rp2040_pac::Peripherals) {
2413
// Now reset all the peripherals, except QSPI and XIP (we're using those
2514
// to execute from external flash!)
26-
2715
p.RESETS.reset.write(|w| {
2816
w.adc().set_bit();
2917
w.busctrl().set_bit();
@@ -53,16 +41,6 @@ unsafe fn setup_chip(p: &mut rp2040_pac::Peripherals) {
5341
w
5442
});
5543

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-
6644
const RESETS_RESET_BITS: u32 = 0x01ffffff;
6745
const RESETS_RESET_USBCTRL_BITS: u32 = 0x01000000;
6846
const RESETS_RESET_UART1_BITS: u32 = 0x00800000;
@@ -72,6 +50,17 @@ unsafe fn setup_chip(p: &mut rp2040_pac::Peripherals) {
7250
const RESETS_RESET_RTC_BITS: u32 = 0x00008000;
7351
const RESETS_RESET_ADC_BITS: u32 = 0x00000001;
7452

53+
// We want to take everything out of reset, except these peripherals:
54+
//
55+
// * ADC
56+
// * RTC
57+
// * SPI0
58+
// * SPI1
59+
// * UART0
60+
// * UART1
61+
// * USBCTRL
62+
//
63+
// These must stay in reset until the clocks are sorted out.
7564
const PERIPHERALS_TO_UNRESET: u32 = RESETS_RESET_BITS
7665
& !(RESETS_RESET_ADC_BITS
7766
| RESETS_RESET_RTC_BITS
@@ -81,8 +70,8 @@ unsafe fn setup_chip(p: &mut rp2040_pac::Peripherals) {
8170
| RESETS_RESET_UART1_BITS
8271
| RESETS_RESET_USBCTRL_BITS);
8372

73+
// Write 0 to the reset field to take it out of reset
8474
p.RESETS.reset.modify(|_r, w| {
85-
// w.adc().clear_bit();
8675
w.busctrl().clear_bit();
8776
w.dma().clear_bit();
8877
w.i2c0().clear_bit();
@@ -97,16 +86,10 @@ unsafe fn setup_chip(p: &mut rp2040_pac::Peripherals) {
9786
w.pll_sys().clear_bit();
9887
w.pll_usb().clear_bit();
9988
w.pwm().clear_bit();
100-
// w.rtc().clear_bit();
101-
// w.spi0().clear_bit();
102-
// w.spi1().clear_bit();
10389
w.syscfg().clear_bit();
10490
w.sysinfo().clear_bit();
10591
w.tbman().clear_bit();
10692
w.timer().clear_bit();
107-
// w.uart0().clear_bit();
108-
// w.uart1().clear_bit();
109-
// w.usbctrl().clear_bit();
11093
w
11194
});
11295

@@ -156,7 +139,7 @@ fn main() -> ! {
156139
});
157140

158141
loop {
159-
for _i in 0..1000000 {
142+
for _i in 0..500000 {
160143
cortex_m::asm::nop();
161144
}
162145

@@ -166,7 +149,7 @@ fn main() -> ! {
166149
w
167150
});
168151

169-
for _i in 0..1000000 {
152+
for _i in 0..500000 {
170153
cortex_m::asm::nop();
171154
}
172155

0 commit comments

Comments
 (0)