Compare commits

..

29 Commits

Author SHA1 Message Date
584fc358fd Merge pull request #2154 from bugadani/executor
Prepare embassy-executor 0.3.2
2023-11-06 20:53:19 +00:00
b8f9341edc Prepare embassy-executor 0.3.2 2023-11-06 21:50:40 +01:00
7ca557b917 Merge pull request #2152 from bugadani/atomic
Executor: Yeet core::sync::atomic from risc-v
2023-11-06 18:46:50 +00:00
8d8d50cc7a Yeet core::sync::atomic, remove futures-util dep 2023-11-06 17:35:02 +01:00
5948d934d3 Merge pull request #2150 from bugadani/block
Ensure TcpIo not blocking when reading into empty slice
2023-11-06 12:44:15 +00:00
746936f8cd Merge pull request #2151 from eZioPan/rcc-init-set-vos
check PLL settings before set VOS
2023-11-06 12:43:29 +00:00
8f543062aa check PLL settings before set VOS 2023-11-06 18:30:59 +08:00
15660cfc68 Ensure TcpIo not blocking when reading into empty slice 2023-11-06 09:12:16 +01:00
74f70dc7b4 Merge pull request #2149 from embassy-rs/usb-fixes3
stm32/otg: fix enumeration on non-f4 chips.
2023-11-06 03:19:50 +00:00
7084570478 stm32/otg: fix enumeration on non-f4 chips.
Fixes regression from #2148
2023-11-06 04:13:06 +01:00
58719dcb58 Merge pull request #2148 from embassy-rs/usb-fixes3
stm32/otg: fix CONTROL OUT transfers on F4.
2023-11-06 02:46:38 +00:00
b4eef6b1ee stm32/otg: fix CONTROL OUT transfers on F4. 2023-11-06 03:38:42 +01:00
70a700e430 stm32/otg: log TRDT 2023-11-06 03:38:13 +01:00
b8679c0cc8 stm32/rcc: set highest VOS on some F4s with no overdrive. 2023-11-06 03:37:39 +01:00
ad861179cc Merge pull request #2147 from xoviat/low-power
stm32: update metapac and use stop data
2023-11-06 02:35:57 +00:00
d9b00c01e0 usb: reject instead of panic on CONTROL OUT longer than the buf. 2023-11-06 03:26:00 +01:00
239ad5ebea stm32: update metapac and use stop data 2023-11-05 20:09:33 -06:00
46cffcc8d4 Merge pull request #2119 from JuliDi/fmc-sram-adc
STM32: Add raw access to FMC peripheral and fix typo in build.rs
2023-11-06 01:31:56 +00:00
e6462f1e88 Merge pull request #2146 from adamgreig/stm32g4-opamp
Remove accidentally leftover println
2023-11-06 01:15:55 +00:00
d464d1a841 Remove accidentally leftover println 2023-11-06 01:11:57 +00:00
980c3cf42b Merge pull request #2142 from adamgreig/stm32g4-opamp
stm32: support internal output on g4 opamps
2023-11-06 00:01:34 +00:00
28eb4cd817 stm32: support internal output on g4 opamps 2023-11-05 23:57:15 +00:00
3de01bc223 Merge pull request #2145 from embassy-rs/rcc-no-spaghetti
stm32/rcc: add shared code for hsi48 with crs support.
2023-11-05 22:58:18 +00:00
0272deb158 stm32/rcc: add shared code for hsi48 with crs support. 2023-11-05 23:52:54 +01:00
c4a8b79dbc Merge pull request #2143 from adamgreig/raw-usb-example
Add raw USB example using control transfers
2023-11-05 17:34:58 +00:00
fa45dcd034 Add raw USB example using control transfers 2023-11-05 16:46:45 +00:00
6ff91851b1 Merge pull request #2141 from embassy-rs/l0l1-modernize
stm32/rcc: switch to modern api for l0, l1.
2023-11-05 02:09:48 +00:00
b1e5b6ffe1 Add raw fmc access implementation 2023-10-28 13:50:02 +02:00
2aaf4bf96b fix typo in build.rs that caused fmc ClkPin to not be implemented 2023-10-15 19:14:34 +02:00
38 changed files with 653 additions and 224 deletions

View File

@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## 0.3.2 - 2023-11-06
- Use `atomic-polyfill` for `riscv32`
- Removed unused dependencies (static_cell, futures-util)
## 0.3.1 - 2023-11-01 ## 0.3.1 - 2023-11-01
- Fix spurious "Found waker not created by the Embassy executor" error in recent nightlies. - Fix spurious "Found waker not created by the Embassy executor" error in recent nightlies.

View File

@ -1,6 +1,6 @@
[package] [package]
name = "embassy-executor" name = "embassy-executor"
version = "0.3.1" version = "0.3.2"
edition = "2021" edition = "2021"
license = "MIT OR Apache-2.0" license = "MIT OR Apache-2.0"
description = "async/await executor designed for embedded usage" description = "async/await executor designed for embedded usage"
@ -57,7 +57,6 @@ defmt = { version = "0.3", optional = true }
log = { version = "0.4.14", optional = true } log = { version = "0.4.14", optional = true }
rtos-trace = { version = "0.1.2", optional = true } rtos-trace = { version = "0.1.2", optional = true }
futures-util = { version = "0.3.17", default-features = false }
embassy-macros = { version = "0.2.1", path = "../embassy-macros" } embassy-macros = { version = "0.2.1", path = "../embassy-macros" }
embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true} embassy-time = { version = "0.1.5", path = "../embassy-time", optional = true}
atomic-polyfill = "1.0.1" atomic-polyfill = "1.0.1"

View File

@ -6,8 +6,8 @@ pub use thread::*;
#[cfg(feature = "executor-thread")] #[cfg(feature = "executor-thread")]
mod thread { mod thread {
use core::marker::PhantomData; use core::marker::PhantomData;
use core::sync::atomic::{AtomicBool, Ordering};
use atomic_polyfill::{AtomicBool, Ordering};
#[cfg(feature = "nightly")] #[cfg(feature = "nightly")]
pub use embassy_macros::main_riscv as main; pub use embassy_macros::main_riscv as main;

View File

@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## Unreleased
- Avoid never resolving `TcpIo::read` when the output buffer is empty.
## 0.2.1 - 2023-10-31 ## 0.2.1 - 2023-10-31
- Re-add impl_trait_projections - Re-add impl_trait_projections

View File

@ -390,6 +390,13 @@ impl<'d> TcpIo<'d> {
// CAUTION: smoltcp semantics around EOF are different to what you'd expect // CAUTION: smoltcp semantics around EOF are different to what you'd expect
// from posix-like IO, so we have to tweak things here. // from posix-like IO, so we have to tweak things here.
self.with_mut(|s, _| match s.recv_slice(buf) { self.with_mut(|s, _| match s.recv_slice(buf) {
// Reading into empty buffer
Ok(0) if buf.is_empty() => {
// embedded_io_async::Read's contract is to not block if buf is empty. While
// this function is not a direct implementor of the trait method, we still don't
// want our future to never resolve.
Poll::Ready(Ok(0))
}
// No data ready // No data ready
Ok(0) => { Ok(0) => {
s.register_recv_waker(cx.waker()); s.register_recv_waker(cx.waker());

View File

@ -58,7 +58,7 @@ rand_core = "0.6.3"
sdio-host = "0.5.0" sdio-host = "0.5.0"
embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true } embedded-sdmmc = { git = "https://github.com/embassy-rs/embedded-sdmmc-rs", rev = "a4f293d3a6f72158385f79c98634cb8a14d0d2fc", optional = true }
critical-section = "1.1" critical-section = "1.1"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73b8c37ae74fc28b247188c989fd99400611bd6b" } stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1374ed622714ef4702826699ca21cc1f741f4133" }
vcell = "0.1.3" vcell = "0.1.3"
bxcan = "0.7.0" bxcan = "0.7.0"
nb = "1.0.0" nb = "1.0.0"
@ -76,7 +76,7 @@ critical-section = { version = "1.1", features = ["std"] }
[build-dependencies] [build-dependencies]
proc-macro2 = "1.0.36" proc-macro2 = "1.0.36"
quote = "1.0.15" quote = "1.0.15"
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-73b8c37ae74fc28b247188c989fd99400611bd6b", default-features = false, features = ["metadata"]} stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-1374ed622714ef4702826699ca21cc1f741f4133", default-features = false, features = ["metadata"]}
[features] [features]

View File

@ -6,7 +6,7 @@ use std::{env, fs};
use proc_macro2::{Ident, TokenStream}; use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote}; use quote::{format_ident, quote};
use stm32_metapac::metadata::ir::{BlockItemInner, Enum, FieldSet}; use stm32_metapac::metadata::ir::{BlockItemInner, Enum, FieldSet};
use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, METADATA}; use stm32_metapac::metadata::{MemoryRegionKind, PeripheralRccRegister, StopMode, METADATA};
fn main() { fn main() {
let target = env::var("TARGET").unwrap(); let target = env::var("TARGET").unwrap();
@ -557,18 +557,18 @@ fn main() {
}; };
/* /*
If LP and non-LP peripherals share the same RCC enable bit, then a refcount leak will result. A refcount leak can result if the same field is shared by peripherals with different stop modes
This should be checked in stm32-data-gen. This condition should be checked in stm32-data
*/ */
let stop_refcount = if p.name.starts_with("LP") { let stop_refcount = match rcc.stop_mode {
quote! { REFCOUNT_STOP2 } StopMode::Standby => None,
} else { StopMode::Stop2 => Some(quote! { REFCOUNT_STOP2 }),
quote! { REFCOUNT_STOP1 } StopMode::Stop1 => Some(quote! { REFCOUNT_STOP1 }),
}; };
let (incr_stop_refcount, decr_stop_refcount) = if p.name != "RTC" { let (incr_stop_refcount, decr_stop_refcount) = match stop_refcount {
( Some(stop_refcount) => (
quote! { quote! {
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
unsafe { crate::rcc::#stop_refcount += 1 }; unsafe { crate::rcc::#stop_refcount += 1 };
@ -577,9 +577,8 @@ fn main() {
#[cfg(feature = "low-power")] #[cfg(feature = "low-power")]
unsafe { crate::rcc::#stop_refcount -= 1 }; unsafe { crate::rcc::#stop_refcount -= 1 };
}, },
) ),
} else { None => (TokenStream::new(), TokenStream::new()),
(quote! {}, quote! {})
}; };
g.extend(quote! { g.extend(quote! {
@ -828,7 +827,7 @@ fn main() {
(("fmc", "NCE"), quote!(crate::fmc::NCEPin)), (("fmc", "NCE"), quote!(crate::fmc::NCEPin)),
(("fmc", "NOE"), quote!(crate::fmc::NOEPin)), (("fmc", "NOE"), quote!(crate::fmc::NOEPin)),
(("fmc", "NWE"), quote!(crate::fmc::NWEPin)), (("fmc", "NWE"), quote!(crate::fmc::NWEPin)),
(("fmc", "Clk"), quote!(crate::fmc::ClkPin)), (("fmc", "CLK"), quote!(crate::fmc::ClkPin)),
(("fmc", "BA0"), quote!(crate::fmc::BA0Pin)), (("fmc", "BA0"), quote!(crate::fmc::BA0Pin)),
(("fmc", "BA1"), quote!(crate::fmc::BA1Pin)), (("fmc", "BA1"), quote!(crate::fmc::BA1Pin)),
(("timer", "CH1"), quote!(crate::timer::Channel1Pin)), (("timer", "CH1"), quote!(crate::timer::Channel1Pin)),
@ -944,17 +943,23 @@ fn main() {
} }
if regs.kind == "opamp" { if regs.kind == "opamp" {
if !pin.signal.starts_with("VP") { if pin.signal.starts_with("VP") {
continue; // Impl NonInvertingPin for the VP* signals (VP0, VP1, VP2, etc)
let peri = format_ident!("{}", p.name);
let pin_name = format_ident!("{}", pin.pin);
let ch: u8 = pin.signal.strip_prefix("VP").unwrap().parse().unwrap();
g.extend(quote! {
impl_opamp_vp_pin!( #peri, #pin_name, #ch);
})
} else if pin.signal == "VOUT" {
// Impl OutputPin for the VOUT pin
let peri = format_ident!("{}", p.name);
let pin_name = format_ident!("{}", pin.pin);
g.extend(quote! {
impl_opamp_vout_pin!( #peri, #pin_name );
})
} }
let peri = format_ident!("{}", p.name);
let pin_name = format_ident!("{}", pin.pin);
let ch: u8 = pin.signal.strip_prefix("VP").unwrap().parse().unwrap();
g.extend(quote! {
impl_opamp_pin!( #peri, #pin_name, #ch);
})
} }
// DAC is special // DAC is special

View File

@ -12,6 +12,37 @@ pub struct Fmc<'d, T: Instance> {
unsafe impl<'d, T> Send for Fmc<'d, T> where T: Instance {} unsafe impl<'d, T> Send for Fmc<'d, T> where T: Instance {}
impl<'d, T> Fmc<'d, T>
where
T: Instance,
{
/// Create a raw FMC instance.
///
/// **Note:** This is currently used to provide access to some basic FMC functions
/// for manual configuration for memory types that stm32-fmc does not support.
pub fn new_raw(_instance: impl Peripheral<P = T> + 'd) -> Self {
Self { peri: PhantomData }
}
/// Enable the FMC peripheral and reset it.
pub fn enable(&mut self) {
T::enable_and_reset();
}
/// Enable the memory controller on applicable chips.
pub fn memory_controller_enable(&mut self) {
// fmc v1 and v2 does not have the fmcen bit
// fsmc v1, v2 and v3 does not have the fmcen bit
// This is a "not" because it is expected that all future versions have this bit
#[cfg(not(any(fmc_v1x3, fmc_v2x1, fsmc_v1x0, fsmc_v1x3, fsmc_v2x3, fsmc_v3x1)))]
T::REGS.bcr1().modify(|r| r.set_fmcen(true));
}
pub fn source_clock_hz(&self) -> u32 {
<T as crate::rcc::sealed::RccPeripheral>::frequency().0
}
}
unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T> unsafe impl<'d, T> stm32_fmc::FmcPeripheral for Fmc<'d, T>
where where
T: Instance, T: Instance,

View File

@ -13,21 +13,50 @@ pub enum OpAmpGain {
Mul16, Mul16,
} }
pub struct OpAmpOutput<'d, 'p, T: Instance, P: NonInvertingPin<T>> { #[derive(Clone, Copy)]
_inner: &'d OpAmp<'d, T>, pub enum OpAmpSpeed {
_input: &'p mut P, Normal,
HighSpeed,
} }
#[cfg(opamp_g4)]
impl From<OpAmpSpeed> for crate::pac::opamp::vals::OpampCsrOpahsm {
fn from(v: OpAmpSpeed) -> Self {
match v {
OpAmpSpeed::Normal => crate::pac::opamp::vals::OpampCsrOpahsm::NORMAL,
OpAmpSpeed::HighSpeed => crate::pac::opamp::vals::OpampCsrOpahsm::HIGHSPEED,
}
}
}
/// OpAmp external outputs, wired to a GPIO pad.
///
/// The GPIO output pad is held by this struct to ensure it cannot be used elsewhere.
///
/// This struct can also be used as an ADC input.
pub struct OpAmpOutput<'d, 'p, T: Instance, P: OutputPin<T>> {
_inner: &'d OpAmp<'d, T>,
_output: &'p mut P,
}
/// OpAmp internal outputs, wired directly to ADC inputs.
///
/// This struct can be used as an ADC input.
pub struct OpAmpInternalOutput<'d, T: Instance> {
_inner: &'d OpAmp<'d, T>,
}
/// OpAmp driver.
pub struct OpAmp<'d, T: Instance> { pub struct OpAmp<'d, T: Instance> {
_inner: PeripheralRef<'d, T>, _inner: PeripheralRef<'d, T>,
} }
impl<'d, T: Instance> OpAmp<'d, T> { impl<'d, T: Instance> OpAmp<'d, T> {
pub fn new(opamp: impl Peripheral<P = T> + 'd) -> Self { /// Create a new driver instance.
Self::new_inner(opamp) ///
} /// Enables the OpAmp and configures the speed, but
/// does not set any other configuration.
fn new_inner(opamp: impl Peripheral<P = T> + 'd) -> Self { pub fn new(opamp: impl Peripheral<P = T> + 'd, #[cfg(opamp_g4)] speed: OpAmpSpeed) -> Self {
into_ref!(opamp); into_ref!(opamp);
#[cfg(opamp_f3)] #[cfg(opamp_f3)]
@ -38,15 +67,34 @@ impl<'d, T: Instance> OpAmp<'d, T> {
#[cfg(opamp_g4)] #[cfg(opamp_g4)]
T::regs().opamp_csr().modify(|w| { T::regs().opamp_csr().modify(|w| {
w.set_opaen(true); w.set_opaen(true);
w.set_opahsm(speed.into());
}); });
Self { _inner: opamp } Self { _inner: opamp }
} }
pub fn buffer_for<'a, 'b, P>(&'a mut self, pin: &'b mut P, gain: OpAmpGain) -> OpAmpOutput<'a, 'b, T, P> /// Configure the OpAmp as a buffer for the provided input pin,
/// outputting to the provided output pin.
///
/// The input pin is configured for analogue mode but not consumed,
/// so it may subsequently be used for ADC or comparator inputs.
///
/// The output pin is held within the returned [`OpAmpOutput`] struct,
/// preventing it being used elsewhere. The `OpAmpOutput` can then be
/// directly used as an ADC input.
pub fn buffer_ext<'a, 'b, IP, OP>(
&'a mut self,
in_pin: &IP,
out_pin: &'b mut OP,
gain: OpAmpGain,
) -> OpAmpOutput<'a, 'b, T, OP>
where where
P: NonInvertingPin<T>, IP: NonInvertingPin<T> + crate::gpio::sealed::Pin,
OP: OutputPin<T> + crate::gpio::sealed::Pin,
{ {
in_pin.set_as_analog();
out_pin.set_as_analog();
let (vm_sel, pga_gain) = match gain { let (vm_sel, pga_gain) = match gain {
OpAmpGain::Mul1 => (0b11, 0b00), OpAmpGain::Mul1 => (0b11, 0b00),
OpAmpGain::Mul2 => (0b10, 0b00), OpAmpGain::Mul2 => (0b10, 0b00),
@ -57,25 +105,76 @@ impl<'d, T: Instance> OpAmp<'d, T> {
#[cfg(opamp_f3)] #[cfg(opamp_f3)]
T::regs().opampcsr().modify(|w| { T::regs().opampcsr().modify(|w| {
w.set_vp_sel(pin.channel()); w.set_vp_sel(in_pin.channel());
w.set_vm_sel(vm_sel); w.set_vm_sel(vm_sel);
w.set_pga_gain(pga_gain); w.set_pga_gain(pga_gain);
w.set_opampen(true);
}); });
#[cfg(opamp_g4)] #[cfg(opamp_g4)]
T::regs().opamp_csr().modify(|w| { T::regs().opamp_csr().modify(|w| {
use crate::pac::opamp::vals::*; use crate::pac::opamp::vals::*;
w.set_vp_sel(OpampCsrVpSel::from_bits(pin.channel())); w.set_vp_sel(OpampCsrVpSel::from_bits(in_pin.channel()));
w.set_vm_sel(OpampCsrVmSel::from_bits(vm_sel)); w.set_vm_sel(OpampCsrVmSel::from_bits(vm_sel));
w.set_pga_gain(OpampCsrPgaGain::from_bits(pga_gain)); w.set_pga_gain(OpampCsrPgaGain::from_bits(pga_gain));
w.set_opaintoen(OpampCsrOpaintoen::OUTPUTPIN);
w.set_opaen(true);
}); });
OpAmpOutput { OpAmpOutput {
_inner: self, _inner: self,
_input: pin, _output: out_pin,
} }
} }
/// Configure the OpAmp as a buffer for the provided input pin,
/// with the output only used internally.
///
/// The input pin is configured for analogue mode but not consumed,
/// so it may be subsequently used for ADC or comparator inputs.
///
/// The returned `OpAmpInternalOutput` struct may be used as an ADC input.
#[cfg(opamp_g4)]
pub fn buffer_int<'a, P>(&'a mut self, pin: &P, gain: OpAmpGain) -> OpAmpInternalOutput<'a, T>
where
P: NonInvertingPin<T> + crate::gpio::sealed::Pin,
{
pin.set_as_analog();
let (vm_sel, pga_gain) = match gain {
OpAmpGain::Mul1 => (0b11, 0b00),
OpAmpGain::Mul2 => (0b10, 0b00),
OpAmpGain::Mul4 => (0b10, 0b01),
OpAmpGain::Mul8 => (0b10, 0b10),
OpAmpGain::Mul16 => (0b10, 0b11),
};
T::regs().opamp_csr().modify(|w| {
use crate::pac::opamp::vals::*;
w.set_vp_sel(OpampCsrVpSel::from_bits(pin.channel()));
w.set_vm_sel(OpampCsrVmSel::from_bits(vm_sel));
w.set_pga_gain(OpampCsrPgaGain::from_bits(pga_gain));
w.set_opaintoen(OpampCsrOpaintoen::ADCCHANNEL);
w.set_opaen(true);
});
OpAmpInternalOutput { _inner: self }
}
}
impl<'d, T: Instance> Drop for OpAmp<'d, T> {
fn drop(&mut self) {
#[cfg(opamp_f3)]
T::regs().opampcsr().modify(|w| {
w.set_opampen(false);
});
#[cfg(opamp_g4)]
T::regs().opamp_csr().modify(|w| {
w.set_opaen(false);
});
}
} }
pub trait Instance: sealed::Instance + 'static {} pub trait Instance: sealed::Instance + 'static {}
@ -92,18 +191,19 @@ pub(crate) mod sealed {
pub trait InvertingPin<T: Instance> { pub trait InvertingPin<T: Instance> {
fn channel(&self) -> u8; fn channel(&self) -> u8;
} }
pub trait OutputPin<T: Instance> {}
} }
pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {} pub trait NonInvertingPin<T: Instance>: sealed::NonInvertingPin<T> {}
pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {} pub trait InvertingPin<T: Instance>: sealed::InvertingPin<T> {}
pub trait OutputPin<T: Instance>: sealed::OutputPin<T> {}
#[cfg(opamp_f3)] macro_rules! impl_opamp_external_output {
macro_rules! impl_opamp_output {
($inst:ident, $adc:ident, $ch:expr) => { ($inst:ident, $adc:ident, $ch:expr) => {
foreach_adc!( foreach_adc!(
($adc, $common_inst:ident, $adc_clock:ident) => { ($adc, $common_inst:ident, $adc_clock:ident) => {
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc> impl<'d, 'p, P: OutputPin<crate::peripherals::$inst>> crate::adc::sealed::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P> for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{ {
fn channel(&self) -> u8 { fn channel(&self) -> u8 {
@ -111,7 +211,7 @@ macro_rules! impl_opamp_output {
} }
} }
impl<'d, 'p, P: NonInvertingPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc> impl<'d, 'p, P: OutputPin<crate::peripherals::$inst>> crate::adc::AdcPin<crate::peripherals::$adc>
for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P> for OpAmpOutput<'d, 'p, crate::peripherals::$inst, P>
{ {
} }
@ -120,19 +220,79 @@ macro_rules! impl_opamp_output {
}; };
} }
#[cfg(opamp_f3)]
foreach_peripheral!( foreach_peripheral!(
(opamp, OPAMP1) => { (opamp, OPAMP1) => {
impl_opamp_output!(OPAMP1, ADC1, 3); impl_opamp_external_output!(OPAMP1, ADC1, 3);
}; };
(opamp, OPAMP2) => { (opamp, OPAMP2) => {
impl_opamp_output!(OPAMP2, ADC2, 3); impl_opamp_external_output!(OPAMP2, ADC2, 3);
}; };
(opamp, OPAMP3) => { (opamp, OPAMP3) => {
impl_opamp_output!(OPAMP3, ADC3, 1); impl_opamp_external_output!(OPAMP3, ADC3, 1);
}; };
// OPAMP4 only in STM32G4 Cat 3 devices
(opamp, OPAMP4) => { (opamp, OPAMP4) => {
impl_opamp_output!(OPAMP4, ADC4, 3); impl_opamp_external_output!(OPAMP4, ADC4, 3);
};
// OPAMP5 only in STM32G4 Cat 3 devices
(opamp, OPAMP5) => {
impl_opamp_external_output!(OPAMP5, ADC5, 1);
};
// OPAMP6 only in STM32G4 Cat 3/4 devices
(opamp, OPAMP6) => {
impl_opamp_external_output!(OPAMP6, ADC1, 14);
};
);
#[cfg(opamp_g4)]
macro_rules! impl_opamp_internal_output {
($inst:ident, $adc:ident, $ch:expr) => {
foreach_adc!(
($adc, $common_inst:ident, $adc_clock:ident) => {
impl<'d> crate::adc::sealed::AdcPin<crate::peripherals::$adc>
for OpAmpInternalOutput<'d, crate::peripherals::$inst>
{
fn channel(&self) -> u8 {
$ch
}
}
impl<'d> crate::adc::AdcPin<crate::peripherals::$adc>
for OpAmpInternalOutput<'d, crate::peripherals::$inst>
{
}
};
);
};
}
#[cfg(opamp_g4)]
foreach_peripheral!(
(opamp, OPAMP1) => {
impl_opamp_internal_output!(OPAMP1, ADC1, 13);
};
(opamp, OPAMP2) => {
impl_opamp_internal_output!(OPAMP2, ADC2, 16);
};
(opamp, OPAMP3) => {
impl_opamp_internal_output!(OPAMP3, ADC2, 18);
// Only in Cat 3/4 devices
impl_opamp_internal_output!(OPAMP3, ADC3, 13);
};
// OPAMP4 only in Cat 3 devices
(opamp, OPAMP4) => {
impl_opamp_internal_output!(OPAMP4, ADC5, 5);
};
// OPAMP5 only in Cat 3 devices
(opamp, OPAMP5) => {
impl_opamp_internal_output!(OPAMP5, ADC5, 3);
};
// OPAMP6 only in Cat 3/4 devices
(opamp, OPAMP6) => {
// Only in Cat 3 devices
impl_opamp_internal_output!(OPAMP6, ADC4, 17);
// Only in Cat 4 devices
impl_opamp_internal_output!(OPAMP6, ADC3, 17);
}; };
); );
@ -145,13 +305,12 @@ foreach_peripheral! {
} }
impl Instance for crate::peripherals::$inst { impl Instance for crate::peripherals::$inst {
} }
}; };
} }
#[allow(unused_macros)] #[allow(unused_macros)]
macro_rules! impl_opamp_pin { macro_rules! impl_opamp_vp_pin {
($inst:ident, $pin:ident, $ch:expr) => { ($inst:ident, $pin:ident, $ch:expr) => {
impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {} impl crate::opamp::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {}
impl crate::opamp::sealed::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin { impl crate::opamp::sealed::NonInvertingPin<peripherals::$inst> for crate::peripherals::$pin {
@ -161,3 +320,11 @@ macro_rules! impl_opamp_pin {
} }
}; };
} }
#[allow(unused_macros)]
macro_rules! impl_opamp_vout_pin {
($inst:ident, $pin:ident) => {
impl crate::opamp::OutputPin<peripherals::$inst> for crate::peripherals::$pin {}
impl crate::opamp::sealed::OutputPin<peripherals::$inst> for crate::peripherals::$pin {}
};
}

View File

@ -1,8 +1,9 @@
use crate::pac::pwr::vals::Vos;
pub use crate::pac::rcc::vals::{ pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp, Pllq, Pllr, Pllsrc as PllSource, Hpre as AHBPrescaler, Pllm as PllPreDiv, Plln as PllMul, Pllp, Pllq, Pllr, Pllsrc as PllSource,
Ppre as APBPrescaler, Sw as Sysclk, Ppre as APBPrescaler, Sw as Sysclk,
}; };
use crate::pac::{FLASH, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -100,12 +101,17 @@ impl Default for Config {
} }
pub(crate) unsafe fn init(config: Config) { pub(crate) unsafe fn init(config: Config) {
// set VOS to SCALE1, if use PLL
// TODO: check real clock speed before set VOS
if config.pll.is_some() {
PWR.cr1().modify(|w| w.set_vos(Vos::SCALE1));
}
// always enable overdrive for now. Make it configurable in the future. // always enable overdrive for now. Make it configurable in the future.
#[cfg(not(any( #[cfg(not(any(
stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f405, stm32f407, stm32f415, stm32f417 stm32f401, stm32f410, stm32f411, stm32f412, stm32f413, stm32f423, stm32f405, stm32f407, stm32f415, stm32f417
)))] )))]
{ {
use crate::pac::PWR;
PWR.cr1().modify(|w| w.set_oden(true)); PWR.cr1().modify(|w| w.set_oden(true));
while !PWR.csr1().read().odrdy() {} while !PWR.csr1().read().odrdy() {}

View File

@ -7,7 +7,6 @@ pub use crate::pac::rcc::vals::{
Pllr as PllR, Ppre as APBPrescaler, Pllr as PllR, Ppre as APBPrescaler,
}; };
use crate::pac::{PWR, RCC}; use crate::pac::{PWR, RCC};
use crate::rcc::sealed::RccPeripheral;
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -67,23 +66,13 @@ pub struct Pll {
pub enum Clock48MhzSrc { pub enum Clock48MhzSrc {
/// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the /// Use the High Speed Internal Oscillator. For USB usage, the CRS must be used to calibrate the
/// oscillator to comply with the USB specification for oscillator tolerance. /// oscillator to comply with the USB specification for oscillator tolerance.
Hsi48(Option<CrsConfig>), Hsi48(super::Hsi48Config),
/// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the /// Use the PLLQ output. The PLL must be configured to output a 48MHz clock. For USB usage the
/// PLL needs to be using the HSE source to comply with the USB specification for oscillator /// PLL needs to be using the HSE source to comply with the USB specification for oscillator
/// tolerance. /// tolerance.
PllQ, PllQ,
} }
/// Sets the sync source for the Clock Recovery System (CRS).
pub enum CrsSyncSource {
/// Use an external GPIO to sync the CRS.
Gpio,
/// Use the Low Speed External oscillator to sync the CRS.
Lse,
/// Use the USB SOF to sync the CRS.
Usb,
}
/// Clocks configutation /// Clocks configutation
pub struct Config { pub struct Config {
pub mux: ClockSrc, pub mux: ClockSrc,
@ -102,12 +91,6 @@ pub struct Config {
pub ls: super::LsConfig, pub ls: super::LsConfig,
} }
/// Configuration for the Clock Recovery System (CRS) used to trim the HSI48 oscillator.
pub struct CrsConfig {
/// Sync source for the CRS.
pub sync_src: CrsSyncSource,
}
impl Default for Config { impl Default for Config {
#[inline] #[inline]
fn default() -> Config { fn default() -> Config {
@ -118,7 +101,7 @@ impl Default for Config {
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
low_power_run: false, low_power_run: false,
pll: None, pll: None,
clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(None)), clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())),
adc12_clock_source: Adcsel::DISABLE, adc12_clock_source: Adcsel::DISABLE,
adc345_clock_source: Adcsel::DISABLE, adc345_clock_source: Adcsel::DISABLE,
ls: Default::default(), ls: Default::default(),
@ -288,33 +271,8 @@ pub(crate) unsafe fn init(config: Config) {
crate::pac::rcc::vals::Clk48sel::PLL1_Q crate::pac::rcc::vals::Clk48sel::PLL1_Q
} }
Clock48MhzSrc::Hsi48(crs_config) => { Clock48MhzSrc::Hsi48(config) => {
// Enable HSI48 super::init_hsi48(config);
RCC.crrcr().modify(|w| w.set_hsi48on(true));
// Wait for HSI48 to turn on
while RCC.crrcr().read().hsi48rdy() == false {}
// Enable and setup CRS if needed
if let Some(crs_config) = crs_config {
crate::peripherals::CRS::enable_and_reset();
let sync_src = match crs_config.sync_src {
CrsSyncSource::Gpio => crate::pac::crs::vals::Syncsrc::GPIO,
CrsSyncSource::Lse => crate::pac::crs::vals::Syncsrc::LSE,
CrsSyncSource::Usb => crate::pac::crs::vals::Syncsrc::USB,
};
crate::pac::CRS.cfgr().modify(|w| {
w.set_syncsrc(sync_src);
});
// These are the correct settings for standard USB operation. If other settings
// are needed there will need to be additional config options for the CRS.
crate::pac::CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
}
crate::pac::rcc::vals::Clk48sel::HSI48 crate::pac::rcc::vals::Clk48sel::HSI48
} }
}; };

View File

@ -21,9 +21,6 @@ pub const HSI_FREQ: Hertz = Hertz(64_000_000);
/// CSI speed /// CSI speed
pub const CSI_FREQ: Hertz = Hertz(4_000_000); pub const CSI_FREQ: Hertz = Hertz(4_000_000);
/// HSI48 speed
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
const VCO_RANGE: RangeInclusive<Hertz> = Hertz(150_000_000)..=Hertz(420_000_000); const VCO_RANGE: RangeInclusive<Hertz> = Hertz(150_000_000)..=Hertz(420_000_000);
#[cfg(any(stm32h5, pwr_h7rm0455))] #[cfg(any(stm32h5, pwr_h7rm0455))]
const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(128_000_000)..=Hertz(560_000_000); const VCO_WIDE_RANGE: RangeInclusive<Hertz> = Hertz(128_000_000)..=Hertz(560_000_000);
@ -126,7 +123,7 @@ pub struct Config {
pub hsi: Option<HSIPrescaler>, pub hsi: Option<HSIPrescaler>,
pub hse: Option<Hse>, pub hse: Option<Hse>,
pub csi: bool, pub csi: bool,
pub hsi48: bool, pub hsi48: Option<super::Hsi48Config>,
pub sys: Sysclk, pub sys: Sysclk,
pub pll1: Option<Pll>, pub pll1: Option<Pll>,
@ -155,7 +152,7 @@ impl Default for Config {
hsi: Some(HSIPrescaler::DIV1), hsi: Some(HSIPrescaler::DIV1),
hse: None, hse: None,
csi: false, csi: false,
hsi48: false, hsi48: Some(Default::default()),
sys: Sysclk::HSI, sys: Sysclk::HSI,
pll1: None, pll1: None,
pll2: None, pll2: None,
@ -301,14 +298,7 @@ pub(crate) unsafe fn init(config: Config) {
}; };
// Configure HSI48. // Configure HSI48.
RCC.cr().modify(|w| w.set_hsi48on(config.hsi48)); let _hsi48 = config.hsi48.map(super::init_hsi48);
let _hsi48 = match config.hsi48 {
false => None,
true => {
while !RCC.cr().read().hsi48rdy() {}
Some(CSI_FREQ)
}
};
// Configure CSI. // Configure CSI.
RCC.cr().modify(|w| w.set_csion(config.csi)); RCC.cr().modify(|w| w.set_csion(config.csi));

View File

@ -0,0 +1,62 @@
#![allow(unused)]
use crate::pac::crs::vals::Syncsrc;
use crate::pac::{CRS, RCC};
use crate::rcc::sealed::RccPeripheral;
use crate::time::Hertz;
/// HSI48 speed
pub const HSI48_FREQ: Hertz = Hertz(48_000_000);
/// Configuration for the HSI48 clock
#[derive(Clone, Copy, Debug)]
pub struct Hsi48Config {
/// Enable CRS Sync from USB Start Of Frame (SOF) events.
/// Required if HSI48 is going to be used as USB clock.
///
/// Other use cases of CRS are not supported yet.
pub sync_from_usb: bool,
}
impl Default for Hsi48Config {
fn default() -> Self {
Self { sync_from_usb: false }
}
}
pub(crate) fn init_hsi48(config: Hsi48Config) -> Hertz {
// Enable VREFINT reference for HSI48 oscillator
#[cfg(stm32l0)]
crate::pac::SYSCFG.cfgr3().modify(|w| {
w.set_enref_hsi48(true);
w.set_en_vrefint(true);
});
// Enable HSI48
#[cfg(not(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32u5, stm32wba, stm32f0)))]
let r = RCC.crrcr();
#[cfg(any(stm32u5, stm32g0, stm32h5, stm32h7, stm32u5, stm32wba))]
let r = RCC.cr();
#[cfg(any(stm32f0))]
let r = RCC.cr2();
r.modify(|w| w.set_hsi48on(true));
while r.read().hsi48rdy() == false {}
if config.sync_from_usb {
crate::peripherals::CRS::enable_and_reset();
CRS.cfgr().modify(|w| {
w.set_syncsrc(Syncsrc::USB);
});
// These are the correct settings for standard USB operation. If other settings
// are needed there will need to be additional config options for the CRS.
crate::pac::CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
}
HSI48_FREQ
}

View File

@ -3,8 +3,6 @@ pub use crate::pac::rcc::vals::{
Hpre as AHBPrescaler, Msirange as MSIRange, Plldiv as PLLDiv, Plldiv as PllDiv, Pllmul as PLLMul, Pllmul as PllMul, Hpre as AHBPrescaler, Msirange as MSIRange, Plldiv as PLLDiv, Plldiv as PllDiv, Pllmul as PLLMul, Pllmul as PllMul,
Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc, Pllsrc as PLLSource, Ppre as APBPrescaler, Sw as ClockSrc,
}; };
#[cfg(crs)]
use crate::pac::{crs, CRS, SYSCFG};
use crate::pac::{FLASH, PWR, RCC}; use crate::pac::{FLASH, PWR, RCC};
use crate::rcc::{set_freqs, Clocks}; use crate::rcc::{set_freqs, Clocks};
use crate::time::Hertz; use crate::time::Hertz;
@ -47,7 +45,7 @@ pub struct Config {
pub hsi: bool, pub hsi: bool,
pub hse: Option<Hse>, pub hse: Option<Hse>,
#[cfg(crs)] #[cfg(crs)]
pub hsi48: bool, pub hsi48: Option<super::Hsi48Config>,
pub pll: Option<Pll>, pub pll: Option<Pll>,
@ -68,7 +66,7 @@ impl Default for Config {
hse: None, hse: None,
hsi: false, hsi: false,
#[cfg(crs)] #[cfg(crs)]
hsi48: false, hsi48: Some(Default::default()),
pll: None, pll: None,
@ -174,37 +172,11 @@ pub(crate) unsafe fn init(config: Config) {
let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre); let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
#[cfg(crs)] #[cfg(crs)]
if config.hsi48 { let _hsi48 = config.hsi48.map(|config| {
// Reset CRS peripheral
RCC.apb1rstr().modify(|w| w.set_crsrst(true));
RCC.apb1rstr().modify(|w| w.set_crsrst(false));
// Enable CRS peripheral
RCC.apb1enr().modify(|w| w.set_crsen(true));
// Initialize CRS
CRS.cfgr().write(|w|
// Select LSE as synchronization source
w.set_syncsrc(crs::vals::Syncsrc::LSE));
CRS.cr().modify(|w| {
w.set_autotrimen(true);
w.set_cen(true);
});
// Enable VREFINT reference for HSI48 oscillator
SYSCFG.cfgr3().modify(|w| {
w.set_enref_hsi48(true);
w.set_en_vrefint(true);
});
// Select HSI48 as USB clock // Select HSI48 as USB clock
RCC.ccipr().modify(|w| w.set_hsi48msel(true)); RCC.ccipr().modify(|w| w.set_hsi48msel(true));
super::init_hsi48(config)
// Enable dedicated USB clock });
RCC.crrcr().modify(|w| w.set_hsi48on(true));
while !RCC.crrcr().read().hsi48rdy() {}
}
set_freqs(Clocks { set_freqs(Clocks {
sys: sys_clk, sys: sys_clk,

View File

@ -58,8 +58,8 @@ pub struct Config {
pub msi: Option<MSIRange>, pub msi: Option<MSIRange>,
pub hsi: bool, pub hsi: bool,
pub hse: Option<Hse>, pub hse: Option<Hse>,
#[cfg(any(all(stm32l4, not(any(stm32l47x, stm32l48x))), stm32l5, stm32wb))] #[cfg(crs)]
pub hsi48: bool, pub hsi48: Option<super::Hsi48Config>,
// pll // pll
pub pll: Option<Pll>, pub pll: Option<Pll>,
@ -108,8 +108,8 @@ impl Default for Config {
pllsai1: None, pllsai1: None,
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))] #[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
pllsai2: None, pllsai2: None,
#[cfg(any(all(stm32l4, not(any(stm32l47x, stm32l48x))), stm32l5, stm32wb))] #[cfg(crs)]
hsi48: true, hsi48: Some(Default::default()),
#[cfg(any(stm32l4, stm32l5, stm32wb))] #[cfg(any(stm32l4, stm32l5, stm32wb))]
clk48_src: Clk48Src::HSI48, clk48_src: Clk48Src::HSI48,
ls: Default::default(), ls: Default::default(),
@ -126,7 +126,8 @@ pub const WPAN_DEFAULT: Config = Config {
prescaler: HsePrescaler::DIV1, prescaler: HsePrescaler::DIV1,
}), }),
mux: ClockSrc::PLL1_R, mux: ClockSrc::PLL1_R,
hsi48: true, #[cfg(crs)]
hsi48: Some(super::Hsi48Config { sync_from_usb: false }),
msi: None, msi: None,
hsi: false, hsi: false,
clk48_src: Clk48Src::PLL1_Q, clk48_src: Clk48Src::PLL1_Q,
@ -216,15 +217,10 @@ pub(crate) unsafe fn init(config: Config) {
hse.freq hse.freq
}); });
#[cfg(any(all(stm32l4, not(any(stm32l47x, stm32l48x))), stm32l5, stm32wb))] #[cfg(crs)]
let hsi48 = config.hsi48.then(|| { let _hsi48 = config.hsi48.map(super::init_hsi48);
RCC.crrcr().modify(|w| w.set_hsi48on(true)); #[cfg(not(crs))]
while !RCC.crrcr().read().hsi48rdy() {} let _hsi48: Option<Hertz> = None;
Hertz(48_000_000)
});
#[cfg(any(stm32l47x, stm32l48x))]
let hsi48 = None;
let _plls = [ let _plls = [
&config.pll, &config.pll,
@ -275,7 +271,7 @@ pub(crate) unsafe fn init(config: Config) {
RCC.ccipr1().modify(|w| w.set_clk48sel(config.clk48_src)); RCC.ccipr1().modify(|w| w.set_clk48sel(config.clk48_src));
#[cfg(any(stm32l4, stm32l5, stm32wb))] #[cfg(any(stm32l4, stm32l5, stm32wb))]
let _clk48 = match config.clk48_src { let _clk48 = match config.clk48_src {
Clk48Src::HSI48 => hsi48, Clk48Src::HSI48 => _hsi48,
Clk48Src::MSI => msi, Clk48Src::MSI => msi,
Clk48Src::PLLSAI1_Q => pllsai1.q, Clk48Src::PLLSAI1_Q => pllsai1.q,
Clk48Src::PLL1_Q => pll.q, Clk48Src::PLL1_Q => pll.q,

View File

@ -9,6 +9,11 @@ mod mco;
pub use bd::*; pub use bd::*;
pub use mco::*; pub use mco::*;
#[cfg(crs)]
mod hsi48;
#[cfg(crs)]
pub use hsi48::*;
#[cfg_attr(rcc_f0, path = "f0.rs")] #[cfg_attr(rcc_f0, path = "f0.rs")]
#[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")] #[cfg_attr(any(rcc_f1, rcc_f100, rcc_f1cl), path = "f1.rs")]
#[cfg_attr(rcc_f2, path = "f2.rs")] #[cfg_attr(rcc_f2, path = "f2.rs")]

View File

@ -115,7 +115,7 @@ pub struct Config {
pub apb1_pre: APBPrescaler, pub apb1_pre: APBPrescaler,
pub apb2_pre: APBPrescaler, pub apb2_pre: APBPrescaler,
pub apb3_pre: APBPrescaler, pub apb3_pre: APBPrescaler,
pub hsi48: bool, pub hsi48: Option<super::Hsi48Config>,
/// The voltage range influences the maximum clock frequencies for different parts of the /// The voltage range influences the maximum clock frequencies for different parts of the
/// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks /// device. In particular, system clocks exceeding 110 MHz require `RANGE1`, and system clocks
/// exceeding 55 MHz require at least `RANGE2`. /// exceeding 55 MHz require at least `RANGE2`.
@ -189,7 +189,7 @@ impl Default for Config {
apb1_pre: APBPrescaler::DIV1, apb1_pre: APBPrescaler::DIV1,
apb2_pre: APBPrescaler::DIV1, apb2_pre: APBPrescaler::DIV1,
apb3_pre: APBPrescaler::DIV1, apb3_pre: APBPrescaler::DIV1,
hsi48: true, hsi48: Some(Default::default()),
voltage_range: VoltageScale::RANGE3, voltage_range: VoltageScale::RANGE3,
ls: Default::default(), ls: Default::default(),
} }
@ -322,10 +322,7 @@ pub(crate) unsafe fn init(config: Config) {
} }
}; };
if config.hsi48 { let _hsi48 = config.hsi48.map(super::init_hsi48);
RCC.cr().modify(|w| w.set_hsi48on(true));
while !RCC.cr().read().hsi48rdy() {}
}
// The clock source is ready // The clock source is ready
// Calculate and set the flash wait states // Calculate and set the flash wait states

View File

@ -40,6 +40,7 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
// Handle RX // Handle RX
while r.gintsts().read().rxflvl() { while r.gintsts().read().rxflvl() {
let status = r.grxstsp().read(); let status = r.grxstsp().read();
trace!("=== status {:08x}", status.0);
let ep_num = status.epnum() as usize; let ep_num = status.epnum() as usize;
let len = status.bcnt() as usize; let len = status.bcnt() as usize;
@ -51,6 +52,15 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
assert!(len == 8, "invalid SETUP packet length={}", len); assert!(len == 8, "invalid SETUP packet length={}", len);
assert!(ep_num == 0, "invalid SETUP packet endpoint={}", ep_num); assert!(ep_num == 0, "invalid SETUP packet endpoint={}", ep_num);
// flushing TX if something stuck in control endpoint
if r.dieptsiz(ep_num).read().pktcnt() != 0 {
r.grstctl().modify(|w| {
w.set_txfnum(ep_num as _);
w.set_txfflsh(true);
});
while r.grstctl().read().txfflsh() {}
}
if state.ep0_setup_ready.load(Ordering::Relaxed) == false { if state.ep0_setup_ready.load(Ordering::Relaxed) == false {
// SAFETY: exclusive access ensured by atomic bool // SAFETY: exclusive access ensured by atomic bool
let data = unsafe { &mut *state.ep0_setup_data.get() }; let data = unsafe { &mut *state.ep0_setup_data.get() };
@ -96,6 +106,11 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
} }
vals::Pktstsd::SETUP_DATA_DONE => { vals::Pktstsd::SETUP_DATA_DONE => {
trace!("SETUP_DATA_DONE ep={}", ep_num); trace!("SETUP_DATA_DONE ep={}", ep_num);
if quirk_setup_late_cnak(r) {
// Clear NAK to indicate we are ready to receive more data
r.doepctl(ep_num).modify(|w| w.set_cnak(true));
}
} }
x => trace!("unknown PKTSTS: {}", x.to_bits()), x => trace!("unknown PKTSTS: {}", x.to_bits()),
} }
@ -911,11 +926,9 @@ impl<'d, T: Instance> embassy_usb_driver::Bus for Bus<'d, T> {
trace!("enumdne"); trace!("enumdne");
let speed = r.dsts().read().enumspd(); let speed = r.dsts().read().enumspd();
trace!(" speed={}", speed.to_bits()); let trdt = calculate_trdt(speed, T::frequency());
trace!(" speed={} trdt={}", speed.to_bits(), trdt);
r.gusbcfg().modify(|w| { r.gusbcfg().modify(|w| w.set_trdt(trdt));
w.set_trdt(calculate_trdt(speed, T::frequency()));
});
r.gintsts().write(|w| w.set_enumdne(true)); // clear r.gintsts().write(|w| w.set_enumdne(true)); // clear
Self::restore_irqs(); Self::restore_irqs();
@ -1304,20 +1317,22 @@ impl<'d, T: Instance> embassy_usb_driver::ControlPipe for ControlPipe<'d, T> {
state.ep_out_wakers[0].register(cx.waker()); state.ep_out_wakers[0].register(cx.waker());
let r = T::regs();
if state.ep0_setup_ready.load(Ordering::Relaxed) { if state.ep0_setup_ready.load(Ordering::Relaxed) {
let data = unsafe { *state.ep0_setup_data.get() }; let data = unsafe { *state.ep0_setup_data.get() };
state.ep0_setup_ready.store(false, Ordering::Release); state.ep0_setup_ready.store(false, Ordering::Release);
// EP0 should not be controlled by `Bus` so this RMW does not need a critical section // EP0 should not be controlled by `Bus` so this RMW does not need a critical section
// Receive 1 SETUP packet // Receive 1 SETUP packet
T::regs().doeptsiz(self.ep_out.info.addr.index()).modify(|w| { r.doeptsiz(self.ep_out.info.addr.index()).modify(|w| {
w.set_rxdpid_stupcnt(1); w.set_rxdpid_stupcnt(1);
}); });
// Clear NAK to indicate we are ready to receive more data // Clear NAK to indicate we are ready to receive more data
T::regs().doepctl(self.ep_out.info.addr.index()).modify(|w| { if !quirk_setup_late_cnak(r) {
w.set_cnak(true); r.doepctl(self.ep_out.info.addr.index()).modify(|w| w.set_cnak(true));
}); }
trace!("SETUP received: {:?}", data); trace!("SETUP received: {:?}", data);
Poll::Ready(data) Poll::Ready(data)
@ -1453,3 +1468,7 @@ fn calculate_trdt(speed: vals::Dspd, ahb_freq: Hertz) -> u8 {
_ => unimplemented!(), _ => unimplemented!(),
} }
} }
fn quirk_setup_late_cnak(r: crate::pac::otg::Otg) -> bool {
r.cid().read().0 & 0xf000 == 0x1000
}

View File

@ -406,6 +406,16 @@ impl<'d, D: Driver<'d>> UsbDevice<'d, D> {
let max_packet_size = self.control.max_packet_size(); let max_packet_size = self.control.max_packet_size();
let mut total = 0; let mut total = 0;
if req_length > self.control_buf.len() {
warn!(
"got CONTROL OUT with length {} higher than the control_buf len {}, rejecting.",
req_length,
self.control_buf.len()
);
self.control.reject().await;
return;
}
let chunks = self.control_buf[..req_length].chunks_mut(max_packet_size); let chunks = self.control_buf[..req_length].chunks_mut(max_packet_size);
for (first, last, chunk) in first_last(chunks) { for (first, last, chunk) in first_last(chunks) {
let size = match self.control.data_out(chunk, first, last).await { let size = match self.control.data_out(chunk, first, last).await {

View File

@ -39,7 +39,7 @@ async fn main(_spawner: Spawner) -> ! {
let mut vrefint = adc.enable_vref(&mut Delay); let mut vrefint = adc.enable_vref(&mut Delay);
let mut temperature = adc.enable_temperature(); let mut temperature = adc.enable_temperature();
let mut buffer = opamp.buffer_for(&mut p.PA7, OpAmpGain::Mul1); let mut buffer = opamp.buffer_ext(&p.PA7, &mut p.PA6, OpAmpGain::Mul1);
loop { loop {
let vref = adc.read(&mut vrefint).await; let vref = adc.read(&mut vrefint).await;

View File

@ -0,0 +1,201 @@
//! Example of using USB without a pre-defined class, but instead responding to
//! raw USB control requests.
//!
//! The host computer can either:
//! * send a command, with a 16-bit request ID, a 16-bit value, and an optional data buffer
//! * request some data, with a 16-bit request ID, a 16-bit value, and a length of data to receive
//!
//! For higher throughput data, you can add some bulk endpoints after creating the alternate,
//! but for low rate command/response, plain control transfers can be very simple and effective.
//!
//! Example code to send/receive data using `nusb`:
//!
//! ```ignore
//! use futures_lite::future::block_on;
//! use nusb::transfer::{ControlIn, ControlOut, ControlType, Recipient};
//!
//! fn main() {
//! let di = nusb::list_devices()
//! .unwrap()
//! .find(|d| d.vendor_id() == 0xc0de && d.product_id() == 0xcafe)
//! .expect("no device found");
//! let device = di.open().expect("error opening device");
//! let interface = device.claim_interface(0).expect("error claiming interface");
//!
//! // Send "hello world" to device
//! let result = block_on(interface.control_out(ControlOut {
//! control_type: ControlType::Vendor,
//! recipient: Recipient::Interface,
//! request: 100,
//! value: 200,
//! index: 0,
//! data: b"hello world",
//! }));
//! println!("{result:?}");
//!
//! // Receive "hello" from device
//! let result = block_on(interface.control_in(ControlIn {
//! control_type: ControlType::Vendor,
//! recipient: Recipient::Interface,
//! request: 101,
//! value: 201,
//! index: 0,
//! length: 5,
//! }));
//! println!("{result:?}");
//! }
//! ```
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::time::Hertz;
use embassy_stm32::usb_otg::Driver;
use embassy_stm32::{bind_interrupts, peripherals, usb_otg, Config};
use embassy_usb::control::{InResponse, OutResponse, Recipient, Request, RequestType};
use embassy_usb::types::InterfaceNumber;
use embassy_usb::{Builder, Handler};
use {defmt_rtt as _, panic_probe as _};
bind_interrupts!(struct Irqs {
OTG_FS => usb_otg::InterruptHandler<peripherals::USB_OTG_FS>;
});
#[embassy_executor::main]
async fn main(_spawner: Spawner) {
info!("Hello World!");
let mut config = Config::default();
{
use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000),
mode: HseMode::Bypass,
});
config.rcc.pll_src = PllSource::HSE;
config.rcc.pll = Some(Pll {
prediv: PllPreDiv::DIV4,
mul: PllMul::MUL168,
divp: Some(Pllp::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
divq: Some(Pllq::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
divr: None,
});
config.rcc.ahb_pre = AHBPrescaler::DIV1;
config.rcc.apb1_pre = APBPrescaler::DIV4;
config.rcc.apb2_pre = APBPrescaler::DIV2;
config.rcc.sys = Sysclk::PLL1_P;
}
let p = embassy_stm32::init(config);
// Create the driver, from the HAL.
let mut ep_out_buffer = [0u8; 256];
let mut config = embassy_stm32::usb_otg::Config::default();
config.vbus_detection = true;
let driver = Driver::new_fs(p.USB_OTG_FS, Irqs, p.PA12, p.PA11, &mut ep_out_buffer, config);
// Create embassy-usb Config
let mut config = embassy_usb::Config::new(0xc0de, 0xcafe);
config.manufacturer = Some("Embassy");
config.product = Some("USB-raw example");
config.serial_number = Some("12345678");
// Required for windows compatibility.
// https://developer.nordicsemi.com/nRF_Connect_SDK/doc/1.9.1/kconfig/CONFIG_CDC_ACM_IAD.html#help
config.device_class = 0xEF;
config.device_sub_class = 0x02;
config.device_protocol = 0x01;
config.composite_with_iads = true;
// Create embassy-usb DeviceBuilder using the driver and config.
// It needs some buffers for building the descriptors.
let mut device_descriptor = [0; 256];
let mut config_descriptor = [0; 256];
let mut bos_descriptor = [0; 256];
let mut control_buf = [0; 64];
let mut handler = ControlHandler {
if_num: InterfaceNumber(0),
};
let mut builder = Builder::new(
driver,
config,
&mut device_descriptor,
&mut config_descriptor,
&mut bos_descriptor,
&mut control_buf,
);
// Add a vendor-specific function (class 0xFF), and corresponding interface,
// that uses our custom handler.
let mut function = builder.function(0xFF, 0, 0);
let mut interface = function.interface();
let _alternate = interface.alt_setting(0xFF, 0, 0, None);
handler.if_num = interface.interface_number();
drop(function);
builder.handler(&mut handler);
// Build the builder.
let mut usb = builder.build();
// Run the USB device.
usb.run().await;
}
/// Handle CONTROL endpoint requests and responses. For many simple requests and responses
/// you can get away with only using the control endpoint.
struct ControlHandler {
if_num: InterfaceNumber,
}
impl Handler for ControlHandler {
/// Respond to HostToDevice control messages, where the host sends us a command and
/// optionally some data, and we can only acknowledge or reject it.
fn control_out<'a>(&'a mut self, req: Request, buf: &'a [u8]) -> Option<OutResponse> {
// Log the request before filtering to help with debugging.
info!("Got control_out, request={}, buf={:a}", req, buf);
// Only handle Vendor request types to an Interface.
if req.request_type != RequestType::Vendor || req.recipient != Recipient::Interface {
return None;
}
// Ignore requests to other interfaces.
if req.index != self.if_num.0 as u16 {
return None;
}
// Accept request 100, value 200, reject others.
if req.request == 100 && req.value == 200 {
Some(OutResponse::Accepted)
} else {
Some(OutResponse::Rejected)
}
}
/// Respond to DeviceToHost control messages, where the host requests some data from us.
fn control_in<'a>(&'a mut self, req: Request, buf: &'a mut [u8]) -> Option<InResponse<'a>> {
info!("Got control_in, request={}", req);
// Only handle Vendor request types to an Interface.
if req.request_type != RequestType::Vendor || req.recipient != Recipient::Interface {
return None;
}
// Ignore requests to other interfaces.
if req.index != self.if_num.0 as u16 {
return None;
}
// Respond "hello" to request 101, value 201, when asked for 5 bytes, otherwise reject.
if req.request == 101 && req.value == 201 && req.length == 5 {
buf[..5].copy_from_slice(b"hello");
Some(InResponse::Accepted(&buf[..5]))
} else {
Some(InResponse::Rejected)
}
}
}

View File

@ -4,7 +4,7 @@
use defmt::{panic, *}; use defmt::{panic, *};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, CrsConfig, CrsSyncSource, Pll, PllM, PllN, PllQ, PllR, PllSrc}; use embassy_stm32::rcc::{Clock48MhzSrc, ClockSrc, Hsi48Config, Pll, PllM, PllN, PllQ, PllR, PllSrc};
use embassy_stm32::time::Hertz; use embassy_stm32::time::Hertz;
use embassy_stm32::usb::{self, Driver, Instance}; use embassy_stm32::usb::{self, Driver, Instance};
use embassy_stm32::{bind_interrupts, peripherals, Config}; use embassy_stm32::{bind_interrupts, peripherals, Config};
@ -41,9 +41,7 @@ async fn main(_spawner: Spawner) {
if USE_HSI48 { if USE_HSI48 {
// Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator. // Sets up the Clock Recovery System (CRS) to use the USB SOF to trim the HSI48 oscillator.
config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Some(CrsConfig { config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::Hsi48(Hsi48Config { sync_from_usb: true }));
sync_src: CrsSyncSource::Usb,
})));
} else { } else {
config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ); config.rcc.clock_48mhz_src = Some(Clock48MhzSrc::PllQ);
} }

View File

@ -37,7 +37,7 @@ async fn net_task(stack: &'static Stack<Device>) -> ! {
async fn main(spawner: Spawner) -> ! { async fn main(spawner: Spawner) -> ! {
let mut config = Config::default(); let mut config = Config::default();
config.rcc.hsi = None; config.rcc.hsi = None;
config.rcc.hsi48 = true; // needed for rng config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.hse = Some(Hse { config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000), freq: Hertz(8_000_000),
mode: HseMode::BypassDigital, mode: HseMode::BypassDigital,

View File

@ -4,9 +4,6 @@
use defmt::{panic, *}; use defmt::{panic, *};
use embassy_executor::Spawner; use embassy_executor::Spawner;
use embassy_stm32::rcc::{
AHBPrescaler, APBPrescaler, Hse, HseMode, Pll, PllDiv, PllMul, PllPreDiv, PllSource, Sysclk, VoltageScale,
};
use embassy_stm32::time::Hertz; use embassy_stm32::time::Hertz;
use embassy_stm32::usb::{Driver, Instance}; use embassy_stm32::usb::{Driver, Instance};
use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config}; use embassy_stm32::{bind_interrupts, pac, peripherals, usb, Config};
@ -23,26 +20,29 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = Config::default(); let mut config = Config::default();
config.rcc.hsi = None; {
config.rcc.hsi48 = true; // needed for usb use embassy_stm32::rcc::*;
config.rcc.hse = Some(Hse { config.rcc.hsi = None;
freq: Hertz(8_000_000), config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
mode: HseMode::BypassDigital, config.rcc.hse = Some(Hse {
}); freq: Hertz(8_000_000),
config.rcc.pll1 = Some(Pll { mode: HseMode::BypassDigital,
source: PllSource::HSE, });
prediv: PllPreDiv::DIV2, config.rcc.pll1 = Some(Pll {
mul: PllMul::MUL125, source: PllSource::HSE,
divp: Some(PllDiv::DIV2), // 250mhz prediv: PllPreDiv::DIV2,
divq: None, mul: PllMul::MUL125,
divr: None, divp: Some(PllDiv::DIV2), // 250mhz
}); divq: None,
config.rcc.ahb_pre = AHBPrescaler::DIV2; divr: None,
config.rcc.apb1_pre = APBPrescaler::DIV4; });
config.rcc.apb2_pre = APBPrescaler::DIV2; config.rcc.ahb_pre = AHBPrescaler::DIV2;
config.rcc.apb3_pre = APBPrescaler::DIV4; config.rcc.apb1_pre = APBPrescaler::DIV4;
config.rcc.sys = Sysclk::PLL1_P; config.rcc.apb2_pre = APBPrescaler::DIV2;
config.rcc.voltage_scale = VoltageScale::Scale0; config.rcc.apb3_pre = APBPrescaler::DIV4;
config.rcc.sys = Sysclk::PLL1_P;
config.rcc.voltage_scale = VoltageScale::Scale0;
}
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
info!("Hello World!"); info!("Hello World!");

View File

@ -36,7 +36,7 @@ async fn main(spawner: Spawner) -> ! {
use embassy_stm32::rcc::*; use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
source: PllSource::HSI, source: PllSource::HSI,
prediv: PllPreDiv::DIV4, prediv: PllPreDiv::DIV4,

View File

@ -37,7 +37,7 @@ async fn main(spawner: Spawner) -> ! {
use embassy_stm32::rcc::*; use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
source: PllSource::HSI, source: PllSource::HSI,
prediv: PllPreDiv::DIV4, prediv: PllPreDiv::DIV4,

View File

@ -19,7 +19,6 @@ async fn main(_spawner: Spawner) {
use embassy_stm32::rcc::*; use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
source: PllSource::HSI, source: PllSource::HSI,
prediv: PllPreDiv::DIV4, prediv: PllPreDiv::DIV4,

View File

@ -15,7 +15,7 @@ bind_interrupts!(struct Irqs {
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = Config::default(); let mut config = Config::default();
config.rcc.hsi48 = true; // needed for RNG. config.rcc.hsi48 = Some(Default::default()); // needed for RNG
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
info!("Hello World!"); info!("Hello World!");

View File

@ -25,7 +25,7 @@ async fn main(_spawner: Spawner) {
use embassy_stm32::rcc::*; use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for USB config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
source: PllSource::HSI, source: PllSource::HSI,
prediv: PllPreDiv::DIV4, prediv: PllPreDiv::DIV4,

View File

@ -11,8 +11,7 @@ use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = Config::default(); let config = Config::default();
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
let button = Input::new(p.PB2, Pull::Up); let button = Input::new(p.PB2, Pull::Up);

View File

@ -23,8 +23,8 @@ const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriatel
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.hsi = true;
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
let mut spi_config = spi::Config::default(); let mut spi_config = spi::Config::default();

View File

@ -33,8 +33,8 @@ const LORAWAN_REGION: region::Region = region::Region::EU868; // warning: set th
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.hsi = true;
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
let mut spi_config = spi::Config::default(); let mut spi_config = spi::Config::default();

View File

@ -23,8 +23,8 @@ const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriatel
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.hsi = true;
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
let mut spi_config = spi::Config::default(); let mut spi_config = spi::Config::default();

View File

@ -23,8 +23,8 @@ const LORA_FREQUENCY_IN_HZ: u32 = 903_900_000; // warning: set this appropriatel
#[embassy_executor::main] #[embassy_executor::main]
async fn main(_spawner: Spawner) { async fn main(_spawner: Spawner) {
let mut config = embassy_stm32::Config::default(); let mut config = embassy_stm32::Config::default();
config.rcc.hsi = true;
config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI; config.rcc.mux = embassy_stm32::rcc::ClockSrc::HSI;
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);
let mut spi_config = spi::Config::default(); let mut spi_config = spi::Config::default();

View File

@ -90,7 +90,7 @@ async fn main(spawner: Spawner) {
divq: None, divq: None,
divr: Some(PllRDiv::DIV2), // sysclk 80Mhz clock (8 / 1 * 20 / 2) divr: Some(PllRDiv::DIV2), // sysclk 80Mhz clock (8 / 1 * 20 / 2)
}); });
config.rcc.hsi48 = true; // needed for rng config.rcc.hsi48 = Some(Default::default()); // needed for RNG
} }
let dp = embassy_stm32::init(config); let dp = embassy_stm32::init(config);

View File

@ -23,7 +23,7 @@ async fn main(_spawner: Spawner) {
info!("Hello World!"); info!("Hello World!");
let mut config = Config::default(); let mut config = Config::default();
config.rcc.hsi48 = true; config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
config.rcc.mux = ClockSrc::PLL1_R; config.rcc.mux = ClockSrc::PLL1_R;
config.rcc.hsi = true; config.rcc.hsi = true;
config.rcc.pll = Some(Pll { config.rcc.pll = Some(Pll {

View File

@ -29,8 +29,7 @@ async fn main(_spawner: Spawner) {
n: Plln::MUL10, n: Plln::MUL10,
r: Plldiv::DIV1, r: Plldiv::DIV1,
}); });
//config.rcc.mux = ClockSrc::MSI(MSIRange::Range48mhz); config.rcc.hsi48 = Some(Hsi48Config { sync_from_usb: true }); // needed for USB
config.rcc.hsi48 = true;
let p = embassy_stm32::init(config); let p = embassy_stm32::init(config);

View File

@ -306,7 +306,7 @@ pub fn config() -> Config {
{ {
use embassy_stm32::rcc::*; use embassy_stm32::rcc::*;
config.rcc.hsi = None; config.rcc.hsi = None;
config.rcc.hsi48 = true; // needed for rng config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.hse = Some(Hse { config.rcc.hse = Some(Hse {
freq: Hertz(8_000_000), freq: Hertz(8_000_000),
mode: HseMode::BypassDigital, mode: HseMode::BypassDigital,
@ -332,7 +332,7 @@ pub fn config() -> Config {
use embassy_stm32::rcc::*; use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
source: PllSource::HSI, source: PllSource::HSI,
prediv: PllPreDiv::DIV4, prediv: PllPreDiv::DIV4,
@ -364,7 +364,7 @@ pub fn config() -> Config {
use embassy_stm32::rcc::*; use embassy_stm32::rcc::*;
config.rcc.hsi = Some(HSIPrescaler::DIV1); config.rcc.hsi = Some(HSIPrescaler::DIV1);
config.rcc.csi = true; config.rcc.csi = true;
config.rcc.hsi48 = true; // needed for RNG config.rcc.hsi48 = Some(Default::default()); // needed for RNG
config.rcc.pll1 = Some(Pll { config.rcc.pll1 = Some(Pll {
source: PllSource::HSI, source: PllSource::HSI,
prediv: PllPreDiv::DIV4, prediv: PllPreDiv::DIV4,