From 5a6384d199e859c54d31a780d3c18b3b38311b45 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Fri, 25 Jun 2021 03:38:03 +0200 Subject: [PATCH] rp: clock setup --- .vscode/settings.json | 3 +- Cargo.example.toml | 2 +- embassy-rp/Cargo.toml | 2 +- embassy-rp/src/clocks.rs | 182 +++++++++++++++++++++++++++++++++++++++ embassy-rp/src/gpio.rs | 2 +- embassy-rp/src/lib.rs | 82 +----------------- embassy-rp/src/pll.rs | 76 ---------------- embassy-rp/src/reset.rs | 17 ++++ embassy-rp/src/resets.rs | 29 ------- embassy-rp/src/uart.rs | 3 +- examples/rp/Cargo.toml | 2 +- 11 files changed, 210 insertions(+), 190 deletions(-) create mode 100644 embassy-rp/src/clocks.rs delete mode 100644 embassy-rp/src/pll.rs create mode 100644 embassy-rp/src/reset.rs delete mode 100644 embassy-rp/src/resets.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index ca242662b..c897dd798 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -11,5 +11,6 @@ "**/.git/objects/**": true, "**/.git/subtree-cache/**": true, "**/target/**": true - } + }, + "git.ignoreLimitWarning": true } \ No newline at end of file diff --git a/Cargo.example.toml b/Cargo.example.toml index d94f7e9bb..c615d29ad 100644 --- a/Cargo.example.toml +++ b/Cargo.example.toml @@ -40,7 +40,7 @@ members = [ # rp2040 #"embassy-rp", - #"examples/rp2040", + #"examples/rp", # std #"embassy-std", diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml index 80c1a8696..323afa1ee 100644 --- a/embassy-rp/Cargo.toml +++ b/embassy-rp/Cargo.toml @@ -22,5 +22,5 @@ cortex-m-rt = "0.6.13" cortex-m = "0.7.1" critical-section = "0.2.1" -rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e", features = ["rt"] } +rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="e8635fd05f43b6c21ec462fb8c06140e1fb26961", features = ["rt"] } embedded-hal = { version = "0.2.4", features = [ "unproven" ] } diff --git a/embassy-rp/src/clocks.rs b/embassy-rp/src/clocks.rs new file mode 100644 index 000000000..71e738c4c --- /dev/null +++ b/embassy-rp/src/clocks.rs @@ -0,0 +1,182 @@ +use pac::clocks::vals::*; + +use crate::{pac, reset}; + +const XOSC_MHZ: u32 = 12; + +pub unsafe fn init() { + // Now reset all the peripherals, except QSPI and XIP (we're using those + // to execute from external flash!) + + // Reset everything except: + // - QSPI (we're using it to run this code!) + // - PLLs (it may be suicide if that's what's clocking us) + let mut peris = reset::ALL_PERIPHERALS; + peris.set_io_qspi(false); + peris.set_pads_qspi(false); + peris.set_pll_sys(false); + peris.set_pll_usb(false); + reset::reset(peris); + + let mut peris = reset::ALL_PERIPHERALS; + peris.set_adc(false); + peris.set_rtc(false); + peris.set_spi0(false); + peris.set_spi1(false); + peris.set_uart0(false); + peris.set_uart1(false); + peris.set_usbctrl(false); + reset::unreset_wait(peris); + + // xosc 12 mhz + pac::WATCHDOG.tick().write(|w| { + w.set_cycles(XOSC_MHZ as u16); + w.set_enable(true); + }); + + let c = pac::CLOCKS; + c.clk_sys_resus_ctrl() + .write_value(pac::clocks::regs::ClkSysResusCtrl(0)); + + // Enable XOSC + const XOSC_MHZ: u32 = 12; + pac::XOSC + .ctrl() + .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); + + let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256; + pac::XOSC + .startup() + .write(|w| w.set_delay(startup_delay as u16)); + pac::XOSC.ctrl().write(|w| { + w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); + w.set_enable(pac::xosc::vals::Enable::ENABLE); + }); + while !pac::XOSC.status().read().stable() {} + + // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. + c.clk_sys_ctrl() + .modify(|w| w.set_src(ClkSysCtrlSrc::CLK_REF)); + while c.clk_sys_selected().read() != 1 {} + c.clk_ref_ctrl() + .modify(|w| w.set_src(ClkRefCtrlSrc::ROSC_CLKSRC_PH)); + while c.clk_ref_selected().read() != 1 {} + + // Configure PLLs + // REF FBDIV VCO POSTDIV + // PLL SYS: 12 / 1 = 12MHz * 125 = 1500MHZ / 6 / 2 = 125MHz + // PLL USB: 12 / 1 = 12MHz * 40 = 480 MHz / 5 / 2 = 48MHz + + let mut peris = reset::Peripherals(0); + peris.set_pll_sys(true); + peris.set_pll_usb(true); + reset::reset(peris); + reset::unreset_wait(peris); + + configure_pll(pac::PLL_SYS, 1, 1500_000_000, 6, 2); + configure_pll(pac::PLL_USB, 1, 480_000_000, 5, 2); + + // CLK_REF = XOSC (12MHz) / 1 = 12MHz2Mhz + c.clk_ref_ctrl().write(|w| { + w.set_src(ClkRefCtrlSrc::XOSC_CLKSRC); + }); + while c.clk_ref_selected().read() != 1 << ClkRefCtrlSrc::XOSC_CLKSRC.0 {} + c.clk_ref_div().write(|w| w.set_int(1)); + + // CLK SYS = PLL SYS (125MHz) / 1 = 125MHz + c.clk_sys_ctrl().write(|w| { + w.set_src(ClkSysCtrlSrc::CLK_REF); + }); + while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLK_REF.0 {} + c.clk_sys_div().write(|w| w.set_int(1)); + c.clk_sys_ctrl().write(|w| { + w.set_auxsrc(ClkSysCtrlAuxsrc::CLKSRC_PLL_SYS); + w.set_src(ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX); + }); + while c.clk_sys_selected().read() != 1 << ClkSysCtrlSrc::CLKSRC_CLK_SYS_AUX.0 {} + + // CLK USB = PLL USB (48MHz) / 1 = 48MHz + c.clk_usb_div().write(|w| w.set_int(1)); + c.clk_usb_ctrl().write(|w| { + w.set_enable(true); + w.set_auxsrc(ClkUsbCtrlAuxsrc::CLKSRC_PLL_USB); + }); + + // CLK ADC = PLL USB (48MHZ) / 1 = 48MHz + c.clk_adc_div().write(|w| w.set_int(1)); + c.clk_adc_ctrl().write(|w| { + w.set_enable(true); + w.set_auxsrc(ClkAdcCtrlAuxsrc::CLKSRC_PLL_USB); + }); + + // CLK RTC = PLL USB (48MHz) / 1024 = 46875Hz + c.clk_rtc_ctrl().modify(|w| { + w.set_enable(false); + }); + c.clk_rtc_div().write(|w| w.set_int(1024)); + c.clk_rtc_ctrl().write(|w| { + w.set_enable(true); + w.set_auxsrc(ClkRtcCtrlAuxsrc::CLKSRC_PLL_USB); + }); + + // CLK PERI = clk_sys. Used as reference clock for Peripherals. No dividers so just select and enable + // Normally choose clk_sys or clk_usb + c.clk_peri_ctrl().write(|w| { + w.set_enable(true); + w.set_auxsrc(ClkPeriCtrlAuxsrc::CLK_SYS); + }); +} + +pub(crate) fn clk_sys_freq() -> u32 { + 125_000_000 +} + +pub(crate) fn clk_peri_freq() -> u32 { + 125_000_000 +} + +pub(crate) fn clk_rtc_freq() -> u32 { + 46875 +} + +unsafe fn configure_pll( + p: pac::pll::Pll, + refdiv: u32, + vco_freq: u32, + post_div1: u8, + post_div2: u8, +) { + // Power off in case it's already running + p.pwr().write(|w| { + w.set_vcopd(true); + w.set_postdivpd(true); + w.set_dsmpd(true); + w.set_pd(true); + }); + p.fbdiv_int().write(|w| w.set_fbdiv_int(0)); + + let ref_mhz = XOSC_MHZ / refdiv; + p.cs().write(|w| w.set_refdiv(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| w.set_fbdiv_int(fbdiv as _)); + + p.pwr().modify(|w| { + w.set_pd(false); + w.set_vcopd(false); + }); + + while !p.cs().read().lock() {} + + p.prim().write(|w| { + w.set_postdiv1(post_div1); + w.set_postdiv2(post_div2); + }); + + p.pwr().modify(|w| w.set_postdivpd(false)); +} diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs index 88d5d0936..ee263fdb2 100644 --- a/embassy-rp/src/gpio.rs +++ b/embassy-rp/src/gpio.rs @@ -1,7 +1,7 @@ use core::marker::PhantomData; use crate::pac; -use crate::pac::generic::{Reg, RW}; +use crate::pac::common::{Reg, RW}; use crate::pac::SIO; use crate::peripherals; diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs index a66ced74a..80761bc50 100644 --- a/embassy-rp/src/lib.rs +++ b/embassy-rp/src/lib.rs @@ -14,10 +14,11 @@ pub mod interrupt; pub mod dma; pub mod gpio; -pub mod pll; -pub mod resets; pub mod uart; +mod clocks; +mod reset; + embassy_extras::peripherals! { PIN_0, PIN_1, @@ -93,83 +94,8 @@ pub fn init(_config: config::Config) -> Peripherals { // before doing anything important. let peripherals = Peripherals::take(); - // Now reset all the peripherals, except QSPI and XIP (we're using those - // to execute from external flash!) - - let resets = resets::Resets::new(); - - // Reset everything except: - // - QSPI (we're using it to run this code!) - // - PLLs (it may be suicide if that's what's clocking us) - let mut peris = resets::ALL_PERIPHERALS; - peris.set_io_qspi(false); - peris.set_pads_qspi(false); - peris.set_pll_sys(false); - peris.set_pll_usb(false); - resets.reset(peris); - - let mut peris = resets::ALL_PERIPHERALS; - peris.set_adc(false); - peris.set_rtc(false); - peris.set_spi0(false); - peris.set_spi1(false); - peris.set_uart0(false); - peris.set_uart1(false); - peris.set_usbctrl(false); - resets.unreset_wait(peris); - unsafe { - // xosc 12 mhz - pac::WATCHDOG.tick().write(|w| { - w.set_cycles(XOSC_MHZ as u16); - w.set_enable(true); - }); - - pac::CLOCKS - .clk_sys_resus_ctrl() - .write_value(pac::clocks::regs::ClkSysResusCtrl(0)); - - // Enable XOSC - // TODO extract to HAL module - const XOSC_MHZ: u32 = 12; - pac::XOSC - .ctrl() - .write(|w| w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ)); - - let startup_delay = (((XOSC_MHZ * 1_000_000) / 1000) + 128) / 256; - pac::XOSC - .startup() - .write(|w| w.set_delay(startup_delay as u16)); - pac::XOSC.ctrl().write(|w| { - w.set_freq_range(pac::xosc::vals::CtrlFreqRange::_1_15MHZ); - w.set_enable(pac::xosc::vals::CtrlEnable::ENABLE); - }); - while !pac::XOSC.status().read().stable() {} - - // Before we touch PLLs, switch sys and ref cleanly away from their aux sources. - pac::CLOCKS - .clk_sys_ctrl() - .modify(|w| w.set_src(pac::clocks::vals::ClkSysCtrlSrc::CLK_REF)); - while pac::CLOCKS.clk_sys_selected().read() != 1 {} - pac::CLOCKS - .clk_ref_ctrl() - .modify(|w| w.set_src(pac::clocks::vals::ClkRefCtrlSrc::ROSC_CLKSRC_PH)); - while pac::CLOCKS.clk_ref_selected().read() != 1 {} - - let mut peris = resets::Peripherals(0); - peris.set_pll_sys(true); - peris.set_pll_usb(true); - resets.reset(peris); - resets.unreset_wait(peris); - - pll::PLL::new(pll::PllSys).configure(1, 1500_000_000, 6, 2); - pll::PLL::new(pll::PllUsb).configure(1, 480_000_000, 5, 2); - - // Activate peripheral clock and take external oscillator as input - pac::CLOCKS.clk_peri_ctrl().write(|w| { - w.set_enable(true); - w.set_auxsrc(pac::clocks::vals::ClkPeriCtrlAuxsrc::XOSC_CLKSRC); - }); + clocks::init(); } peripherals diff --git a/embassy-rp/src/pll.rs b/embassy-rp/src/pll.rs deleted file mode 100644 index 13c16baf8..000000000 --- a/embassy-rp/src/pll.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::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) { - unsafe { - let p = self.inner.regs(); - // Power off in case it's already running - p.pwr().write(|w| { - w.set_vcopd(true); - w.set_postdivpd(true); - w.set_dsmpd(true); - w.set_pd(true); - }); - p.fbdiv_int().write(|w| w.set_fbdiv_int(0)); - - let ref_mhz = XOSC_MHZ / refdiv; - p.cs().write(|w| w.set_refdiv(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| w.set_fbdiv_int(fbdiv as _)); - - p.pwr().modify(|w| { - w.set_pd(false); - w.set_vcopd(false); - }); - - while !p.cs().read().lock() {} - - p.prim().write(|w| { - w.set_postdiv1(post_div1); - w.set_postdiv2(post_div2); - }); - - p.pwr().modify(|w| w.set_postdivpd(false)); - } - } -} - -mod sealed { - pub trait Instance {} - impl Instance for super::PllSys {} - impl Instance for super::PllUsb {} -} - -// todo make owned -pub struct PllSys; -pub struct PllUsb; - -pub trait Instance { - fn regs(&self) -> pac::pll::Pll; -} -impl Instance for PllSys { - fn regs(&self) -> pac::pll::Pll { - pac::PLL_SYS - } -} -impl Instance for PllUsb { - fn regs(&self) -> pac::pll::Pll { - pac::PLL_USB - } -} diff --git a/embassy-rp/src/reset.rs b/embassy-rp/src/reset.rs new file mode 100644 index 000000000..914e6a698 --- /dev/null +++ b/embassy-rp/src/reset.rs @@ -0,0 +1,17 @@ +use crate::pac; + +pub use pac::resets::regs::Peripherals; + +pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); + +pub unsafe fn reset(peris: Peripherals) { + pac::RESETS.reset().write_value(peris); +} + +pub unsafe fn unreset_wait(peris: Peripherals) { + // TODO use the "atomic clear" register version + pac::RESETS + .reset() + .modify(|v| *v = Peripherals(v.0 & !peris.0)); + while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {} +} diff --git a/embassy-rp/src/resets.rs b/embassy-rp/src/resets.rs deleted file mode 100644 index 29610e202..000000000 --- a/embassy-rp/src/resets.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::pac; - -pub use pac::resets::regs::Peripherals; - -pub const ALL_PERIPHERALS: Peripherals = Peripherals(0x01ffffff); - -pub struct Resets {} - -impl Resets { - pub fn new() -> Self { - Self {} - } - - pub fn reset(&self, peris: Peripherals) { - unsafe { - pac::RESETS.reset().write_value(peris); - } - } - - pub fn unreset_wait(&self, peris: Peripherals) { - unsafe { - // TODO use the "atomic clear" register version - pac::RESETS - .reset() - .modify(|v| *v = Peripherals(v.0 & !peris.0)); - while ((!pac::RESETS.reset_done().read().0) & peris.0) != 0 {} - } - } -} diff --git a/embassy-rp/src/uart.rs b/embassy-rp/src/uart.rs index 2c8986302..6d354e7c4 100644 --- a/embassy-rp/src/uart.rs +++ b/embassy-rp/src/uart.rs @@ -42,8 +42,7 @@ impl<'d, T: Instance> Uart<'d, T> { unsafe { let p = inner.regs(); - // todo get this from somewhere - let clk_base = 12_000_000; + let clk_base = crate::clocks::clk_peri_freq(); let baud_rate_div = (8 * clk_base) / config.baudrate; let mut baud_ibrd = baud_rate_div >> 7; diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 71b48129f..e45bf5943 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml @@ -19,7 +19,7 @@ defmt-error = [] [dependencies] embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] } embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["defmt", "defmt-trace"] } -rp2040-pac2 = { git = "https://github.com/Dirbaio/rp2040-pac", rev="254f4677937801155ca3cb17c7bb9d38eb62683e" } +rp2040-pac2 = { git = "https://github.com/embassy-rs/rp2040-pac2", rev="e8635fd05f43b6c21ec462fb8c06140e1fb26961" } atomic-polyfill = { version = "0.1.1" } defmt = "0.2.0"