├── .cargo └── config ├── .gitignore ├── .vscode └── settings.json ├── CODE_OF_CONDUCT.md ├── Cargo.toml ├── README.md ├── build.rs ├── memory.x ├── probe-run.sh └── src ├── main.rs ├── pll.rs └── resets.rs /.cargo/config: -------------------------------------------------------------------------------- 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] 2 | #runner = "./probe-run.sh" 3 | runner = "probe-run-rp --chip RP2040" 4 | 5 | rustflags = [ 6 | "-C", "link-arg=--nmagic", 7 | "-C", "link-arg=-Tlink.x", 8 | "-C", "link-arg=-Tdefmt.x", 9 | 10 | # Code-size optimizations. 11 | "-Z", "trap-unreachable=no", 12 | "-C", "inline-threshold=5", 13 | "-C", "no-vectorize-loops", 14 | ] 15 | 16 | [build] 17 | # Pick ONE of these compilation targets 18 | target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+ 19 | # target = "thumbv7m-none-eabi" # Cortex-M3 20 | # target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU) 21 | # target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU) 22 | # target = "thumbv8m.base-none-eabi" # Cortex-M23 23 | # target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU) 24 | # target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU) 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/*.rs.bk 2 | .#* 3 | .gdb_history 4 | Cargo.lock 5 | target/ 6 | 7 | # editor files 8 | .vscode/* 9 | !.vscode/*.md 10 | !.vscode/*.svd 11 | !.vscode/launch.json 12 | !.vscode/tasks.json 13 | !.vscode/extensions.json 14 | !.vscode/settings.json -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true 3 | } -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Contribution to these projects is organized under the terms of the [Rust Code of Conduct](https://www.rust-lang.org/policies/code-of-conduct) 2 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Dario Nieuwenhuis "] 3 | edition = "2018" 4 | readme = "README.md" 5 | name = "rp-test" 6 | version = "0.1.0" 7 | 8 | [dependencies] 9 | cortex-m = { version = "0.7.1", features = ["inline-asm"] } 10 | cortex-m-rt = "0.6.10" 11 | 12 | defmt = "0.1.3" 13 | defmt-rtt = "0.1.0" 14 | panic-probe = "0.1.0" 15 | 16 | rp2040-pac = { git = "https://github.com/rp-rs/rp2040-pac", branch="main" } 17 | rp2040-boot2 = { git = "https://github.com/rp-rs/rp2040-boot2-rs", branch="main" } 18 | #rp2040-pac = { path = "../rp2040-pac" } 19 | #rp2040-boot2 = { path = "../rp2040-boot2-rs" } 20 | 21 | [patch.crates-io] 22 | cortex-m = { git = "https://github.com/rust-embedded/cortex-m" } 23 | 24 | [features] 25 | default = [ 26 | "defmt-default", 27 | ] 28 | defmt-default = [] 29 | defmt-trace = [] 30 | defmt-debug = [] 31 | defmt-info = [] 32 | defmt-warn = [] 33 | defmt-error = [] 34 | 35 | 36 | # this lets you use `cargo fix`! 37 | [[bin]] 38 | name = "rp-test" 39 | test = false 40 | bench = false 41 | 42 | [profile.dev] 43 | codegen-units = 1 44 | debug = 2 45 | debug-assertions = true 46 | incremental = false 47 | opt-level = 3 48 | overflow-checks = true 49 | 50 | [profile.release] 51 | codegen-units = 1 52 | debug = 2 53 | debug-assertions = false 54 | incremental = false 55 | lto = "fat" 56 | opt-level = 's' 57 | overflow-checks = false 58 | 59 | # do not optimize proc-macro crates = faster builds from scratch 60 | [profile.dev.build-override] 61 | codegen-units = 8 62 | debug = false 63 | debug-assertions = false 64 | opt-level = 0 65 | overflow-checks = false 66 | 67 | [profile.release.build-override] 68 | codegen-units = 8 69 | debug = false 70 | debug-assertions = false 71 | opt-level = 0 72 | overflow-checks = false 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raspberry pico RP2040 rust test! 2 | 3 | # Notice: this project has been deprecated. Please use https://github.com/rp-rs/rp2040-project-template 4 | 5 | ## Requirements 6 | 7 | - Recent nightly Rust 8 | - `probe-run-rp` installed. 9 | - A CMSIS-DAP probe. (JLink probes sort of work but are very unstable. Other probes won't work at all) 10 | 11 | `probe-run-rp` is a version of `probe-run` using a `probe-rs` fork with support for the RP2040 chip. To install it use the following command. 12 | 13 | cargo install --git https://github.com/rp-rs/probe-run --branch main 14 | 15 | Note that this installs the binary with name `probe-run-rp`, so you can still have the original `probe-run` installed in parallel. This is important because `probe-run-rp` ONLY works with the RP2040 chip. 16 | 17 | 18 | ## Running 19 | 20 | Just do `cargo run` :) 21 | 22 | ## License 23 | 24 | This project is licensed under either of 25 | 26 | - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or 27 | http://www.apache.org/licenses/LICENSE-2.0) 28 | 29 | - MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 30 | 31 | at your option. 32 | -------------------------------------------------------------------------------- /build.rs: -------------------------------------------------------------------------------- 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 | } 32 | -------------------------------------------------------------------------------- /memory.x: -------------------------------------------------------------------------------- 1 | MEMORY { 2 | BOOT2 : ORIGIN = 0x10000000, LENGTH = 0x100 3 | FLASH : ORIGIN = 0x10000100, LENGTH = 2048K - 0x100 4 | RAM : ORIGIN = 0x20000000, LENGTH = 256K 5 | } 6 | 7 | SECTIONS { 8 | /* ### Boot loader */ 9 | .boot2 ORIGIN(BOOT2) : 10 | { 11 | KEEP(*(.boot2)); 12 | } > BOOT2 13 | } INSERT BEFORE .text; -------------------------------------------------------------------------------- /probe-run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | bin="$PWD/$1" 4 | shift 5 | 6 | cd ../probe-run 7 | cargo run -- "$bin" "$@" --chip RP2040 8 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | #![feature(asm)] 4 | 5 | use core::sync::atomic::{AtomicUsize, Ordering}; 6 | use cortex_m_rt::entry; 7 | use defmt::*; 8 | use defmt_rtt as _; 9 | use pac::{watchdog, xosc}; 10 | use panic_probe as _; 11 | use rp2040_pac as pac; 12 | 13 | mod pll; 14 | mod resets; 15 | 16 | #[link_section = ".boot2"] 17 | #[used] 18 | pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; 19 | 20 | #[defmt::timestamp] 21 | fn timestamp() -> u64 { 22 | static COUNT: AtomicUsize = AtomicUsize::new(0); 23 | // NOTE(no-CAS) `timestamps` runs with interrupts disabled 24 | let n = COUNT.load(Ordering::Relaxed); 25 | COUNT.store(n + 1, Ordering::Relaxed); 26 | n as u64 27 | } 28 | 29 | fn init( 30 | resets: pac::RESETS, 31 | watchdog: pac::WATCHDOG, 32 | clocks: pac::CLOCKS, 33 | xosc: pac::XOSC, 34 | pll_sys: pac::PLL_SYS, 35 | pll_usb: pac::PLL_USB, 36 | ) { 37 | // Now reset all the peripherals, except QSPI and XIP (we're using those 38 | // to execute from external flash!) 39 | 40 | let resets = resets::Resets::new(resets); 41 | 42 | // Reset everything except: 43 | // - QSPI (we're using it to run this code!) 44 | // - PLLs (it may be suicide if that's what's clocking us) 45 | resets.reset(!(resets::IO_QSPI | resets::PADS_QSPI | resets::PLL_SYS | resets::PLL_USB)); 46 | 47 | resets.unreset_wait( 48 | resets::ALL 49 | & !(resets::ADC 50 | | resets::RTC 51 | | resets::SPI0 52 | | resets::SPI1 53 | | resets::UART0 54 | | resets::UART1 55 | | resets::USBCTRL), 56 | ); 57 | 58 | // xosc 12 mhz 59 | watchdog 60 | .tick 61 | .write(|w| unsafe { w.cycles().bits(XOSC_MHZ as u16).enable().set_bit() }); 62 | 63 | clocks.clk_sys_resus_ctrl.write(|w| unsafe { w.bits(0) }); 64 | 65 | // Enable XOSC 66 | // TODO extract to HAL module 67 | const XOSC_MHZ: u32 = 12; 68 | xosc.ctrl.write(|w| w.freq_range()._1_15mhz()); 69 | let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256; 70 | xosc.startup 71 | .write(|w| unsafe { w.delay().bits(startup_delay as u16) }); 72 | xosc.ctrl 73 | .write(|w| w.freq_range()._1_15mhz().enable().enable()); 74 | while !xosc.status.read().stable().bit_is_set() {} 75 | 76 | // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. 77 | clocks.clk_sys_ctrl.modify(|_, w| w.src().clk_ref()); 78 | while clocks.clk_sys_selected.read().bits() != 1 {} 79 | clocks.clk_ref_ctrl.modify(|_, w| w.src().rosc_clksrc_ph()); 80 | while clocks.clk_ref_selected.read().bits() != 1 {} 81 | 82 | resets.reset(resets::PLL_SYS | resets::PLL_USB); 83 | resets.unreset_wait(resets::PLL_SYS | resets::PLL_USB); 84 | 85 | pll::PLL::new(pll_sys).configure(1, 1500_000_000, 6, 2); 86 | pll::PLL::new(pll_usb).configure(1, 480_000_000, 5, 2); 87 | } 88 | 89 | #[entry] 90 | fn main() -> ! { 91 | info!("Hello World!"); 92 | 93 | let p = pac::Peripherals::take().unwrap(); 94 | 95 | init(p.RESETS, p.WATCHDOG, p.CLOCKS, p.XOSC, p.PLL_SYS, p.PLL_USB); 96 | 97 | let led_pin = 25; 98 | 99 | loop { 100 | info!("on!"); 101 | p.IO_BANK0.gpio[led_pin].gpio_ctrl.write(|w| { 102 | w.oeover().enable(); 103 | w.outover().high(); 104 | w 105 | }); 106 | 107 | cortex_m::asm::delay(1_000_000); 108 | 109 | info!("off!"); 110 | p.IO_BANK0.gpio[led_pin].gpio_ctrl.write(|w| { 111 | w.oeover().enable(); 112 | w.outover().low(); 113 | w 114 | }); 115 | 116 | cortex_m::asm::delay(1_000_000); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/pll.rs: -------------------------------------------------------------------------------- 1 | use core::ops::Deref; 2 | use defmt::{assert, *}; 3 | 4 | use rp2040_pac as pac; 5 | 6 | const XOSC_MHZ: u32 = 12; 7 | 8 | pub struct PLL { 9 | inner: T, 10 | } 11 | 12 | impl PLL { 13 | pub fn new(inner: T) -> Self { 14 | Self { inner } 15 | } 16 | 17 | pub fn configure(&mut self, refdiv: u32, vco_freq: u32, post_div1: u8, post_div2: u8) { 18 | let p = &self.inner; 19 | 20 | // Power off in case it's already running 21 | p.pwr.reset(); 22 | p.fbdiv_int.reset(); 23 | 24 | let ref_mhz = XOSC_MHZ / refdiv; 25 | p.cs.write(|w| unsafe { w.bits(ref_mhz as _) }); 26 | 27 | let fbdiv = vco_freq / (ref_mhz * 1_000_000); 28 | assert!(fbdiv >= 16 && fbdiv <= 520); 29 | assert!((post_div1 >= 1 && post_div1 <= 7) && (post_div2 >= 1 && post_div2 <= 7)); 30 | assert!(post_div2 <= post_div1); 31 | assert!(ref_mhz <= (vco_freq / 16)); 32 | 33 | p.fbdiv_int.write(|w| unsafe { w.bits(fbdiv) }); 34 | 35 | p.pwr.modify(|_, w| w.pd().clear_bit().vcopd().clear_bit()); 36 | 37 | while !p.cs.read().lock().bits() {} 38 | 39 | p.prim.write(|w| unsafe { 40 | w.postdiv1().bits(post_div1); 41 | w.postdiv2().bits(post_div2); 42 | w 43 | }); 44 | 45 | p.pwr.modify(|_, w| w.postdivpd().clear_bit()); 46 | } 47 | } 48 | 49 | mod sealed { 50 | use rp2040_pac as pac; 51 | 52 | pub trait Instance {} 53 | impl Instance for pac::PLL_SYS {} 54 | impl Instance for pac::PLL_USB {} 55 | } 56 | 57 | pub trait Instance: Deref {} 58 | impl Instance for pac::PLL_SYS {} 59 | impl Instance for pac::PLL_USB {} 60 | -------------------------------------------------------------------------------- /src/resets.rs: -------------------------------------------------------------------------------- 1 | use rp2040_pac as pac; 2 | 3 | pub const ALL: u32 = 0x01ffffff; 4 | pub const USBCTRL: u32 = 0x01000000; 5 | pub const UART1: u32 = 0x00800000; 6 | pub const UART0: u32 = 0x00400000; 7 | pub const TIMER: u32 = 0x00200000; 8 | pub const TBMAN: u32 = 0x00100000; 9 | pub const SYSINFO: u32 = 0x00080000; 10 | pub const SYSCFG: u32 = 0x00040000; 11 | pub const SPI1: u32 = 0x00020000; 12 | pub const SPI0: u32 = 0x00010000; 13 | pub const RTC: u32 = 0x00008000; 14 | pub const PWM: u32 = 0x00004000; 15 | pub const PLL_USB: u32 = 0x00002000; 16 | pub const PLL_SYS: u32 = 0x00001000; 17 | pub const PIO1: u32 = 0x00000800; 18 | pub const PIO0: u32 = 0x00000400; 19 | pub const PADS_QSPI: u32 = 0x00000200; 20 | pub const PADS_BANK0: u32 = 0x00000100; 21 | pub const JTAG: u32 = 0x00000080; 22 | pub const IO_QSPI: u32 = 0x00000040; 23 | pub const IO_BANK0: u32 = 0x00000020; 24 | pub const I2C1: u32 = 0x00000010; 25 | pub const I2C0: u32 = 0x00000008; 26 | pub const DMA: u32 = 0x00000004; 27 | pub const BUSCTRL: u32 = 0x00000002; 28 | pub const ADC: u32 = 0x00000001; 29 | 30 | pub struct Resets { 31 | inner: pac::RESETS, 32 | } 33 | 34 | impl Resets { 35 | pub fn new(inner: pac::RESETS) -> Self { 36 | Self { inner } 37 | } 38 | 39 | pub fn reset(&self, bits: u32) { 40 | self.inner.reset.write(|w| unsafe { w.bits(bits) }) 41 | } 42 | 43 | pub fn unreset_wait(&self, bits: u32) { 44 | // TODO use the "atomic clear" register version 45 | self.inner 46 | .reset 47 | .modify(|r, w| unsafe { w.bits(r.bits() & !bits) }); 48 | while ((!self.inner.reset_done.read().bits()) & bits) != 0 {} 49 | } 50 | } 51 | --------------------------------------------------------------------------------