├── img ├── Raspberry_Pi_Pico_pinout.png └── Raspberry_Pico_Reset_Button_small.png ├── memory.x ├── config.toml ├── src ├── fmt.rs └── main.rs ├── debug_probes.md ├── Cargo.toml └── README.md /img/Raspberry_Pi_Pico_pinout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaocarvalhoopen/Raspberry_Pi_Pico_in_Rust__Proj_Template_with_RTIC_USB-Serial_UF2/HEAD/img/Raspberry_Pi_Pico_pinout.png -------------------------------------------------------------------------------- /img/Raspberry_Pico_Reset_Button_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/joaocarvalhoopen/Raspberry_Pi_Pico_in_Rust__Proj_Template_with_RTIC_USB-Serial_UF2/HEAD/img/Raspberry_Pico_Reset_Button_small.png -------------------------------------------------------------------------------- /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 | EXTERN(BOOT2_FIRMWARE) 8 | 9 | SECTIONS { 10 | /* ### Boot loader */ 11 | .boot2 ORIGIN(BOOT2) : 12 | { 13 | KEEP(*(.boot2)); 14 | } > BOOT2 15 | } INSERT BEFORE .text; -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | # Choose a default "cargo run" tool. 2 | # probe-run is recommended if you have a debugger 3 | # elf2uf2-rs loads firmware over USB when the rp2040 is in boot mode 4 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] 5 | # runner = "probe-run --chip RP2040" 6 | runner = "elf2uf2-rs -d" 7 | 8 | rustflags = [ 9 | "-C", "linker=flip-link", 10 | "-C", "link-arg=--nmagic", 11 | "-C", "link-arg=-Tlink.x", 12 | "-C", "link-arg=-Tdefmt.x", 13 | 14 | # Code-size optimizations. 15 | # trap unreachable can save a lot of space, but requires nightly compiler. 16 | # uncomment the next line if you wish to enable it 17 | # "-Z", "trap-unreachable=no", 18 | "-C", "inline-threshold=5", 19 | "-C", "no-vectorize-loops", 20 | ] 21 | 22 | [build] 23 | target = "thumbv6m-none-eabi" 24 | 25 | [env] 26 | DEFMT_LOG = "debug" 27 | -------------------------------------------------------------------------------- /src/fmt.rs: -------------------------------------------------------------------------------- 1 | // NOTE: This file came from: 2 | // https://github.com/Nashenas88/dactyl-manuform-kb2040-rs/blob/main/src/fmt.rs 3 | 4 | //! Formatting module for helping with logging over a serial connection. This 5 | //! is useful on the kb2040 since there are no debugging pins exposed on the 6 | //! board. 7 | 8 | use core::fmt; 9 | 10 | pub(crate) struct Wrapper<'a> { 11 | buf: &'a mut [u8], 12 | offset: usize, 13 | } 14 | 15 | impl<'a> Wrapper<'a> { 16 | pub(crate) fn new(buf: &'a mut [u8]) -> Self { 17 | Wrapper { buf, offset: 0 } 18 | } 19 | } 20 | 21 | impl<'a> fmt::Write for Wrapper<'a> { 22 | fn write_str(&mut self, s: &str) -> fmt::Result { 23 | let bytes = s.as_bytes(); 24 | 25 | // Skip over already-copied data. 26 | let remainder = &mut self.buf[self.offset..]; 27 | // Check if there is space remaining (return error instead of panicking). 28 | if remainder.len() < bytes.len() { 29 | return Err(core::fmt::Error); 30 | } 31 | 32 | // Make the two slices the same length. 33 | let remainder = &mut remainder[..bytes.len()]; 34 | // Copy. 35 | remainder.copy_from_slice(bytes); 36 | 37 | // Update offset to avoid overwriting. 38 | self.offset += bytes.len(); 39 | 40 | Ok(()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /debug_probes.md: -------------------------------------------------------------------------------- 1 | # Compatible CMSIS-DAP debug probes 2 | 3 | ## Raspberry Pi Pico 4 | 5 | You can use a second Pico as your debugger. 6 | 7 | - Download this file: https://github.com/majbthrd/DapperMime/releases/download/20210225/raspberry_pi_pico-DapperMime.uf2 8 | - Boot the Pico in bootloader mode by holding the bootset button while plugging it in 9 | - Open the drive RPI-RP2 when prompted 10 | - Copy raspberry_pi_pico-DapperMime.uf2 from Downloads into RPI-RP2 11 | - Connect the debug pins of your CMSIS-DAP Pico to the target one 12 | - Connect GP2 on the Probe to SWCLK on the Target 13 | - Connect GP3 on the Probe to SWDIO on the Target 14 | - Connect a ground line from the CMSIS-DAP Probe to the Target too 15 | 16 | ## WeAct MiniF4 17 | https://therealprof.github.io/blog/usb-c-pill-part1/ 18 | 19 | ## HS-Probe 20 | https://github.com/probe-rs/hs-probe 21 | 22 | ## ST-LINK v2 clone 23 | It's getting harder to source these with stm32f103's as time goes on, so you might be better off choosing a stm32f103 dev board 24 | 25 | Firmware: https://github.com/devanlai/dap42 26 | 27 | ## LPC-Link2 28 | https://www.nxp.com/design/microcontrollers-developer-resources/lpc-link2:OM13054 29 | 30 | ## MCU-Link 31 | https://www.nxp.com/part/MCU-LINK#/ 32 | 33 | ## DAPLink 34 | You can use DAPLink firmware with any of it's supported chips (LPC4322, LPC11U35, K20, K22, KL26). You'll need to use the 'develop' branch to use GCC to build it. You'll need to find a chip with the correct 35 | 36 | Firmware source: https://github.com/ARMmbed/DAPLink/tree/develop 37 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | authors = ["Several and Joao carvalho"] 3 | edition = "2018" 4 | readme = "README.md" 5 | name = "rp2040-project-template" 6 | version = "0.1.0" 7 | resolver = "2" 8 | 9 | [dependencies] 10 | cortex-m = "0.7.3" 11 | cortex-m-rt = "0.7.0" 12 | embedded-hal = { version = "0.2.5", features=["unproven"] } 13 | embedded-time = "0.12.0" 14 | 15 | # jnc 16 | usb-device = "0.2.8" 17 | usbd-serial = "0.1.1" 18 | usbd-hid = "0.5.1" 19 | futures = { version = "0.3", default-features = false, optional = true } 20 | 21 | # jnc commnet pico-probe 22 | defmt = "0.3.0" 23 | defmt-rtt = "0.3.1" 24 | panic-probe = { version = "0.3.0", features = ["print-defmt"] } 25 | 26 | # We're using a Pico by default on this template 27 | rp-pico = "0.2.0" 28 | 29 | # but you can use any BSP. Uncomment this to use the pro_micro_rp2040 BSP instead 30 | # sparkfun-pro-micro-rp2040 = "0.1.0" 31 | 32 | # If you're not going to use a Board Support Package you'll need these: 33 | rp2040-hal = { version="0.3.0", features=["rt"] } 34 | # rp2040-hal = { path = "../rp-hal-main/rp2040-hal", version = "0.4.0" } 35 | 36 | rp2040-boot2 = {version="0.2.0", optional = true } 37 | 38 | 39 | # [dev-dependencies] 40 | panic-halt= "0.2.0" 41 | # embedded-hal ="0.2.5" 42 | # cortex-m-rtic = "0.6.0-rc.4" 43 | # nb = "1.0" 44 | # heapless = "0.7.9" 45 | 46 | # jnc commented for test pico-probe 47 | # defmt = "0.3.0" 48 | # defmt-rtt = "0.3.0" 49 | 50 | 51 | # cortex-m-rtic = "0.6.0-rc.4" 52 | cortex-m-rtic = "1.0.0" 53 | 54 | # static-box = "0.2.0" 55 | 56 | 57 | 58 | # cargo build/run 59 | [profile.dev] 60 | codegen-units = 1 61 | debug = 2 62 | debug-assertions = true 63 | incremental = false 64 | opt-level = 3 65 | overflow-checks = true 66 | 67 | # cargo build/run --release 68 | [profile.release] 69 | codegen-units = 1 70 | debug = 2 71 | debug-assertions = false 72 | incremental = false 73 | lto = 'fat' 74 | opt-level = 3 75 | overflow-checks = false 76 | 77 | # do not optimize proc-macro crates = faster builds from scratch 78 | [profile.dev.build-override] 79 | codegen-units = 8 80 | debug = false 81 | debug-assertions = false 82 | opt-level = 0 83 | overflow-checks = false 84 | 85 | [profile.release.build-override] 86 | codegen-units = 8 87 | debug = false 88 | debug-assertions = false 89 | opt-level = 0 90 | overflow-checks = false 91 | 92 | # cargo test 93 | [profile.test] 94 | codegen-units = 1 95 | debug = 2 96 | debug-assertions = true 97 | incremental = false 98 | opt-level = 3 99 | overflow-checks = true 100 | 101 | # cargo test --release 102 | [profile.bench] 103 | codegen-units = 1 104 | debug = 2 105 | debug-assertions = false 106 | incremental = false 107 | lto = 'fat' 108 | opt-level = 3 109 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use defmt_rtt as _; 5 | use panic_halt as _; 6 | 7 | mod fmt; 8 | 9 | #[rtic::app(device = rp_pico::hal::pac, peripherals = true)] 10 | mod app { 11 | 12 | use crate::fmt::Wrapper; 13 | use core::fmt::Write; 14 | use embedded_hal::digital::v2::OutputPin; 15 | use embedded_time::duration::Extensions; 16 | 17 | use rp_pico::hal; 18 | use rp_pico::pac; 19 | use rp_pico::XOSC_CRYSTAL_FREQ; 20 | 21 | // USB Device support 22 | use usb_device::{class_prelude::*, prelude::*}; 23 | // USB Communications Class Device support 24 | use usbd_serial::SerialPort; 25 | 26 | // Blinck time 5 seconds 27 | const SCAN_TIME_US: u32 = 5000000; // 200000; // 5000000; // 1000000; // 200000; 28 | 29 | // IMPORTANT: The USB-Serial with RTIC github project example that I'm following. 30 | // I tried to use the Pico board examples of USB-Serial (without interrupts 31 | // and with interrupts with success, but when using with RTIC I could not make 32 | // it work when merged with the RTIC example.) So I asked some questions 33 | // in the in Matrix chat and received links to examples of there github 34 | // project where it was working, then a used and adapted some parts there 35 | // in this project template. 36 | // This were the kind folks that helped me in the Matrix chat, the 3 projects 37 | // that they suggest me to study are good examples of programs made with RTIC 38 | // and USB and should be studied. 39 | // 40 | // Paul Daniel Faria 41 | // https://github.com/Nashenas88/dactyl-manuform-kb2040-rs/blob/main/src/main.rs#L80 42 | // 43 | // see also: 44 | // korken89 45 | // https://github.com/korken89/pico-probe/tree/master/src 46 | // 47 | // see also: 48 | // Mathias 49 | // https://github.com/mgottschlag/rp2040-usb-sound-card/blob/b8078b57361c1b08755e5ab5f9992c56457ec18b/src/main.rs#L188 50 | // 51 | // 52 | // Global Static variable, has to be written inside unsafe blocks. 53 | // A reference can be obtained with as_ref() method. 54 | 55 | pub struct Counter { 56 | counter: u32, 57 | enable: bool, 58 | } 59 | 60 | impl Counter { 61 | fn new() -> Self { 62 | Counter { 63 | counter: 0_u32, 64 | enable: true, 65 | } 66 | } 67 | 68 | fn get(&self) -> u32 { 69 | self.counter 70 | } 71 | 72 | fn reset(&mut self) { 73 | self.counter = 0_u32; 74 | } 75 | 76 | fn increment(&mut self) { 77 | self.counter += 1_u32; 78 | } 79 | 80 | fn enable(&mut self, state: bool) { 81 | self.enable = state; 82 | } 83 | } 84 | 85 | #[shared] 86 | struct Shared { 87 | timer: hal::Timer, 88 | alarm: hal::timer::Alarm0, 89 | led: hal::gpio::Pin, 90 | led_blink_enable: bool, 91 | 92 | serial: SerialPort<'static, hal::usb::UsbBus>, 93 | usb_dev: usb_device::device::UsbDevice<'static, hal::usb::UsbBus>, 94 | 95 | counter: Counter, 96 | } 97 | 98 | #[local] 99 | struct Local {} 100 | 101 | #[init(local = [usb_bus: Option> = None])] 102 | fn init(c: init::Context) -> (Shared, Local, init::Monotonics) { 103 | //******* 104 | // Initialization of the system clock. 105 | 106 | let mut resets = c.device.RESETS; 107 | let mut watchdog = hal::watchdog::Watchdog::new(c.device.WATCHDOG); 108 | 109 | // Configure the clocks - The default is to generate a 125 MHz system clock 110 | let clocks = hal::clocks::init_clocks_and_plls( 111 | XOSC_CRYSTAL_FREQ, 112 | c.device.XOSC, 113 | c.device.CLOCKS, 114 | c.device.PLL_SYS, 115 | c.device.PLL_USB, 116 | &mut resets, 117 | &mut watchdog, 118 | ) 119 | .ok() 120 | .unwrap(); 121 | 122 | //******* 123 | // Initialization of the USB and Serial and USB Device ID. 124 | 125 | // USB 126 | // 127 | // Set up the USB driver 128 | // The bus that is used to manage the device and class below. 129 | let usb_bus: &'static _ = 130 | c.local 131 | .usb_bus 132 | .insert(UsbBusAllocator::new(hal::usb::UsbBus::new( 133 | c.device.USBCTRL_REGS, 134 | c.device.USBCTRL_DPRAM, 135 | clocks.usb_clock, 136 | true, 137 | &mut resets, 138 | ))); 139 | 140 | // Set up the USB Communications Class Device driver. 141 | let serial = SerialPort::new(usb_bus); 142 | 143 | // Create a USB device with a fake VID and PID 144 | let usb_dev = UsbDeviceBuilder::new(usb_bus, UsbVidPid(0x16c0, 0x27dd)) 145 | .manufacturer("Fake company") 146 | .product("Serial port") 147 | .serial_number("TEST") 148 | .device_class(2) // from: https://www.usb.org/defined-class-codes 149 | .build(); 150 | 151 | //******* 152 | // Initialization of the LED GPIO and the timer. 153 | 154 | let sio = hal::Sio::new(c.device.SIO); 155 | let pins = rp_pico::Pins::new( 156 | c.device.IO_BANK0, 157 | c.device.PADS_BANK0, 158 | sio.gpio_bank0, 159 | &mut resets, 160 | ); 161 | let mut led = pins.led.into_push_pull_output(); 162 | led.set_low().unwrap(); 163 | 164 | let mut timer = hal::Timer::new(c.device.TIMER, &mut resets); 165 | let mut alarm = timer.alarm_0().unwrap(); 166 | let _ = alarm.schedule(SCAN_TIME_US.microseconds()); 167 | alarm.enable_interrupt(&mut timer); 168 | 169 | // Enable led_blink. 170 | let led_blink_enable = true; 171 | 172 | // Reset the counter 173 | let counter = Counter::new(); 174 | 175 | //******** 176 | // Return the Shared variables struct, the Local variables struct and the XPTO Monitonics 177 | // (Note: Read again the RTIC book in the section of Monotonics timers) 178 | ( 179 | Shared { 180 | timer, 181 | alarm, 182 | led, 183 | led_blink_enable, 184 | 185 | serial, 186 | usb_dev, 187 | 188 | counter, 189 | }, 190 | Local {}, 191 | init::Monotonics(), 192 | ) 193 | } 194 | 195 | /// Task that blinks the rp-pico onboard LED and that send a message "LED ON!" and "LED OFF!" do USB-Serial. 196 | #[task( 197 | binds = TIMER_IRQ_0, 198 | priority = 1, 199 | shared = [timer, alarm, led, led_blink_enable, serial, counter], 200 | local = [tog: bool = true], 201 | )] 202 | fn timer_irq(mut cx: timer_irq::Context) { 203 | let mut buf = [0u8; 64]; 204 | 205 | let led = cx.shared.led; 206 | let led_blink_enable = cx.shared.led_blink_enable; 207 | let counter = cx.shared.counter; 208 | 209 | let tog = cx.local.tog; 210 | 211 | // Blinks the LED ON / OFF. 212 | (led, led_blink_enable, counter).lock(|led_a, led_blink_enable_a, counter_a| { 213 | let led_state_str: &str; 214 | if *led_blink_enable_a { 215 | if *tog { 216 | led_a.set_high().unwrap(); 217 | led_state_str = "ON "; 218 | } else { 219 | led_a.set_low().unwrap(); 220 | led_state_str = "OFF"; 221 | } 222 | let _ = writeln!( 223 | Wrapper::new(&mut buf), 224 | "LED {}! counter = {}", 225 | led_state_str, 226 | counter_a.get() 227 | ); 228 | } 229 | if counter_a.enable { 230 | counter_a.increment(); 231 | } 232 | 233 | if *led_blink_enable_a { 234 | *tog = !*tog; 235 | } 236 | }); 237 | 238 | // Clears the timer interrupt and Set's the new delta_time in the future. 239 | let mut timer = cx.shared.timer; 240 | let mut alarm = cx.shared.alarm; 241 | (alarm).lock(|a| { 242 | (timer).lock(|timer_a| { 243 | a.clear_interrupt(timer_a); 244 | let _ = a.schedule(SCAN_TIME_US.microseconds()); 245 | }); 246 | }); 247 | 248 | // Write the message "blabla! 2" do USB-Serial. 249 | cx.shared.serial.lock(|s| { 250 | write_serial(s, unsafe { core::str::from_utf8_unchecked(&buf) }, false); 251 | }); 252 | 253 | /* 254 | // Write the message "blabla! 2" do USB-Serial. 255 | c.shared.serial.lock(|s| { 256 | let mut buf = [0u8; 64]; 257 | let _ = writeln!(Wrapper::new(&mut buf), "blabla! {}", 2); /*"{:?}"*/ 258 | write_serial(s, unsafe { core::str::from_utf8_unchecked(&buf) }, false); 259 | }); 260 | */ 261 | } 262 | 263 | /// Usb interrupt handler. Runs every time the host requests new data. 264 | #[task(binds = USBCTRL_IRQ, priority = 3, shared = [led, led_blink_enable, serial, usb_dev, counter])] 265 | fn usb_rx(cx: usb_rx::Context) { 266 | let led = cx.shared.led; 267 | let led_blink_enable = cx.shared.led_blink_enable; 268 | 269 | let usb_dev = cx.shared.usb_dev; 270 | let serial = cx.shared.serial; 271 | let counter = cx.shared.counter; 272 | 273 | (led, led_blink_enable, usb_dev, serial, counter).lock( 274 | |led_a, led_blink_enable_a, usb_dev_a, serial_a, counter_a| { 275 | // Check for new data 276 | if usb_dev_a.poll(&mut [serial_a]) { 277 | let mut buf = [0u8; 64]; 278 | match serial_a.read(&mut buf) { 279 | Err(_e) => { 280 | // Do nothing 281 | // let _ = serial_a.write(b"Error."); 282 | // let _ = serial_a.flush(); 283 | } 284 | Ok(0) => { 285 | // Do nothing 286 | let _ = serial_a.write(b"Didn't received data."); 287 | let _ = serial_a.flush(); 288 | } 289 | Ok(_count) => { 290 | match_usb_serial_buf( 291 | &buf, 292 | led_a, 293 | led_blink_enable_a, 294 | serial_a, 295 | counter_a, 296 | ); 297 | 298 | /* 299 | // Code to echo the characters in Upper Case. 300 | 301 | // Convert to upper case 302 | buf.iter_mut().take(count).for_each(|b| { 303 | b.make_ascii_uppercase(); 304 | }); 305 | if count > 0 { 306 | let _ = serial_a.write(b"Received data! "); 307 | let _ = serial_a.flush(); 308 | } 309 | 310 | // Send back to the host 311 | let mut wr_ptr = &buf[..count]; 312 | while !wr_ptr.is_empty() { 313 | match serial_a.write(wr_ptr) { 314 | Ok(len) => { 315 | wr_ptr = &wr_ptr[len..]; 316 | // if wr_ptr.len() == 0 { 317 | // let _ = serial_a.write(b""); 318 | let _ = serial_a.flush(); 319 | // } 320 | } 321 | // On error, just drop unwritten data. 322 | // One possible error is Err(WouldBlock), meaning the USB 323 | // write buffer is full. 324 | Err(_) => break, 325 | }; 326 | } 327 | 328 | */ 329 | } 330 | } 331 | } 332 | }, 333 | ); 334 | } 335 | 336 | // Task with least priority that only runs when nothing else is running. 337 | #[idle(local = [x: u32 = 0])] 338 | fn idle(_cx: idle::Context) -> ! { 339 | // Locals in idle have lifetime 'static 340 | // let _x: &'static mut u32 = cx.local.x; 341 | 342 | //hprintln!("idle").unwrap(); 343 | 344 | loop { 345 | cortex_m::asm::nop(); 346 | } 347 | } 348 | 349 | /* New Tasks */ 350 | 351 | /// This function come from the github with USB-Serial example (see link above). 352 | /// 353 | /// Helper function to ensure all data is written across the serial interface. 354 | fn write_serial(serial: &mut SerialPort<'static, hal::usb::UsbBus>, buf: &str, block: bool) { 355 | let write_ptr = buf.as_bytes(); 356 | 357 | // Because the buffer is of constant size and initialized to zero (0) we here 358 | // add a test to determine the size that's really occupied by the str that we 359 | // wan't to send. From index zero to first byte that is as the zero byte value. 360 | let mut index = 0; 361 | while index < write_ptr.len() && write_ptr[index] != 0 { 362 | index += 1; 363 | } 364 | let mut write_ptr = &write_ptr[0..index]; 365 | 366 | while !write_ptr.is_empty() { 367 | match serial.write(write_ptr) { 368 | Ok(len) => write_ptr = &write_ptr[len..], 369 | // Meaning the USB write buffer is full 370 | Err(UsbError::WouldBlock) => { 371 | if !block { 372 | break; 373 | } 374 | } 375 | // On error, just drop unwritten data. 376 | Err(_) => break, 377 | } 378 | } 379 | // let _ = serial.write("\n".as_bytes()); 380 | let _ = serial.flush(); 381 | } 382 | 383 | fn match_usb_serial_buf( 384 | buf: &[u8; 64], 385 | led: &mut hal::gpio::Pin, 386 | led_blink_enable: &mut bool, 387 | serial: &mut SerialPort<'static, hal::usb::UsbBus>, 388 | counter: &mut Counter, 389 | ) { 390 | let _buf_len = buf.len(); 391 | match buf[0] { 392 | // Print Menu 393 | b'M' | b'm' => { 394 | write_serial(serial, "M - Print Menu\n", false); 395 | print_menu(serial); 396 | } 397 | // 0 - Reset counter 398 | b'0' => { 399 | write_serial(serial, "M - Print Menu\n", false); 400 | counter.reset(); 401 | } 402 | // 1 - Increment counter 403 | b'1' => { 404 | write_serial(serial, "1 - Increment counter\n", false); 405 | counter.increment(); 406 | } 407 | // 2 - Start continues counter 408 | b'2' => { 409 | write_serial(serial, "2 - Start continues counter\n", false); 410 | counter.enable(true); 411 | } 412 | // 3 - Stop continues counter 413 | b'3' => { 414 | write_serial(serial, "3 - Stop continues counter\n", false); 415 | counter.enable(false); 416 | } 417 | // 4 - Get switch and LED state 418 | b'4' => { 419 | write_serial(serial, "4 - Get switch and LED state\n", false); 420 | 421 | // GPIO 25 onboard LED, we are going to read the bit 8 of the gpio_status register. 422 | // OUTFROMPERI - output signal from selected peripheral, before register 423 | // override is applied. 424 | // See pag 272 of the Pico Datasets: 425 | // https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#_gpio_functions 426 | 427 | let led_status_reg = 428 | unsafe { (*pac::IO_BANK0::ptr()).gpio[25].gpio_status.read().bits() }; 429 | 430 | // Reserved bit. 431 | // let sio_pin_value = unsafe { (*pac::SIO::ptr()).gpio_out.read().bits() }; 432 | 433 | let (led_bool, led_status) = if ((led_status_reg & 1 << 8) >> 8) == 1_u32 { 434 | (true, "ON") 435 | } else { 436 | (false, "OFF") 437 | }; 438 | 439 | let mut buf = [0u8; 64]; 440 | let _ = writeln!( 441 | Wrapper::new(&mut buf), 442 | "LED Status {:b}, {} LED {}", 443 | led_status_reg, 444 | led_bool, 445 | led_status 446 | ); 447 | write_serial( 448 | serial, 449 | unsafe { core::str::from_utf8_unchecked(&buf) }, 450 | false, 451 | ); 452 | 453 | // unsafe { (*pac::TIMER::ptr()).timerawh.read().bits() }; 454 | } 455 | // 5 - Set LED on 456 | b'5' => { 457 | write_serial(serial, "5 - Set LED on\n", false); 458 | *led_blink_enable = false; 459 | let _ = led.set_high(); 460 | } 461 | // 6 - Set LED off 462 | b'6' => { 463 | write_serial(serial, "6 - Set LED off\n", false); 464 | *led_blink_enable = false; 465 | let _ = led.set_low(); 466 | } 467 | // 7 - Set LED blink enable 468 | b'7' => { 469 | write_serial(serial, "7 - Set LED blink enable\n", false); 470 | *led_blink_enable = true; 471 | } 472 | b'8' => { 473 | write_serial(serial, "8 - Display data rate\n", false); 474 | 475 | let data_rate = serial.line_coding().data_rate(); 476 | let mut buf = [0u8; 64]; 477 | let _ = writeln!(Wrapper::new(&mut buf), "Data rate: {} bit/s", data_rate); 478 | write_serial( 479 | serial, 480 | unsafe { core::str::from_utf8_unchecked(&buf) }, 481 | false, 482 | ); 483 | } 484 | _ => { 485 | write_serial( 486 | serial, 487 | unsafe { core::str::from_utf8_unchecked(buf) }, 488 | false, 489 | ); 490 | write_serial(serial, "Invalid option!\n", false); 491 | } 492 | } 493 | } 494 | 495 | fn print_menu(serial: &mut SerialPort<'static, hal::usb::UsbBus>) { 496 | let mut _buf = [0u8; 273]; 497 | 498 | // Create the Menu. 499 | let menu_str = "***************** 500 | * Menu: 501 | * 502 | * M / m - Print menu 503 | * 0 - Reset counter 504 | * 1 - Increment counter 505 | * 2 - Start continues counter 506 | * 3 - Stop continues counter 507 | * 4 - Get switch and LED state 508 | * 5 - Set LED on 509 | * 6 - Set LED off 510 | * 7 - Set LED blink enable 511 | * 8 - Display data rate 512 | ***************** 513 | Enter option: "; 514 | 515 | write_serial(serial, menu_str, true); 516 | 517 | // Send out the data to USB-Serial. 518 | // let _ = serial.write(menu_str); 519 | 520 | // let _ = writeln!(Wrapper::new(&mut buf), &menu_str); 521 | // write_serial(serial, unsafe { core::str::from_utf8_unchecked(menu_str) }); 522 | } 523 | } 524 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raspberry Pi Pico in Rust Proj Template with RTIC USB-Serial and UF2 2 | A template for my Rust projects with Raspberry Pi Pico. 3 | 4 | ## Description 5 | 6 | Hi, this is my starting project template for my developments in Embedded Rust with the Raspberry Pi Pico (rp2040 micro-controller).
7 |
8 | 9 | **It is a example of a program developed with:** 10 | * The RTIC operating system or scheduler for ARM Micro-controllers. 11 | * The USB-Serial emulation of a serial port, it can emulate other types of USB devices. 12 | * Uf2 method of programming the Pico, but probe-run can also be used by uncommenting one line. 13 | * It's an example of using shared and local state in RTIC. 14 | * It's an example of using interrupts in RTIC. 15 | * It's an example on processing the input from serial and sending a menu to serial terminal, printing long test, and format text with variables to serial terminal. 16 | * It's an example of doing direct register access in Rust with PAC. 17 | * It's an example of using the rp2040-hal. 18 | * It's an example of using the rp-pico bsp abstraction layer. 19 |
20 | 21 | I developed and tested this project in Linux Ubuntu 20.04, but it probably will compile and run in any computer (Linux, Windows, Mac and Raspberry Pi) connected to a Raspberry Pi Pico. This project feeds from several other projects.
22 |
23 | 24 | This project was made after studying all Rust Pico examples and the RTIC book. By starting with the [Project template for rp2040-hal](https://github.com/rp-rs/rp2040-project-template) configuring it to UF2 and changing it to suit my needs. I then added all the dependency libs for it to work with many of the examples of [rp-pico board in the rp-hal](https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico) and the examples in [rp2040-hal in the rp-hal](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples). Then I started with the code from example [pico_rtic.rs](https://github.com/rp-rs/rp-hal/blob/main/boards/rp-pico/examples/pico_rtic.rs) and mixed it with the example [pico_usb_serial.rs](https://github.com/rp-rs/rp-hal/blob/main/boards/rp-pico/examples/pico_usb_serial.rs) and [pico_usb_serial_interrupt.rs](https://github.com/rp-rs/rp-hal/blob/main/boards/rp-pico/examples/pico_usb_serial_interrupt.rs) 25 | but I couldn't make it all compile in RTIC. Then searched online for clues and arrived at Matrix chat room for the rp-hal [https://matrix.to/#/#rp-rs:matrix.org](https://matrix.to/#/#rp-rs:matrix.org). There I found a very warm and helpful community, that gave me links to examples of working USB in RTIC with Pico. Using this information I come up with this cool and useful (at least to me) project template. I extensively used the example that Paul Daniel Faria gave me - Nashenas88 - dactyl-manuform-kb2040-rs [https://github.com/Nashenas88/dactyl-manuform-kb2040-rs](https://github.com/Nashenas88/dactyl-manuform-kb2040-rs). 26 | 27 | 28 | ## RP-Pico Pinout 29 | 30 | ![rp-pico pinout](./img/Raspberry_Pi_Pico_pinout.png) 31 | 32 | 33 | # Specifications RP-Pico Board: 34 | * Low cost 35 | * Dual core ARM Cortex M0 at 133 MHz that some people made it working at 420 MHZ 36 | * 3.3V operating voltage 37 | * 12MHz system crystal 38 | * DMA controller 39 | * JTAG/SWD header 40 | * 2 MByte external Fash, 264 KByte SRAM 41 | * 2x SPI, 2x USART, 2x I2C 42 | * 16x PWM 43 | * 30 GPIO Pins only at 3.3V (not 5V-tolerant) 44 | * 1x USB 1.1 controller and PHY, with host and device support 45 | * 1x ADC (12-bit / 5-channel / one temperature sensor) 46 | * 30 GPIO pins, 4 of which can be used as analogue inputs 47 | * 8x PIO - Programmable Input Output Controllers 48 | * 3.3V LDO voltage regulator, max current 150mA 49 | * Micro USB for power and data 50 | * Onboard user LED (GPIO 25) 51 | * 1x button for bootloader selection 52 | * You can install a Reset button glued and soldered to the top of rp-pico board. 53 | * 2x20 side pins + 1x3 SWD pins 54 | * Note: Space to install a Reset button. 55 | * See the datasheet for more accurate specs. 56 | 57 | 58 | ## RP-HAL development environment installation steps 59 | 60 | 1. Install Rust on your computer.
61 | Follow the Rust site steps.
62 | [https://www.rust-lang.org/](https://www.rust-lang.org/) 63 | 64 | 2. Install the packages specific to Embedded development and / or specific to Raspberry Pico.
65 | Read the README.md page in
66 | [rp-hal - https://github.com/rp-rs/rp-hal](https://github.com/rp-rs/rp-hal) 67 | 68 | ``` 69 | $ rustup self update 70 | $ rustup update stable 71 | $ rustup target add thumbv6m-none-eabi 72 | 73 | # Useful to creating UF2 images for the RP2040 USB Bootloader 74 | $ cargo install elf2uf2-rs --locked 75 | 76 | # Useful for flashing over the SWD pins using a supported JTAG probe 77 | $ cargo install probe-run 78 | 79 | # Useful to detect stack overflow in your developed firmware. 80 | $ cargo install flip-link 81 | ``` 82 | 83 | Configure your permissions to the USB-Serial port of your computer by your user.
84 | 85 | ``` 86 | # Connect the Pico and see the USB_Serial current connections 87 | $ ls -l /dev/ttyUSB* /dev/ttyACM* 88 | 89 | # Give permissions to the user to use the Serial port 90 | $ usermod -a -G dialout $USER 91 | 92 | ``` 93 | 94 | 3. Install a Serial Terminal program like
95 | 96 | 1. GTKTerminal
97 | From the Ubuntu App install. 98 | 99 | 2. or Install CuteCom
100 | $ sudo apt install cutecom 101 | 102 | 3. or this one, that is the one that **I end up using more**.
103 | **CoolTerm**
104 | Because it has a line mode, a better GUI and works in Linux, Windows and Mac.
105 | [https://freeware.the-meiers.org/](https://freeware.the-meiers.org/)
106 | On the executable do ```chmod +x CoolTerm``` 107 | 108 | 4. Install a **Serial Plot GUI**
109 | Very useful to easily monitor ADC plots.
110 | **SerialPlot** - Realtime Plotting Software
111 | [https://hackaday.io/project/5334-serialplot-realtime-plotting-software](https://hackaday.io/project/5334-serialplot-realtime-plotting-software)
112 | On the executable do ```chmod +x SerialPlot``` 113 | 114 | 5. Download the latest version of rp-hal github repo to a directory and unzip it.
115 | rp-hal - Rust support for the "Raspberry Silicon" family of micro-controllers
116 | [https://github.com/rp-rs/rp-hal](https://github.com/rp-rs/rp-hal) 117 | 118 | 6. Download this project repository and unzip it to the some directory where you put the root of the previous rp-hal. Because we will be using it for the new version 4.0.0 of the rp2040-hal in our dependencies.
119 | **Raspberry Pi Pico in Rust Proj Template with RTIC USB-Serial and UF2** 120 | 121 | 7. Change the project directory name from the unzip name to ```rp2040-project-template-main``` . 122 | 123 | 8. Compile it and upload the firmware to the Raspberry Pico.
124 | Remove the USB cable and **press the white bootload button**, while pressing, connect the cable again. It will enter in the USB - UF2 bootload mode that you can use to program the Pico by copyng the file (Cargo run does this automatically). Later you can install a Reset button in the Pico that will simplify this process.
125 | 126 | ``` 127 | # To Clean do: 128 | $ cargo clean 129 | $ clear 130 | 131 | # To Compile and upload the firmware do: 132 | $ cargo run --release 133 | ``` 134 | 135 | 9. Open CoolTerm.
136 | Then Menu -> Connection -> Options and select ```/dev/tttyACM0``` 115200 bps 8 N 1 (8 data bits, Parity None, Stop Bits 1). And in the Terminal choose "Line Mode" so that it will only send data when you press enter.
137 | Then press "**M**" and the menu will appear. Then try the different options. 138 | 139 | 10. Play with the code and understand it. See it, as an example of RTIC development with USB-Serial and UF2 programming and then change it (use it as a template) into your project. The only thing that you have to make is to change the root directory name into your project name and change the Cargo.toml file project name in the field ```name = "rp2040-project-template"```. This file and your project name as to match, use only lower case letter and "-" or "_". 140 | 141 | **Note_1:** UF2 - Make sure your .cargo/config.toml contains the following (it should by default if you are working in this repository for uf2 method):
142 | 143 | ``` 144 | [target.thumbv6m-none-eabi] 145 | runner = "elf2uf2-rs -d" 146 | ``` 147 | 148 | **Note_2:** Compile and Run with probe-run and another Pico as a external debugger.
149 | 150 | * **Loading with probe-run**
151 | See rp-hal page for more details.
152 | Connect your USB JTAG/debug probe (such as a Raspberry Pi Pico running this firmware) to the SWD programming pins on your RP2040 board. 153 | 154 | * **Dapper Mime**
155 | [https://github.com/majbthrd/DapperMime](https://github.com/majbthrd/DapperMime) 156 | 157 | * **Connection diagram in here**
158 | [https://user-images.githubusercontent.com/12226419/134785445-5f651d5a-eda9-4e94-8860-d2ef619dc27a.png](https://user-images.githubusercontent.com/12226419/134785445-5f651d5a-eda9-4e94-8860-d2ef619dc27a.png) 159 | 160 | **Note_3:** For this project template you don't need the Rust nightly version but if you need you can change between stable and nightly versions by doing the following.
161 | 162 | ``` 163 | # To go to Rust nightly version 164 | $ rustup default nightly 165 | 166 | # The add the architecture support for the nightly 167 | $ rustup target add thumbv6m-none-eabi 168 | 169 | # To go back to Rust stable version do 170 | $ rustup default stable 171 | ``` 172 | 173 | ## This project can also be programmed with other Raspberry Pi Pico as the programmer. 174 | 175 | I tested the probe program firmware that should be loaded into a second Pico, the programmer. That allows you to program the first Pico. **Rpi Pico-Probe** from **korken89** that implements a CMSIS DAP V1 and V2 Probe and it works well. Currently Pico-Probe is still under heavy development so many new features should appear but currently it already works well to program the Pico.
176 | 177 | * **korken89 – pico-probe**
178 | [https://github.com/korken89/pico-probe](https://github.com/korken89/pico-probe) 179 | 180 | To program **follow the instructions** in the ```README.md``` in the above link. You have to connect the two Pico’s. You have to compile the Pico-Probe, upload it as a UF2 and after that you can use it to program the target Pico. 181 | 182 | ``` 183 | # Don’t forget to change the .cargo/config.toml in my template project, 184 | 185 | # comment the runner line for UF2 programming type 186 | runner = "elf2uf2-rs -d" 187 | 188 | # and uncomment the line 189 | runner = "probe-run --chip RP2040" 190 | 191 | # then do 192 | $ cargo clean 193 | $ cargo run --release 194 | 195 | # to exit CMSIS DAP terminal do a ctrl + C 196 | ``` 197 | 198 | The connection diagram that I used (but you can change the pins in the Pico-Probe code ```setup.rs```) was: 199 | 200 | | Pin on programmer Pico | Description | Pin on target Pico | 201 | | ---------------------- | ----------- | --------------------- | 202 | | GPIO13 | nRESET | Run Pin | 203 | | GPIO14 | SWDIO | SWDIO in 3 pin header | 204 | | GPIO15 | SWCLK | SWCLK in 3 pin header | 205 | | VSYS | Power | VSYS | 206 | | GND | Ground | GND | 207 | | GND | Ground | GND in 3 pin header | 208 | 209 | 210 | ## Good Pico in Rust References 211 | 212 | 0. **Book - Get Started with MicroPython on Raspberry Pi Pico**
213 | [https://hackspace.raspberrypi.com/books/micropython-pico](https://hackspace.raspberrypi.com/books/micropython-pico) 214 | 215 | 1. **Video - An Overview of the Embedded Rust Ecosystem**
216 | [https://www.youtube.com/watch?v=vLYit_HHPaY](https://www.youtube.com/watch?v=vLYit_HHPaY) 217 | 218 | 2. **rp-hal** - **Rust support for the "Raspberry Silicon" family of micro-controllers**
219 | Your primary source of information for Rust developments with Raspberry Pico.
220 | [https://github.com/rp-rs/rp-hal](https://github.com/rp-rs/rp-hal) 221 | 222 | 3. **Crate rp2040_hal - Docs**
223 | Your primary source of doc information on the HAL - Hardware Abstraction Layer.
224 | [https://docs.rs/rp2040-hal/latest/rp2040_hal/](https://docs.rs/rp2040-hal/latest/rp2040_hal/) 225 | 226 | 4. **Raspberry Pi Pico Board - Rust Code Examples**
227 | Study them all!
228 | [https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico/examples](https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico/examples) 229 | 230 | 5. **Examples for the HAL - Hardware Abstraction Layer**
231 | rp-hal - rp2040-hal - examples
232 | [https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples) 233 | 234 | 6. **Github rp2040-hal**
235 | [https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal) 236 | 237 | 7. **Getting Started with Rust on a Raspberry Pi Pico (Part 1)**
238 | [https://reltech.substack.com/p/getting-started-with-rust-on-a-raspberry](https://reltech.substack.com/p/getting-started-with-rust-on-a-raspberry) 239 | 240 | 8. **Getting Started with Rust on a Raspberry Pi Pico (Part 2)**
241 | [https://reltech.substack.com/p/getting-started-with-raspberry-pi](https://reltech.substack.com/p/getting-started-with-raspberry-pi) 242 | 243 | 9. **Getting Started with Rust on a Raspberry Pi Pico (Part 3)**
244 | [https://reltech.substack.com/p/getting-started-with-rust-on-a-raspberry-a88](https://reltech.substack.com/p/getting-started-with-rust-on-a-raspberry-a88) 245 | 246 | 10. **Multilingual blink for Raspberry Pi Pico - Alasdair Allan**
247 | [https://www.raspberrypi.com/news/multilingual-blink-for-raspberry-pi-pico/](https://www.raspberrypi.com/news/multilingual-blink-for-raspberry-pi-pico/) 248 | 249 | 11. **Video - How can we write the best device driver for a Hal in Rust?**
250 | [https://www.youtube.com/watch?v=z9z74VpqO9A](https://www.youtube.com/watch?v=z9z74VpqO9A) 251 | 252 | 12. **258 drivers para Embedded-HAL**
253 | [https://crates.io/search?q=embedded-hal%20driver](https://crates.io/search?q=embedded-hal%20driver) 254 | 255 | 13. **Video - RTIC - Real Time Interrupt driven Concurrency**
256 | RTIC is a RTOS - Real Time Operating System.
257 | [https://www.youtube.com/watch?v=saNdh0m_qHc](https://www.youtube.com/watch?v=saNdh0m_qHc) 258 | 259 | 14. **RTIC Book**
260 | Real-Time Interrupt-driven Concurrency.
261 | A very efficient preemptive multitasking framework that supports task prioritization and dead lock free execution.
262 | [https://rtic.rs/1/book/en/](https://rtic.rs/1/book/en/) 263 | 264 | 15. **Github - rtic-rs - cortex-m-rtic**
265 | [https://github.com/rtic-rs/cortex-m-rtic](https://github.com/rtic-rs/cortex-m-rtic) 266 | 267 | 16. **Video - Grepit about the Rust RTIC framework**
268 | [https://www.youtube.com/watch?v=sSJ-Md8nwIM](https://www.youtube.com/watch?v=sSJ-Md8nwIM) 269 | 270 | 17. Good **example 1** of **advanced Pico with RTIC** to Study
271 | Paul Daniel Faria
272 | Nashenas88 - dactyl-manuform-kb2040-rs
273 | Dactyl Manuform firmware for Adafruit kb2040 in Rust
274 | [https://github.com/Nashenas88/dactyl-manuform-kb2040-rs](https://github.com/Nashenas88/dactyl-manuform-kb2040-rs) 275 | 276 | 18. Good **example 2** of **advanced Pico with RTIC** to Study
277 | korken89
278 | korken89 - pico-probe
279 | [https://github.com/korken89/pico-probe](https://github.com/korken89/pico-probe) 280 | 281 | 19. Good **example 3** of **advanced Pico with RTIC** to Study
282 | Mathias
283 | mgottschlag - rp2040-usb-sound-card
284 | [https://github.com/mgottschlag/rp2040-usb-sound-card](https://github.com/mgottschlag/rp2040-usb-sound-card) 285 | 286 | 20. Good **example 4** of **advanced Pico with RTIC** to Study
287 | kalkyl - Playground for RTIC on RP2040
288 | 3 good examples
289 | [https://github.com/kalkyl/rp-rtic](https://github.com/kalkyl/rp-rtic) 290 | 291 | 21. **Project template for rp2040-hal**
292 | The starting point for the project that you are current reading.
293 | [https://github.com/rp-rs/rp2040-project-template](https://github.com/rp-rs/rp2040-project-template) 294 | 295 | 22. **pio-rs - Support for the Raspberry Silicon RP2040's PIO State Machines**
296 | [https://github.com/rp-rs/pio-rs ](https://github.com/rp-rs/pio-rs ) 297 | 298 | 23. **embedded-hal**
299 | Use this if you are writing code that should run on any micro-controller
300 | [https://github.com/rust-embedded/embedded-hal](https://github.com/rust-embedded/embedded-hal) 301 | 302 | 24. **raspberrypi picotool - Not really neaded in Rust**
303 | [https://github.com/raspberrypi/picotool](https://github.com/raspberrypi/picotool) 304 | 305 | 25. **usb-device - Experimental device-side USB stack for embedded devices**
306 | [https://crates.io/crates/usb-device](https://crates.io/crates/usb-device) 307 | 308 | 26. **probe-rs - A modern, embedded debugging toolkit, written in Rust**
309 | [https://probe.rs/](https://probe.rs/) 310 | 311 | 27. **GitHub probe-rs**
312 | [https://github.com/probe-rs/probe-rs](https://github.com/probe-rs/probe-rs) 313 | 314 | 28. **Video - probe-rs: Your Embedded Tome**
315 | [https://www.youtube.com/watch?v=esNPoXbhHkU](https://www.youtube.com/watch?v=esNPoXbhHkU) 316 | 317 | 29. **rust-embedded - cortex-m-quickstart**
318 | [https://github.com/rust-embedded/cortex-m-quickstart](https://github.com/rust-embedded/cortex-m-quickstart) 319 | 320 | 30. **STM32 - Discovery - Book**
321 | [https://docs.rust-embedded.org/discovery/](https://docs.rust-embedded.org/discovery/) 322 | 323 | 31. **The Embedded Rust Book**
324 | [https://docs.rust-embedded.org/book/](https://docs.rust-embedded.org/book/) 325 | 326 | 32. **The Embedonomicon Book**
327 | Deep dive into the inner workings.
328 | [https://docs.rust-embedded.org/embedonomicon/](https://docs.rust-embedded.org/embedonomicon/) 329 | 330 | 33. **More gdb commands cheat-sheet**
331 | [https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf](https://darkdust.net/files/GDB%20Cheat%20Sheet.pdf) 332 | 333 | 34. **Video - Getting Started with Debugging using GDB**
334 | Find Bugs in Your Code with A Couple Easy Commands
335 | [https://www.youtube.com/watch?v=Dq8l1_-QgAc](https://www.youtube.com/watch?v=Dq8l1_-QgAc) 336 | 337 | 35. **Play List - Embedded Rust BluePill - Vers Binarii**
338 | [https://www.youtube.com/playlist?list=PLP_X41VhYn5X6Wwjnm0bRwI3n2pdaszxU](https://www.youtube.com/playlist?list=PLP_X41VhYn5X6Wwjnm0bRwI3n2pdaszxU) 339 | 340 | 36. **Play List - Embedded Rust course - JaJakub** - 2022
341 | [https://www.youtube.com/playlist?list=PLL2SCPK5xSRWBPj-nKOVYIhxRw7C4kYeI](https://www.youtube.com/playlist?list=PLL2SCPK5xSRWBPj-nKOVYIhxRw7C4kYeI) 342 | 343 | 37. **joaocarvalhoopen - stm32_bluepill_in_rust__Template**
344 | [https://github.com/joaocarvalhoopen/stm32_bluepill_in_rust__Template](https://github.com/joaocarvalhoopen/stm32_bluepill_in_rust__Template) 345 | 346 | 38. **Awesome Embedded Rust**
347 | [https://github.com/rust-embedded/awesome-embedded-rust](https://github.com/rust-embedded/awesome-embedded-rust) 348 | 349 | 39. **How to learn modern Rust**
350 | [https://github.com/joaocarvalhoopen/How_to_learn_modern_Rust](https://github.com/joaocarvalhoopen/How_to_learn_modern_Rust) 351 | 352 | 353 | ## Datasheets and other specific info for the RP2040 micro-controller 354 | 355 | 1. **Raspberry Pi Pico Site**
356 | [https://www.raspberrypi.com/products/raspberry-pi-pico/](https://www.raspberrypi.com/products/raspberry-pi-pico/) 357 | 358 | 2. **Pico RP2040 documentation**
359 | [https://www.raspberrypi.com/documentation/microcontrollers/](https://www.raspberrypi.com/documentation/microcontrollers/) 360 | 361 | 3. **RP2040 Micro-controller - Datasheet - PDF**
362 | [https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf) 363 | 364 | 4. **Pico board Datasheet - PDF**
365 | [https://datasheets.raspberrypi.com/pico/pico-datasheet.pdf](https://datasheets.raspberrypi.com/pico/pico-datasheet.pdf) 366 | 367 | 5. **Pico C/C++ SDK - Libraries and Tools - PDF**
368 | [https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf](https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-c-sdk.pdf) 369 | 370 | 6. **Pico Python SDK - PDF**
371 | [https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-python-sdk.pdf](https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-python-sdk.pdf) 372 | 373 | 7. **Pico FAQ - PDF**
374 | [https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-faq.pdf](https://datasheets.raspberrypi.com/pico/raspberry-pi-pico-faq.pdf) 375 | 376 | 8. Raspberry Pi **Pico Overclocking**, beware there is a catch! - Part 1
377 | The part 2 will resolve the flash issue.
378 | [https://www.youtube.com/watch?v=G2BuoFNLoDM](https://www.youtube.com/watch?v=G2BuoFNLoDM) 379 | 380 | 9. **Pico Overclock Part 2**. Fixing the catch with the flash. - Part 2
381 | [https://www.youtube.com/watch?v=rU381A-b79c](https://www.youtube.com/watch?v=rU381A-b79c) 382 | 383 | 10. **Play List - Raspberry Pi Pico - Low Level Learning**
384 | [https://www.youtube.com/playlist?list=PLc7W4b0WHTAV6EYRVayb9c9dEsq-NeXAt](https://www.youtube.com/playlist?list=PLc7W4b0WHTAV6EYRVayb9c9dEsq-NeXAt) 385 | 386 | 11. **Play List - Intro to Raspberry Pi Pico and RP2040 - DigiKey**
387 | [https://www.youtube.com/playlist?list=PLEBQazB0HUyQO6rJxKr2umPCgmfAU-cqR](https://www.youtube.com/playlist?list=PLEBQazB0HUyQO6rJxKr2umPCgmfAU-cqR) 388 | 389 | 12. **Video - In-depth: Raspberry Pi Pico's PIO - programmable I/O**
390 | [https://www.youtube.com/watch?v=yYnQYF_Xa8g](https://www.youtube.com/watch?v=yYnQYF_Xa8g) 391 | 392 | 13. **Raspberry Pi Pico 200Khz Digital Oscilloscope**
393 | [https://www.instructables.com/Raspberry-Pi-Pico-200Khz-Digital-Oscilloscope/](https://www.instructables.com/Raspberry-Pi-Pico-200Khz-Digital-Oscilloscope/) 394 | 395 | 14. **The Pico ADC**
396 | Integral Non-Linearity (INL) and Differential Non-Linearity (DNL) are used to measure the error of the quantization of the incoming signal that the ADC generates
397 | Pag. 589 e Pag. 590 do Pico Datasheet
398 | [https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf) 399 | 400 | 15. **Characterizing the Raspberry Pi Pico ADC - markomo**
401 | [https://pico-adc.markomo.me/](https://pico-adc.markomo.me/) 402 | 403 | 16. **Pico ADC - Power Supply Noise and Spectrum Testing**
404 | [https://pico-adc.markomo.me/PSU-Noise/](https://pico-adc.markomo.me/PSU-Noise/) 405 | 406 | 17. **Using a HD44780 LCD display with MicroPython on the Raspberry Pi Pico**
407 | [https://raphaelkabo.com/blog/pi-pico-hd44780/](https://raphaelkabo.com/blog/pi-pico-hd44780/) 408 | 409 | 18. **How to connect a piezo speaker to a microcontroller?**
410 | [https://www.eevblog.com/forum/projects/how-to-connect-a-piezo-speaker-to-a-microcontroller/](https://www.eevblog.com/forum/projects/how-to-connect-a-piezo-speaker-to-a-microcontroller/) 411 | 412 | 19. **Electrical Symbols & Electronic Symbols**
413 | [https://www.rapidtables.com/electric/electrical_symbols.html](https://www.rapidtables.com/electric/electrical_symbols.html) 414 | 415 | 416 | ## How to install a Raspberry Pi Pico Reset Button 417 | 418 | Solder a push button between the GND and Run pin's and then glue it over RP-Pico board empty space.
419 |
420 | 421 | ![Pico Reset Button soldered and glued over the RP-Pico Board](./img/Raspberry_Pico_Reset_Button_small.png)
422 | 423 | ``` 424 | The Reset process to enter UF2 programming mode, instead of doing: 425 | 1. Remove USB Cable. 426 | 3. Press Bootload Button. 427 | 4. While pressing re-insert the USB cable. 428 | 5. Upload the C/C++ or Rust firmware 429 | 430 | You will do: 431 | 1. Press the reset button. 432 | 2. Press the Bootload Button. 433 | 1. Release the reset button. 434 | 2. Release the Bootload Button. 435 | 5. Upload the C/C++ or Rust firmware 436 | ``` 437 | 438 | 1. Video - Pico Quick Reset Button
439 | [https://www.youtube.com/watch?v=OVM_spenILE](https://www.youtube.com/watch?v=OVM_spenILE) 440 | 441 | 442 | ## Order in which you should study the Rust examples for the RP2040 Micro-Controller and the RP-Pico Board 443 | 444 | Use the following documentation while studying the examples: 445 | 446 | * **Crate rp2040_hal - Docs**
447 | Your primary source of doc information on the HAL - Hardware Abstraction Layer.
448 | [https://docs.rs/rp2040-hal/latest/rp2040_hal/](https://docs.rs/rp2040-hal/latest/rp2040_hal/) 449 | 450 | * **RP2040 Micro-controller - Datasheet - PDF**
451 | [https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf) 452 | 453 | * **RTIC Book**
454 | Real-Time Interrupt-driven Concurrency.
455 | A very efficient preemptive multitasking framework that supports task prioritization and dead lock free execution.
456 | [https://rtic.rs/1/book/en/](https://rtic.rs/1.0/book/en/) 457 | 458 | 459 | **The examples:**
460 | 461 | * **Examples for the RP-Pico Board**
462 | rp-hal - boards - rp-pico - examples
463 | [https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico/examples](https://github.com/rp-rs/rp-hal/tree/main/boards/rp-pico/examples) 464 | 465 | ``` 466 | 1. - pico_blinky.rs 467 | 2. - pico_gpio_in_out.rs 468 | 3. - pico_rtic.rs 469 | 4. - pico_countdown_blinky.rs 470 | 5. - pico_pwm_blink.rs 471 | 6. - pico_usb_serial.rs 472 | 7. - pico_usb_serial_interrupt.rs 473 | 8. - pico_usb_twitchy_mouse.rs 474 | 9. - pico_uart_irq_buffer.rs 475 | 10. - pico_uart_irq_echo.rs 476 | 11. - pico_i2c_oled_display_ssd1306.rs 477 | 12. - pico_i2c_pio.rs 478 | 13. - pico_spi_sd_card.rs 479 | 14. - pico_ws2812_led.rs 480 | ``` 481 | 482 | * **Examples for the HAL - Hardware Abstraction Layer**
483 | rp-hal - **rp2040-hal** - examples
484 | [https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal/examples) 485 | 486 | ``` 487 | 1. - blinky.rs 488 | 2. - gpio_in_out.rs 489 | 490 | 3. - multicore_fifo_blink.rs 491 | 4. - adc.rs 492 | 493 | 5. - lcd_display.rs 494 | 6. - watchdog.rs 495 | 496 | 7. - pwm_blink.rs 497 | 498 | 8. - rom_funcs.rs 499 | 500 | 9. - dht11.rs 501 | 11. - i2c.rs 502 | 12. - spi.rs 503 | 13. - uart.rs 504 | 505 | 14. - pio_blink.rs 506 | 15. - pio_proc_blink.rs 507 | 16. - pio_side_set.rs 508 | ``` 509 | 510 | Then study My example Template.
511 |
512 | 513 | Then the following RTIC examples with USB.
514 |
515 | 516 | * Good **example 1** of **advanced Pico with RTIC** to Study
517 | Paul Daniel Faria
518 | Nashenas88 - dactyl-manuform-kb2040-rs
519 | Dactyl Manuform firmware for Adafruit kb2040 in Rust
520 | [https://github.com/Nashenas88/dactyl-manuform-kb2040-rs](https://github.com/Nashenas88/dactyl-manuform-kb2040-rs) 521 | 522 | * Good **example 2** of **advanced Pico with RTIC** to Study
523 | korken89
524 | korken89 - pico-probe
525 | [https://github.com/korken89/pico-probe](https://github.com/korken89/pico-probe) 526 | 527 | * Good **example 3** of **advanced Pico with RTIC** to Study
528 | Mathias
529 | mgottschlag - rp2040-usb-sound-card
530 | [https://github.com/mgottschlag/rp2040-usb-sound-card](https://github.com/mgottschlag/rp2040-usb-sound-card) 531 | 532 | * Good **example 4** of **advanced Pico with RTIC** to Study
533 | kalkyl - Playground for RTIC on RP2040
534 | 3 good examples
535 | [https://github.com/kalkyl/rp-rtic](https://github.com/kalkyl/rp-rtic) 536 | 537 | 538 | ## How to program the Pico in Rust? 539 | 540 | First if possible try to use RTIC framework for concurrency. It’s like a small and lightweight operating system that simplifies the development process.
541 | Then you should use BSP (Board level support package) features where available.
542 | Then use rp2040-hal (Hardware Abstraction Layer) features for the majority of development and if you need something that is not yet supported by the HAL or if you need a more fine grained control over the hardware, you should use rp2040-pac (Peripheral Access Crate) direct access through the registers and consult the rp2040 datasheet to discover each register name, what each register do and how to use them.
543 | 544 | * **Crate rp2040_pac**
545 | [https://docs.rs/rp2040-pac/0.3.0/rp2040_pac/](https://docs.rs/rp2040-pac/0.3.0/rp2040_pac/) 546 | 547 | * **To know how the syntax to access and use the registers see...**
548 | svd2rust
549 | [https://docs.rs/svd2rust/0.21.0/svd2rust/#peripheral-api](https://docs.rs/svd2rust/0.21.0/svd2rust/#peripheral-api) 550 | 551 | * **RP2040 Micro-controller - Datasheet - PDF**
552 | [https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf) 553 | 554 | ``` Rust 555 | // Example 556 | use rp_pico::hal; 557 | use rp_pico::pac; 558 | let led_status_reg = unsafe { (*pac::IO_BANK0::ptr()).gpio[25].gpio_status.read().bits() }; 559 | let sio_pin_value = unsafe { (*pac::SIO::ptr()).gpio_out.read().bits() }; 560 | 561 | let (led_bool, led_str) = if ((led_status_reg & 1 << 8) >> 8) == 1_u32 { 562 | (true, "ON") 563 | } else { 564 | (false, "OFF") 565 | }; 566 | ``` 567 | 568 | 569 | ## License 570 | The contents of this repository are dual-licensed under the _MIT OR Apache 571 | 2.0_ License. That means you can chose either the MIT licence or the 572 | Apache-2.0 licence when you re-use this code. See `MIT` or `APACHE2.0` for more 573 | information on each specific licence. 574 | 575 | 576 | ## Have fun! 577 | Best regards,
578 | João Nuno Carvalho 579 | --------------------------------------------------------------------------------