Skip to content

Commit

Permalink
Merge pull request #884 from PietPtr/feature/GpInSupport
Browse files Browse the repository at this point in the history
  • Loading branch information
thejpster authored Jan 7, 2025
2 parents 2fb6306 + a8c902f commit 3c8e39c
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 21 deletions.
79 changes: 79 additions & 0 deletions rp2040-hal-examples/src/bin/gpin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! # gpin External Clocks example
//!
//! This application demonstrates how to clock the processor using an external clock on GPIO20
//!
//! It may need to be adapted to your particular board layout and/or pin assignment.
//!
//! See the top-level `README.md` file for Copyright and license details.
#![no_std]
#![no_main]

use embedded_hal_0_2::digital::v2::ToggleableOutputPin;
// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _;

// To use the .MHz() function
use fugit::RateExtU32;

use rp2040_hal::clocks::ClockSource;
// Alias for our HAL crate
use rp2040_hal as hal;

// Necessary HAL types
use hal::{clocks::ClocksManager, gpin::GpIn0, gpio, Clock, Sio};

// A shorter alias for the Peripheral Access Crate, which provides low-level
// register access
use hal::pac;

/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
/// Note: This boot block is not necessary when using a rp-hal based BSP
/// as the BSPs already perform this step.
#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;

// The external clock provided to GPIO pin 20.
const GPIN_EXTERNAL_CLOCK_FREQ_HZ: u32 = 1_000_000u32;

/// Entry point to our bare-metal application.
///
/// The `#[rp2040_hal::entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables and the spinlock are initialised.
///
/// The function configures the RP2040 to accept an external clock on Gpio20,
/// then configures the system clock to run off this clock.
#[rp2040_hal::entry]
fn main() -> ! {
let mut pac = pac::Peripherals::take().unwrap();

let sio = Sio::new(pac.SIO);

let pins = gpio::Pins::new(
pac.IO_BANK0,
pac.PADS_BANK0,
sio.gpio_bank0,
&mut pac.RESETS,
);

let gpin0_pin = pins.gpio20.reconfigure();
let gpin0: GpIn0 = GpIn0::new(gpin0_pin, GPIN_EXTERNAL_CLOCK_FREQ_HZ.Hz());

let mut clocks = ClocksManager::new(pac.CLOCKS);

clocks
.system_clock
.configure_clock(&gpin0, gpin0.get_freq())
.unwrap();

let mut test_pin = pins.gpio0.into_push_pull_output();

loop {
// Continuously toggle a pin so it's possible to observe on a scope that the pico runs on
// the externally provided frequency, and is synchronized to it.
test_pin.toggle().unwrap();
}
}
18 changes: 8 additions & 10 deletions rp2040-hal/src/clocks/clock_sources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,8 @@
use super::*;
use crate::{
gpio::{
bank0::{Gpio20, Gpio22},
FunctionClock, Pin, PullNone, PullType,
},
gpin,
gpio::{PullNone, PullType},
rosc::{Enabled, RingOscillator},
};

Expand Down Expand Up @@ -73,17 +71,17 @@ impl ClockSource for RingOscillator<Enabled> {
}

// GPIN0
pub(crate) type GPin0<M = PullNone> = Pin<Gpio20, FunctionClock, M>;
impl<M: PullType> ClockSource for GPin0<M> {
pub(crate) type GpIn0<M = PullNone> = gpin::GpIn0<M>;
impl<M: PullType> ClockSource for GpIn0<M> {
fn get_freq(&self) -> HertzU32 {
todo!()
self.frequency()
}
}

// GPIN1
pub(crate) type GPin1<M = PullNone> = Pin<Gpio22, FunctionClock, M>;
impl<M: PullType> ClockSource for Pin<Gpio22, FunctionClock, M> {
pub(crate) type GpIn1<M = PullNone> = gpin::GpIn1<M>;
impl<M: PullType> ClockSource for GpIn1<M> {
fn get_freq(&self) -> HertzU32 {
todo!()
self.frequency()
}
}
22 changes: 11 additions & 11 deletions rp2040-hal/src/clocks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ mod clock_sources;

use clock_sources::PllSys;

use self::clock_sources::{GPin0, GPin1, PllUsb, Rosc, Xosc};
use self::clock_sources::{GpIn0, GpIn1, PllUsb, Rosc, Xosc};

bitfield::bitfield! {
/// Bit field mapping clock enable bits.
Expand Down Expand Up @@ -341,64 +341,64 @@ clocks! {
struct GpioOutput0Clock {
init_freq: 0,
reg: clk_gpout0,
auxsrc: {PllSys:CLKSRC_PLL_SYS, GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC, Xosc: XOSC_CLKSRC, SystemClock: CLK_SYS, UsbClock: CLK_USB, AdcClock: CLK_ADC, RtcClock: CLK_RTC, ReferenceClock:CLK_REF}
auxsrc: {PllSys:CLKSRC_PLL_SYS, GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC, Xosc: XOSC_CLKSRC, SystemClock: CLK_SYS, UsbClock: CLK_USB, AdcClock: CLK_ADC, RtcClock: CLK_RTC, ReferenceClock:CLK_REF}
}
/// GPIO Output 1 Clock
struct GpioOutput1Clock {
init_freq: 0,
reg: clk_gpout1,
auxsrc: {PllSys:CLKSRC_PLL_SYS, GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC, Xosc: XOSC_CLKSRC, SystemClock: CLK_SYS, UsbClock: CLK_USB, AdcClock: CLK_ADC, RtcClock: CLK_RTC, ReferenceClock:CLK_REF}
auxsrc: {PllSys:CLKSRC_PLL_SYS, GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC, Xosc: XOSC_CLKSRC, SystemClock: CLK_SYS, UsbClock: CLK_USB, AdcClock: CLK_ADC, RtcClock: CLK_RTC, ReferenceClock:CLK_REF}
}
/// GPIO Output 2 Clock
struct GpioOutput2Clock {
init_freq: 0,
reg: clk_gpout2,
auxsrc: {PllSys:CLKSRC_PLL_SYS, GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC, SystemClock: CLK_SYS, UsbClock: CLK_USB, AdcClock: CLK_ADC, RtcClock: CLK_RTC, ReferenceClock:CLK_REF}
auxsrc: {PllSys:CLKSRC_PLL_SYS, GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC, SystemClock: CLK_SYS, UsbClock: CLK_USB, AdcClock: CLK_ADC, RtcClock: CLK_RTC, ReferenceClock:CLK_REF}
}
/// GPIO Output 3 Clock
struct GpioOutput3Clock {
init_freq: 0,
reg: clk_gpout3,
auxsrc: {PllSys:CLKSRC_PLL_SYS, GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC, SystemClock: CLK_SYS, UsbClock: CLK_USB, AdcClock: CLK_ADC, RtcClock: CLK_RTC, ReferenceClock:CLK_REF}
auxsrc: {PllSys:CLKSRC_PLL_SYS, GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC, SystemClock: CLK_SYS, UsbClock: CLK_USB, AdcClock: CLK_ADC, RtcClock: CLK_RTC, ReferenceClock:CLK_REF}
}
/// Reference Clock
struct ReferenceClock {
init_freq: 12_000_000, // Starts from ROSC which actually varies with input voltage etc, but 12 MHz seems to be a good value
reg: clk_ref,
src: {Rosc: ROSC_CLKSRC_PH, Xosc:XOSC_CLKSRC},
auxsrc: {PllUsb:CLKSRC_PLL_USB, GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1}
auxsrc: {PllUsb:CLKSRC_PLL_USB, GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1}
}
/// System Clock
struct SystemClock {
init_freq: 12_000_000, // ref_clk is 12 MHz
reg: clk_sys,
src: {ReferenceClock: CLK_REF},
auxsrc: {PllSys: CLKSRC_PLL_SYS, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC, Xosc: XOSC_CLKSRC,GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1}
auxsrc: {PllSys: CLKSRC_PLL_SYS, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC, Xosc: XOSC_CLKSRC,GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1}
}
/// Peripheral Clock
struct PeripheralClock {
init_freq: 12_000_000, // sys_clk is 12 MHz
reg: clk_peri,
auxsrc: {SystemClock: CLK_SYS, PllSys: CLKSRC_PLL_SYS, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC,GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1 },
auxsrc: {SystemClock: CLK_SYS, PllSys: CLKSRC_PLL_SYS, PllUsb:CLKSRC_PLL_USB, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC,GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1 },
div: false
}
/// USB Clock
struct UsbClock {
init_freq: 0,
reg: clk_usb,
auxsrc: {PllUsb:CLKSRC_PLL_USB,PllSys: CLKSRC_PLL_SYS, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC,GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1}
auxsrc: {PllUsb:CLKSRC_PLL_USB,PllSys: CLKSRC_PLL_SYS, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC,GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1}
}
/// Adc Clock
struct AdcClock {
init_freq: 0,
reg: clk_adc,
auxsrc: {PllUsb:CLKSRC_PLL_USB,PllSys: CLKSRC_PLL_SYS, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC,GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1}
auxsrc: {PllUsb:CLKSRC_PLL_USB,PllSys: CLKSRC_PLL_SYS, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC,GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1}
}
/// RTC Clock
struct RtcClock {
init_freq: 0,
reg: clk_rtc,
auxsrc: {PllUsb:CLKSRC_PLL_USB,PllSys: CLKSRC_PLL_SYS, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC,GPin0:CLKSRC_GPIN0, GPin1:CLKSRC_GPIN1}
auxsrc: {PllUsb:CLKSRC_PLL_USB,PllSys: CLKSRC_PLL_SYS, Rosc: ROSC_CLKSRC_PH, Xosc: XOSC_CLKSRC,GpIn0:CLKSRC_GPIN0, GpIn1:CLKSRC_GPIN1}
}
}

Expand Down
56 changes: 56 additions & 0 deletions rp2040-hal/src/gpin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//! Defines a wrapper for the GPIO pins that can route external clocks into the RP2040.
//!
//! See [2.15.2.3. External Clocks](https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf) for more details.
//! Or see [examples/gpin.rs](https://github.com/rp-rs/rp-hal/tree/main/rp2040-hal-examples/src/bin/gpin.rs) for a practical example
use fugit::HertzU32;

use crate::{
gpio::{
bank0::{Gpio20, Gpio22},
FunctionClock, Pin, PullNone, PullType,
},
typelevel::Sealed,
};

macro_rules! gpin {
($id:ident, $pin:ident) => {
/// A gpin pin: a pin that can be used as a clock input.
pub struct $id<M = PullNone>
where
M: PullType,
{
pin: Pin<$pin, FunctionClock, M>,
frequency: HertzU32,
}

impl<M: PullType> $id<M> {
#[doc = concat!("Creates a new ", stringify!($id), " given the input pin.")]
pub fn new(pin: Pin<$pin, FunctionClock, M>, frequency: HertzU32) -> Self {
Self { pin, frequency }
}

/// Set the frequency of the externally applied clock signal.
/// This frequency is used when computing clock dividers.
pub fn set_frequency(mut self, frequency: HertzU32) -> Self {
self.frequency = frequency;
self
}

/// Retrieve frequency
pub fn frequency(&self) -> HertzU32 {
self.frequency
}

#[doc = concat!("Release the underlying device and ", stringify!($pin), ".")]
pub fn free(self) -> Pin<$pin, FunctionClock, M> {
self.pin
}
}

impl<M: PullType> Sealed for $id<M> {}
};
}

gpin!(GpIn0, Gpio20);
gpin!(GpIn1, Gpio22);
1 change: 1 addition & 0 deletions rp2040-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub mod clocks;
mod critical_section_impl;
pub mod dma;
mod float;
pub mod gpin;
pub mod gpio;
pub mod i2c;
pub mod multicore;
Expand Down

0 comments on commit 3c8e39c

Please sign in to comment.