diff options
| -rw-r--r-- | embassy-stm32/build.rs | 17 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/f4.rs | 165 | ||||
| -rw-r--r-- | embassy-stm32/src/rcc/l4.rs | 133 | ||||
| -rw-r--r-- | examples/stm32f4/src/bin/mco.rs | 31 | ||||
| -rw-r--r-- | examples/stm32l4/src/bin/mco.rs | 27 |
5 files changed, 371 insertions, 2 deletions
diff --git a/embassy-stm32/build.rs b/embassy-stm32/build.rs index 3780c5a40..481fec677 100644 --- a/embassy-stm32/build.rs +++ b/embassy-stm32/build.rs | |||
| @@ -50,10 +50,13 @@ fn main() { | |||
| 50 | // We *shouldn't* have singletons for these, but the HAL currently requires | 50 | // We *shouldn't* have singletons for these, but the HAL currently requires |
| 51 | // singletons, for using with RccPeripheral to enable/disable clocks to them. | 51 | // singletons, for using with RccPeripheral to enable/disable clocks to them. |
| 52 | "rcc" => { | 52 | "rcc" => { |
| 53 | if r.version.starts_with("h7") { | 53 | if r.version.starts_with("h7") || r.version.starts_with("f4") { |
| 54 | singletons.push("MCO1".to_string()); | 54 | singletons.push("MCO1".to_string()); |
| 55 | singletons.push("MCO2".to_string()); | 55 | singletons.push("MCO2".to_string()); |
| 56 | } | 56 | } |
| 57 | if r.version.starts_with("l4") { | ||
| 58 | singletons.push("MCO".to_string()); | ||
| 59 | } | ||
| 57 | singletons.push(p.name.to_string()); | 60 | singletons.push(p.name.to_string()); |
| 58 | } | 61 | } |
| 59 | //"dbgmcu" => {} | 62 | //"dbgmcu" => {} |
| @@ -258,6 +261,7 @@ fn main() { | |||
| 258 | (("i2c", "SCL"), quote!(crate::i2c::SclPin)), | 261 | (("i2c", "SCL"), quote!(crate::i2c::SclPin)), |
| 259 | (("rcc", "MCO_1"), quote!(crate::rcc::McoPin)), | 262 | (("rcc", "MCO_1"), quote!(crate::rcc::McoPin)), |
| 260 | (("rcc", "MCO_2"), quote!(crate::rcc::McoPin)), | 263 | (("rcc", "MCO_2"), quote!(crate::rcc::McoPin)), |
| 264 | (("rcc", "MCO"), quote!(crate::rcc::McoPin)), | ||
| 261 | (("dcmi", "D0"), quote!(crate::dcmi::D0Pin)), | 265 | (("dcmi", "D0"), quote!(crate::dcmi::D0Pin)), |
| 262 | (("dcmi", "D1"), quote!(crate::dcmi::D1Pin)), | 266 | (("dcmi", "D1"), quote!(crate::dcmi::D1Pin)), |
| 263 | (("dcmi", "D2"), quote!(crate::dcmi::D2Pin)), | 267 | (("dcmi", "D2"), quote!(crate::dcmi::D2Pin)), |
| @@ -447,13 +451,22 @@ fn main() { | |||
| 447 | // MCO is special | 451 | // MCO is special |
| 448 | if pin.signal.starts_with("MCO_") { | 452 | if pin.signal.starts_with("MCO_") { |
| 449 | // Supported in H7 only for now | 453 | // Supported in H7 only for now |
| 450 | if regs.version.starts_with("h7") { | 454 | if regs.version.starts_with("h7") || regs.version.starts_with("f4") { |
| 451 | peri = format_ident!("{}", pin.signal.replace("_", "")); | 455 | peri = format_ident!("{}", pin.signal.replace("_", "")); |
| 452 | } else { | 456 | } else { |
| 453 | continue; | 457 | continue; |
| 454 | } | 458 | } |
| 455 | } | 459 | } |
| 456 | 460 | ||
| 461 | if pin.signal == "MCO" { | ||
| 462 | // Supported in H7 only for now | ||
| 463 | if regs.version.starts_with("l4") { | ||
| 464 | peri = format_ident!("MCO"); | ||
| 465 | } else { | ||
| 466 | continue; | ||
| 467 | } | ||
| 468 | } | ||
| 469 | |||
| 457 | g.extend(quote! { | 470 | g.extend(quote! { |
| 458 | pin_trait_impl!(#tr, #peri, #pin_name, #af); | 471 | pin_trait_impl!(#tr, #peri, #pin_name, #af); |
| 459 | }) | 472 | }) |
diff --git a/embassy-stm32/src/rcc/f4.rs b/embassy-stm32/src/rcc/f4.rs index 200bcce9c..d0e0d585a 100644 --- a/embassy-stm32/src/rcc/f4.rs +++ b/embassy-stm32/src/rcc/f4.rs | |||
| @@ -1,8 +1,16 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_common::into_ref; | ||
| 4 | use stm32_metapac::rcc::vals::{Mco1, Mco2, Mcopre}; | ||
| 5 | |||
| 1 | use super::sealed::RccPeripheral; | 6 | use super::sealed::RccPeripheral; |
| 7 | use crate::gpio::sealed::AFType; | ||
| 8 | use crate::gpio::Speed; | ||
| 2 | use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; | 9 | use crate::pac::rcc::vals::{Hpre, Ppre, Sw}; |
| 3 | use crate::pac::{FLASH, PWR, RCC}; | 10 | use crate::pac::{FLASH, PWR, RCC}; |
| 4 | use crate::rcc::{set_freqs, Clocks}; | 11 | use crate::rcc::{set_freqs, Clocks}; |
| 5 | use crate::time::Hertz; | 12 | use crate::time::Hertz; |
| 13 | use crate::{peripherals, Peripheral}; | ||
| 6 | 14 | ||
| 7 | /// HSI speed | 15 | /// HSI speed |
| 8 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | 16 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); |
| @@ -96,6 +104,163 @@ unsafe fn setup_pll(pllsrcclk: u32, use_hse: bool, pllsysclk: Option<u32>, pll48 | |||
| 96 | } | 104 | } |
| 97 | } | 105 | } |
| 98 | 106 | ||
| 107 | pub enum McoClock { | ||
| 108 | DIV1, | ||
| 109 | DIV2, | ||
| 110 | DIV3, | ||
| 111 | DIV4, | ||
| 112 | DIV5, | ||
| 113 | } | ||
| 114 | |||
| 115 | impl McoClock { | ||
| 116 | fn into_raw(&self) -> Mcopre { | ||
| 117 | match self { | ||
| 118 | McoClock::DIV1 => Mcopre::DIV1, | ||
| 119 | McoClock::DIV2 => Mcopre::DIV2, | ||
| 120 | McoClock::DIV3 => Mcopre::DIV3, | ||
| 121 | McoClock::DIV4 => Mcopre::DIV4, | ||
| 122 | McoClock::DIV5 => Mcopre::DIV5, | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | #[derive(Copy, Clone)] | ||
| 128 | pub enum Mco1Source { | ||
| 129 | Hsi, | ||
| 130 | Lse, | ||
| 131 | Hse, | ||
| 132 | Pll, | ||
| 133 | } | ||
| 134 | |||
| 135 | impl Default for Mco1Source { | ||
| 136 | fn default() -> Self { | ||
| 137 | Self::Hsi | ||
| 138 | } | ||
| 139 | } | ||
| 140 | |||
| 141 | pub trait McoSource { | ||
| 142 | type Raw; | ||
| 143 | |||
| 144 | fn into_raw(&self) -> Self::Raw; | ||
| 145 | } | ||
| 146 | |||
| 147 | impl McoSource for Mco1Source { | ||
| 148 | type Raw = Mco1; | ||
| 149 | fn into_raw(&self) -> Self::Raw { | ||
| 150 | match self { | ||
| 151 | Mco1Source::Hsi => Mco1::HSI, | ||
| 152 | Mco1Source::Lse => Mco1::LSE, | ||
| 153 | Mco1Source::Hse => Mco1::HSE, | ||
| 154 | Mco1Source::Pll => Mco1::PLL, | ||
| 155 | } | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | #[derive(Copy, Clone)] | ||
| 160 | pub enum Mco2Source { | ||
| 161 | SysClk, | ||
| 162 | Plli2s, | ||
| 163 | Hse, | ||
| 164 | Pll, | ||
| 165 | } | ||
| 166 | |||
| 167 | impl Default for Mco2Source { | ||
| 168 | fn default() -> Self { | ||
| 169 | Self::SysClk | ||
| 170 | } | ||
| 171 | } | ||
| 172 | |||
| 173 | impl McoSource for Mco2Source { | ||
| 174 | type Raw = Mco2; | ||
| 175 | fn into_raw(&self) -> Self::Raw { | ||
| 176 | match self { | ||
| 177 | Mco2Source::SysClk => Mco2::SYSCLK, | ||
| 178 | Mco2Source::Plli2s => Mco2::PLLI2S, | ||
| 179 | Mco2Source::Hse => Mco2::HSE, | ||
| 180 | Mco2Source::Pll => Mco2::PLL, | ||
| 181 | } | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | pub(crate) mod sealed { | ||
| 186 | use stm32_metapac::rcc::vals::Mcopre; | ||
| 187 | pub trait McoInstance { | ||
| 188 | type Source; | ||
| 189 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre); | ||
| 190 | } | ||
| 191 | } | ||
| 192 | |||
| 193 | pub trait McoInstance: sealed::McoInstance + 'static {} | ||
| 194 | |||
| 195 | pin_trait!(McoPin, McoInstance); | ||
| 196 | |||
| 197 | impl sealed::McoInstance for peripherals::MCO1 { | ||
| 198 | type Source = Mco1; | ||
| 199 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) { | ||
| 200 | RCC.cfgr().modify(|w| { | ||
| 201 | w.set_mco1(source); | ||
| 202 | w.set_mco1pre(prescaler); | ||
| 203 | }); | ||
| 204 | match source { | ||
| 205 | Mco1::PLL => { | ||
| 206 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 207 | while !RCC.cr().read().pllrdy() {} | ||
| 208 | } | ||
| 209 | Mco1::HSI => { | ||
| 210 | RCC.cr().modify(|w| w.set_hsion(true)); | ||
| 211 | while !RCC.cr().read().hsirdy() {} | ||
| 212 | } | ||
| 213 | _ => {} | ||
| 214 | } | ||
| 215 | } | ||
| 216 | } | ||
| 217 | impl McoInstance for peripherals::MCO1 {} | ||
| 218 | |||
| 219 | impl sealed::McoInstance for peripherals::MCO2 { | ||
| 220 | type Source = Mco2; | ||
| 221 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) { | ||
| 222 | RCC.cfgr().modify(|w| { | ||
| 223 | w.set_mco2(source); | ||
| 224 | w.set_mco2pre(prescaler); | ||
| 225 | }); | ||
| 226 | match source { | ||
| 227 | Mco2::PLL => { | ||
| 228 | RCC.cr().modify(|w| w.set_pllon(true)); | ||
| 229 | while !RCC.cr().read().pllrdy() {} | ||
| 230 | } | ||
| 231 | Mco2::PLLI2S => { | ||
| 232 | RCC.cr().modify(|w| w.set_plli2son(true)); | ||
| 233 | while !RCC.cr().read().plli2srdy() {} | ||
| 234 | } | ||
| 235 | _ => {} | ||
| 236 | } | ||
| 237 | } | ||
| 238 | } | ||
| 239 | impl McoInstance for peripherals::MCO2 {} | ||
| 240 | |||
| 241 | pub struct Mco<'d, T: McoInstance> { | ||
| 242 | phantom: PhantomData<&'d mut T>, | ||
| 243 | } | ||
| 244 | |||
| 245 | impl<'d, T: McoInstance> Mco<'d, T> { | ||
| 246 | pub fn new( | ||
| 247 | _peri: impl Peripheral<P = T> + 'd, | ||
| 248 | pin: impl Peripheral<P = impl McoPin<T>> + 'd, | ||
| 249 | source: impl McoSource<Raw = T::Source>, | ||
| 250 | prescaler: McoClock, | ||
| 251 | ) -> Self { | ||
| 252 | into_ref!(pin); | ||
| 253 | |||
| 254 | critical_section::with(|_| unsafe { | ||
| 255 | T::apply_clock_settings(source.into_raw(), prescaler.into_raw()); | ||
| 256 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | ||
| 257 | pin.set_speed(Speed::VeryHigh); | ||
| 258 | }); | ||
| 259 | |||
| 260 | Self { phantom: PhantomData } | ||
| 261 | } | ||
| 262 | } | ||
| 263 | |||
| 99 | unsafe fn flash_setup(sysclk: u32) { | 264 | unsafe fn flash_setup(sysclk: u32) { |
| 100 | use crate::pac::flash::vals::Latency; | 265 | use crate::pac::flash::vals::Latency; |
| 101 | 266 | ||
diff --git a/embassy-stm32/src/rcc/l4.rs b/embassy-stm32/src/rcc/l4.rs index e650490fe..c1bf7d0cd 100644 --- a/embassy-stm32/src/rcc/l4.rs +++ b/embassy-stm32/src/rcc/l4.rs | |||
| @@ -1,7 +1,15 @@ | |||
| 1 | use core::marker::PhantomData; | ||
| 2 | |||
| 3 | use embassy_hal_common::into_ref; | ||
| 4 | use stm32_metapac::rcc::vals::{Mcopre, Mcosel}; | ||
| 5 | |||
| 6 | use crate::gpio::sealed::AFType; | ||
| 7 | use crate::gpio::Speed; | ||
| 1 | use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; | 8 | use crate::pac::rcc::vals::{Hpre, Msirange, Pllsrc, Ppre, Sw}; |
| 2 | use crate::pac::{FLASH, RCC}; | 9 | use crate::pac::{FLASH, RCC}; |
| 3 | use crate::rcc::{set_freqs, Clocks}; | 10 | use crate::rcc::{set_freqs, Clocks}; |
| 4 | use crate::time::Hertz; | 11 | use crate::time::Hertz; |
| 12 | use crate::{peripherals, Peripheral}; | ||
| 5 | 13 | ||
| 6 | /// HSI speed | 14 | /// HSI speed |
| 7 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); | 15 | pub const HSI_FREQ: Hertz = Hertz(16_000_000); |
| @@ -298,6 +306,131 @@ impl Default for Config { | |||
| 298 | } | 306 | } |
| 299 | } | 307 | } |
| 300 | 308 | ||
| 309 | pub enum McoClock { | ||
| 310 | DIV1, | ||
| 311 | DIV2, | ||
| 312 | DIV4, | ||
| 313 | DIV8, | ||
| 314 | DIV16, | ||
| 315 | } | ||
| 316 | |||
| 317 | impl McoClock { | ||
| 318 | fn into_raw(&self) -> Mcopre { | ||
| 319 | match self { | ||
| 320 | McoClock::DIV1 => Mcopre::DIV1, | ||
| 321 | McoClock::DIV2 => Mcopre::DIV2, | ||
| 322 | McoClock::DIV4 => Mcopre::DIV4, | ||
| 323 | McoClock::DIV8 => Mcopre::DIV8, | ||
| 324 | McoClock::DIV16 => Mcopre::DIV16, | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | #[derive(Copy, Clone)] | ||
| 330 | pub enum Mco1Source { | ||
| 331 | Disabled, | ||
| 332 | Lse, | ||
| 333 | Lsi, | ||
| 334 | Hse, | ||
| 335 | Hsi16, | ||
| 336 | PllClk, | ||
| 337 | SysClk, | ||
| 338 | Msi, | ||
| 339 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | ||
| 340 | Hsi48, | ||
| 341 | } | ||
| 342 | |||
| 343 | impl Default for Mco1Source { | ||
| 344 | fn default() -> Self { | ||
| 345 | Self::Hsi16 | ||
| 346 | } | ||
| 347 | } | ||
| 348 | |||
| 349 | pub trait McoSource { | ||
| 350 | type Raw; | ||
| 351 | |||
| 352 | fn into_raw(&self) -> Self::Raw; | ||
| 353 | } | ||
| 354 | |||
| 355 | impl McoSource for Mco1Source { | ||
| 356 | type Raw = Mcosel; | ||
| 357 | fn into_raw(&self) -> Self::Raw { | ||
| 358 | match self { | ||
| 359 | Mco1Source::Disabled => Mcosel::NOCLOCK, | ||
| 360 | Mco1Source::Lse => Mcosel::LSE, | ||
| 361 | Mco1Source::Lsi => Mcosel::LSI, | ||
| 362 | Mco1Source::Hse => Mcosel::HSE, | ||
| 363 | Mco1Source::Hsi16 => Mcosel::HSI16, | ||
| 364 | Mco1Source::PllClk => Mcosel::PLL, | ||
| 365 | Mco1Source::SysClk => Mcosel::SYSCLK, | ||
| 366 | Mco1Source::Msi => Mcosel::MSI, | ||
| 367 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | ||
| 368 | Mco1Source::Hsi48 => Mcosel::HSI48, | ||
| 369 | } | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | pub(crate) mod sealed { | ||
| 374 | use stm32_metapac::rcc::vals::Mcopre; | ||
| 375 | pub trait McoInstance { | ||
| 376 | type Source; | ||
| 377 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre); | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | pub trait McoInstance: sealed::McoInstance + 'static {} | ||
| 382 | |||
| 383 | pin_trait!(McoPin, McoInstance); | ||
| 384 | |||
| 385 | impl sealed::McoInstance for peripherals::MCO { | ||
| 386 | type Source = Mcosel; | ||
| 387 | |||
| 388 | unsafe fn apply_clock_settings(source: Self::Source, prescaler: Mcopre) { | ||
| 389 | RCC.cfgr().modify(|w| { | ||
| 390 | w.set_mcosel(source); | ||
| 391 | w.set_mcopre(prescaler); | ||
| 392 | }); | ||
| 393 | |||
| 394 | match source { | ||
| 395 | Mcosel::HSI16 => { | ||
| 396 | RCC.cr().modify(|w| w.set_hsion(true)); | ||
| 397 | while !RCC.cr().read().hsirdy() {} | ||
| 398 | } | ||
| 399 | #[cfg(not(any(stm32l471, stm32l475, stm32l476, stm32l486)))] | ||
| 400 | Mcosel::HSI48 => { | ||
| 401 | RCC.crrcr().modify(|w| w.set_hsi48on(true)); | ||
| 402 | while !RCC.crrcr().read().hsi48rdy() {} | ||
| 403 | } | ||
| 404 | _ => {} | ||
| 405 | } | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | impl McoInstance for peripherals::MCO {} | ||
| 410 | |||
| 411 | pub struct Mco<'d, T: McoInstance> { | ||
| 412 | phantom: PhantomData<&'d mut T>, | ||
| 413 | } | ||
| 414 | |||
| 415 | impl<'d, T: McoInstance> Mco<'d, T> { | ||
| 416 | pub fn new( | ||
| 417 | _peri: impl Peripheral<P = T> + 'd, | ||
| 418 | pin: impl Peripheral<P = impl McoPin<T>> + 'd, | ||
| 419 | source: impl McoSource<Raw = T::Source>, | ||
| 420 | prescaler: McoClock, | ||
| 421 | ) -> Self { | ||
| 422 | into_ref!(pin); | ||
| 423 | |||
| 424 | critical_section::with(|_| unsafe { | ||
| 425 | T::apply_clock_settings(source.into_raw(), prescaler.into_raw()); | ||
| 426 | pin.set_as_af(pin.af_num(), AFType::OutputPushPull); | ||
| 427 | pin.set_speed(Speed::VeryHigh); | ||
| 428 | }); | ||
| 429 | |||
| 430 | Self { phantom: PhantomData } | ||
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 301 | pub(crate) unsafe fn init(config: Config) { | 434 | pub(crate) unsafe fn init(config: Config) { |
| 302 | let (sys_clk, sw) = match config.mux { | 435 | let (sys_clk, sw) = match config.mux { |
| 303 | ClockSrc::MSI(range) => { | 436 | ClockSrc::MSI(range) => { |
diff --git a/examples/stm32f4/src/bin/mco.rs b/examples/stm32f4/src/bin/mco.rs new file mode 100644 index 000000000..5d780f94d --- /dev/null +++ b/examples/stm32f4/src/bin/mco.rs | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 8 | use embassy_stm32::rcc::{Mco, Mco1Source, Mco2Source, McoClock}; | ||
| 9 | use embassy_time::{Duration, Timer}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let p = embassy_stm32::init(Default::default()); | ||
| 15 | info!("Hello World!"); | ||
| 16 | |||
| 17 | |||
| 18 | let _mco1 = Mco::new(p.MCO1, p.PA8, Mco1Source::Hsi, McoClock::DIV1); | ||
| 19 | let _mco2 = Mco::new(p.MCO2, p.PC9, Mco2Source::Pll, McoClock::DIV4); | ||
| 20 | let mut led = Output::new(p.PB7, Level::High, Speed::Low); | ||
| 21 | |||
| 22 | loop { | ||
| 23 | info!("high"); | ||
| 24 | led.set_high(); | ||
| 25 | Timer::after(Duration::from_millis(300)).await; | ||
| 26 | |||
| 27 | info!("low"); | ||
| 28 | led.set_low(); | ||
| 29 | Timer::after(Duration::from_millis(300)).await; | ||
| 30 | } | ||
| 31 | } | ||
diff --git a/examples/stm32l4/src/bin/mco.rs b/examples/stm32l4/src/bin/mco.rs new file mode 100644 index 000000000..dea0c66e0 --- /dev/null +++ b/examples/stm32l4/src/bin/mco.rs | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | #![feature(type_alias_impl_trait)] | ||
| 4 | |||
| 5 | use defmt::*; | ||
| 6 | use embassy_executor::Spawner; | ||
| 7 | use embassy_stm32::gpio::{Level, Output, Speed}; | ||
| 8 | use embassy_stm32::rcc::{Mco, Mco1Source, McoClock}; | ||
| 9 | use embassy_time::{Duration, Timer}; | ||
| 10 | use {defmt_rtt as _, panic_probe as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) { | ||
| 14 | let p = embassy_stm32::init(Default::default()); | ||
| 15 | info!("Hello World!"); | ||
| 16 | |||
| 17 | let _mco = Mco::new(p.MCO, p.PA8, Mco1Source::Hsi16, McoClock::DIV1); | ||
| 18 | |||
| 19 | let mut led = Output::new(p.PB14, Level::High, Speed::Low); | ||
| 20 | |||
| 21 | loop { | ||
| 22 | led.set_high(); | ||
| 23 | Timer::after(Duration::from_millis(300)).await; | ||
| 24 | led.set_low(); | ||
| 25 | Timer::after(Duration::from_millis(300)).await; | ||
| 26 | } | ||
| 27 | } | ||
