Skip to content

Commit

Permalink
Merge pull request #143 from jamwaffles/add-mco
Browse files Browse the repository at this point in the history
Add MCO support
  • Loading branch information
hannobraun authored Feb 12, 2021
2 parents 9799a49 + 8097e6f commit 22aeb3a
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 0 deletions.
40 changes: 40 additions & 0 deletions examples/mco.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! Configure the MCO (Microcontroller Clock Output) to give a 2MHz signal on PA8 and PA9, sourced
//! from the internal HSI16 16MHz oscillator.
#![deny(unsafe_code)]
#![no_main]
#![no_std]

extern crate panic_halt;

use cortex_m_rt::entry;
use stm32l0xx_hal::{
pac::{
self,
rcc::cfgr::{MCOPRE_A, MCOSEL_A},
},
prelude::*,
rcc::Config,
};

#[entry]
fn main() -> ! {
let dp = pac::Peripherals::take().unwrap();

// Configure the 16MHz internal clock
let mut rcc = dp.RCC.freeze(Config::hsi16());

let gpioa = dp.GPIOA.split(&mut rcc);

// Source MCO from HSI16, configure prescaler to divide by 8 to get 2MHz output.
rcc.configure_mco(MCOSEL_A::HSI16, MCOPRE_A::DIV8, (gpioa.pa8, gpioa.pa9));

// Individual pins can also be set by passing them directly:
// rcc.enable_mco(MCOSEL_A::HSI16, MCOPRE_A::DIV8, gpioa.pa8);

// Or for larger devices, all 3 MCO pins can be configured:
// rcc.configure_mco(MCOSEL_A::HSI16, MCOPRE_A::DIV8, (gpioa.pa8, gpioa.pa9, gpiob.pb13));

// Probe PA8 or PA9 to see generated 2MHz MCO signal.
loop {}
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ pub mod gpio;
))]
pub mod i2c;
pub mod lptim;
pub mod mco;
pub mod prelude;
pub mod pwm;
pub mod pwr;
Expand Down
52 changes: 52 additions & 0 deletions src/mco.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
//! MCO (Microcontroller Clock Output)
//!
//! MCO is available on PA8 or PA9. See "Table 16. Alternate function port A" in the datasheet.
use crate::gpio::{gpioa, gpiob, AltMode, Analog};

pub trait Pin {
fn into_mco(self);
}

impl Pin for gpioa::PA8<Analog> {
fn into_mco(self) {
self.set_alt_mode(AltMode::AF0);
}
}

impl Pin for gpioa::PA9<Analog> {
fn into_mco(self) {
self.set_alt_mode(AltMode::AF0);
}
}

impl Pin for gpiob::PB13<Analog> {
fn into_mco(self) {
self.set_alt_mode(AltMode::AF2);
}
}

// Blanket impls to allow configuration of all MCO pins.
impl<P1, P2> Pin for (P1, P2)
where
P1: Pin,
P2: Pin,
{
fn into_mco(self) {
self.0.into_mco();
self.1.into_mco();
}
}

impl<P1, P2, P3> Pin for (P1, P2, P3)
where
P1: Pin,
P2: Pin,
P3: Pin,
{
fn into_mco(self) {
self.0.into_mco();
self.1.into_mco();
self.2.into_mco();
}
}
30 changes: 30 additions & 0 deletions src/rcc.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::mco;
use crate::pac::rcc::cfgr::{MCOPRE_A, MCOSEL_A};
use crate::pac::RCC;
use crate::time::{Hertz, U32Ext};

Expand Down Expand Up @@ -226,6 +228,28 @@ impl Rcc {
}
}

impl Rcc {
/// Configure MCO (Microcontroller Clock Output).
pub fn configure_mco<P>(
&mut self,
source: MCOSEL_A,
prescaler: MCOPRE_A,
output_pin: P,
) -> MCOEnabled
where
P: mco::Pin,
{
output_pin.into_mco();

self.rb.cfgr.modify(|_, w| {
w.mcosel().variant(source);
w.mcopre().variant(prescaler)
});

MCOEnabled(())
}
}

/// Extension trait that freezes the `RCC` peripheral with provided clocks configuration
pub trait RccExt {
fn freeze(self, config: Config) -> Rcc;
Expand Down Expand Up @@ -425,3 +449,9 @@ impl Clocks {
/// You can get an instance of this struct by calling [`Rcc::enable_hsi48`].
#[derive(Clone, Copy)]
pub struct HSI48(());

/// Token that exists only if MCO (Microcontroller Clock Out) has been enabled.
///
/// You can get an instance of this struct by calling [`Rcc::configure_mco`].
#[derive(Clone, Copy)]
pub struct MCOEnabled(());

0 comments on commit 22aeb3a

Please sign in to comment.