diff --git a/Cargo.toml b/Cargo.toml index d016547..b7ea693 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,15 +8,17 @@ version = "0.1.0" [dependencies] cortex-m = { version = "0.7.1", features = ["inline-asm"] } cortex-m-rt = "0.6.10" +embedded-hal = { version = "0.2.5", features=["unproven"] } +embedded-time = "0.12.0" defmt = "0.1.3" defmt-rtt = "0.1.0" panic-probe = "0.1.0" -rp2040-pac = { git = "https://github.com/rp-rs/rp2040-pac", branch="main" } +rp2040-hal = { git = "https://github.com/rp-rs/rp-hal", branch="main" } rp2040-boot2 = { git = "https://github.com/rp-rs/rp2040-boot2-rs", branch="main" } -#rp2040-pac = { path = "../rp2040-pac" } -#rp2040-boot2 = { path = "../rp2040-boot2-rs" } +panic-halt = "0.2.0" + [patch.crates-io] cortex-m = { git = "https://github.com/rust-embedded/cortex-m" } diff --git a/src/main.rs b/src/main.rs index e500874..9a12d44 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,118 +1,43 @@ +//! Blinks the LED on a Pico board +//! +//! This will blink an LED attached to GP25, which is the pin the Pico uses for the on-board LED. #![no_std] #![no_main] -#![feature(asm)] -use core::sync::atomic::{AtomicUsize, Ordering}; use cortex_m_rt::entry; use defmt::*; use defmt_rtt as _; -use pac::{watchdog, xosc}; +use embedded_hal::digital::v2::OutputPin; +use hal::pac; +use hal::sio::Sio; use panic_probe as _; -use rp2040_pac as pac; - -mod pll; -mod resets; +use rp2040_hal as hal; #[link_section = ".boot2"] #[used] pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER; -#[defmt::timestamp] -fn timestamp() -> u64 { - static COUNT: AtomicUsize = AtomicUsize::new(0); - // NOTE(no-CAS) `timestamps` runs with interrupts disabled - let n = COUNT.load(Ordering::Relaxed); - COUNT.store(n + 1, Ordering::Relaxed); - n as u64 -} - -fn init( - resets: pac::RESETS, - watchdog: pac::WATCHDOG, - clocks: pac::CLOCKS, - xosc: pac::XOSC, - pll_sys: pac::PLL_SYS, - pll_usb: pac::PLL_USB, -) { - // Now reset all the peripherals, except QSPI and XIP (we're using those - // to execute from external flash!) - - let resets = resets::Resets::new(resets); - - // Reset everything except: - // - QSPI (we're using it to run this code!) - // - PLLs (it may be suicide if that's what's clocking us) - resets.reset(!(resets::IO_QSPI | resets::PADS_QSPI | resets::PLL_SYS | resets::PLL_USB)); - - resets.unreset_wait( - resets::ALL - & !(resets::ADC - | resets::RTC - | resets::SPI0 - | resets::SPI1 - | resets::UART0 - | resets::UART1 - | resets::USBCTRL), - ); - - // xosc 12 mhz - watchdog - .tick - .write(|w| unsafe { w.cycles().bits(XOSC_MHZ as u16).enable().set_bit() }); - - clocks.clk_sys_resus_ctrl.write(|w| unsafe { w.bits(0) }); - - // Enable XOSC - // TODO extract to HAL module - const XOSC_MHZ: u32 = 12; - xosc.ctrl.write(|w| w.freq_range()._1_15mhz()); - let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256; - xosc.startup - .write(|w| unsafe { w.delay().bits(startup_delay as u16) }); - xosc.ctrl - .write(|w| w.freq_range()._1_15mhz().enable().enable()); - while !xosc.status.read().stable().bit_is_set() {} - - // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. - clocks.clk_sys_ctrl.modify(|_, w| w.src().clk_ref()); - while clocks.clk_sys_selected.read().bits() != 1 {} - clocks.clk_ref_ctrl.modify(|_, w| w.src().rosc_clksrc_ph()); - while clocks.clk_ref_selected.read().bits() != 1 {} - - resets.reset(resets::PLL_SYS | resets::PLL_USB); - resets.unreset_wait(resets::PLL_SYS | resets::PLL_USB); - - pll::PLL::new(pll_sys).configure(1, 1500_000_000, 6, 2); - pll::PLL::new(pll_usb).configure(1, 480_000_000, 5, 2); -} - #[entry] fn main() -> ! { + let mut pac = pac::Peripherals::take().unwrap(); + info!("Hello World!"); - - let p = pac::Peripherals::take().unwrap(); - - init(p.RESETS, p.WATCHDOG, p.CLOCKS, p.XOSC, p.PLL_SYS, p.PLL_USB); - - let led_pin = 25; + let sio = Sio::new(pac.SIO); + let pins = hal::gpio::Pins::new( + pac.IO_BANK0, + pac.PADS_BANK0, + sio.gpio_bank0, + &mut pac.RESETS, + ); + let mut led_pin = pins.gpio25.into_push_pull_output(); loop { info!("on!"); - p.IO_BANK0.gpio[led_pin].gpio_ctrl.write(|w| { - w.oeover().enable(); - w.outover().high(); - w - }); - - cortex_m::asm::delay(1_000_000); - + led_pin.set_high().unwrap(); + // TODO: Replace with proper 1s delays once we have clocks working + cortex_m::asm::delay(500_000); info!("off!"); - p.IO_BANK0.gpio[led_pin].gpio_ctrl.write(|w| { - w.oeover().enable(); - w.outover().low(); - w - }); - - cortex_m::asm::delay(1_000_000); + led_pin.set_low().unwrap(); + cortex_m::asm::delay(500_000); } } diff --git a/src/pll.rs b/src/pll.rs deleted file mode 100644 index 2faf91b..0000000 --- a/src/pll.rs +++ /dev/null @@ -1,59 +0,0 @@ -use core::ops::Deref; -use defmt::{assert, *}; - -use rp2040_pac as pac; - -const XOSC_MHZ: u32 = 12; - -pub struct PLL { - inner: T, -} - -impl PLL { - pub fn new(inner: T) -> Self { - Self { inner } - } - - pub fn configure(&mut self, refdiv: u32, vco_freq: u32, post_div1: u8, post_div2: u8) { - let p = &self.inner; - - // Power off in case it's already running - p.pwr.reset(); - p.fbdiv_int.reset(); - - let ref_mhz = XOSC_MHZ / refdiv; - p.cs.write(|w| unsafe { w.bits(ref_mhz as _) }); - - let fbdiv = vco_freq / (ref_mhz * 1_000_000); - assert!(fbdiv >= 16 && fbdiv <= 520); - assert!((post_div1 >= 1 && post_div1 <= 7) && (post_div2 >= 1 && post_div2 <= 7)); - assert!(post_div2 <= post_div1); - assert!(ref_mhz <= (vco_freq / 16)); - - p.fbdiv_int.write(|w| unsafe { w.bits(fbdiv) }); - - p.pwr.modify(|_, w| w.pd().clear_bit().vcopd().clear_bit()); - - while !p.cs.read().lock().bits() {} - - p.prim.write(|w| unsafe { - w.postdiv1().bits(post_div1); - w.postdiv2().bits(post_div2); - w - }); - - p.pwr.modify(|_, w| w.postdivpd().clear_bit()); - } -} - -mod sealed { - use rp2040_pac as pac; - - pub trait Instance {} - impl Instance for pac::PLL_SYS {} - impl Instance for pac::PLL_USB {} -} - -pub trait Instance: Deref {} -impl Instance for pac::PLL_SYS {} -impl Instance for pac::PLL_USB {} diff --git a/src/resets.rs b/src/resets.rs deleted file mode 100644 index 97178e2..0000000 --- a/src/resets.rs +++ /dev/null @@ -1,50 +0,0 @@ -use rp2040_pac as pac; - -pub const ALL: u32 = 0x01ffffff; -pub const USBCTRL: u32 = 0x01000000; -pub const UART1: u32 = 0x00800000; -pub const UART0: u32 = 0x00400000; -pub const TIMER: u32 = 0x00200000; -pub const TBMAN: u32 = 0x00100000; -pub const SYSINFO: u32 = 0x00080000; -pub const SYSCFG: u32 = 0x00040000; -pub const SPI1: u32 = 0x00020000; -pub const SPI0: u32 = 0x00010000; -pub const RTC: u32 = 0x00008000; -pub const PWM: u32 = 0x00004000; -pub const PLL_USB: u32 = 0x00002000; -pub const PLL_SYS: u32 = 0x00001000; -pub const PIO1: u32 = 0x00000800; -pub const PIO0: u32 = 0x00000400; -pub const PADS_QSPI: u32 = 0x00000200; -pub const PADS_BANK0: u32 = 0x00000100; -pub const JTAG: u32 = 0x00000080; -pub const IO_QSPI: u32 = 0x00000040; -pub const IO_BANK0: u32 = 0x00000020; -pub const I2C1: u32 = 0x00000010; -pub const I2C0: u32 = 0x00000008; -pub const DMA: u32 = 0x00000004; -pub const BUSCTRL: u32 = 0x00000002; -pub const ADC: u32 = 0x00000001; - -pub struct Resets { - inner: pac::RESETS, -} - -impl Resets { - pub fn new(inner: pac::RESETS) -> Self { - Self { inner } - } - - pub fn reset(&self, bits: u32) { - self.inner.reset.write(|w| unsafe { w.bits(bits) }) - } - - pub fn unreset_wait(&self, bits: u32) { - // TODO use the "atomic clear" register version - self.inner - .reset - .modify(|r, w| unsafe { w.bits(r.bits() & !bits) }); - while ((!self.inner.reset_done.read().bits()) & bits) != 0 {} - } -}