Basic port to use the HAL blinky

This commit is contained in:
9names 2021-08-01 20:08:26 +10:00
parent 64e2eb5607
commit c88c783c28
4 changed files with 27 additions and 209 deletions

View File

@ -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" }

View File

@ -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);
}
}

View File

@ -1,59 +0,0 @@
use core::ops::Deref;
use defmt::{assert, *};
use rp2040_pac as pac;
const XOSC_MHZ: u32 = 12;
pub struct PLL<T: Instance> {
inner: T,
}
impl<T: Instance> PLL<T> {
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<Target = pac::pll_sys::RegisterBlock> {}
impl Instance for pac::PLL_SYS {}
impl Instance for pac::PLL_USB {}

View File

@ -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 {}
}
}