From bce909ec1eea95f93a6887aae5aa0b37d953ec85 Mon Sep 17 00:00:00 2001 From: Mariusz Ryndzionek Date: Sun, 26 Sep 2021 17:08:22 +0200 Subject: [PATCH 1/3] Initial STM32F1 family support with two examples for STM32F103C8 (Blue Pill) --- .github/workflows/rust.yml | 2 + embassy-stm32/Cargo.toml | 96 +++++++++++ embassy-stm32/src/exti.rs | 10 +- embassy-stm32/src/gpio.rs | 135 ++++++++++++++-- embassy-stm32/src/i2c/mod.rs | 1 + embassy-stm32/src/rcc/f1/mod.rs | 214 +++++++++++++++++++++++++ embassy-stm32/src/rcc/mod.rs | 5 +- embassy-stm32/src/usart/mod.rs | 1 + examples/stm32f1/.cargo/config.toml | 18 +++ examples/stm32f1/Cargo.toml | 35 ++++ examples/stm32f1/src/bin/blinky.rs | 29 ++++ examples/stm32f1/src/bin/hello.rs | 27 ++++ examples/stm32f1/src/example_common.rs | 17 ++ stm32-gen-features/src/lib.rs | 3 +- 14 files changed, 573 insertions(+), 20 deletions(-) create mode 100644 embassy-stm32/src/rcc/f1/mod.rs create mode 100644 examples/stm32f1/.cargo/config.toml create mode 100644 examples/stm32f1/Cargo.toml create mode 100644 examples/stm32f1/src/bin/blinky.rs create mode 100644 examples/stm32f1/src/bin/hello.rs create mode 100644 examples/stm32f1/src/example_common.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5cdf75d7b..b728c0db8 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -101,6 +101,8 @@ jobs: target: thumbv6m-none-eabi - package: examples/wasm target: wasm32-unknown-unknown + - package: examples/stm32f1 + target: thumbv7m-none-eabi steps: - uses: actions/checkout@v2 with: diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index aedb54b74..6881f13e8 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -28,6 +28,7 @@ stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt" vcell = { version = "0.1.3", optional = true } bxcan = "0.5.1" seq-macro = "0.2.2" +cast = { version = "0.2.2", default-features = false } cfg-if = "1.0.0" @@ -134,6 +135,101 @@ stm32f091vc = [ "stm32-metapac/stm32f091vc" ] stm32f098cc = [ "stm32-metapac/stm32f098cc" ] stm32f098rc = [ "stm32-metapac/stm32f098rc" ] stm32f098vc = [ "stm32-metapac/stm32f098vc" ] +stm32f100c4 = [ "stm32-metapac/stm32f100c4" ] +stm32f100c6 = [ "stm32-metapac/stm32f100c6" ] +stm32f100c8 = [ "stm32-metapac/stm32f100c8" ] +stm32f100cb = [ "stm32-metapac/stm32f100cb" ] +stm32f100r4 = [ "stm32-metapac/stm32f100r4" ] +stm32f100r6 = [ "stm32-metapac/stm32f100r6" ] +stm32f100r8 = [ "stm32-metapac/stm32f100r8" ] +stm32f100rb = [ "stm32-metapac/stm32f100rb" ] +stm32f100rc = [ "stm32-metapac/stm32f100rc" ] +stm32f100rd = [ "stm32-metapac/stm32f100rd" ] +stm32f100re = [ "stm32-metapac/stm32f100re" ] +stm32f100v8 = [ "stm32-metapac/stm32f100v8" ] +stm32f100vb = [ "stm32-metapac/stm32f100vb" ] +stm32f100vc = [ "stm32-metapac/stm32f100vc" ] +stm32f100vd = [ "stm32-metapac/stm32f100vd" ] +stm32f100ve = [ "stm32-metapac/stm32f100ve" ] +stm32f100zc = [ "stm32-metapac/stm32f100zc" ] +stm32f100zd = [ "stm32-metapac/stm32f100zd" ] +stm32f100ze = [ "stm32-metapac/stm32f100ze" ] +stm32f101c4 = [ "stm32-metapac/stm32f101c4" ] +stm32f101c6 = [ "stm32-metapac/stm32f101c6" ] +stm32f101c8 = [ "stm32-metapac/stm32f101c8" ] +stm32f101cb = [ "stm32-metapac/stm32f101cb" ] +stm32f101r4 = [ "stm32-metapac/stm32f101r4" ] +stm32f101r6 = [ "stm32-metapac/stm32f101r6" ] +stm32f101r8 = [ "stm32-metapac/stm32f101r8" ] +stm32f101rb = [ "stm32-metapac/stm32f101rb" ] +stm32f101rc = [ "stm32-metapac/stm32f101rc" ] +stm32f101rd = [ "stm32-metapac/stm32f101rd" ] +stm32f101re = [ "stm32-metapac/stm32f101re" ] +stm32f101rf = [ "stm32-metapac/stm32f101rf" ] +stm32f101rg = [ "stm32-metapac/stm32f101rg" ] +stm32f101t4 = [ "stm32-metapac/stm32f101t4" ] +stm32f101t6 = [ "stm32-metapac/stm32f101t6" ] +stm32f101t8 = [ "stm32-metapac/stm32f101t8" ] +stm32f101tb = [ "stm32-metapac/stm32f101tb" ] +stm32f101v8 = [ "stm32-metapac/stm32f101v8" ] +stm32f101vb = [ "stm32-metapac/stm32f101vb" ] +stm32f101vc = [ "stm32-metapac/stm32f101vc" ] +stm32f101vd = [ "stm32-metapac/stm32f101vd" ] +stm32f101ve = [ "stm32-metapac/stm32f101ve" ] +stm32f101vf = [ "stm32-metapac/stm32f101vf" ] +stm32f101vg = [ "stm32-metapac/stm32f101vg" ] +stm32f101zc = [ "stm32-metapac/stm32f101zc" ] +stm32f101zd = [ "stm32-metapac/stm32f101zd" ] +stm32f101ze = [ "stm32-metapac/stm32f101ze" ] +stm32f101zf = [ "stm32-metapac/stm32f101zf" ] +stm32f101zg = [ "stm32-metapac/stm32f101zg" ] +stm32f102c4 = [ "stm32-metapac/stm32f102c4" ] +stm32f102c6 = [ "stm32-metapac/stm32f102c6" ] +stm32f102c8 = [ "stm32-metapac/stm32f102c8" ] +stm32f102cb = [ "stm32-metapac/stm32f102cb" ] +stm32f102r4 = [ "stm32-metapac/stm32f102r4" ] +stm32f102r6 = [ "stm32-metapac/stm32f102r6" ] +stm32f102r8 = [ "stm32-metapac/stm32f102r8" ] +stm32f102rb = [ "stm32-metapac/stm32f102rb" ] +stm32f103c4 = [ "stm32-metapac/stm32f103c4" ] +stm32f103c6 = [ "stm32-metapac/stm32f103c6" ] +stm32f103c8 = [ "stm32-metapac/stm32f103c8" ] +stm32f103cb = [ "stm32-metapac/stm32f103cb" ] +stm32f103r4 = [ "stm32-metapac/stm32f103r4" ] +stm32f103r6 = [ "stm32-metapac/stm32f103r6" ] +stm32f103r8 = [ "stm32-metapac/stm32f103r8" ] +stm32f103rb = [ "stm32-metapac/stm32f103rb" ] +stm32f103rc = [ "stm32-metapac/stm32f103rc" ] +stm32f103rd = [ "stm32-metapac/stm32f103rd" ] +stm32f103re = [ "stm32-metapac/stm32f103re" ] +stm32f103rf = [ "stm32-metapac/stm32f103rf" ] +stm32f103rg = [ "stm32-metapac/stm32f103rg" ] +stm32f103t4 = [ "stm32-metapac/stm32f103t4" ] +stm32f103t6 = [ "stm32-metapac/stm32f103t6" ] +stm32f103t8 = [ "stm32-metapac/stm32f103t8" ] +stm32f103tb = [ "stm32-metapac/stm32f103tb" ] +stm32f103v8 = [ "stm32-metapac/stm32f103v8" ] +stm32f103vb = [ "stm32-metapac/stm32f103vb" ] +stm32f103vc = [ "stm32-metapac/stm32f103vc" ] +stm32f103vd = [ "stm32-metapac/stm32f103vd" ] +stm32f103ve = [ "stm32-metapac/stm32f103ve" ] +stm32f103vf = [ "stm32-metapac/stm32f103vf" ] +stm32f103vg = [ "stm32-metapac/stm32f103vg" ] +stm32f103zc = [ "stm32-metapac/stm32f103zc" ] +stm32f103zd = [ "stm32-metapac/stm32f103zd" ] +stm32f103ze = [ "stm32-metapac/stm32f103ze" ] +stm32f103zf = [ "stm32-metapac/stm32f103zf" ] +stm32f103zg = [ "stm32-metapac/stm32f103zg" ] +stm32f105r8 = [ "stm32-metapac/stm32f105r8" ] +stm32f105rb = [ "stm32-metapac/stm32f105rb" ] +stm32f105rc = [ "stm32-metapac/stm32f105rc" ] +stm32f105v8 = [ "stm32-metapac/stm32f105v8" ] +stm32f105vb = [ "stm32-metapac/stm32f105vb" ] +stm32f105vc = [ "stm32-metapac/stm32f105vc" ] +stm32f107rb = [ "stm32-metapac/stm32f107rb" ] +stm32f107rc = [ "stm32-metapac/stm32f107rc" ] +stm32f107vb = [ "stm32-metapac/stm32f107vb" ] +stm32f107vc = [ "stm32-metapac/stm32f107vc" ] stm32f401cb = [ "stm32-metapac/stm32f401cb" ] stm32f401cc = [ "stm32-metapac/stm32f401cc" ] stm32f401cd = [ "stm32-metapac/stm32f401cd" ] diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs index 6d3de3a15..565b92f32 100644 --- a/embassy-stm32/src/exti.rs +++ b/embassy-stm32/src/exti.rs @@ -30,7 +30,7 @@ fn cpu_regs() -> pac::exti::Exti { EXTI } -#[cfg(not(any(exti_g0, exti_l5)))] +#[cfg(not(any(exti_g0, exti_l5, gpio_v1)))] fn exticr_regs() -> pac::syscfg::Syscfg { pac::SYSCFG } @@ -38,6 +38,10 @@ fn exticr_regs() -> pac::syscfg::Syscfg { fn exticr_regs() -> pac::exti::Exti { EXTI } +#[cfg(gpio_v1)] +fn exticr_regs() -> pac::afio::Afio { + pac::AFIO +} pub unsafe fn on_irq() { #[cfg(not(any(exti_g0, exti_l5)))] @@ -296,6 +300,8 @@ pub(crate) unsafe fn init() { foreach_exti_irq!(enable_irq); - #[cfg(not(any(rcc_wb, rcc_wl5)))] + #[cfg(not(any(rcc_wb, rcc_wl5, rcc_f1)))] ::enable(); + #[cfg(rcc_f1)] + ::enable(); } diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index a67d4e73f..c7b644e94 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -18,6 +18,7 @@ pub enum Pull { Down, } +#[cfg(gpio_v2)] impl From for vals::Pupdr { fn from(pull: Pull) -> Self { use Pull::*; @@ -36,11 +37,25 @@ impl From for vals::Pupdr { pub enum Speed { Low, Medium, - #[cfg(not(syscfg_f0))] + #[cfg(not(any(syscfg_f0, gpio_v1)))] High, VeryHigh, } +#[cfg(gpio_v1)] +impl From for vals::Mode { + fn from(speed: Speed) -> Self { + use Speed::*; + + match speed { + Low => vals::Mode::OUTPUT2, + Medium => vals::Mode::OUTPUT, + VeryHigh => vals::Mode::OUTPUT50, + } + } +} + +#[cfg(gpio_v2)] impl From for vals::Ospeedr { fn from(speed: Speed) -> Self { use Speed::*; @@ -68,9 +83,29 @@ impl<'d, T: Pin> Input<'d, T> { cortex_m::interrupt::free(|_| unsafe { let r = pin.block(); let n = pin.pin() as usize; - r.pupdr().modify(|w| w.set_pupdr(n, pull.into())); - r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); - r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); + #[cfg(gpio_v1)] + { + let crlh = if n < 8 { 0 } else { 1 }; + match pull { + Pull::Up => r.bsrr().write(|w| w.set_bs(n, true)), + Pull::Down => r.bsrr().write(|w| w.set_br(n, true)), + Pull::None => {} + } + if pull == Pull::None { + r.cr(crlh) + .modify(|w| w.set_cnf(n % 8, vals::Cnf::OPENDRAIN)); + } else { + r.cr(crlh) + .modify(|w| w.set_cnf(n % 8, vals::Cnf::ALTPUSHPULL)); + } + r.cr(crlh).modify(|w| w.set_mode(n % 8, vals::Mode::INPUT)); + } + #[cfg(gpio_v2)] + { + r.pupdr().modify(|w| w.set_pupdr(n, pull.into())); + r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); + r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); + } }); Self { @@ -85,6 +120,13 @@ impl<'d, T: Pin> Drop for Input<'d, T> { cortex_m::interrupt::free(|_| unsafe { let r = self.pin.block(); let n = self.pin.pin() as usize; + #[cfg(gpio_v1)] + { + let crlh = if n < 8 { 0 } else { 1 }; + r.cr(crlh) + .modify(|w| w.set_cnf(n % 8, vals::Cnf::OPENDRAIN)); + } + #[cfg(gpio_v2)] r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); }); } @@ -129,10 +171,19 @@ impl<'d, T: Pin> Output<'d, T> { cortex_m::interrupt::free(|_| unsafe { let r = pin.block(); let n = pin.pin() as usize; - r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); - r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); - pin.set_speed(speed); - r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); + #[cfg(gpio_v1)] + { + let crlh = if n < 8 { 0 } else { 1 }; + r.cr(crlh).modify(|w| w.set_cnf(n % 8, vals::Cnf::PUSHPULL)); + r.cr(crlh).modify(|w| w.set_mode(n % 8, speed.into())); + } + #[cfg(gpio_v2)] + { + r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); + r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); + pin.set_speed(speed); + r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); + } }); Self { @@ -147,8 +198,18 @@ impl<'d, T: Pin> Drop for Output<'d, T> { cortex_m::interrupt::free(|_| unsafe { let r = self.pin.block(); let n = self.pin.pin() as usize; - r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); - r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); + #[cfg(gpio_v1)] + { + let crlh = if n < 8 { 0 } else { 1 }; + r.cr(crlh) + .modify(|w| w.set_cnf(n % 8, vals::Cnf::OPENDRAIN)); + r.cr(crlh).modify(|w| w.set_mode(n % 8, vals::Mode::INPUT)); + } + #[cfg(gpio_v2)] + { + r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); + r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); + } }); } } @@ -207,10 +268,25 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> { cortex_m::interrupt::free(|_| unsafe { let r = pin.block(); let n = pin.pin() as usize; - r.pupdr().modify(|w| w.set_pupdr(n, pull.into())); - r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN)); - pin.set_speed(speed); - r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); + #[cfg(gpio_v1)] + { + let crlh = if n < 8 { 0 } else { 1 }; + match pull { + Pull::Up => r.bsrr().write(|w| w.set_bs(n, true)), + Pull::Down => r.bsrr().write(|w| w.set_br(n, true)), + Pull::None => {} + } + r.cr(crlh).modify(|w| w.set_mode(n % 8, speed.into())); + r.cr(crlh) + .modify(|w| w.set_cnf(n % 8, vals::Cnf::OPENDRAIN)); + } + #[cfg(gpio_v2)] + { + r.pupdr().modify(|w| w.set_pupdr(n, pull.into())); + r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN)); + pin.set_speed(speed); + r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); + } }); Self { @@ -225,8 +301,18 @@ impl<'d, T: Pin> Drop for OutputOpenDrain<'d, T> { cortex_m::interrupt::free(|_| unsafe { let r = self.pin.block(); let n = self.pin.pin() as usize; - r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); - r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); + #[cfg(gpio_v1)] + { + let crlh = if n < 8 { 0 } else { 1 }; + r.cr(crlh) + .modify(|w| w.set_cnf(n % 8, vals::Cnf::OPENDRAIN)); + r.cr(crlh).modify(|w| w.set_mode(n % 8, vals::Mode::INPUT)); + } + #[cfg(gpio_v2)] + { + r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); + r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); + } }); } } @@ -307,6 +393,11 @@ pub(crate) mod sealed { } } + #[cfg(gpio_v1)] + unsafe fn set_as_af(&self, _af_num: u8, _af_type: OutputType) { + panic!("F1 alternate GPIO functions not supported yet!"); + } + #[cfg(gpio_v2)] unsafe fn set_as_af(&self, af_num: u8, af_type: OutputType) { let pin = self._pin() as usize; let block = self.block(); @@ -333,11 +424,23 @@ pub(crate) mod sealed { unsafe fn set_as_analog(&self) { let pin = self._pin() as usize; let block = self.block(); + #[cfg(gpio_v1)] + { + let crlh = if pin < 8 { 0 } else { 1 }; + block + .cr(crlh) + .modify(|w| w.set_cnf(pin % 8, vals::Cnf::PUSHPULL)); + block + .cr(crlh) + .modify(|w| w.set_mode(pin % 8, vals::Mode::INPUT)); + } + #[cfg(gpio_v2)] block .moder() .modify(|w| w.set_moder(pin, vals::Moder::ANALOG)); } + #[cfg(gpio_v2)] unsafe fn set_speed(&self, speed: Speed) { let pin = self._pin() as usize; self.block() diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 523a0b83a..4af5051db 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -96,6 +96,7 @@ crate::pac::interrupts!( }; ); +#[cfg(not(rcc_f1))] macro_rules! impl_pin { ($inst:ident, $pin:ident, $signal:ident, $af:expr) => { impl $signal for peripherals::$pin {} diff --git a/embassy-stm32/src/rcc/f1/mod.rs b/embassy-stm32/src/rcc/f1/mod.rs new file mode 100644 index 000000000..75367d421 --- /dev/null +++ b/embassy-stm32/src/rcc/f1/mod.rs @@ -0,0 +1,214 @@ +use core::marker::PhantomData; + +use embassy::util::Unborrow; + +use crate::pac::flash::vals::Latency; +use crate::pac::{FLASH, RCC}; +use crate::peripherals; +use crate::time::Hertz; + +use cast::u32; + +use super::{set_freqs, Clocks}; + +const HSI: u32 = 8_000_000; + +/// Configuration of the clocks +/// +#[non_exhaustive] +#[derive(Default)] +pub struct Config { + pub hse: Option, + + pub sys_ck: Option, + pub hclk: Option, + pub pclk1: Option, + pub pclk2: Option, + pub adcclk: Option, +} + +pub struct Rcc<'d> { + inner: PhantomData<&'d ()>, + config: Config, +} + +impl<'d> Rcc<'d> { + pub fn new(_rcc: impl Unborrow + 'd, config: Config) -> Self { + Self { + inner: PhantomData, + config, + } + } + + pub fn freeze(self) -> Clocks { + use crate::pac::rcc::vals::{Adcpre, Hpre, Pllmul, Pllsrc, Ppre1, Sw, Usbpre}; + + let pllsrcclk = self.config.hse.map(|hse| hse.0).unwrap_or(HSI / 2); + let sysclk = self.config.sys_ck.map(|sys| sys.0).unwrap_or(pllsrcclk); + let pllmul = sysclk / pllsrcclk; + + let (pllmul_bits, real_sysclk) = if pllmul == 1 { + (None, self.config.hse.map(|hse| hse.0).unwrap_or(HSI)) + } else { + let pllmul = core::cmp::min(core::cmp::max(pllmul, 1), 16); + (Some(pllmul as u8 - 2), pllsrcclk * pllmul) + }; + + assert!(real_sysclk <= 72_000_000); + + let hpre_bits = self + .config + .hclk + .map(|hclk| match real_sysclk / hclk.0 { + 0 => unreachable!(), + 1 => 0b0111, + 2 => 0b1000, + 3..=5 => 0b1001, + 6..=11 => 0b1010, + 12..=39 => 0b1011, + 40..=95 => 0b1100, + 96..=191 => 0b1101, + 192..=383 => 0b1110, + _ => 0b1111, + }) + .unwrap_or(0b0111); + + let hclk = if hpre_bits >= 0b1100 { + real_sysclk / (1 << (hpre_bits - 0b0110)) + } else { + real_sysclk / (1 << (hpre_bits - 0b0111)) + }; + + assert!(hclk <= 72_000_000); + + let ppre1_bits = self + .config + .pclk1 + .map(|pclk1| match hclk / pclk1.0 { + 0 => unreachable!(), + 1 => 0b011, + 2 => 0b100, + 3..=5 => 0b101, + 6..=11 => 0b110, + _ => 0b111, + }) + .unwrap_or(0b011); + + let ppre1: i32 = 1 << (ppre1_bits - 0b011); + let pclk1 = hclk / u32(ppre1).unwrap(); + let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; + + assert!(pclk1 <= 36_000_000); + + let ppre2_bits = self + .config + .pclk2 + .map(|pclk2| match hclk / pclk2.0 { + 0 => unreachable!(), + 1 => 0b011, + 2 => 0b100, + 3..=5 => 0b101, + 6..=11 => 0b110, + _ => 0b111, + }) + .unwrap_or(0b011); + + let ppre2: i32 = 1 << (ppre2_bits - 0b011); + let pclk2 = hclk / u32(ppre2).unwrap(); + let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; + + assert!(pclk2 <= 72_000_000); + + // Only needed for stm32f103? + // NOTE(safety) Atomic write + unsafe { + FLASH.acr().write(|w| { + w.set_latency(if real_sysclk <= 24_000_000 { + Latency(0b000) + } else if real_sysclk <= 48_000_000 { + Latency(0b001) + } else { + Latency(0b010) + }); + }) + } + + // the USB clock is only valid if an external crystal is used, the PLL is enabled, and the + // PLL output frequency is a supported one. + // usbpre == false: divide clock by 1.5, otherwise no division + let (usbpre, _usbclk_valid) = match (self.config.hse, pllmul_bits, real_sysclk) { + (Some(_), Some(_), 72_000_000) => (false, true), + (Some(_), Some(_), 48_000_000) => (true, true), + _ => (true, false), + }; + + let apre_bits: u8 = self + .config + .adcclk + .map(|adcclk| match pclk2 / adcclk.0 { + 0..=2 => 0b00, + 3..=4 => 0b01, + 5..=7 => 0b10, + _ => 0b11, + }) + .unwrap_or(0b11); + + let apre = (apre_bits + 1) << 1; + let adcclk = pclk2 / u32(apre); + + assert!(adcclk <= 14_000_000); + + unsafe { + if self.config.hse.is_some() { + // enable HSE and wait for it to be ready + RCC.cr().modify(|w| w.set_hseon(true)); + while !RCC.cr().read().hserdy() {} + } + + if let Some(pllmul_bits) = pllmul_bits { + // enable PLL and wait for it to be ready + RCC.cfgr().modify(|w| { + w.set_pllmul(Pllmul(pllmul_bits)); + w.set_pllsrc(Pllsrc(self.config.hse.is_some() as u8)); + }); + + RCC.cr().modify(|w| w.set_pllon(true)); + while !RCC.cr().read().pllrdy() {} + } + + // Only needed for stm32f103? + RCC.cfgr().modify(|w| { + w.set_adcpre(Adcpre(apre_bits)); + w.set_ppre2(Ppre1(ppre2_bits)); + w.set_ppre1(Ppre1(ppre1_bits)); + w.set_hpre(Hpre(hpre_bits)); + w.set_usbpre(Usbpre(usbpre as u8)); + w.set_sw(Sw(if pllmul_bits.is_some() { + // PLL + 0b10 + } else if self.config.hse.is_some() { + // HSE + 0b1 + } else { + // HSI + 0b0 + })); + }); + } + + Clocks { + sys: Hertz(real_sysclk), + apb1: Hertz(pclk1), + apb2: Hertz(pclk2), + apb1_tim: Hertz(pclk1 * timer_mul1), + apb2_tim: Hertz(pclk2 * timer_mul2), + ahb: Hertz(hclk), + } + } +} + +pub unsafe fn init(config: Config) { + let rcc = Rcc::new(::steal(), config); + let clocks = rcc.freeze(); + set_freqs(clocks); +} diff --git a/embassy-stm32/src/rcc/mod.rs b/embassy-stm32/src/rcc/mod.rs index d6b4bec5f..ef1d6a859 100644 --- a/embassy-stm32/src/rcc/mod.rs +++ b/embassy-stm32/src/rcc/mod.rs @@ -27,7 +27,7 @@ pub struct Clocks { #[cfg(rcc_wl5)] pub apb3: Hertz, - #[cfg(any(rcc_l0, rcc_l1, rcc_f0, rcc_f0x0, rcc_g0))] + #[cfg(any(rcc_l0, rcc_l1, rcc_f0, rcc_f1, rcc_f0x0, rcc_g0))] pub ahb: Hertz, #[cfg(any(rcc_l4, rcc_f4, rcc_h7, rcc_wb, rcc_wl5))] @@ -79,6 +79,9 @@ cfg_if::cfg_if! { } else if #[cfg(rcc_l4)] { mod l4; pub use l4::*; + } else if #[cfg(rcc_f1)] { + mod f1; + pub use f1::*; } else if #[cfg(rcc_f4)] { mod f4; pub use f4::*; diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index c1cdd8d73..e64f8d1d9 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -127,6 +127,7 @@ crate::pac::interrupts!( }; ); +#[cfg(not(rcc_f1))] macro_rules! impl_pin { ($inst:ident, $pin:ident, $signal:ident, $af:expr) => { impl sealed::$signal for peripherals::$pin { diff --git a/examples/stm32f1/.cargo/config.toml b/examples/stm32f1/.cargo/config.toml new file mode 100644 index 000000000..28df61383 --- /dev/null +++ b/examples/stm32f1/.cargo/config.toml @@ -0,0 +1,18 @@ +[target.'cfg(all(target_arch = "arm", target_os = "none"))'] +# replace STM32F103C8 with your chip as listed in `probe-run --list-chips` +runner = "probe-run --chip STM32F103C8" + +rustflags = [ + # LLD (shipped with the Rust toolchain) is used as the default linker + "-C", "link-arg=--nmagic", + "-C", "link-arg=-Tlink.x", + "-C", "link-arg=-Tdefmt.x", + + # Code-size optimizations. + "-Z", "trap-unreachable=no", + "-C", "inline-threshold=5", + "-C", "no-vectorize-loops", +] + +[build] +target = "thumbv7m-none-eabi" diff --git a/examples/stm32f1/Cargo.toml b/examples/stm32f1/Cargo.toml new file mode 100644 index 000000000..9b4e831ef --- /dev/null +++ b/examples/stm32f1/Cargo.toml @@ -0,0 +1,35 @@ +[package] +authors = ["Dario Nieuwenhuis "] +edition = "2018" +name = "embassy-stm32f1-examples" +version = "0.1.0" +resolver = "2" + +[features] +default = [ + "defmt-default", +] +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] + +[dependencies] +embassy = { version = "0.1.0", path = "../../embassy", features = ["defmt", "defmt-trace"] } +embassy-traits = { version = "0.1.0", path = "../../embassy-traits", features = ["defmt"] } +embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "defmt-trace", "stm32f103c8", "unstable-pac", "memory-x", "time-driver-tim2"] } +embassy-hal-common = {version = "0.1.0", path = "../../embassy-hal-common" } + +defmt = "0.2.3" +defmt-rtt = "0.2.0" + +cortex-m = "0.7.3" +cortex-m-rt = "0.7.0" +embedded-hal = "0.2.6" +panic-probe = { version = "0.2.0", features = ["print-defmt"] } +futures = { version = "0.3.17", default-features = false, features = ["async-await"] } +rtt-target = { version = "0.3.1", features = ["cortex-m"] } +heapless = { version = "0.7.5", default-features = false } +nb = "1.0.0" diff --git a/examples/stm32f1/src/bin/blinky.rs b/examples/stm32f1/src/bin/blinky.rs new file mode 100644 index 000000000..1e4f2deec --- /dev/null +++ b/examples/stm32f1/src/bin/blinky.rs @@ -0,0 +1,29 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +#[path = "../example_common.rs"] +mod example_common; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_stm32::gpio::{Level, Output, Speed}; +use embassy_stm32::Peripherals; +use embedded_hal::digital::v2::OutputPin; +use example_common::*; + +#[embassy::main] +async fn main(_spawner: Spawner, p: Peripherals) { + info!("Hello World!"); + + let mut led = Output::new(p.PC13, Level::High, Speed::Low); + + loop { + info!("high"); + unwrap!(led.set_high()); + Timer::after(Duration::from_millis(300)).await; + + info!("low"); + unwrap!(led.set_low()); + Timer::after(Duration::from_millis(300)).await; + } +} diff --git a/examples/stm32f1/src/bin/hello.rs b/examples/stm32f1/src/bin/hello.rs new file mode 100644 index 000000000..efcb9a244 --- /dev/null +++ b/examples/stm32f1/src/bin/hello.rs @@ -0,0 +1,27 @@ +#![no_std] +#![no_main] +#![feature(type_alias_impl_trait)] + +use defmt::info; +use embassy::executor::Spawner; +use embassy::time::{Duration, Timer}; +use embassy_stm32::time::Hertz; +use embassy_stm32::Config; +use embassy_stm32::Peripherals; + +#[path = "../example_common.rs"] +mod example_common; + +fn config() -> Config { + let mut config = Config::default(); + config.rcc.sys_ck = Some(Hertz(36_000_000)); + config +} + +#[embassy::main(config = "config()")] +async fn main(_spawner: Spawner, _p: Peripherals) -> ! { + loop { + info!("Hello World!"); + Timer::after(Duration::from_secs(1)).await; + } +} diff --git a/examples/stm32f1/src/example_common.rs b/examples/stm32f1/src/example_common.rs new file mode 100644 index 000000000..54d633837 --- /dev/null +++ b/examples/stm32f1/src/example_common.rs @@ -0,0 +1,17 @@ +#![macro_use] + +use defmt_rtt as _; // global logger +use panic_probe as _; + +pub use defmt::*; + +use core::sync::atomic::{AtomicUsize, Ordering}; + +defmt::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 + } +} diff --git a/stm32-gen-features/src/lib.rs b/stm32-gen-features/src/lib.rs index 75eb7d756..426984cb0 100644 --- a/stm32-gen-features/src/lib.rs +++ b/stm32-gen-features/src/lib.rs @@ -2,8 +2,9 @@ use std::{iter::FilterMap, path::Path, slice::Iter}; -const SUPPORTED_FAMILIES: [&str; 9] = [ +const SUPPORTED_FAMILIES: [&str; 10] = [ "stm32f0", + "stm32f1", "stm32f4", "stm32g0", "stm32l0", From ce361abb1bd2eeecfe3b4708a55db0d519480b59 Mon Sep 17 00:00:00 2001 From: Mariusz Ryndzionek Date: Tue, 28 Sep 2021 18:27:07 +0200 Subject: [PATCH 2/3] Changing the casts (code review request) --- embassy-stm32/Cargo.toml | 1 - embassy-stm32/src/rcc/f1/mod.rs | 13 ++++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index 6881f13e8..b2f863377 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -28,7 +28,6 @@ stm32-metapac = { version = "0.1.0", path = "../stm32-metapac", features = ["rt" vcell = { version = "0.1.3", optional = true } bxcan = "0.5.1" seq-macro = "0.2.2" -cast = { version = "0.2.2", default-features = false } cfg-if = "1.0.0" diff --git a/embassy-stm32/src/rcc/f1/mod.rs b/embassy-stm32/src/rcc/f1/mod.rs index 75367d421..fc9fc128f 100644 --- a/embassy-stm32/src/rcc/f1/mod.rs +++ b/embassy-stm32/src/rcc/f1/mod.rs @@ -1,3 +1,4 @@ +use core::convert::TryFrom; use core::marker::PhantomData; use embassy::util::Unborrow; @@ -7,8 +8,6 @@ use crate::pac::{FLASH, RCC}; use crate::peripherals; use crate::time::Hertz; -use cast::u32; - use super::{set_freqs, Clocks}; const HSI: u32 = 8_000_000; @@ -94,8 +93,8 @@ impl<'d> Rcc<'d> { }) .unwrap_or(0b011); - let ppre1: i32 = 1 << (ppre1_bits - 0b011); - let pclk1 = hclk / u32(ppre1).unwrap(); + let ppre1 = 1 << (ppre1_bits - 0b011); + let pclk1 = hclk / u32::try_from(ppre1).unwrap(); let timer_mul1 = if ppre1 == 1 { 1 } else { 2 }; assert!(pclk1 <= 36_000_000); @@ -113,8 +112,8 @@ impl<'d> Rcc<'d> { }) .unwrap_or(0b011); - let ppre2: i32 = 1 << (ppre2_bits - 0b011); - let pclk2 = hclk / u32(ppre2).unwrap(); + let ppre2 = 1 << (ppre2_bits - 0b011); + let pclk2 = hclk / u32::try_from(ppre2).unwrap(); let timer_mul2 = if ppre2 == 1 { 1 } else { 2 }; assert!(pclk2 <= 72_000_000); @@ -154,7 +153,7 @@ impl<'d> Rcc<'d> { .unwrap_or(0b11); let apre = (apre_bits + 1) << 1; - let adcclk = pclk2 / u32(apre); + let adcclk = pclk2 / unwrap!(u32::try_from(apre)); assert!(adcclk <= 14_000_000); From d14e555ee76a842809c7f76f8b111003f70ab064 Mon Sep 17 00:00:00 2001 From: Mariusz Ryndzionek Date: Tue, 28 Sep 2021 18:45:27 +0200 Subject: [PATCH 3/3] Bump stm32-data --- stm32-data | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stm32-data b/stm32-data index 9e8e34786..e78ea6f05 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit 9e8e34786222b76a7d1bbbc1baf14cd3b33cd2d7 +Subproject commit e78ea6f05058dc1eff1dd4a4f07227d502a3b657