mirror of
https://github.com/embassy-rs/embassy.git
synced 2024-11-22 06:42:32 +00:00
Merge branch 'main' into hash
This commit is contained in:
commit
1f940bf9e8
7
ci.sh
7
ci.sh
@ -67,6 +67,9 @@ cargo batch \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv7em-none-eabi --features nrf52840,gpiote,defmt,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time,time-driver-rtc1 \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,defmt,time \
|
||||
--- build --release --manifest-path embassy-nrf/Cargo.toml --target thumbv6m-none-eabi --features nrf51,time \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,defmt \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,log \
|
||||
--- build --release --manifest-path embassy-rp/Cargo.toml --target thumbv6m-none-eabi --features time-driver,intrinsics \
|
||||
@ -148,6 +151,7 @@ cargo batch \
|
||||
--- build --release --manifest-path examples/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/examples/nrf52840 \
|
||||
--- build --release --manifest-path examples/nrf5340/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf5340 \
|
||||
--- build --release --manifest-path examples/nrf9160/Cargo.toml --target thumbv8m.main-none-eabihf --out-dir out/examples/nrf9160 \
|
||||
--- build --release --manifest-path examples/nrf51/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/nrf51 \
|
||||
--- build --release --manifest-path examples/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/rp \
|
||||
--- build --release --manifest-path examples/stm32f0/Cargo.toml --target thumbv6m-none-eabi --out-dir out/examples/stm32f0 \
|
||||
--- build --release --manifest-path examples/stm32f1/Cargo.toml --target thumbv7m-none-eabi --out-dir out/examples/stm32f1 \
|
||||
@ -211,7 +215,8 @@ cargo batch \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32l496zg --out-dir out/tests/stm32l496zg \
|
||||
--- build --release --manifest-path tests/stm32/Cargo.toml --target thumbv7em-none-eabi --features stm32wl55jc --out-dir out/tests/stm32wl55jc \
|
||||
--- build --release --manifest-path tests/rp/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/rpi-pico \
|
||||
--- build --release --manifest-path tests/nrf/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
|
||||
--- build --release --manifest-path tests/nrf52840/Cargo.toml --target thumbv7em-none-eabi --out-dir out/tests/nrf52840-dk \
|
||||
--- build --release --manifest-path tests/nrf51422/Cargo.toml --target thumbv6m-none-eabi --out-dir out/tests/nrf51-dk \
|
||||
--- build --release --manifest-path tests/riscv32/Cargo.toml --target riscv32imac-unknown-none-elf \
|
||||
$BUILD_EXTRA
|
||||
|
||||
|
@ -342,7 +342,7 @@ impl<'a> TcpSocket<'a> {
|
||||
self.io.with(|s, _| s.may_send())
|
||||
}
|
||||
|
||||
/// return whether the recieve half of the full-duplex connection is open.
|
||||
/// return whether the receive half of the full-duplex connection is open.
|
||||
/// This function returns true if it’s possible to receive data from the remote endpoint.
|
||||
/// It will return true while there is data in the receive buffer, and if there isn’t,
|
||||
/// as long as the remote endpoint has not closed the connection.
|
||||
@ -471,7 +471,7 @@ impl<'d> TcpIo<'d> {
|
||||
s.register_recv_waker(cx.waker());
|
||||
Poll::Pending
|
||||
} else {
|
||||
// if we can't receive because the recieve half of the duplex connection is closed then return an error
|
||||
// if we can't receive because the receive half of the duplex connection is closed then return an error
|
||||
Poll::Ready(Err(Error::ConnectionReset))
|
||||
}
|
||||
} else {
|
||||
|
@ -15,6 +15,7 @@ src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-nrf/s
|
||||
|
||||
features = ["time", "defmt", "unstable-pac", "gpiote", "time-driver-rtc1"]
|
||||
flavors = [
|
||||
{ regex_feature = "nrf51", target = "thumbv6m-none-eabi" },
|
||||
{ regex_feature = "nrf52.*", target = "thumbv7em-none-eabihf" },
|
||||
{ regex_feature = "nrf53.*", target = "thumbv8m.main-none-eabihf" },
|
||||
{ regex_feature = "nrf91.*", target = "thumbv8m.main-none-eabihf" },
|
||||
@ -28,6 +29,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
||||
default = ["rt"]
|
||||
## Cortex-M runtime (enabled by default)
|
||||
rt = [
|
||||
"nrf51-pac?/rt",
|
||||
"nrf52805-pac?/rt",
|
||||
"nrf52810-pac?/rt",
|
||||
"nrf52811-pac?/rt",
|
||||
@ -71,6 +73,8 @@ reset-pin-as-gpio = []
|
||||
qspi-multiwrite-flash = []
|
||||
|
||||
#! ### Chip selection features
|
||||
## nRF51
|
||||
nrf51 = ["nrf51-pac", "_nrf51"]
|
||||
## nRF52805
|
||||
nrf52805 = ["nrf52805-pac", "_nrf52"]
|
||||
## nRF52810
|
||||
@ -104,6 +108,7 @@ _nrf5340-net = ["_nrf5340", "nrf5340-net-pac"]
|
||||
_nrf5340 = ["_gpio-p1", "_dppi"]
|
||||
_nrf9160 = ["nrf9160-pac", "_dppi"]
|
||||
_nrf52 = ["_ppi"]
|
||||
_nrf51 = ["_ppi"]
|
||||
|
||||
_time-driver = ["dep:embassy-time-driver", "embassy-time-driver?/tick-hz-32_768"]
|
||||
|
||||
@ -144,6 +149,7 @@ embedded-storage-async = "0.4.0"
|
||||
cfg-if = "1.0.0"
|
||||
document-features = "0.2.7"
|
||||
|
||||
nrf51-pac = { version = "0.12.0", optional = true }
|
||||
nrf52805-pac = { version = "0.12.0", optional = true }
|
||||
nrf52810-pac = { version = "0.12.0", optional = true }
|
||||
nrf52811-pac = { version = "0.12.0", optional = true }
|
||||
|
@ -14,11 +14,12 @@ For a complete list of available peripherals and features, see the [embassy-nrf
|
||||
|
||||
The `embassy-nrf` HAL supports most variants of the nRF family:
|
||||
|
||||
* nRF51 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf51))
|
||||
* nRF52 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf52840))
|
||||
* nRF53 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf5340))
|
||||
* nRF91 ([examples](https://github.com/embassy-rs/embassy/tree/main/examples/nrf9160))
|
||||
|
||||
Most peripherals are supported. To check what's available, make sure to pick the MCU you're targeting in the top menu in the [documentation](https://docs.embassy.dev/embassy-nrf).
|
||||
Most peripherals are supported, but can vary between chip families. To check what's available, make sure to pick the MCU you're targeting in the top menu in the [documentation](https://docs.embassy.dev/embassy-nrf).
|
||||
|
||||
For MCUs with TrustZone support, both Secure (S) and Non-Secure (NS) modes are supported. Running in Secure mode
|
||||
allows running Rust code without a SPM or TF-M binary, saving flash space and simplifying development.
|
||||
|
169
embassy-nrf/src/chips/nrf51.rs
Normal file
169
embassy-nrf/src/chips/nrf51.rs
Normal file
@ -0,0 +1,169 @@
|
||||
pub use nrf51_pac as pac;
|
||||
|
||||
/// The maximum buffer size that the EasyDMA can send/recv in one operation.
|
||||
pub const EASY_DMA_SIZE: usize = (1 << 14) - 1;
|
||||
|
||||
pub const FLASH_SIZE: usize = 128 * 1024;
|
||||
|
||||
embassy_hal_internal::peripherals! {
|
||||
// RTC
|
||||
RTC0,
|
||||
RTC1,
|
||||
|
||||
// WDT
|
||||
WDT,
|
||||
|
||||
// NVMC
|
||||
NVMC,
|
||||
|
||||
// RNG
|
||||
RNG,
|
||||
|
||||
// UARTE
|
||||
UART0,
|
||||
|
||||
// SPI/TWI
|
||||
TWI0,
|
||||
SPI0,
|
||||
|
||||
// ADC
|
||||
ADC,
|
||||
|
||||
// TIMER
|
||||
TIMER0,
|
||||
TIMER1,
|
||||
TIMER2,
|
||||
|
||||
// GPIOTE
|
||||
GPIOTE_CH0,
|
||||
GPIOTE_CH1,
|
||||
GPIOTE_CH2,
|
||||
GPIOTE_CH3,
|
||||
|
||||
// PPI
|
||||
PPI_CH0,
|
||||
PPI_CH1,
|
||||
PPI_CH2,
|
||||
PPI_CH3,
|
||||
PPI_CH4,
|
||||
PPI_CH5,
|
||||
PPI_CH6,
|
||||
PPI_CH7,
|
||||
PPI_CH8,
|
||||
PPI_CH9,
|
||||
PPI_CH10,
|
||||
PPI_CH11,
|
||||
PPI_CH12,
|
||||
PPI_CH13,
|
||||
PPI_CH14,
|
||||
PPI_CH15,
|
||||
|
||||
PPI_GROUP0,
|
||||
PPI_GROUP1,
|
||||
PPI_GROUP2,
|
||||
PPI_GROUP3,
|
||||
|
||||
// GPIO port 0
|
||||
P0_00,
|
||||
P0_01,
|
||||
P0_02,
|
||||
P0_03,
|
||||
P0_04,
|
||||
P0_05,
|
||||
P0_06,
|
||||
P0_07,
|
||||
P0_08,
|
||||
P0_09,
|
||||
P0_10,
|
||||
P0_11,
|
||||
P0_12,
|
||||
P0_13,
|
||||
P0_14,
|
||||
P0_15,
|
||||
P0_16,
|
||||
P0_17,
|
||||
P0_18,
|
||||
P0_19,
|
||||
P0_20,
|
||||
P0_21,
|
||||
P0_22,
|
||||
P0_23,
|
||||
P0_24,
|
||||
P0_25,
|
||||
P0_26,
|
||||
P0_27,
|
||||
P0_28,
|
||||
P0_29,
|
||||
P0_30,
|
||||
P0_31,
|
||||
|
||||
// TEMP
|
||||
TEMP,
|
||||
}
|
||||
|
||||
impl_timer!(TIMER0, TIMER0, TIMER0);
|
||||
impl_timer!(TIMER1, TIMER1, TIMER1);
|
||||
impl_timer!(TIMER2, TIMER2, TIMER2);
|
||||
|
||||
impl_rng!(RNG, RNG, RNG);
|
||||
|
||||
impl_pin!(P0_00, 0, 0);
|
||||
impl_pin!(P0_01, 0, 1);
|
||||
impl_pin!(P0_02, 0, 2);
|
||||
impl_pin!(P0_03, 0, 3);
|
||||
impl_pin!(P0_04, 0, 4);
|
||||
impl_pin!(P0_05, 0, 5);
|
||||
impl_pin!(P0_06, 0, 6);
|
||||
impl_pin!(P0_07, 0, 7);
|
||||
impl_pin!(P0_08, 0, 8);
|
||||
impl_pin!(P0_09, 0, 9);
|
||||
impl_pin!(P0_10, 0, 10);
|
||||
impl_pin!(P0_11, 0, 11);
|
||||
impl_pin!(P0_12, 0, 12);
|
||||
impl_pin!(P0_13, 0, 13);
|
||||
impl_pin!(P0_14, 0, 14);
|
||||
impl_pin!(P0_15, 0, 15);
|
||||
impl_pin!(P0_16, 0, 16);
|
||||
impl_pin!(P0_17, 0, 17);
|
||||
impl_pin!(P0_18, 0, 18);
|
||||
impl_pin!(P0_19, 0, 19);
|
||||
impl_pin!(P0_20, 0, 20);
|
||||
impl_pin!(P0_21, 0, 21);
|
||||
impl_pin!(P0_22, 0, 22);
|
||||
impl_pin!(P0_23, 0, 23);
|
||||
impl_pin!(P0_24, 0, 24);
|
||||
impl_pin!(P0_25, 0, 25);
|
||||
impl_pin!(P0_26, 0, 26);
|
||||
impl_pin!(P0_27, 0, 27);
|
||||
impl_pin!(P0_28, 0, 28);
|
||||
impl_pin!(P0_29, 0, 29);
|
||||
impl_pin!(P0_30, 0, 30);
|
||||
impl_pin!(P0_31, 0, 31);
|
||||
|
||||
embassy_hal_internal::interrupt_mod!(
|
||||
POWER_CLOCK,
|
||||
RADIO,
|
||||
UART0,
|
||||
SPI0_TWI0,
|
||||
SPI1_TWI1,
|
||||
GPIOTE,
|
||||
ADC,
|
||||
TIMER0,
|
||||
TIMER1,
|
||||
TIMER2,
|
||||
RTC0,
|
||||
TEMP,
|
||||
RNG,
|
||||
ECB,
|
||||
CCM_AAR,
|
||||
WDT,
|
||||
RTC1,
|
||||
QDEC,
|
||||
LPCOMP,
|
||||
SWI0,
|
||||
SWI1,
|
||||
SWI2,
|
||||
SWI3,
|
||||
SWI4,
|
||||
SWI5,
|
||||
);
|
@ -8,7 +8,13 @@ use cfg_if::cfg_if;
|
||||
use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef};
|
||||
|
||||
use self::sealed::Pin as _;
|
||||
#[cfg(feature = "nrf51")]
|
||||
use crate::pac::gpio;
|
||||
#[cfg(feature = "nrf51")]
|
||||
use crate::pac::gpio::pin_cnf::{DRIVE_A, PULL_A};
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
use crate::pac::p0 as gpio;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
use crate::pac::p0::pin_cnf::{DRIVE_A, PULL_A};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
@ -376,6 +382,9 @@ pub(crate) mod sealed {
|
||||
fn block(&self) -> &gpio::RegisterBlock {
|
||||
unsafe {
|
||||
match self.pin_port() / 32 {
|
||||
#[cfg(feature = "nrf51")]
|
||||
0 => &*pac::GPIO::ptr(),
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
0 => &*pac::P0::ptr(),
|
||||
#[cfg(feature = "_gpio-p1")]
|
||||
1 => &*pac::P1::ptr(),
|
||||
@ -478,6 +487,7 @@ impl<'a, P: Pin> PselBits for Option<PeripheralRef<'a, P>> {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn deconfigure_pin(psel_bits: u32) {
|
||||
if psel_bits & 0x8000_0000 != 0 {
|
||||
return;
|
||||
|
@ -40,6 +40,7 @@ pub(crate) mod util;
|
||||
#[cfg(feature = "_time-driver")]
|
||||
mod time_driver;
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod buffered_uarte;
|
||||
pub mod gpio;
|
||||
#[cfg(feature = "gpiote")]
|
||||
@ -58,7 +59,12 @@ pub mod nvmc;
|
||||
))]
|
||||
pub mod pdm;
|
||||
pub mod ppi;
|
||||
#[cfg(not(any(feature = "nrf52805", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
#[cfg(not(any(
|
||||
feature = "nrf51",
|
||||
feature = "nrf52805",
|
||||
feature = "nrf52820",
|
||||
feature = "_nrf5340-net"
|
||||
)))]
|
||||
pub mod pwm;
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf9160", feature = "_nrf5340-net")))]
|
||||
pub mod qdec;
|
||||
@ -66,15 +72,20 @@ pub mod qdec;
|
||||
pub mod qspi;
|
||||
#[cfg(not(any(feature = "_nrf5340-app", feature = "_nrf9160")))]
|
||||
pub mod rng;
|
||||
#[cfg(not(any(feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
#[cfg(not(any(feature = "nrf51", feature = "nrf52820", feature = "_nrf5340-net")))]
|
||||
pub mod saadc;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod spim;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod spis;
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
pub mod temp;
|
||||
pub mod timer;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod twim;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod twis;
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
pub mod uarte;
|
||||
#[cfg(any(
|
||||
feature = "_nrf5340-app",
|
||||
@ -87,6 +98,7 @@ pub mod usb;
|
||||
pub mod wdt;
|
||||
|
||||
// This mod MUST go last, so that it sees all the `impl_foo!` macros
|
||||
#[cfg_attr(feature = "nrf51", path = "chips/nrf51.rs")]
|
||||
#[cfg_attr(feature = "nrf52805", path = "chips/nrf52805.rs")]
|
||||
#[cfg_attr(feature = "nrf52810", path = "chips/nrf52810.rs")]
|
||||
#[cfg_attr(feature = "nrf52811", path = "chips/nrf52811.rs")]
|
||||
@ -324,6 +336,7 @@ mod consts {
|
||||
pub const APPROTECT_DISABLED: u32 = 0x0000_005a;
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
enum WriteResult {
|
||||
@ -335,10 +348,12 @@ enum WriteResult {
|
||||
Failed,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult {
|
||||
uicr_write_masked(address, value, 0xFFFF_FFFF)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
unsafe fn uicr_write_masked(address: *mut u32, value: u32, mask: u32) -> WriteResult {
|
||||
let curr_val = address.read_volatile();
|
||||
if curr_val & mask == value & mask {
|
||||
@ -371,9 +386,11 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
// before doing anything important.
|
||||
let peripherals = Peripherals::take();
|
||||
|
||||
#[allow(unused_mut)]
|
||||
let mut needs_reset = false;
|
||||
|
||||
// Setup debug protection.
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
match config.debug {
|
||||
config::Debug::Allowed => {
|
||||
#[cfg(feature = "_nrf52")]
|
||||
@ -489,7 +506,7 @@ pub fn init(config: config::Config) -> Peripherals {
|
||||
}
|
||||
|
||||
// Configure LFCLK.
|
||||
#[cfg(not(any(feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
#[cfg(not(any(feature = "nrf51", feature = "_nrf5340", feature = "_nrf9160")))]
|
||||
match config.lfclk_source {
|
||||
config::LfclkSource::InternalRC => r.lfclksrc.write(|w| w.src().rc()),
|
||||
config::LfclkSource::Synthesized => r.lfclksrc.write(|w| w.src().synth()),
|
||||
|
@ -284,6 +284,7 @@ impl ConfigurableChannel for AnyConfigurableChannel {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
macro_rules! impl_ppi_channel {
|
||||
($type:ident, $number:expr) => {
|
||||
impl crate::ppi::sealed::Channel for peripherals::$type {}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use embassy_hal_internal::into_ref;
|
||||
|
||||
use super::{Channel, ConfigurableChannel, Event, Ppi, StaticChannel, Task};
|
||||
use super::{Channel, ConfigurableChannel, Event, Ppi, Task};
|
||||
use crate::{pac, Peripheral};
|
||||
|
||||
impl<'d> Task<'d> {
|
||||
@ -19,7 +19,7 @@ pub(crate) fn regs() -> &'static pac::ppi::RegisterBlock {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "nrf51"))] // Not for nrf51 because of the fork task
|
||||
impl<'d, C: StaticChannel> Ppi<'d, C, 0, 1> {
|
||||
impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> {
|
||||
/// Configure PPI channel to trigger `task`.
|
||||
pub fn new_zero_to_one(ch: impl Peripheral<P = C> + 'd, task: Task) -> Self {
|
||||
into_ref!(ch);
|
||||
@ -84,6 +84,7 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for
|
||||
let n = self.ch.number();
|
||||
r.ch[n].eep.write(|w| unsafe { w.bits(0) });
|
||||
r.ch[n].tep.write(|w| unsafe { w.bits(0) });
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
r.fork[n].tep.write(|w| unsafe { w.bits(0) });
|
||||
}
|
||||
}
|
||||
|
@ -5,12 +5,10 @@
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::ptr;
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
use core::task::Poll;
|
||||
|
||||
use embassy_hal_internal::drop::OnDrop;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::{interrupt, Peripheral};
|
||||
@ -22,7 +20,6 @@ pub struct InterruptHandler<T: Instance> {
|
||||
|
||||
impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let s = T::state();
|
||||
let r = T::regs();
|
||||
|
||||
// Clear the event.
|
||||
@ -30,46 +27,25 @@ impl<T: Instance> interrupt::typelevel::Handler<T::Interrupt> for InterruptHandl
|
||||
|
||||
// Mutate the slice within a critical section,
|
||||
// so that the future isn't dropped in between us loading the pointer and actually dereferencing it.
|
||||
let (ptr, end) = critical_section::with(|_| {
|
||||
let ptr = s.ptr.load(Ordering::Relaxed);
|
||||
critical_section::with(|cs| {
|
||||
let mut state = T::state().borrow_mut(cs);
|
||||
// We need to make sure we haven't already filled the whole slice,
|
||||
// in case the interrupt fired again before the executor got back to the future.
|
||||
let end = s.end.load(Ordering::Relaxed);
|
||||
if !ptr.is_null() && ptr != end {
|
||||
if !state.ptr.is_null() && state.ptr != state.end {
|
||||
// If the future was dropped, the pointer would have been set to null,
|
||||
// so we're still good to mutate the slice.
|
||||
// The safety contract of `Rng::new` means that the future can't have been dropped
|
||||
// without calling its destructor.
|
||||
unsafe {
|
||||
*ptr = r.value.read().value().bits();
|
||||
*state.ptr = r.value.read().value().bits();
|
||||
state.ptr = state.ptr.add(1);
|
||||
}
|
||||
|
||||
if state.ptr == state.end {
|
||||
state.waker.wake();
|
||||
}
|
||||
}
|
||||
(ptr, end)
|
||||
});
|
||||
|
||||
if ptr.is_null() || ptr == end {
|
||||
// If the future was dropped, there's nothing to do.
|
||||
// If `ptr == end`, we were called by mistake, so return.
|
||||
return;
|
||||
}
|
||||
|
||||
let new_ptr = unsafe { ptr.add(1) };
|
||||
match s
|
||||
.ptr
|
||||
.compare_exchange(ptr, new_ptr, Ordering::Relaxed, Ordering::Relaxed)
|
||||
{
|
||||
Ok(_) => {
|
||||
let end = s.end.load(Ordering::Relaxed);
|
||||
// It doesn't matter if `end` was changed under our feet, because then this will just be false.
|
||||
if new_ptr == end {
|
||||
s.waker.wake();
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// If the future was dropped or finished, there's no point trying to wake it.
|
||||
// It will have already stopped the RNG, so there's no need to do that either.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,13 +112,14 @@ impl<'d, T: Instance> Rng<'d, T> {
|
||||
return; // Nothing to fill
|
||||
}
|
||||
|
||||
let s = T::state();
|
||||
|
||||
let range = dest.as_mut_ptr_range();
|
||||
// Even if we've preempted the interrupt, it can't preempt us again,
|
||||
// so we don't need to worry about the order we write these in.
|
||||
s.ptr.store(range.start, Ordering::Relaxed);
|
||||
s.end.store(range.end, Ordering::Relaxed);
|
||||
critical_section::with(|cs| {
|
||||
let mut state = T::state().borrow_mut(cs);
|
||||
state.ptr = range.start;
|
||||
state.end = range.end;
|
||||
});
|
||||
|
||||
self.enable_irq();
|
||||
self.start();
|
||||
@ -151,24 +128,24 @@ impl<'d, T: Instance> Rng<'d, T> {
|
||||
self.stop();
|
||||
self.disable_irq();
|
||||
|
||||
// The interrupt is now disabled and can't preempt us anymore, so the order doesn't matter here.
|
||||
s.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
s.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
critical_section::with(|cs| {
|
||||
let mut state = T::state().borrow_mut(cs);
|
||||
state.ptr = ptr::null_mut();
|
||||
state.end = ptr::null_mut();
|
||||
});
|
||||
});
|
||||
|
||||
poll_fn(|cx| {
|
||||
s.waker.register(cx.waker());
|
||||
|
||||
// The interrupt will never modify `end`, so load it first and then get the most up-to-date `ptr`.
|
||||
let end = s.end.load(Ordering::Relaxed);
|
||||
let ptr = s.ptr.load(Ordering::Relaxed);
|
||||
|
||||
if ptr == end {
|
||||
// We're done.
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
critical_section::with(|cs| {
|
||||
let mut s = T::state().borrow_mut(cs);
|
||||
s.waker.register(cx.waker());
|
||||
if s.ptr == s.end {
|
||||
// We're done.
|
||||
Poll::Ready(())
|
||||
} else {
|
||||
Poll::Pending
|
||||
}
|
||||
})
|
||||
})
|
||||
.await;
|
||||
|
||||
@ -194,9 +171,11 @@ impl<'d, T: Instance> Rng<'d, T> {
|
||||
impl<'d, T: Instance> Drop for Rng<'d, T> {
|
||||
fn drop(&mut self) {
|
||||
self.stop();
|
||||
let s = T::state();
|
||||
s.ptr.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
s.end.store(ptr::null_mut(), Ordering::Relaxed);
|
||||
critical_section::with(|cs| {
|
||||
let mut state = T::state().borrow_mut(cs);
|
||||
state.ptr = ptr::null_mut();
|
||||
state.end = ptr::null_mut();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -227,21 +206,48 @@ impl<'d, T: Instance> rand_core::RngCore for Rng<'d, T> {
|
||||
impl<'d, T: Instance> rand_core::CryptoRng for Rng<'d, T> {}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use core::cell::{Ref, RefCell, RefMut};
|
||||
|
||||
use critical_section::{CriticalSection, Mutex};
|
||||
use embassy_sync::waitqueue::WakerRegistration;
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Peripheral static state
|
||||
pub struct State {
|
||||
pub ptr: AtomicPtr<u8>,
|
||||
pub end: AtomicPtr<u8>,
|
||||
pub waker: AtomicWaker,
|
||||
inner: Mutex<RefCell<InnerState>>,
|
||||
}
|
||||
|
||||
pub struct InnerState {
|
||||
pub ptr: *mut u8,
|
||||
pub end: *mut u8,
|
||||
pub waker: WakerRegistration,
|
||||
}
|
||||
|
||||
unsafe impl Send for InnerState {}
|
||||
|
||||
impl State {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
ptr: AtomicPtr::new(ptr::null_mut()),
|
||||
end: AtomicPtr::new(ptr::null_mut()),
|
||||
waker: AtomicWaker::new(),
|
||||
inner: Mutex::new(RefCell::new(InnerState::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow<'cs>(&'cs self, cs: CriticalSection<'cs>) -> Ref<'cs, InnerState> {
|
||||
self.inner.borrow(cs).borrow()
|
||||
}
|
||||
|
||||
pub fn borrow_mut<'cs>(&'cs self, cs: CriticalSection<'cs>) -> RefMut<'cs, InnerState> {
|
||||
self.inner.borrow(cs).borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl InnerState {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
ptr: ptr::null_mut(),
|
||||
end: ptr::null_mut(),
|
||||
waker: WakerRegistration::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +171,8 @@ impl RtcDriver {
|
||||
fn next_period(&self) {
|
||||
critical_section::with(|cs| {
|
||||
let r = rtc();
|
||||
let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
|
||||
let period = self.period.load(Ordering::Relaxed) + 1;
|
||||
self.period.store(period, Ordering::Relaxed);
|
||||
let t = (period as u64) << 23;
|
||||
|
||||
for n in 0..ALARM_COUNT {
|
||||
@ -219,18 +220,15 @@ impl Driver for RtcDriver {
|
||||
}
|
||||
|
||||
unsafe fn allocate_alarm(&self) -> Option<AlarmHandle> {
|
||||
let id = self.alarm_count.fetch_update(Ordering::AcqRel, Ordering::Acquire, |x| {
|
||||
if x < ALARM_COUNT as u8 {
|
||||
Some(x + 1)
|
||||
critical_section::with(|_| {
|
||||
let id = self.alarm_count.load(Ordering::Relaxed);
|
||||
if id < ALARM_COUNT as u8 {
|
||||
self.alarm_count.store(id + 1, Ordering::Relaxed);
|
||||
Some(AlarmHandle::new(id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
match id {
|
||||
Ok(id) => Some(AlarmHandle::new(id)),
|
||||
Err(_) => None,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) {
|
||||
|
@ -111,7 +111,7 @@ impl<'d, T: Instance> Timer<'d, T> {
|
||||
Self::new_inner(timer, true)
|
||||
}
|
||||
|
||||
fn new_inner(timer: impl Peripheral<P = T> + 'd, is_counter: bool) -> Self {
|
||||
fn new_inner(timer: impl Peripheral<P = T> + 'd, _is_counter: bool) -> Self {
|
||||
into_ref!(timer);
|
||||
|
||||
let regs = T::regs();
|
||||
@ -122,12 +122,16 @@ impl<'d, T: Instance> Timer<'d, T> {
|
||||
// since changing BITMODE while running can cause 'unpredictable behaviour' according to the specification.
|
||||
this.stop();
|
||||
|
||||
if is_counter {
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
if _is_counter {
|
||||
regs.mode.write(|w| w.mode().low_power_counter());
|
||||
} else {
|
||||
regs.mode.write(|w| w.mode().timer());
|
||||
}
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
regs.mode.write(|w| w.mode().timer());
|
||||
|
||||
// Make the counter's max value as high as possible.
|
||||
// TODO: is there a reason someone would want to set this lower?
|
||||
regs.bitmode.write(|w| w.bitmode()._32bit());
|
||||
@ -238,7 +242,11 @@ pub struct Cc<'d, T: Instance> {
|
||||
impl<'d, T: Instance> Cc<'d, T> {
|
||||
/// Get the current value stored in the register.
|
||||
pub fn read(&self) -> u32 {
|
||||
T::regs().cc[self.n].read().cc().bits()
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
return T::regs().cc[self.n].read().cc().bits();
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
return T::regs().cc[self.n].read().bits();
|
||||
}
|
||||
|
||||
/// Set the value stored in the register.
|
||||
@ -246,7 +254,11 @@ impl<'d, T: Instance> Cc<'d, T> {
|
||||
/// `event_compare` will fire when the timer's counter reaches this value.
|
||||
pub fn write(&self, value: u32) {
|
||||
// SAFETY: there are no invalid values for the CC register.
|
||||
T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) })
|
||||
#[cfg(not(feature = "nrf51"))]
|
||||
T::regs().cc[self.n].write(|w| unsafe { w.cc().bits(value) });
|
||||
|
||||
#[cfg(feature = "nrf51")]
|
||||
T::regs().cc[self.n].write(|w| unsafe { w.bits(value) });
|
||||
}
|
||||
|
||||
/// Capture the current value of the timer's counter in this register, and return it.
|
||||
|
@ -1,3 +1,4 @@
|
||||
#![allow(dead_code)]
|
||||
use core::mem;
|
||||
|
||||
const SRAM_LOWER: usize = 0x2000_0000;
|
||||
|
@ -44,6 +44,8 @@ defmt = ["dep:defmt", "embassy-sync/defmt", "embassy-embedded-hal/defmt", "embas
|
||||
ble = ["dep:stm32wb-hci"]
|
||||
mac = ["dep:bitflags", "dep:embassy-net-driver" ]
|
||||
|
||||
extended = []
|
||||
|
||||
stm32wb10cc = [ "embassy-stm32/stm32wb10cc" ]
|
||||
stm32wb15cc = [ "embassy-stm32/stm32wb15cc" ]
|
||||
stm32wb30ce = [ "embassy-stm32/stm32wb30ce" ]
|
||||
|
@ -18,9 +18,22 @@ fn main() {
|
||||
// stm32wb tl_mbox link sections
|
||||
|
||||
let out_file = out_dir.join("tl_mbox.x").to_string_lossy().to_string();
|
||||
fs::write(out_file, fs::read_to_string("tl_mbox.x.in").unwrap()).unwrap();
|
||||
let in_file;
|
||||
if env::var_os("CARGO_FEATURE_EXTENDED").is_some() {
|
||||
if env::vars()
|
||||
.map(|(a, _)| a)
|
||||
.any(|x| x.starts_with("CARGO_FEATURE_STM32WB1"))
|
||||
{
|
||||
in_file = "tl_mbox_extended_wb1.x.in";
|
||||
} else {
|
||||
in_file = "tl_mbox_extended_wbx5.x.in";
|
||||
}
|
||||
} else {
|
||||
in_file = "tl_mbox.x.in";
|
||||
}
|
||||
fs::write(out_file, fs::read_to_string(in_file).unwrap()).unwrap();
|
||||
println!("cargo:rustc-link-search={}", out_dir.display());
|
||||
println!("cargo:rerun-if-changed=tl_mbox.x.in");
|
||||
println!("cargo:rerun-if-changed={}", in_file);
|
||||
}
|
||||
|
||||
enum GetOneError {
|
||||
|
16
embassy-stm32-wpan/tl_mbox_extended_wb1.x.in
Normal file
16
embassy-stm32-wpan/tl_mbox_extended_wb1.x.in
Normal file
@ -0,0 +1,16 @@
|
||||
MEMORY
|
||||
{
|
||||
RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 4K
|
||||
RAMB_SHARED (xrw) : ORIGIN = 0x20030028, LENGTH = 4K
|
||||
}
|
||||
|
||||
/*
|
||||
* Scatter the mailbox interface memory sections in shared memory
|
||||
*/
|
||||
SECTIONS
|
||||
{
|
||||
TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
|
||||
|
||||
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAMB_SHARED
|
||||
MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAMB_SHARED
|
||||
}
|
16
embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in
Normal file
16
embassy-stm32-wpan/tl_mbox_extended_wbx5.x.in
Normal file
@ -0,0 +1,16 @@
|
||||
MEMORY
|
||||
{
|
||||
RAM_SHARED (xrw) : ORIGIN = 0x20030000, LENGTH = 2K
|
||||
RAMB_SHARED (xrw) : ORIGIN = 0x20038000, LENGTH = 10K
|
||||
}
|
||||
|
||||
/*
|
||||
* Scatter the mailbox interface memory sections in shared memory
|
||||
*/
|
||||
SECTIONS
|
||||
{
|
||||
TL_REF_TABLE (NOLOAD) : { *(TL_REF_TABLE) } >RAM_SHARED
|
||||
|
||||
MB_MEM1 (NOLOAD) : { *(MB_MEM1) } >RAMB_SHARED
|
||||
MB_MEM2 (NOLOAD) : { _sMB_MEM2 = . ; *(MB_MEM2) ; _eMB_MEM2 = . ; } >RAMB_SHARED
|
||||
}
|
@ -68,7 +68,7 @@ rand_core = "0.6.3"
|
||||
sdio-host = "0.5.0"
|
||||
critical-section = "1.1"
|
||||
#stm32-metapac = { version = "15" }
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15" }
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3e3b53df78b4c90ae9c44a58b4f9f93c93a415b7" }
|
||||
vcell = "0.1.3"
|
||||
bxcan = "0.7.0"
|
||||
nb = "1.0.0"
|
||||
@ -80,6 +80,8 @@ chrono = { version = "^0.4", default-features = false, optional = true}
|
||||
bit_field = "0.10.2"
|
||||
document-features = "0.2.7"
|
||||
|
||||
fdcan = { version = "0.2.0", optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
critical-section = { version = "1.1", features = ["std"] }
|
||||
|
||||
@ -87,7 +89,7 @@ critical-section = { version = "1.1", features = ["std"] }
|
||||
proc-macro2 = "1.0.36"
|
||||
quote = "1.0.15"
|
||||
#stm32-metapac = { version = "15", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-0cb3a4fcaec702c93b3700715de796636d562b15", default-features = false, features = ["metadata"]}
|
||||
stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-3e3b53df78b4c90ae9c44a58b4f9f93c93a415b7", default-features = false, features = ["metadata"]}
|
||||
|
||||
|
||||
[features]
|
||||
@ -693,373 +695,373 @@ stm32f779ai = [ "stm32-metapac/stm32f779ai" ]
|
||||
stm32f779bi = [ "stm32-metapac/stm32f779bi" ]
|
||||
stm32f779ii = [ "stm32-metapac/stm32f779ii" ]
|
||||
stm32f779ni = [ "stm32-metapac/stm32f779ni" ]
|
||||
stm32g030c6 = [ "stm32-metapac/stm32g030c6" ]
|
||||
stm32g030c8 = [ "stm32-metapac/stm32g030c8" ]
|
||||
stm32g030f6 = [ "stm32-metapac/stm32g030f6" ]
|
||||
stm32g030j6 = [ "stm32-metapac/stm32g030j6" ]
|
||||
stm32g030k6 = [ "stm32-metapac/stm32g030k6" ]
|
||||
stm32g030k8 = [ "stm32-metapac/stm32g030k8" ]
|
||||
stm32g031c4 = [ "stm32-metapac/stm32g031c4" ]
|
||||
stm32g031c6 = [ "stm32-metapac/stm32g031c6" ]
|
||||
stm32g031c8 = [ "stm32-metapac/stm32g031c8" ]
|
||||
stm32g031f4 = [ "stm32-metapac/stm32g031f4" ]
|
||||
stm32g031f6 = [ "stm32-metapac/stm32g031f6" ]
|
||||
stm32g031f8 = [ "stm32-metapac/stm32g031f8" ]
|
||||
stm32g031g4 = [ "stm32-metapac/stm32g031g4" ]
|
||||
stm32g031g6 = [ "stm32-metapac/stm32g031g6" ]
|
||||
stm32g031g8 = [ "stm32-metapac/stm32g031g8" ]
|
||||
stm32g031j4 = [ "stm32-metapac/stm32g031j4" ]
|
||||
stm32g031j6 = [ "stm32-metapac/stm32g031j6" ]
|
||||
stm32g031k4 = [ "stm32-metapac/stm32g031k4" ]
|
||||
stm32g031k6 = [ "stm32-metapac/stm32g031k6" ]
|
||||
stm32g031k8 = [ "stm32-metapac/stm32g031k8" ]
|
||||
stm32g031y8 = [ "stm32-metapac/stm32g031y8" ]
|
||||
stm32g041c6 = [ "stm32-metapac/stm32g041c6" ]
|
||||
stm32g041c8 = [ "stm32-metapac/stm32g041c8" ]
|
||||
stm32g041f6 = [ "stm32-metapac/stm32g041f6" ]
|
||||
stm32g041f8 = [ "stm32-metapac/stm32g041f8" ]
|
||||
stm32g041g6 = [ "stm32-metapac/stm32g041g6" ]
|
||||
stm32g041g8 = [ "stm32-metapac/stm32g041g8" ]
|
||||
stm32g041j6 = [ "stm32-metapac/stm32g041j6" ]
|
||||
stm32g041k6 = [ "stm32-metapac/stm32g041k6" ]
|
||||
stm32g041k8 = [ "stm32-metapac/stm32g041k8" ]
|
||||
stm32g041y8 = [ "stm32-metapac/stm32g041y8" ]
|
||||
stm32g050c6 = [ "stm32-metapac/stm32g050c6" ]
|
||||
stm32g050c8 = [ "stm32-metapac/stm32g050c8" ]
|
||||
stm32g050f6 = [ "stm32-metapac/stm32g050f6" ]
|
||||
stm32g050k6 = [ "stm32-metapac/stm32g050k6" ]
|
||||
stm32g050k8 = [ "stm32-metapac/stm32g050k8" ]
|
||||
stm32g051c6 = [ "stm32-metapac/stm32g051c6" ]
|
||||
stm32g051c8 = [ "stm32-metapac/stm32g051c8" ]
|
||||
stm32g051f6 = [ "stm32-metapac/stm32g051f6" ]
|
||||
stm32g051f8 = [ "stm32-metapac/stm32g051f8" ]
|
||||
stm32g051g6 = [ "stm32-metapac/stm32g051g6" ]
|
||||
stm32g051g8 = [ "stm32-metapac/stm32g051g8" ]
|
||||
stm32g051k6 = [ "stm32-metapac/stm32g051k6" ]
|
||||
stm32g051k8 = [ "stm32-metapac/stm32g051k8" ]
|
||||
stm32g061c6 = [ "stm32-metapac/stm32g061c6" ]
|
||||
stm32g061c8 = [ "stm32-metapac/stm32g061c8" ]
|
||||
stm32g061f6 = [ "stm32-metapac/stm32g061f6" ]
|
||||
stm32g061f8 = [ "stm32-metapac/stm32g061f8" ]
|
||||
stm32g061g6 = [ "stm32-metapac/stm32g061g6" ]
|
||||
stm32g061g8 = [ "stm32-metapac/stm32g061g8" ]
|
||||
stm32g061k6 = [ "stm32-metapac/stm32g061k6" ]
|
||||
stm32g061k8 = [ "stm32-metapac/stm32g061k8" ]
|
||||
stm32g070cb = [ "stm32-metapac/stm32g070cb" ]
|
||||
stm32g070kb = [ "stm32-metapac/stm32g070kb" ]
|
||||
stm32g070rb = [ "stm32-metapac/stm32g070rb" ]
|
||||
stm32g071c6 = [ "stm32-metapac/stm32g071c6" ]
|
||||
stm32g071c8 = [ "stm32-metapac/stm32g071c8" ]
|
||||
stm32g071cb = [ "stm32-metapac/stm32g071cb" ]
|
||||
stm32g071eb = [ "stm32-metapac/stm32g071eb" ]
|
||||
stm32g071g6 = [ "stm32-metapac/stm32g071g6" ]
|
||||
stm32g071g8 = [ "stm32-metapac/stm32g071g8" ]
|
||||
stm32g071gb = [ "stm32-metapac/stm32g071gb" ]
|
||||
stm32g071k6 = [ "stm32-metapac/stm32g071k6" ]
|
||||
stm32g071k8 = [ "stm32-metapac/stm32g071k8" ]
|
||||
stm32g071kb = [ "stm32-metapac/stm32g071kb" ]
|
||||
stm32g071r6 = [ "stm32-metapac/stm32g071r6" ]
|
||||
stm32g071r8 = [ "stm32-metapac/stm32g071r8" ]
|
||||
stm32g071rb = [ "stm32-metapac/stm32g071rb" ]
|
||||
stm32g081cb = [ "stm32-metapac/stm32g081cb" ]
|
||||
stm32g081eb = [ "stm32-metapac/stm32g081eb" ]
|
||||
stm32g081gb = [ "stm32-metapac/stm32g081gb" ]
|
||||
stm32g081kb = [ "stm32-metapac/stm32g081kb" ]
|
||||
stm32g081rb = [ "stm32-metapac/stm32g081rb" ]
|
||||
stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce" ]
|
||||
stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke" ]
|
||||
stm32g0b0re = [ "stm32-metapac/stm32g0b0re" ]
|
||||
stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve" ]
|
||||
stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb" ]
|
||||
stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc" ]
|
||||
stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce" ]
|
||||
stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb" ]
|
||||
stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc" ]
|
||||
stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke" ]
|
||||
stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb" ]
|
||||
stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc" ]
|
||||
stm32g0b1me = [ "stm32-metapac/stm32g0b1me" ]
|
||||
stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne" ]
|
||||
stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb" ]
|
||||
stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc" ]
|
||||
stm32g0b1re = [ "stm32-metapac/stm32g0b1re" ]
|
||||
stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb" ]
|
||||
stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc" ]
|
||||
stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve" ]
|
||||
stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc" ]
|
||||
stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce" ]
|
||||
stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc" ]
|
||||
stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke" ]
|
||||
stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc" ]
|
||||
stm32g0c1me = [ "stm32-metapac/stm32g0c1me" ]
|
||||
stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne" ]
|
||||
stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc" ]
|
||||
stm32g0c1re = [ "stm32-metapac/stm32g0c1re" ]
|
||||
stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc" ]
|
||||
stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve" ]
|
||||
stm32g431c6 = [ "stm32-metapac/stm32g431c6" ]
|
||||
stm32g431c8 = [ "stm32-metapac/stm32g431c8" ]
|
||||
stm32g431cb = [ "stm32-metapac/stm32g431cb" ]
|
||||
stm32g431k6 = [ "stm32-metapac/stm32g431k6" ]
|
||||
stm32g431k8 = [ "stm32-metapac/stm32g431k8" ]
|
||||
stm32g431kb = [ "stm32-metapac/stm32g431kb" ]
|
||||
stm32g431m6 = [ "stm32-metapac/stm32g431m6" ]
|
||||
stm32g431m8 = [ "stm32-metapac/stm32g431m8" ]
|
||||
stm32g431mb = [ "stm32-metapac/stm32g431mb" ]
|
||||
stm32g431r6 = [ "stm32-metapac/stm32g431r6" ]
|
||||
stm32g431r8 = [ "stm32-metapac/stm32g431r8" ]
|
||||
stm32g431rb = [ "stm32-metapac/stm32g431rb" ]
|
||||
stm32g431v6 = [ "stm32-metapac/stm32g431v6" ]
|
||||
stm32g431v8 = [ "stm32-metapac/stm32g431v8" ]
|
||||
stm32g431vb = [ "stm32-metapac/stm32g431vb" ]
|
||||
stm32g441cb = [ "stm32-metapac/stm32g441cb" ]
|
||||
stm32g441kb = [ "stm32-metapac/stm32g441kb" ]
|
||||
stm32g441mb = [ "stm32-metapac/stm32g441mb" ]
|
||||
stm32g441rb = [ "stm32-metapac/stm32g441rb" ]
|
||||
stm32g441vb = [ "stm32-metapac/stm32g441vb" ]
|
||||
stm32g471cc = [ "stm32-metapac/stm32g471cc" ]
|
||||
stm32g471ce = [ "stm32-metapac/stm32g471ce" ]
|
||||
stm32g471mc = [ "stm32-metapac/stm32g471mc" ]
|
||||
stm32g471me = [ "stm32-metapac/stm32g471me" ]
|
||||
stm32g471qc = [ "stm32-metapac/stm32g471qc" ]
|
||||
stm32g471qe = [ "stm32-metapac/stm32g471qe" ]
|
||||
stm32g471rc = [ "stm32-metapac/stm32g471rc" ]
|
||||
stm32g471re = [ "stm32-metapac/stm32g471re" ]
|
||||
stm32g471vc = [ "stm32-metapac/stm32g471vc" ]
|
||||
stm32g471ve = [ "stm32-metapac/stm32g471ve" ]
|
||||
stm32g473cb = [ "stm32-metapac/stm32g473cb" ]
|
||||
stm32g473cc = [ "stm32-metapac/stm32g473cc" ]
|
||||
stm32g473ce = [ "stm32-metapac/stm32g473ce" ]
|
||||
stm32g473mb = [ "stm32-metapac/stm32g473mb" ]
|
||||
stm32g473mc = [ "stm32-metapac/stm32g473mc" ]
|
||||
stm32g473me = [ "stm32-metapac/stm32g473me" ]
|
||||
stm32g473pb = [ "stm32-metapac/stm32g473pb" ]
|
||||
stm32g473pc = [ "stm32-metapac/stm32g473pc" ]
|
||||
stm32g473pe = [ "stm32-metapac/stm32g473pe" ]
|
||||
stm32g473qb = [ "stm32-metapac/stm32g473qb" ]
|
||||
stm32g473qc = [ "stm32-metapac/stm32g473qc" ]
|
||||
stm32g473qe = [ "stm32-metapac/stm32g473qe" ]
|
||||
stm32g473rb = [ "stm32-metapac/stm32g473rb" ]
|
||||
stm32g473rc = [ "stm32-metapac/stm32g473rc" ]
|
||||
stm32g473re = [ "stm32-metapac/stm32g473re" ]
|
||||
stm32g473vb = [ "stm32-metapac/stm32g473vb" ]
|
||||
stm32g473vc = [ "stm32-metapac/stm32g473vc" ]
|
||||
stm32g473ve = [ "stm32-metapac/stm32g473ve" ]
|
||||
stm32g474cb = [ "stm32-metapac/stm32g474cb" ]
|
||||
stm32g474cc = [ "stm32-metapac/stm32g474cc" ]
|
||||
stm32g474ce = [ "stm32-metapac/stm32g474ce" ]
|
||||
stm32g474mb = [ "stm32-metapac/stm32g474mb" ]
|
||||
stm32g474mc = [ "stm32-metapac/stm32g474mc" ]
|
||||
stm32g474me = [ "stm32-metapac/stm32g474me" ]
|
||||
stm32g474pb = [ "stm32-metapac/stm32g474pb" ]
|
||||
stm32g474pc = [ "stm32-metapac/stm32g474pc" ]
|
||||
stm32g474pe = [ "stm32-metapac/stm32g474pe" ]
|
||||
stm32g474qb = [ "stm32-metapac/stm32g474qb" ]
|
||||
stm32g474qc = [ "stm32-metapac/stm32g474qc" ]
|
||||
stm32g474qe = [ "stm32-metapac/stm32g474qe" ]
|
||||
stm32g474rb = [ "stm32-metapac/stm32g474rb" ]
|
||||
stm32g474rc = [ "stm32-metapac/stm32g474rc" ]
|
||||
stm32g474re = [ "stm32-metapac/stm32g474re" ]
|
||||
stm32g474vb = [ "stm32-metapac/stm32g474vb" ]
|
||||
stm32g474vc = [ "stm32-metapac/stm32g474vc" ]
|
||||
stm32g474ve = [ "stm32-metapac/stm32g474ve" ]
|
||||
stm32g483ce = [ "stm32-metapac/stm32g483ce" ]
|
||||
stm32g483me = [ "stm32-metapac/stm32g483me" ]
|
||||
stm32g483pe = [ "stm32-metapac/stm32g483pe" ]
|
||||
stm32g483qe = [ "stm32-metapac/stm32g483qe" ]
|
||||
stm32g483re = [ "stm32-metapac/stm32g483re" ]
|
||||
stm32g483ve = [ "stm32-metapac/stm32g483ve" ]
|
||||
stm32g484ce = [ "stm32-metapac/stm32g484ce" ]
|
||||
stm32g484me = [ "stm32-metapac/stm32g484me" ]
|
||||
stm32g484pe = [ "stm32-metapac/stm32g484pe" ]
|
||||
stm32g484qe = [ "stm32-metapac/stm32g484qe" ]
|
||||
stm32g484re = [ "stm32-metapac/stm32g484re" ]
|
||||
stm32g484ve = [ "stm32-metapac/stm32g484ve" ]
|
||||
stm32g491cc = [ "stm32-metapac/stm32g491cc" ]
|
||||
stm32g491ce = [ "stm32-metapac/stm32g491ce" ]
|
||||
stm32g491kc = [ "stm32-metapac/stm32g491kc" ]
|
||||
stm32g491ke = [ "stm32-metapac/stm32g491ke" ]
|
||||
stm32g491mc = [ "stm32-metapac/stm32g491mc" ]
|
||||
stm32g491me = [ "stm32-metapac/stm32g491me" ]
|
||||
stm32g491rc = [ "stm32-metapac/stm32g491rc" ]
|
||||
stm32g491re = [ "stm32-metapac/stm32g491re" ]
|
||||
stm32g491vc = [ "stm32-metapac/stm32g491vc" ]
|
||||
stm32g491ve = [ "stm32-metapac/stm32g491ve" ]
|
||||
stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce" ]
|
||||
stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke" ]
|
||||
stm32g4a1me = [ "stm32-metapac/stm32g4a1me" ]
|
||||
stm32g4a1re = [ "stm32-metapac/stm32g4a1re" ]
|
||||
stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve" ]
|
||||
stm32h503cb = [ "stm32-metapac/stm32h503cb" ]
|
||||
stm32h503eb = [ "stm32-metapac/stm32h503eb" ]
|
||||
stm32h503kb = [ "stm32-metapac/stm32h503kb" ]
|
||||
stm32h503rb = [ "stm32-metapac/stm32h503rb" ]
|
||||
stm32h562ag = [ "stm32-metapac/stm32h562ag" ]
|
||||
stm32h562ai = [ "stm32-metapac/stm32h562ai" ]
|
||||
stm32h562ig = [ "stm32-metapac/stm32h562ig" ]
|
||||
stm32h562ii = [ "stm32-metapac/stm32h562ii" ]
|
||||
stm32h562rg = [ "stm32-metapac/stm32h562rg" ]
|
||||
stm32h562ri = [ "stm32-metapac/stm32h562ri" ]
|
||||
stm32h562vg = [ "stm32-metapac/stm32h562vg" ]
|
||||
stm32h562vi = [ "stm32-metapac/stm32h562vi" ]
|
||||
stm32h562zg = [ "stm32-metapac/stm32h562zg" ]
|
||||
stm32h562zi = [ "stm32-metapac/stm32h562zi" ]
|
||||
stm32h563ag = [ "stm32-metapac/stm32h563ag" ]
|
||||
stm32h563ai = [ "stm32-metapac/stm32h563ai" ]
|
||||
stm32h563ig = [ "stm32-metapac/stm32h563ig" ]
|
||||
stm32h563ii = [ "stm32-metapac/stm32h563ii" ]
|
||||
stm32h563mi = [ "stm32-metapac/stm32h563mi" ]
|
||||
stm32h563rg = [ "stm32-metapac/stm32h563rg" ]
|
||||
stm32h563ri = [ "stm32-metapac/stm32h563ri" ]
|
||||
stm32h563vg = [ "stm32-metapac/stm32h563vg" ]
|
||||
stm32h563vi = [ "stm32-metapac/stm32h563vi" ]
|
||||
stm32h563zg = [ "stm32-metapac/stm32h563zg" ]
|
||||
stm32h563zi = [ "stm32-metapac/stm32h563zi" ]
|
||||
stm32h573ai = [ "stm32-metapac/stm32h573ai" ]
|
||||
stm32h573ii = [ "stm32-metapac/stm32h573ii" ]
|
||||
stm32h573mi = [ "stm32-metapac/stm32h573mi" ]
|
||||
stm32h573ri = [ "stm32-metapac/stm32h573ri" ]
|
||||
stm32h573vi = [ "stm32-metapac/stm32h573vi" ]
|
||||
stm32h573zi = [ "stm32-metapac/stm32h573zi" ]
|
||||
stm32h723ve = [ "stm32-metapac/stm32h723ve" ]
|
||||
stm32h723vg = [ "stm32-metapac/stm32h723vg" ]
|
||||
stm32h723ze = [ "stm32-metapac/stm32h723ze" ]
|
||||
stm32h723zg = [ "stm32-metapac/stm32h723zg" ]
|
||||
stm32h725ae = [ "stm32-metapac/stm32h725ae" ]
|
||||
stm32h725ag = [ "stm32-metapac/stm32h725ag" ]
|
||||
stm32h725ie = [ "stm32-metapac/stm32h725ie" ]
|
||||
stm32h725ig = [ "stm32-metapac/stm32h725ig" ]
|
||||
stm32h725re = [ "stm32-metapac/stm32h725re" ]
|
||||
stm32h725rg = [ "stm32-metapac/stm32h725rg" ]
|
||||
stm32h725ve = [ "stm32-metapac/stm32h725ve" ]
|
||||
stm32h725vg = [ "stm32-metapac/stm32h725vg" ]
|
||||
stm32h725ze = [ "stm32-metapac/stm32h725ze" ]
|
||||
stm32h725zg = [ "stm32-metapac/stm32h725zg" ]
|
||||
stm32h730ab = [ "stm32-metapac/stm32h730ab" ]
|
||||
stm32h730ib = [ "stm32-metapac/stm32h730ib" ]
|
||||
stm32h730vb = [ "stm32-metapac/stm32h730vb" ]
|
||||
stm32h730zb = [ "stm32-metapac/stm32h730zb" ]
|
||||
stm32h733vg = [ "stm32-metapac/stm32h733vg" ]
|
||||
stm32h733zg = [ "stm32-metapac/stm32h733zg" ]
|
||||
stm32h735ag = [ "stm32-metapac/stm32h735ag" ]
|
||||
stm32h735ig = [ "stm32-metapac/stm32h735ig" ]
|
||||
stm32h735rg = [ "stm32-metapac/stm32h735rg" ]
|
||||
stm32h735vg = [ "stm32-metapac/stm32h735vg" ]
|
||||
stm32h735zg = [ "stm32-metapac/stm32h735zg" ]
|
||||
stm32h742ag = [ "stm32-metapac/stm32h742ag" ]
|
||||
stm32h742ai = [ "stm32-metapac/stm32h742ai" ]
|
||||
stm32h742bg = [ "stm32-metapac/stm32h742bg" ]
|
||||
stm32h742bi = [ "stm32-metapac/stm32h742bi" ]
|
||||
stm32h742ig = [ "stm32-metapac/stm32h742ig" ]
|
||||
stm32h742ii = [ "stm32-metapac/stm32h742ii" ]
|
||||
stm32h742vg = [ "stm32-metapac/stm32h742vg" ]
|
||||
stm32h742vi = [ "stm32-metapac/stm32h742vi" ]
|
||||
stm32h742xg = [ "stm32-metapac/stm32h742xg" ]
|
||||
stm32h742xi = [ "stm32-metapac/stm32h742xi" ]
|
||||
stm32h742zg = [ "stm32-metapac/stm32h742zg" ]
|
||||
stm32h742zi = [ "stm32-metapac/stm32h742zi" ]
|
||||
stm32h743ag = [ "stm32-metapac/stm32h743ag" ]
|
||||
stm32h743ai = [ "stm32-metapac/stm32h743ai" ]
|
||||
stm32h743bg = [ "stm32-metapac/stm32h743bg" ]
|
||||
stm32h743bi = [ "stm32-metapac/stm32h743bi" ]
|
||||
stm32h743ig = [ "stm32-metapac/stm32h743ig" ]
|
||||
stm32h743ii = [ "stm32-metapac/stm32h743ii" ]
|
||||
stm32h743vg = [ "stm32-metapac/stm32h743vg" ]
|
||||
stm32h743vi = [ "stm32-metapac/stm32h743vi" ]
|
||||
stm32h743xg = [ "stm32-metapac/stm32h743xg" ]
|
||||
stm32h743xi = [ "stm32-metapac/stm32h743xi" ]
|
||||
stm32h743zg = [ "stm32-metapac/stm32h743zg" ]
|
||||
stm32h743zi = [ "stm32-metapac/stm32h743zi" ]
|
||||
stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7" ]
|
||||
stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4" ]
|
||||
stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7" ]
|
||||
stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4" ]
|
||||
stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7" ]
|
||||
stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4" ]
|
||||
stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7" ]
|
||||
stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4" ]
|
||||
stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7" ]
|
||||
stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4" ]
|
||||
stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7" ]
|
||||
stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4" ]
|
||||
stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7" ]
|
||||
stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4" ]
|
||||
stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7" ]
|
||||
stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4" ]
|
||||
stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7" ]
|
||||
stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4" ]
|
||||
stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7" ]
|
||||
stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4" ]
|
||||
stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7" ]
|
||||
stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4" ]
|
||||
stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7" ]
|
||||
stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4" ]
|
||||
stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7" ]
|
||||
stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4" ]
|
||||
stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7" ]
|
||||
stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4" ]
|
||||
stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7" ]
|
||||
stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4" ]
|
||||
stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7" ]
|
||||
stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4" ]
|
||||
stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7" ]
|
||||
stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4" ]
|
||||
stm32h750ib = [ "stm32-metapac/stm32h750ib" ]
|
||||
stm32h750vb = [ "stm32-metapac/stm32h750vb" ]
|
||||
stm32h750xb = [ "stm32-metapac/stm32h750xb" ]
|
||||
stm32h750zb = [ "stm32-metapac/stm32h750zb" ]
|
||||
stm32h753ai = [ "stm32-metapac/stm32h753ai" ]
|
||||
stm32h753bi = [ "stm32-metapac/stm32h753bi" ]
|
||||
stm32h753ii = [ "stm32-metapac/stm32h753ii" ]
|
||||
stm32h753vi = [ "stm32-metapac/stm32h753vi" ]
|
||||
stm32h753xi = [ "stm32-metapac/stm32h753xi" ]
|
||||
stm32h753zi = [ "stm32-metapac/stm32h753zi" ]
|
||||
stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7" ]
|
||||
stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4" ]
|
||||
stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7" ]
|
||||
stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4" ]
|
||||
stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7" ]
|
||||
stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4" ]
|
||||
stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7" ]
|
||||
stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4" ]
|
||||
stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7" ]
|
||||
stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4" ]
|
||||
stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7" ]
|
||||
stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4" ]
|
||||
stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7" ]
|
||||
stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4" ]
|
||||
stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7" ]
|
||||
stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4" ]
|
||||
stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7" ]
|
||||
stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4" ]
|
||||
stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag" ]
|
||||
stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai" ]
|
||||
stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig" ]
|
||||
stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii" ]
|
||||
stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg" ]
|
||||
stm32h7a3li = [ "stm32-metapac/stm32h7a3li" ]
|
||||
stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng" ]
|
||||
stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni" ]
|
||||
stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi" ]
|
||||
stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg" ]
|
||||
stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri" ]
|
||||
stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg" ]
|
||||
stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi" ]
|
||||
stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg" ]
|
||||
stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi" ]
|
||||
stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab" ]
|
||||
stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib" ]
|
||||
stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb" ]
|
||||
stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb" ]
|
||||
stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb" ]
|
||||
stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai" ]
|
||||
stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii" ]
|
||||
stm32h7b3li = [ "stm32-metapac/stm32h7b3li" ]
|
||||
stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni" ]
|
||||
stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi" ]
|
||||
stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri" ]
|
||||
stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi" ]
|
||||
stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi" ]
|
||||
stm32g030c6 = [ "stm32-metapac/stm32g030c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g030c8 = [ "stm32-metapac/stm32g030c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g030f6 = [ "stm32-metapac/stm32g030f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g030j6 = [ "stm32-metapac/stm32g030j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g030k6 = [ "stm32-metapac/stm32g030k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g030k8 = [ "stm32-metapac/stm32g030k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031c4 = [ "stm32-metapac/stm32g031c4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031c6 = [ "stm32-metapac/stm32g031c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031c8 = [ "stm32-metapac/stm32g031c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031f4 = [ "stm32-metapac/stm32g031f4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031f6 = [ "stm32-metapac/stm32g031f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031f8 = [ "stm32-metapac/stm32g031f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031g4 = [ "stm32-metapac/stm32g031g4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031g6 = [ "stm32-metapac/stm32g031g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031g8 = [ "stm32-metapac/stm32g031g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031j4 = [ "stm32-metapac/stm32g031j4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031j6 = [ "stm32-metapac/stm32g031j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031k4 = [ "stm32-metapac/stm32g031k4", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031k6 = [ "stm32-metapac/stm32g031k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031k8 = [ "stm32-metapac/stm32g031k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g031y8 = [ "stm32-metapac/stm32g031y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041c6 = [ "stm32-metapac/stm32g041c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041c8 = [ "stm32-metapac/stm32g041c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041f6 = [ "stm32-metapac/stm32g041f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041f8 = [ "stm32-metapac/stm32g041f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041g6 = [ "stm32-metapac/stm32g041g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041g8 = [ "stm32-metapac/stm32g041g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041j6 = [ "stm32-metapac/stm32g041j6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041k6 = [ "stm32-metapac/stm32g041k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041k8 = [ "stm32-metapac/stm32g041k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g041y8 = [ "stm32-metapac/stm32g041y8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g050c6 = [ "stm32-metapac/stm32g050c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g050c8 = [ "stm32-metapac/stm32g050c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g050f6 = [ "stm32-metapac/stm32g050f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g050k6 = [ "stm32-metapac/stm32g050k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g050k8 = [ "stm32-metapac/stm32g050k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g051c6 = [ "stm32-metapac/stm32g051c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g051c8 = [ "stm32-metapac/stm32g051c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g051f6 = [ "stm32-metapac/stm32g051f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g051f8 = [ "stm32-metapac/stm32g051f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g051g6 = [ "stm32-metapac/stm32g051g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g051g8 = [ "stm32-metapac/stm32g051g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g051k6 = [ "stm32-metapac/stm32g051k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g051k8 = [ "stm32-metapac/stm32g051k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g061c6 = [ "stm32-metapac/stm32g061c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g061c8 = [ "stm32-metapac/stm32g061c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g061f6 = [ "stm32-metapac/stm32g061f6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g061f8 = [ "stm32-metapac/stm32g061f8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g061g6 = [ "stm32-metapac/stm32g061g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g061g8 = [ "stm32-metapac/stm32g061g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g061k6 = [ "stm32-metapac/stm32g061k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g061k8 = [ "stm32-metapac/stm32g061k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g070cb = [ "stm32-metapac/stm32g070cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g070kb = [ "stm32-metapac/stm32g070kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g070rb = [ "stm32-metapac/stm32g070rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071c6 = [ "stm32-metapac/stm32g071c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071c8 = [ "stm32-metapac/stm32g071c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071cb = [ "stm32-metapac/stm32g071cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071eb = [ "stm32-metapac/stm32g071eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071g6 = [ "stm32-metapac/stm32g071g6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071g8 = [ "stm32-metapac/stm32g071g8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071gb = [ "stm32-metapac/stm32g071gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071k6 = [ "stm32-metapac/stm32g071k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071k8 = [ "stm32-metapac/stm32g071k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071kb = [ "stm32-metapac/stm32g071kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071r6 = [ "stm32-metapac/stm32g071r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071r8 = [ "stm32-metapac/stm32g071r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g071rb = [ "stm32-metapac/stm32g071rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g081cb = [ "stm32-metapac/stm32g081cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g081eb = [ "stm32-metapac/stm32g081eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g081gb = [ "stm32-metapac/stm32g081gb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g081kb = [ "stm32-metapac/stm32g081kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g081rb = [ "stm32-metapac/stm32g081rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b0ce = [ "stm32-metapac/stm32g0b0ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b0ke = [ "stm32-metapac/stm32g0b0ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b0re = [ "stm32-metapac/stm32g0b0re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b0ve = [ "stm32-metapac/stm32g0b0ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1cb = [ "stm32-metapac/stm32g0b1cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1cc = [ "stm32-metapac/stm32g0b1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1ce = [ "stm32-metapac/stm32g0b1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1kb = [ "stm32-metapac/stm32g0b1kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1kc = [ "stm32-metapac/stm32g0b1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1ke = [ "stm32-metapac/stm32g0b1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1mb = [ "stm32-metapac/stm32g0b1mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1mc = [ "stm32-metapac/stm32g0b1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1me = [ "stm32-metapac/stm32g0b1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1ne = [ "stm32-metapac/stm32g0b1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1rb = [ "stm32-metapac/stm32g0b1rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1rc = [ "stm32-metapac/stm32g0b1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1re = [ "stm32-metapac/stm32g0b1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1vb = [ "stm32-metapac/stm32g0b1vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1vc = [ "stm32-metapac/stm32g0b1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0b1ve = [ "stm32-metapac/stm32g0b1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1cc = [ "stm32-metapac/stm32g0c1cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1ce = [ "stm32-metapac/stm32g0c1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1kc = [ "stm32-metapac/stm32g0c1kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1ke = [ "stm32-metapac/stm32g0c1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1mc = [ "stm32-metapac/stm32g0c1mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1me = [ "stm32-metapac/stm32g0c1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1ne = [ "stm32-metapac/stm32g0c1ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1rc = [ "stm32-metapac/stm32g0c1rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1re = [ "stm32-metapac/stm32g0c1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1vc = [ "stm32-metapac/stm32g0c1vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g0c1ve = [ "stm32-metapac/stm32g0c1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431c6 = [ "stm32-metapac/stm32g431c6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431c8 = [ "stm32-metapac/stm32g431c8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431cb = [ "stm32-metapac/stm32g431cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431k6 = [ "stm32-metapac/stm32g431k6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431k8 = [ "stm32-metapac/stm32g431k8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431kb = [ "stm32-metapac/stm32g431kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431m6 = [ "stm32-metapac/stm32g431m6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431m8 = [ "stm32-metapac/stm32g431m8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431mb = [ "stm32-metapac/stm32g431mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431r6 = [ "stm32-metapac/stm32g431r6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431r8 = [ "stm32-metapac/stm32g431r8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431rb = [ "stm32-metapac/stm32g431rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431v6 = [ "stm32-metapac/stm32g431v6", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431v8 = [ "stm32-metapac/stm32g431v8", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g431vb = [ "stm32-metapac/stm32g431vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g441cb = [ "stm32-metapac/stm32g441cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g441kb = [ "stm32-metapac/stm32g441kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g441mb = [ "stm32-metapac/stm32g441mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g441rb = [ "stm32-metapac/stm32g441rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g441vb = [ "stm32-metapac/stm32g441vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471cc = [ "stm32-metapac/stm32g471cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471ce = [ "stm32-metapac/stm32g471ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471mc = [ "stm32-metapac/stm32g471mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471me = [ "stm32-metapac/stm32g471me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471qc = [ "stm32-metapac/stm32g471qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471qe = [ "stm32-metapac/stm32g471qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471rc = [ "stm32-metapac/stm32g471rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471re = [ "stm32-metapac/stm32g471re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471vc = [ "stm32-metapac/stm32g471vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g471ve = [ "stm32-metapac/stm32g471ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473cb = [ "stm32-metapac/stm32g473cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473cc = [ "stm32-metapac/stm32g473cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473ce = [ "stm32-metapac/stm32g473ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473mb = [ "stm32-metapac/stm32g473mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473mc = [ "stm32-metapac/stm32g473mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473me = [ "stm32-metapac/stm32g473me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473pb = [ "stm32-metapac/stm32g473pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473pc = [ "stm32-metapac/stm32g473pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473pe = [ "stm32-metapac/stm32g473pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473qb = [ "stm32-metapac/stm32g473qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473qc = [ "stm32-metapac/stm32g473qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473qe = [ "stm32-metapac/stm32g473qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473rb = [ "stm32-metapac/stm32g473rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473rc = [ "stm32-metapac/stm32g473rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473re = [ "stm32-metapac/stm32g473re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473vb = [ "stm32-metapac/stm32g473vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473vc = [ "stm32-metapac/stm32g473vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g473ve = [ "stm32-metapac/stm32g473ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474cb = [ "stm32-metapac/stm32g474cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474cc = [ "stm32-metapac/stm32g474cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474ce = [ "stm32-metapac/stm32g474ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474mb = [ "stm32-metapac/stm32g474mb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474mc = [ "stm32-metapac/stm32g474mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474me = [ "stm32-metapac/stm32g474me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474pb = [ "stm32-metapac/stm32g474pb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474pc = [ "stm32-metapac/stm32g474pc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474pe = [ "stm32-metapac/stm32g474pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474qb = [ "stm32-metapac/stm32g474qb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474qc = [ "stm32-metapac/stm32g474qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474qe = [ "stm32-metapac/stm32g474qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474rb = [ "stm32-metapac/stm32g474rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474rc = [ "stm32-metapac/stm32g474rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474re = [ "stm32-metapac/stm32g474re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474vb = [ "stm32-metapac/stm32g474vb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474vc = [ "stm32-metapac/stm32g474vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g474ve = [ "stm32-metapac/stm32g474ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g483ce = [ "stm32-metapac/stm32g483ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g483me = [ "stm32-metapac/stm32g483me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g483pe = [ "stm32-metapac/stm32g483pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g483qe = [ "stm32-metapac/stm32g483qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g483re = [ "stm32-metapac/stm32g483re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g483ve = [ "stm32-metapac/stm32g483ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g484ce = [ "stm32-metapac/stm32g484ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g484me = [ "stm32-metapac/stm32g484me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g484pe = [ "stm32-metapac/stm32g484pe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g484qe = [ "stm32-metapac/stm32g484qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g484re = [ "stm32-metapac/stm32g484re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g484ve = [ "stm32-metapac/stm32g484ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491cc = [ "stm32-metapac/stm32g491cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491ce = [ "stm32-metapac/stm32g491ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491kc = [ "stm32-metapac/stm32g491kc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491ke = [ "stm32-metapac/stm32g491ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491mc = [ "stm32-metapac/stm32g491mc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491me = [ "stm32-metapac/stm32g491me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491rc = [ "stm32-metapac/stm32g491rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491re = [ "stm32-metapac/stm32g491re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491vc = [ "stm32-metapac/stm32g491vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g491ve = [ "stm32-metapac/stm32g491ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g4a1ce = [ "stm32-metapac/stm32g4a1ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g4a1ke = [ "stm32-metapac/stm32g4a1ke", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g4a1me = [ "stm32-metapac/stm32g4a1me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g4a1re = [ "stm32-metapac/stm32g4a1re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32g4a1ve = [ "stm32-metapac/stm32g4a1ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h503cb = [ "stm32-metapac/stm32h503cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h503eb = [ "stm32-metapac/stm32h503eb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h503kb = [ "stm32-metapac/stm32h503kb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h503rb = [ "stm32-metapac/stm32h503rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562ag = [ "stm32-metapac/stm32h562ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562ai = [ "stm32-metapac/stm32h562ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562ig = [ "stm32-metapac/stm32h562ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562ii = [ "stm32-metapac/stm32h562ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562rg = [ "stm32-metapac/stm32h562rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562ri = [ "stm32-metapac/stm32h562ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562vg = [ "stm32-metapac/stm32h562vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562vi = [ "stm32-metapac/stm32h562vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562zg = [ "stm32-metapac/stm32h562zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h562zi = [ "stm32-metapac/stm32h562zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563ag = [ "stm32-metapac/stm32h563ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563ai = [ "stm32-metapac/stm32h563ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563ig = [ "stm32-metapac/stm32h563ig", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563ii = [ "stm32-metapac/stm32h563ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563mi = [ "stm32-metapac/stm32h563mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563rg = [ "stm32-metapac/stm32h563rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563ri = [ "stm32-metapac/stm32h563ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563vg = [ "stm32-metapac/stm32h563vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563vi = [ "stm32-metapac/stm32h563vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563zg = [ "stm32-metapac/stm32h563zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h563zi = [ "stm32-metapac/stm32h563zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h573ai = [ "stm32-metapac/stm32h573ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h573ii = [ "stm32-metapac/stm32h573ii", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h573mi = [ "stm32-metapac/stm32h573mi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h573ri = [ "stm32-metapac/stm32h573ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h573vi = [ "stm32-metapac/stm32h573vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h573zi = [ "stm32-metapac/stm32h573zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32h723ve = [ "stm32-metapac/stm32h723ve", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h723vg = [ "stm32-metapac/stm32h723vg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h723ze = [ "stm32-metapac/stm32h723ze", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h723zg = [ "stm32-metapac/stm32h723zg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725ae = [ "stm32-metapac/stm32h725ae", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725ag = [ "stm32-metapac/stm32h725ag", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725ie = [ "stm32-metapac/stm32h725ie", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725ig = [ "stm32-metapac/stm32h725ig", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725re = [ "stm32-metapac/stm32h725re", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725rg = [ "stm32-metapac/stm32h725rg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725ve = [ "stm32-metapac/stm32h725ve", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725vg = [ "stm32-metapac/stm32h725vg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725ze = [ "stm32-metapac/stm32h725ze", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h725zg = [ "stm32-metapac/stm32h725zg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h730ab = [ "stm32-metapac/stm32h730ab", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h730ib = [ "stm32-metapac/stm32h730ib", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h730vb = [ "stm32-metapac/stm32h730vb", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h730zb = [ "stm32-metapac/stm32h730zb", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h733vg = [ "stm32-metapac/stm32h733vg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h733zg = [ "stm32-metapac/stm32h733zg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h735ag = [ "stm32-metapac/stm32h735ag", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h735ig = [ "stm32-metapac/stm32h735ig", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h735rg = [ "stm32-metapac/stm32h735rg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h735vg = [ "stm32-metapac/stm32h735vg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h735zg = [ "stm32-metapac/stm32h735zg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742ag = [ "stm32-metapac/stm32h742ag", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742ai = [ "stm32-metapac/stm32h742ai", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742bg = [ "stm32-metapac/stm32h742bg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742bi = [ "stm32-metapac/stm32h742bi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742ig = [ "stm32-metapac/stm32h742ig", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742ii = [ "stm32-metapac/stm32h742ii", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742vg = [ "stm32-metapac/stm32h742vg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742vi = [ "stm32-metapac/stm32h742vi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742xg = [ "stm32-metapac/stm32h742xg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742xi = [ "stm32-metapac/stm32h742xi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742zg = [ "stm32-metapac/stm32h742zg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h742zi = [ "stm32-metapac/stm32h742zi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743ag = [ "stm32-metapac/stm32h743ag", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743ai = [ "stm32-metapac/stm32h743ai", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743bg = [ "stm32-metapac/stm32h743bg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743bi = [ "stm32-metapac/stm32h743bi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743ig = [ "stm32-metapac/stm32h743ig", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743ii = [ "stm32-metapac/stm32h743ii", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743vg = [ "stm32-metapac/stm32h743vg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743vi = [ "stm32-metapac/stm32h743vi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743xg = [ "stm32-metapac/stm32h743xg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743xi = [ "stm32-metapac/stm32h743xi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743zg = [ "stm32-metapac/stm32h743zg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h743zi = [ "stm32-metapac/stm32h743zi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745bg-cm7 = [ "stm32-metapac/stm32h745bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745bg-cm4 = [ "stm32-metapac/stm32h745bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745bi-cm7 = [ "stm32-metapac/stm32h745bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745bi-cm4 = [ "stm32-metapac/stm32h745bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745ig-cm7 = [ "stm32-metapac/stm32h745ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745ig-cm4 = [ "stm32-metapac/stm32h745ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745ii-cm7 = [ "stm32-metapac/stm32h745ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745ii-cm4 = [ "stm32-metapac/stm32h745ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745xg-cm7 = [ "stm32-metapac/stm32h745xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745xg-cm4 = [ "stm32-metapac/stm32h745xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745xi-cm7 = [ "stm32-metapac/stm32h745xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745xi-cm4 = [ "stm32-metapac/stm32h745xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745zg-cm7 = [ "stm32-metapac/stm32h745zg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745zg-cm4 = [ "stm32-metapac/stm32h745zg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745zi-cm7 = [ "stm32-metapac/stm32h745zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h745zi-cm4 = [ "stm32-metapac/stm32h745zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747ag-cm7 = [ "stm32-metapac/stm32h747ag-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747ag-cm4 = [ "stm32-metapac/stm32h747ag-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747ai-cm7 = [ "stm32-metapac/stm32h747ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747ai-cm4 = [ "stm32-metapac/stm32h747ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747bg-cm7 = [ "stm32-metapac/stm32h747bg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747bg-cm4 = [ "stm32-metapac/stm32h747bg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747bi-cm7 = [ "stm32-metapac/stm32h747bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747bi-cm4 = [ "stm32-metapac/stm32h747bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747ig-cm7 = [ "stm32-metapac/stm32h747ig-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747ig-cm4 = [ "stm32-metapac/stm32h747ig-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747ii-cm7 = [ "stm32-metapac/stm32h747ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747ii-cm4 = [ "stm32-metapac/stm32h747ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747xg-cm7 = [ "stm32-metapac/stm32h747xg-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747xg-cm4 = [ "stm32-metapac/stm32h747xg-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747xi-cm7 = [ "stm32-metapac/stm32h747xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747xi-cm4 = [ "stm32-metapac/stm32h747xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747zi-cm7 = [ "stm32-metapac/stm32h747zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h747zi-cm4 = [ "stm32-metapac/stm32h747zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h750ib = [ "stm32-metapac/stm32h750ib", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h750vb = [ "stm32-metapac/stm32h750vb", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h750xb = [ "stm32-metapac/stm32h750xb", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h750zb = [ "stm32-metapac/stm32h750zb", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h753ai = [ "stm32-metapac/stm32h753ai", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h753bi = [ "stm32-metapac/stm32h753bi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h753ii = [ "stm32-metapac/stm32h753ii", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h753vi = [ "stm32-metapac/stm32h753vi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h753xi = [ "stm32-metapac/stm32h753xi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h753zi = [ "stm32-metapac/stm32h753zi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h755bi-cm7 = [ "stm32-metapac/stm32h755bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h755bi-cm4 = [ "stm32-metapac/stm32h755bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h755ii-cm7 = [ "stm32-metapac/stm32h755ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h755ii-cm4 = [ "stm32-metapac/stm32h755ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h755xi-cm7 = [ "stm32-metapac/stm32h755xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h755xi-cm4 = [ "stm32-metapac/stm32h755xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h755zi-cm7 = [ "stm32-metapac/stm32h755zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h755zi-cm4 = [ "stm32-metapac/stm32h755zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757ai-cm7 = [ "stm32-metapac/stm32h757ai-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757ai-cm4 = [ "stm32-metapac/stm32h757ai-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757bi-cm7 = [ "stm32-metapac/stm32h757bi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757bi-cm4 = [ "stm32-metapac/stm32h757bi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757ii-cm7 = [ "stm32-metapac/stm32h757ii-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757ii-cm4 = [ "stm32-metapac/stm32h757ii-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757xi-cm7 = [ "stm32-metapac/stm32h757xi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757xi-cm4 = [ "stm32-metapac/stm32h757xi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757zi-cm7 = [ "stm32-metapac/stm32h757zi-cm7", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h757zi-cm4 = [ "stm32-metapac/stm32h757zi-cm4", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3ag = [ "stm32-metapac/stm32h7a3ag", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3ai = [ "stm32-metapac/stm32h7a3ai", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3ig = [ "stm32-metapac/stm32h7a3ig", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3ii = [ "stm32-metapac/stm32h7a3ii", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3lg = [ "stm32-metapac/stm32h7a3lg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3li = [ "stm32-metapac/stm32h7a3li", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3ng = [ "stm32-metapac/stm32h7a3ng", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3ni = [ "stm32-metapac/stm32h7a3ni", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3qi = [ "stm32-metapac/stm32h7a3qi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3rg = [ "stm32-metapac/stm32h7a3rg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3ri = [ "stm32-metapac/stm32h7a3ri", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3vg = [ "stm32-metapac/stm32h7a3vg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3vi = [ "stm32-metapac/stm32h7a3vi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3zg = [ "stm32-metapac/stm32h7a3zg", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7a3zi = [ "stm32-metapac/stm32h7a3zi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b0ab = [ "stm32-metapac/stm32h7b0ab", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b0ib = [ "stm32-metapac/stm32h7b0ib", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b0rb = [ "stm32-metapac/stm32h7b0rb", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b0vb = [ "stm32-metapac/stm32h7b0vb", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b0zb = [ "stm32-metapac/stm32h7b0zb", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b3ai = [ "stm32-metapac/stm32h7b3ai", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b3ii = [ "stm32-metapac/stm32h7b3ii", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b3li = [ "stm32-metapac/stm32h7b3li", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b3ni = [ "stm32-metapac/stm32h7b3ni", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b3qi = [ "stm32-metapac/stm32h7b3qi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b3ri = [ "stm32-metapac/stm32h7b3ri", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b3vi = [ "stm32-metapac/stm32h7b3vi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32h7b3zi = [ "stm32-metapac/stm32h7b3zi", "dep:fdcan", "fdcan/fdcan_h7" ]
|
||||
stm32l010c6 = [ "stm32-metapac/stm32l010c6" ]
|
||||
stm32l010f4 = [ "stm32-metapac/stm32l010f4" ]
|
||||
stm32l010k4 = [ "stm32-metapac/stm32l010k4" ]
|
||||
@ -1386,86 +1388,86 @@ stm32l4s7zi = [ "stm32-metapac/stm32l4s7zi" ]
|
||||
stm32l4s9ai = [ "stm32-metapac/stm32l4s9ai" ]
|
||||
stm32l4s9vi = [ "stm32-metapac/stm32l4s9vi" ]
|
||||
stm32l4s9zi = [ "stm32-metapac/stm32l4s9zi" ]
|
||||
stm32l552cc = [ "stm32-metapac/stm32l552cc" ]
|
||||
stm32l552ce = [ "stm32-metapac/stm32l552ce" ]
|
||||
stm32l552me = [ "stm32-metapac/stm32l552me" ]
|
||||
stm32l552qc = [ "stm32-metapac/stm32l552qc" ]
|
||||
stm32l552qe = [ "stm32-metapac/stm32l552qe" ]
|
||||
stm32l552rc = [ "stm32-metapac/stm32l552rc" ]
|
||||
stm32l552re = [ "stm32-metapac/stm32l552re" ]
|
||||
stm32l552vc = [ "stm32-metapac/stm32l552vc" ]
|
||||
stm32l552ve = [ "stm32-metapac/stm32l552ve" ]
|
||||
stm32l552zc = [ "stm32-metapac/stm32l552zc" ]
|
||||
stm32l552ze = [ "stm32-metapac/stm32l552ze" ]
|
||||
stm32l562ce = [ "stm32-metapac/stm32l562ce" ]
|
||||
stm32l562me = [ "stm32-metapac/stm32l562me" ]
|
||||
stm32l562qe = [ "stm32-metapac/stm32l562qe" ]
|
||||
stm32l562re = [ "stm32-metapac/stm32l562re" ]
|
||||
stm32l562ve = [ "stm32-metapac/stm32l562ve" ]
|
||||
stm32l562ze = [ "stm32-metapac/stm32l562ze" ]
|
||||
stm32u535cb = [ "stm32-metapac/stm32u535cb" ]
|
||||
stm32u535cc = [ "stm32-metapac/stm32u535cc" ]
|
||||
stm32u535ce = [ "stm32-metapac/stm32u535ce" ]
|
||||
stm32u535je = [ "stm32-metapac/stm32u535je" ]
|
||||
stm32u535nc = [ "stm32-metapac/stm32u535nc" ]
|
||||
stm32u535ne = [ "stm32-metapac/stm32u535ne" ]
|
||||
stm32u535rb = [ "stm32-metapac/stm32u535rb" ]
|
||||
stm32u535rc = [ "stm32-metapac/stm32u535rc" ]
|
||||
stm32u535re = [ "stm32-metapac/stm32u535re" ]
|
||||
stm32u535vc = [ "stm32-metapac/stm32u535vc" ]
|
||||
stm32u535ve = [ "stm32-metapac/stm32u535ve" ]
|
||||
stm32u545ce = [ "stm32-metapac/stm32u545ce" ]
|
||||
stm32u545je = [ "stm32-metapac/stm32u545je" ]
|
||||
stm32u545ne = [ "stm32-metapac/stm32u545ne" ]
|
||||
stm32u545re = [ "stm32-metapac/stm32u545re" ]
|
||||
stm32u545ve = [ "stm32-metapac/stm32u545ve" ]
|
||||
stm32u575ag = [ "stm32-metapac/stm32u575ag" ]
|
||||
stm32u575ai = [ "stm32-metapac/stm32u575ai" ]
|
||||
stm32u575cg = [ "stm32-metapac/stm32u575cg" ]
|
||||
stm32u575ci = [ "stm32-metapac/stm32u575ci" ]
|
||||
stm32u575og = [ "stm32-metapac/stm32u575og" ]
|
||||
stm32u575oi = [ "stm32-metapac/stm32u575oi" ]
|
||||
stm32u575qg = [ "stm32-metapac/stm32u575qg" ]
|
||||
stm32u575qi = [ "stm32-metapac/stm32u575qi" ]
|
||||
stm32u575rg = [ "stm32-metapac/stm32u575rg" ]
|
||||
stm32u575ri = [ "stm32-metapac/stm32u575ri" ]
|
||||
stm32u575vg = [ "stm32-metapac/stm32u575vg" ]
|
||||
stm32u575vi = [ "stm32-metapac/stm32u575vi" ]
|
||||
stm32u575zg = [ "stm32-metapac/stm32u575zg" ]
|
||||
stm32u575zi = [ "stm32-metapac/stm32u575zi" ]
|
||||
stm32u585ai = [ "stm32-metapac/stm32u585ai" ]
|
||||
stm32u585ci = [ "stm32-metapac/stm32u585ci" ]
|
||||
stm32u585oi = [ "stm32-metapac/stm32u585oi" ]
|
||||
stm32u585qi = [ "stm32-metapac/stm32u585qi" ]
|
||||
stm32u585ri = [ "stm32-metapac/stm32u585ri" ]
|
||||
stm32u585vi = [ "stm32-metapac/stm32u585vi" ]
|
||||
stm32u585zi = [ "stm32-metapac/stm32u585zi" ]
|
||||
stm32u595ai = [ "stm32-metapac/stm32u595ai" ]
|
||||
stm32u595aj = [ "stm32-metapac/stm32u595aj" ]
|
||||
stm32u595qi = [ "stm32-metapac/stm32u595qi" ]
|
||||
stm32u595qj = [ "stm32-metapac/stm32u595qj" ]
|
||||
stm32u595ri = [ "stm32-metapac/stm32u595ri" ]
|
||||
stm32u595rj = [ "stm32-metapac/stm32u595rj" ]
|
||||
stm32u595vi = [ "stm32-metapac/stm32u595vi" ]
|
||||
stm32u595vj = [ "stm32-metapac/stm32u595vj" ]
|
||||
stm32u595zi = [ "stm32-metapac/stm32u595zi" ]
|
||||
stm32u595zj = [ "stm32-metapac/stm32u595zj" ]
|
||||
stm32u599bj = [ "stm32-metapac/stm32u599bj" ]
|
||||
stm32u599ni = [ "stm32-metapac/stm32u599ni" ]
|
||||
stm32u599nj = [ "stm32-metapac/stm32u599nj" ]
|
||||
stm32u599vi = [ "stm32-metapac/stm32u599vi" ]
|
||||
stm32u599vj = [ "stm32-metapac/stm32u599vj" ]
|
||||
stm32u599zi = [ "stm32-metapac/stm32u599zi" ]
|
||||
stm32u599zj = [ "stm32-metapac/stm32u599zj" ]
|
||||
stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj" ]
|
||||
stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj" ]
|
||||
stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj" ]
|
||||
stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj" ]
|
||||
stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj" ]
|
||||
stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj" ]
|
||||
stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj" ]
|
||||
stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj" ]
|
||||
stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj" ]
|
||||
stm32l552cc = [ "stm32-metapac/stm32l552cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552ce = [ "stm32-metapac/stm32l552ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552me = [ "stm32-metapac/stm32l552me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552qc = [ "stm32-metapac/stm32l552qc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552qe = [ "stm32-metapac/stm32l552qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552rc = [ "stm32-metapac/stm32l552rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552re = [ "stm32-metapac/stm32l552re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552vc = [ "stm32-metapac/stm32l552vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552ve = [ "stm32-metapac/stm32l552ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552zc = [ "stm32-metapac/stm32l552zc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l552ze = [ "stm32-metapac/stm32l552ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l562ce = [ "stm32-metapac/stm32l562ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l562me = [ "stm32-metapac/stm32l562me", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l562qe = [ "stm32-metapac/stm32l562qe", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l562re = [ "stm32-metapac/stm32l562re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l562ve = [ "stm32-metapac/stm32l562ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32l562ze = [ "stm32-metapac/stm32l562ze", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535cb = [ "stm32-metapac/stm32u535cb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535cc = [ "stm32-metapac/stm32u535cc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535ce = [ "stm32-metapac/stm32u535ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535je = [ "stm32-metapac/stm32u535je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535nc = [ "stm32-metapac/stm32u535nc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535ne = [ "stm32-metapac/stm32u535ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535rb = [ "stm32-metapac/stm32u535rb", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535rc = [ "stm32-metapac/stm32u535rc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535re = [ "stm32-metapac/stm32u535re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535vc = [ "stm32-metapac/stm32u535vc", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u535ve = [ "stm32-metapac/stm32u535ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u545ce = [ "stm32-metapac/stm32u545ce", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u545je = [ "stm32-metapac/stm32u545je", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u545ne = [ "stm32-metapac/stm32u545ne", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u545re = [ "stm32-metapac/stm32u545re", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u545ve = [ "stm32-metapac/stm32u545ve", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575ag = [ "stm32-metapac/stm32u575ag", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575ai = [ "stm32-metapac/stm32u575ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575cg = [ "stm32-metapac/stm32u575cg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575ci = [ "stm32-metapac/stm32u575ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575og = [ "stm32-metapac/stm32u575og", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575oi = [ "stm32-metapac/stm32u575oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575qg = [ "stm32-metapac/stm32u575qg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575qi = [ "stm32-metapac/stm32u575qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575rg = [ "stm32-metapac/stm32u575rg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575ri = [ "stm32-metapac/stm32u575ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575vg = [ "stm32-metapac/stm32u575vg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575vi = [ "stm32-metapac/stm32u575vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575zg = [ "stm32-metapac/stm32u575zg", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u575zi = [ "stm32-metapac/stm32u575zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u585ai = [ "stm32-metapac/stm32u585ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u585ci = [ "stm32-metapac/stm32u585ci", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u585oi = [ "stm32-metapac/stm32u585oi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u585qi = [ "stm32-metapac/stm32u585qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u585ri = [ "stm32-metapac/stm32u585ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u585vi = [ "stm32-metapac/stm32u585vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u585zi = [ "stm32-metapac/stm32u585zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595ai = [ "stm32-metapac/stm32u595ai", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595aj = [ "stm32-metapac/stm32u595aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595qi = [ "stm32-metapac/stm32u595qi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595qj = [ "stm32-metapac/stm32u595qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595ri = [ "stm32-metapac/stm32u595ri", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595rj = [ "stm32-metapac/stm32u595rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595vi = [ "stm32-metapac/stm32u595vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595vj = [ "stm32-metapac/stm32u595vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595zi = [ "stm32-metapac/stm32u595zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u595zj = [ "stm32-metapac/stm32u595zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u599bj = [ "stm32-metapac/stm32u599bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u599ni = [ "stm32-metapac/stm32u599ni", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u599nj = [ "stm32-metapac/stm32u599nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u599vi = [ "stm32-metapac/stm32u599vi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u599vj = [ "stm32-metapac/stm32u599vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u599zi = [ "stm32-metapac/stm32u599zi", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u599zj = [ "stm32-metapac/stm32u599zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u5a5aj = [ "stm32-metapac/stm32u5a5aj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u5a5qj = [ "stm32-metapac/stm32u5a5qj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u5a5rj = [ "stm32-metapac/stm32u5a5rj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u5a5vj = [ "stm32-metapac/stm32u5a5vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u5a5zj = [ "stm32-metapac/stm32u5a5zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u5a9bj = [ "stm32-metapac/stm32u5a9bj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u5a9nj = [ "stm32-metapac/stm32u5a9nj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u5a9vj = [ "stm32-metapac/stm32u5a9vj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32u5a9zj = [ "stm32-metapac/stm32u5a9zj", "dep:fdcan", "fdcan/fdcan_g0_g4_l5" ]
|
||||
stm32wb10cc = [ "stm32-metapac/stm32wb10cc" ]
|
||||
stm32wb15cc = [ "stm32-metapac/stm32wb15cc" ]
|
||||
stm32wb30ce = [ "stm32-metapac/stm32wb30ce" ]
|
||||
|
@ -449,9 +449,20 @@ fn main() {
|
||||
// ========
|
||||
// Generate RccPeripheral impls
|
||||
|
||||
let refcounted_peripherals = HashSet::from(["usart", "adc"]);
|
||||
// count how many times each xxENR field is used, to enable refcounting if used more than once.
|
||||
let mut rcc_field_count: HashMap<_, usize> = HashMap::new();
|
||||
for p in METADATA.peripherals {
|
||||
if let Some(rcc) = &p.rcc {
|
||||
let en = rcc.enable.as_ref().unwrap();
|
||||
*rcc_field_count.entry((en.register, en.field)).or_insert(0) += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let force_refcount = HashSet::from(["usart"]);
|
||||
let mut refcount_statics = BTreeSet::new();
|
||||
|
||||
let mut clock_names = BTreeSet::new();
|
||||
|
||||
for p in METADATA.peripherals {
|
||||
if !singletons.contains(&p.name.to_string()) {
|
||||
continue;
|
||||
@ -483,11 +494,12 @@ fn main() {
|
||||
|
||||
let ptype = if let Some(reg) = &p.registers { reg.kind } else { "" };
|
||||
let pname = format_ident!("{}", p.name);
|
||||
let clk = format_ident!("{}", rcc.clock);
|
||||
let en_reg = format_ident!("{}", en.register);
|
||||
let set_en_field = format_ident!("set_{}", en.field);
|
||||
|
||||
let (before_enable, before_disable) = if refcounted_peripherals.contains(ptype) {
|
||||
let refcount =
|
||||
force_refcount.contains(ptype) || *rcc_field_count.get(&(en.register, en.field)).unwrap() > 1;
|
||||
let (before_enable, before_disable) = if refcount {
|
||||
let refcount_static =
|
||||
format_ident!("{}_{}", en.register.to_ascii_uppercase(), en.field.to_ascii_uppercase());
|
||||
|
||||
@ -511,14 +523,7 @@ fn main() {
|
||||
(TokenStream::new(), TokenStream::new())
|
||||
};
|
||||
|
||||
let mux_supported = HashSet::from(["c0", "h5", "h50", "h7", "h7ab", "h7rm0433", "g0", "g4", "l4"])
|
||||
.contains(rcc_registers.version);
|
||||
let mux_for = |mux: Option<&'static PeripheralRccRegister>| {
|
||||
// restrict mux implementation to supported versions
|
||||
if !mux_supported {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mux = mux?;
|
||||
let fieldset = rcc_enum_map.get(mux.register)?;
|
||||
let enumm = fieldset.get(mux.field)?;
|
||||
@ -539,15 +544,9 @@ fn main() {
|
||||
.map(|v| {
|
||||
let variant_name = format_ident!("{}", v.name);
|
||||
let clock_name = format_ident!("{}", v.name.to_ascii_lowercase());
|
||||
|
||||
if v.name.starts_with("HCLK") || v.name.starts_with("PCLK") || v.name == "SYS" {
|
||||
quote! {
|
||||
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name },
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
|
||||
}
|
||||
clock_names.insert(v.name.to_ascii_lowercase());
|
||||
quote! {
|
||||
#enum_name::#variant_name => unsafe { crate::rcc::get_freqs().#clock_name.unwrap() },
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@ -558,19 +557,21 @@ fn main() {
|
||||
#[allow(unreachable_patterns)]
|
||||
match crate::pac::RCC.#fieldset_name().read().#field_name() {
|
||||
#match_arms
|
||||
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
None => quote! {
|
||||
unsafe { crate::rcc::get_freqs().#clk }
|
||||
},
|
||||
None => {
|
||||
let clock_name = format_ident!("{}", rcc.clock);
|
||||
clock_names.insert(rcc.clock.to_string());
|
||||
quote! {
|
||||
unsafe { crate::rcc::get_freqs().#clock_name.unwrap() }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
A refcount leak can result if the same field is shared by peripherals with different stop modes
|
||||
|
||||
This condition should be checked in stm32-data
|
||||
*/
|
||||
let stop_refcount = match rcc.stop_mode {
|
||||
@ -617,6 +618,39 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Generate RCC
|
||||
clock_names.insert("sys".to_string());
|
||||
clock_names.insert("rtc".to_string());
|
||||
let clock_idents: Vec<_> = clock_names.iter().map(|n| format_ident!("{}", n)).collect();
|
||||
g.extend(quote! {
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct Clocks {
|
||||
#(
|
||||
pub #clock_idents: Option<crate::time::Hertz>,
|
||||
)*
|
||||
}
|
||||
});
|
||||
|
||||
let clocks_macro = quote!(
|
||||
macro_rules! set_clocks {
|
||||
($($(#[$m:meta])* $k:ident: $v:expr,)*) => {
|
||||
{
|
||||
#[allow(unused)]
|
||||
struct Temp {
|
||||
$($(#[$m])* $k: Option<crate::time::Hertz>,)*
|
||||
}
|
||||
let all = Temp {
|
||||
$($(#[$m])* $k: $v,)*
|
||||
};
|
||||
crate::rcc::set_freqs(crate::rcc::Clocks {
|
||||
#( #clock_idents: all.#clock_idents, )*
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
let refcount_mod: TokenStream = refcount_statics
|
||||
.iter()
|
||||
.map(|refcount_static| {
|
||||
@ -735,13 +769,20 @@ fn main() {
|
||||
(("can", "TX"), quote!(crate::can::TxPin)),
|
||||
(("can", "RX"), quote!(crate::can::RxPin)),
|
||||
(("eth", "REF_CLK"), quote!(crate::eth::RefClkPin)),
|
||||
(("eth", "RX_CLK"), quote!(crate::eth::RXClkPin)),
|
||||
(("eth", "TX_CLK"), quote!(crate::eth::TXClkPin)),
|
||||
(("eth", "MDIO"), quote!(crate::eth::MDIOPin)),
|
||||
(("eth", "MDC"), quote!(crate::eth::MDCPin)),
|
||||
(("eth", "CRS_DV"), quote!(crate::eth::CRSPin)),
|
||||
(("eth", "RX_DV"), quote!(crate::eth::RXDVPin)),
|
||||
(("eth", "RXD0"), quote!(crate::eth::RXD0Pin)),
|
||||
(("eth", "RXD1"), quote!(crate::eth::RXD1Pin)),
|
||||
(("eth", "RXD2"), quote!(crate::eth::RXD2Pin)),
|
||||
(("eth", "RXD3"), quote!(crate::eth::RXD3Pin)),
|
||||
(("eth", "TXD0"), quote!(crate::eth::TXD0Pin)),
|
||||
(("eth", "TXD1"), quote!(crate::eth::TXD1Pin)),
|
||||
(("eth", "TXD2"), quote!(crate::eth::TXD2Pin)),
|
||||
(("eth", "TXD3"), quote!(crate::eth::TXD3Pin)),
|
||||
(("eth", "TX_EN"), quote!(crate::eth::TXEnPin)),
|
||||
(("fmc", "A0"), quote!(crate::fmc::A0Pin)),
|
||||
(("fmc", "A1"), quote!(crate::fmc::A1Pin)),
|
||||
@ -942,9 +983,9 @@ fn main() {
|
||||
} else if pin.signal.starts_with("INN") {
|
||||
// TODO handle in the future when embassy supports differential measurements
|
||||
None
|
||||
} else if pin.signal.starts_with("IN") && pin.signal.ends_with("b") {
|
||||
} else if pin.signal.starts_with("IN") && pin.signal.ends_with('b') {
|
||||
// we number STM32L1 ADC bank 1 as 0..=31, bank 2 as 32..=63
|
||||
let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix("b").unwrap();
|
||||
let signal = pin.signal.strip_prefix("IN").unwrap().strip_suffix('b').unwrap();
|
||||
Some(32u8 + signal.parse::<u8>().unwrap())
|
||||
} else if pin.signal.starts_with("IN") {
|
||||
Some(pin.signal.strip_prefix("IN").unwrap().parse().unwrap())
|
||||
@ -1016,6 +1057,10 @@ fn main() {
|
||||
(("dac", "CH2"), quote!(crate::dac::DacDma2)),
|
||||
(("timer", "UP"), quote!(crate::timer::UpDma)),
|
||||
(("hash", "IN"), quote!(crate::hash::Dma)),
|
||||
(("timer", "CH1"), quote!(crate::timer::Ch1Dma)),
|
||||
(("timer", "CH2"), quote!(crate::timer::Ch2Dma)),
|
||||
(("timer", "CH3"), quote!(crate::timer::Ch3Dma)),
|
||||
(("timer", "CH4"), quote!(crate::timer::Ch4Dma)),
|
||||
]
|
||||
.into();
|
||||
|
||||
@ -1031,16 +1076,6 @@ fn main() {
|
||||
}
|
||||
|
||||
if let Some(tr) = signals.get(&(regs.kind, ch.signal)) {
|
||||
// TIM6 of stm32f334 is special, DMA channel for TIM6 depending on SYSCFG state
|
||||
if chip_name.starts_with("stm32f334") && p.name == "TIM6" {
|
||||
continue;
|
||||
}
|
||||
|
||||
// TIM6 of stm32f378 is special, DMA channel for TIM6 depending on SYSCFG state
|
||||
if chip_name.starts_with("stm32f378") && p.name == "TIM6" {
|
||||
continue;
|
||||
}
|
||||
|
||||
let peri = format_ident!("{}", p.name);
|
||||
|
||||
let channel = if let Some(channel) = &ch.channel {
|
||||
@ -1199,7 +1234,7 @@ fn main() {
|
||||
ADC3 and higher are assigned to the adc34 clock in the table
|
||||
The adc3_common cfg directive is added if ADC3_COMMON exists
|
||||
*/
|
||||
let has_adc3 = METADATA.peripherals.iter().find(|p| p.name == "ADC3_COMMON").is_some();
|
||||
let has_adc3 = METADATA.peripherals.iter().any(|p| p.name == "ADC3_COMMON");
|
||||
let set_adc345 = HashSet::from(["ADC3", "ADC4", "ADC5"]);
|
||||
|
||||
for m in METADATA
|
||||
@ -1338,7 +1373,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let mut m = String::new();
|
||||
let mut m = clocks_macro.to_string();
|
||||
|
||||
// DO NOT ADD more macros like these.
|
||||
// These turned to be a bad idea!
|
||||
@ -1383,6 +1418,7 @@ fn main() {
|
||||
|
||||
// =======
|
||||
// ADC3_COMMON is present
|
||||
#[allow(clippy::print_literal)]
|
||||
if has_adc3 {
|
||||
println!("cargo:rustc-cfg={}", "adc3_common");
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ use embassy_hal_internal::into_ref;
|
||||
use embedded_hal_02::blocking::delay::DelayUs;
|
||||
|
||||
use crate::adc::{Adc, AdcPin, Instance, SampleTime};
|
||||
use crate::rcc::get_freqs;
|
||||
use crate::time::Hertz;
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
@ -80,7 +79,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
|
||||
fn freq() -> Hertz {
|
||||
unsafe { get_freqs() }.adc.unwrap()
|
||||
T::frequency()
|
||||
}
|
||||
|
||||
pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
|
||||
|
@ -102,7 +102,7 @@ impl<'d, T: Instance> Adc<'d, T> {
|
||||
}
|
||||
|
||||
fn freq() -> Hertz {
|
||||
<T as crate::adc::sealed::Instance>::frequency()
|
||||
<T as crate::rcc::sealed::RccPeripheral>::frequency()
|
||||
}
|
||||
|
||||
pub fn sample_time_for_us(&self, us: u32) -> SampleTime {
|
||||
|
@ -61,8 +61,6 @@ pub(crate) mod sealed {
|
||||
fn regs() -> crate::pac::adc::Adc;
|
||||
#[cfg(not(any(adc_f1, adc_v1, adc_f3_v2, adc_f3_v1_1, adc_g0)))]
|
||||
fn common_regs() -> crate::pac::adccommon::AdcCommon;
|
||||
#[cfg(adc_f3)]
|
||||
fn frequency() -> crate::time::Hertz;
|
||||
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
|
||||
fn state() -> &'static State;
|
||||
}
|
||||
@ -103,11 +101,6 @@ foreach_adc!(
|
||||
return crate::pac::$common_inst
|
||||
}
|
||||
|
||||
#[cfg(adc_f3)]
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
unsafe { crate::rcc::get_freqs() }.$clock.unwrap()
|
||||
}
|
||||
|
||||
#[cfg(any(adc_f1, adc_f3, adc_v1, adc_f3_v1_1))]
|
||||
fn state() -> &'static sealed::State {
|
||||
static STATE: sealed::State = sealed::State::new();
|
||||
|
@ -34,7 +34,7 @@ impl AdcPin<ADC1> for Temperature {}
|
||||
impl super::sealed::AdcPin<ADC1> for Temperature {
|
||||
fn channel(&self) -> u8 {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(any(stm32f40, stm32f41))] {
|
||||
if #[cfg(any(stm32f2, stm32f40, stm32f41))] {
|
||||
16
|
||||
} else {
|
||||
18
|
||||
@ -67,7 +67,11 @@ enum Prescaler {
|
||||
|
||||
impl Prescaler {
|
||||
fn from_pclk2(freq: Hertz) -> Self {
|
||||
// Datasheet for F2 specifies min frequency 0.6 MHz, and max 30 MHz (with VDDA 2.4-3.6V).
|
||||
#[cfg(stm32f2)]
|
||||
const MAX_FREQUENCY: Hertz = Hertz(30_000_000);
|
||||
// Datasheet for both F4 and F7 specifies min frequency 0.6 MHz, typ freq. 30 MHz and max 36 MHz.
|
||||
#[cfg(not(stm32f2))]
|
||||
const MAX_FREQUENCY: Hertz = Hertz(36_000_000);
|
||||
let raw_div = freq.0 / MAX_FREQUENCY.0;
|
||||
match raw_div {
|
||||
|
@ -13,9 +13,12 @@ use crate::gpio::sealed::AFType;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::pac::can::vals::{Ide, Lec};
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::time::Hertz;
|
||||
use crate::{interrupt, peripherals, Peripheral};
|
||||
|
||||
pub mod enums;
|
||||
use enums::*;
|
||||
pub mod util;
|
||||
|
||||
/// Contains CAN frame and additional metadata.
|
||||
///
|
||||
/// Timestamp is available if `time` feature is enabled.
|
||||
@ -93,23 +96,6 @@ pub struct Can<'d, T: Instance> {
|
||||
can: bxcan::Can<BxcanInstance<'d, T>>,
|
||||
}
|
||||
|
||||
/// CAN bus error
|
||||
#[allow(missing_docs)]
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BusError {
|
||||
Stuff,
|
||||
Form,
|
||||
Acknowledge,
|
||||
BitRecessive,
|
||||
BitDominant,
|
||||
Crc,
|
||||
Software,
|
||||
BusOff,
|
||||
BusPassive,
|
||||
BusWarning,
|
||||
}
|
||||
|
||||
/// Error returned by `try_read`
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
@ -186,8 +172,15 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
|
||||
/// Set CAN bit rate.
|
||||
pub fn set_bitrate(&mut self, bitrate: u32) {
|
||||
let bit_timing = Self::calc_bxcan_timings(T::frequency(), bitrate).unwrap();
|
||||
self.can.modify_config().set_bit_timing(bit_timing).leave_disabled();
|
||||
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
|
||||
let sjw = u8::from(bit_timing.sync_jump_width) as u32;
|
||||
let seg1 = u8::from(bit_timing.seg1) as u32;
|
||||
let seg2 = u8::from(bit_timing.seg2) as u32;
|
||||
let prescaler = u16::from(bit_timing.prescaler) as u32;
|
||||
self.can
|
||||
.modify_config()
|
||||
.set_bit_timing((sjw - 1) << 24 | (seg1 - 1) << 16 | (seg2 - 1) << 20 | (prescaler - 1))
|
||||
.leave_disabled();
|
||||
}
|
||||
|
||||
/// Enables the peripheral and synchronizes with the bus.
|
||||
@ -302,97 +295,6 @@ impl<'d, T: Instance> Can<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
const fn calc_bxcan_timings(periph_clock: Hertz, can_bitrate: u32) -> Option<u32> {
|
||||
const BS1_MAX: u8 = 16;
|
||||
const BS2_MAX: u8 = 8;
|
||||
const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
|
||||
|
||||
let periph_clock = periph_clock.0;
|
||||
|
||||
if can_bitrate < 1000 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
|
||||
// CAN in Automation, 2003
|
||||
//
|
||||
// According to the source, optimal quanta per bit are:
|
||||
// Bitrate Optimal Maximum
|
||||
// 1000 kbps 8 10
|
||||
// 500 kbps 16 17
|
||||
// 250 kbps 16 17
|
||||
// 125 kbps 16 17
|
||||
let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 };
|
||||
|
||||
// Computing (prescaler * BS):
|
||||
// BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
|
||||
// BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
|
||||
// let:
|
||||
// BS = 1 + BS1 + BS2 -- Number of time quanta per bit
|
||||
// PRESCALER_BS = PRESCALER * BS
|
||||
// ==>
|
||||
// PRESCALER_BS = PCLK / BITRATE
|
||||
let prescaler_bs = periph_clock / can_bitrate;
|
||||
|
||||
// Searching for such prescaler value so that the number of quanta per bit is highest.
|
||||
let mut bs1_bs2_sum = max_quanta_per_bit - 1;
|
||||
while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
|
||||
if bs1_bs2_sum <= 2 {
|
||||
return None; // No solution
|
||||
}
|
||||
bs1_bs2_sum -= 1;
|
||||
}
|
||||
|
||||
let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
|
||||
if (prescaler < 1) || (prescaler > 1024) {
|
||||
return None; // No solution
|
||||
}
|
||||
|
||||
// Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
|
||||
// We need to find such values so that the sample point is as close as possible to the optimal value,
|
||||
// which is 87.5%, which is 7/8.
|
||||
//
|
||||
// Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
|
||||
// {{bs2 -> (1 + bs1)/7}}
|
||||
//
|
||||
// Hence:
|
||||
// bs2 = (1 + bs1) / 7
|
||||
// bs1 = (7 * bs1_bs2_sum - 1) / 8
|
||||
//
|
||||
// Sample point location can be computed as follows:
|
||||
// Sample point location = (1 + bs1) / (1 + bs1 + bs2)
|
||||
//
|
||||
// Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
|
||||
// - With rounding to nearest
|
||||
// - With rounding to zero
|
||||
let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first
|
||||
let mut bs2 = bs1_bs2_sum - bs1;
|
||||
core::assert!(bs1_bs2_sum > bs1);
|
||||
|
||||
let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16;
|
||||
if sample_point_permill > MAX_SAMPLE_POINT_PERMILL {
|
||||
// Nope, too far; now rounding to zero
|
||||
bs1 = (7 * bs1_bs2_sum - 1) / 8;
|
||||
bs2 = bs1_bs2_sum - bs1;
|
||||
}
|
||||
|
||||
// Check is BS1 and BS2 are in range
|
||||
if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Check if final bitrate matches the requested
|
||||
if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// One is recommended by DS-015, CANOpen, and DeviceNet
|
||||
let sjw = 1;
|
||||
|
||||
// Pack into BTR register values
|
||||
Some((sjw - 1) << 24 | (bs1 as u32 - 1) << 16 | (bs2 as u32 - 1) << 20 | (prescaler - 1))
|
||||
}
|
||||
|
||||
/// Split the CAN driver into transmit and receive halves.
|
||||
///
|
||||
/// Useful for doing separate transmit/receive tasks.
|
||||
|
30
embassy-stm32/src/can/enums.rs
Normal file
30
embassy-stm32/src/can/enums.rs
Normal file
@ -0,0 +1,30 @@
|
||||
//! Enums shared between CAN controller types.
|
||||
|
||||
/// Bus error
|
||||
#[derive(Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum BusError {
|
||||
/// Bit stuffing error - more than 5 equal bits
|
||||
Stuff,
|
||||
/// Form error - A fixed format part of a received message has wrong format
|
||||
Form,
|
||||
/// The message transmitted by the FDCAN was not acknowledged by another node.
|
||||
Acknowledge,
|
||||
/// Bit0Error: During the transmission of a message the device wanted to send a dominant level
|
||||
/// but the monitored bus value was recessive.
|
||||
BitRecessive,
|
||||
/// Bit1Error: During the transmission of a message the device wanted to send a recessive level
|
||||
/// but the monitored bus value was dominant.
|
||||
BitDominant,
|
||||
/// The CRC check sum of a received message was incorrect. The CRC of an
|
||||
/// incoming message does not match with the CRC calculated from the received data.
|
||||
Crc,
|
||||
/// A software error occured
|
||||
Software,
|
||||
/// The FDCAN is in Bus_Off state.
|
||||
BusOff,
|
||||
/// The FDCAN is in the Error_Passive state.
|
||||
BusPassive,
|
||||
/// At least one of error counter has reached the Error_Warning limit of 96.
|
||||
BusWarning,
|
||||
}
|
@ -1,14 +1,577 @@
|
||||
use crate::peripherals;
|
||||
use core::future::poll_fn;
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::{Deref, DerefMut};
|
||||
use core::task::Poll;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use embassy_hal_internal::{into_ref, PeripheralRef};
|
||||
pub use fdcan::frame::{FrameFormat, RxFrameInfo, TxFrameHeader};
|
||||
pub use fdcan::id::{ExtendedId, Id, StandardId};
|
||||
use fdcan::message_ram::RegisterBlock;
|
||||
use fdcan::{self, LastErrorCode};
|
||||
pub use fdcan::{config, filter};
|
||||
|
||||
use crate::gpio::sealed::AFType;
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
use crate::rcc::RccPeripheral;
|
||||
use crate::{interrupt, peripherals, Peripheral};
|
||||
|
||||
pub mod enums;
|
||||
use enums::*;
|
||||
pub mod util;
|
||||
|
||||
/// CAN Frame returned by read
|
||||
pub struct RxFrame {
|
||||
/// CAN Header info: frame ID, data length and other meta
|
||||
pub header: RxFrameInfo,
|
||||
/// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
|
||||
pub data: Data,
|
||||
/// Reception time.
|
||||
#[cfg(feature = "time")]
|
||||
pub timestamp: embassy_time::Instant,
|
||||
}
|
||||
|
||||
/// CAN frame used for write
|
||||
pub struct TxFrame {
|
||||
/// CAN Header info: frame ID, data length and other meta
|
||||
pub header: TxFrameHeader,
|
||||
/// CAN(0-8 bytes) or FDCAN(0-64 bytes) Frame data
|
||||
pub data: Data,
|
||||
}
|
||||
|
||||
impl TxFrame {
|
||||
/// Create new TX frame from header and data
|
||||
pub fn new(header: TxFrameHeader, data: &[u8]) -> Option<Self> {
|
||||
if data.len() < header.len as usize {
|
||||
return None;
|
||||
}
|
||||
|
||||
let Some(data) = Data::new(data) else { return None };
|
||||
|
||||
Some(TxFrame { header, data })
|
||||
}
|
||||
|
||||
fn from_preserved(header: TxFrameHeader, data32: &[u32]) -> Option<Self> {
|
||||
let mut data = [0u8; 64];
|
||||
|
||||
for i in 0..data32.len() {
|
||||
data[4 * i..][..4].copy_from_slice(&data32[i].to_le_bytes());
|
||||
}
|
||||
|
||||
let Some(data) = Data::new(&data) else { return None };
|
||||
|
||||
Some(TxFrame { header, data })
|
||||
}
|
||||
|
||||
/// Access frame data. Slice length will match header.
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data.bytes[..(self.header.len as usize)]
|
||||
}
|
||||
}
|
||||
|
||||
impl RxFrame {
|
||||
pub(crate) fn new(
|
||||
header: RxFrameInfo,
|
||||
data: &[u8],
|
||||
#[cfg(feature = "time")] timestamp: embassy_time::Instant,
|
||||
) -> Self {
|
||||
let data = Data::new(&data).unwrap_or_else(|| Data::empty());
|
||||
|
||||
RxFrame {
|
||||
header,
|
||||
data,
|
||||
#[cfg(feature = "time")]
|
||||
timestamp,
|
||||
}
|
||||
}
|
||||
|
||||
/// Access frame data. Slice length will match header.
|
||||
pub fn data(&self) -> &[u8] {
|
||||
&self.data.bytes[..(self.header.len as usize)]
|
||||
}
|
||||
}
|
||||
|
||||
/// Payload of a (FD)CAN data frame.
|
||||
///
|
||||
/// Contains 0 to 64 Bytes of data.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct Data {
|
||||
pub(crate) bytes: [u8; 64],
|
||||
}
|
||||
|
||||
impl Data {
|
||||
/// Creates a data payload from a raw byte slice.
|
||||
///
|
||||
/// Returns `None` if `data` is more than 64 bytes (which is the maximum) or
|
||||
/// cannot be represented with an FDCAN DLC.
|
||||
pub fn new(data: &[u8]) -> Option<Self> {
|
||||
if !Data::is_valid_len(data.len()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let mut bytes = [0; 64];
|
||||
bytes[..data.len()].copy_from_slice(data);
|
||||
|
||||
Some(Self { bytes })
|
||||
}
|
||||
|
||||
/// Raw read access to data.
|
||||
pub fn raw(&self) -> &[u8] {
|
||||
&self.bytes
|
||||
}
|
||||
|
||||
/// Checks if the length can be encoded in FDCAN DLC field.
|
||||
pub const fn is_valid_len(len: usize) -> bool {
|
||||
match len {
|
||||
0..=8 => true,
|
||||
12 => true,
|
||||
16 => true,
|
||||
20 => true,
|
||||
24 => true,
|
||||
32 => true,
|
||||
48 => true,
|
||||
64 => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an empty data payload containing 0 bytes.
|
||||
#[inline]
|
||||
pub const fn empty() -> Self {
|
||||
Self { bytes: [0; 64] }
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt handler channel 0.
|
||||
pub struct IT0InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
// We use IT0 for everything currently
|
||||
impl<T: Instance> interrupt::typelevel::Handler<T::IT0Interrupt> for IT0InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {
|
||||
let regs = T::regs();
|
||||
|
||||
let ir = regs.ir().read();
|
||||
|
||||
if ir.tc() {
|
||||
regs.ir().write(|w| w.set_tc(true));
|
||||
T::state().tx_waker.wake();
|
||||
}
|
||||
|
||||
if ir.tefn() {
|
||||
regs.ir().write(|w| w.set_tefn(true));
|
||||
T::state().tx_waker.wake();
|
||||
}
|
||||
|
||||
if ir.ped() || ir.pea() {
|
||||
regs.ir().write(|w| {
|
||||
w.set_ped(true);
|
||||
w.set_pea(true);
|
||||
});
|
||||
}
|
||||
|
||||
if ir.rfn(0) {
|
||||
regs.ir().write(|w| w.set_rfn(0, true));
|
||||
T::state().rx_waker.wake();
|
||||
}
|
||||
|
||||
if ir.rfn(1) {
|
||||
regs.ir().write(|w| w.set_rfn(1, true));
|
||||
T::state().rx_waker.wake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Interrupt handler channel 1.
|
||||
pub struct IT1InterruptHandler<T: Instance> {
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Instance> interrupt::typelevel::Handler<T::IT1Interrupt> for IT1InterruptHandler<T> {
|
||||
unsafe fn on_interrupt() {}
|
||||
}
|
||||
|
||||
impl BusError {
|
||||
fn try_from(lec: LastErrorCode) -> Option<BusError> {
|
||||
match lec {
|
||||
LastErrorCode::AckError => Some(BusError::Acknowledge),
|
||||
// `0` data bit encodes a dominant state. `1` data bit is recessive.
|
||||
// Bit0Error: During transmit, the node wanted to send a 0 but monitored a 1
|
||||
LastErrorCode::Bit0Error => Some(BusError::BitRecessive),
|
||||
LastErrorCode::Bit1Error => Some(BusError::BitDominant),
|
||||
LastErrorCode::CRCError => Some(BusError::Crc),
|
||||
LastErrorCode::FormError => Some(BusError::Form),
|
||||
LastErrorCode::StuffError => Some(BusError::Stuff),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Operating modes trait
|
||||
pub trait FdcanOperatingMode {}
|
||||
impl FdcanOperatingMode for fdcan::PoweredDownMode {}
|
||||
impl FdcanOperatingMode for fdcan::ConfigMode {}
|
||||
impl FdcanOperatingMode for fdcan::InternalLoopbackMode {}
|
||||
impl FdcanOperatingMode for fdcan::ExternalLoopbackMode {}
|
||||
impl FdcanOperatingMode for fdcan::NormalOperationMode {}
|
||||
impl FdcanOperatingMode for fdcan::RestrictedOperationMode {}
|
||||
impl FdcanOperatingMode for fdcan::BusMonitoringMode {}
|
||||
impl FdcanOperatingMode for fdcan::TestMode {}
|
||||
|
||||
/// FDCAN Instance
|
||||
pub struct Fdcan<'d, T: Instance, M: FdcanOperatingMode> {
|
||||
/// Reference to internals.
|
||||
pub can: fdcan::FdCan<FdcanInstance<'d, T>, M>,
|
||||
ns_per_timer_tick: u64, // For FDCAN internal timer
|
||||
}
|
||||
|
||||
fn calc_ns_per_timer_tick<T: Instance>(mode: config::FrameTransmissionConfig) -> u64 {
|
||||
match mode {
|
||||
// Use timestamp from Rx FIFO to adjust timestamp reported to user
|
||||
config::FrameTransmissionConfig::ClassicCanOnly => {
|
||||
let freq = T::frequency();
|
||||
let prescale: u64 =
|
||||
({ T::regs().nbtp().read().nbrp() } + 1) as u64 * ({ T::regs().tscc().read().tcp() } + 1) as u64;
|
||||
1_000_000_000 as u64 / (freq.0 as u64 * prescale)
|
||||
}
|
||||
// For VBR this is too hard because the FDCAN timer switches clock rate you need to configure to use
|
||||
// timer3 instead which is too hard to do from this module.
|
||||
_ => 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "time")]
|
||||
fn calc_timestamp<T: Instance>(ns_per_timer_tick: u64, ts_val: u16) -> embassy_time::Instant {
|
||||
let now_embassy = embassy_time::Instant::now();
|
||||
if ns_per_timer_tick == 0 {
|
||||
return now_embassy;
|
||||
}
|
||||
let now_can = { T::regs().tscv().read().tsc() };
|
||||
let delta = now_can.overflowing_sub(ts_val).0 as u64;
|
||||
let ns = ns_per_timer_tick * delta as u64;
|
||||
now_embassy - embassy_time::Duration::from_nanos(ns)
|
||||
}
|
||||
|
||||
fn curr_error<T: Instance>() -> Option<BusError> {
|
||||
let err = { T::regs().psr().read() };
|
||||
if err.bo() {
|
||||
return Some(BusError::BusOff);
|
||||
} else if err.ep() {
|
||||
return Some(BusError::BusPassive);
|
||||
} else if err.ew() {
|
||||
return Some(BusError::BusWarning);
|
||||
} else {
|
||||
cfg_if! {
|
||||
if #[cfg(stm32h7)] {
|
||||
let lec = err.lec();
|
||||
} else {
|
||||
let lec = err.lec().to_bits();
|
||||
}
|
||||
}
|
||||
if let Ok(err) = LastErrorCode::try_from(lec) {
|
||||
return BusError::try_from(err);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
impl<'d, T: Instance> Fdcan<'d, T, fdcan::ConfigMode> {
|
||||
/// Creates a new Fdcan instance, keeping the peripheral in sleep mode.
|
||||
/// You must call [Fdcan::enable_non_blocking] to use the peripheral.
|
||||
pub fn new(
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
rx: impl Peripheral<P = impl RxPin<T>> + 'd,
|
||||
tx: impl Peripheral<P = impl TxPin<T>> + 'd,
|
||||
_irqs: impl interrupt::typelevel::Binding<T::IT0Interrupt, IT0InterruptHandler<T>>
|
||||
+ interrupt::typelevel::Binding<T::IT1Interrupt, IT1InterruptHandler<T>>
|
||||
+ 'd,
|
||||
) -> Fdcan<'d, T, fdcan::ConfigMode> {
|
||||
into_ref!(peri, rx, tx);
|
||||
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
|
||||
T::enable_and_reset();
|
||||
|
||||
rx.set_as_af(rx.af_num(), AFType::Input);
|
||||
tx.set_as_af(tx.af_num(), AFType::OutputPushPull);
|
||||
|
||||
let mut can = fdcan::FdCan::new(FdcanInstance(peri)).into_config_mode();
|
||||
|
||||
T::configure_msg_ram();
|
||||
unsafe {
|
||||
// Enable timestamping
|
||||
#[cfg(not(stm32h7))]
|
||||
T::regs()
|
||||
.tscc()
|
||||
.write(|w| w.set_tss(stm32_metapac::can::vals::Tss::INCREMENT));
|
||||
#[cfg(stm32h7)]
|
||||
T::regs().tscc().write(|w| w.set_tss(0x01));
|
||||
|
||||
T::IT0Interrupt::unpend(); // Not unsafe
|
||||
T::IT0Interrupt::enable();
|
||||
|
||||
T::IT1Interrupt::unpend(); // Not unsafe
|
||||
T::IT1Interrupt::enable();
|
||||
|
||||
// this isn't really documented in the reference manual
|
||||
// but corresponding txbtie bit has to be set for the TC (TxComplete) interrupt to fire
|
||||
T::regs().txbtie().write(|w| w.0 = 0xffff_ffff);
|
||||
}
|
||||
|
||||
can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo0NewMsg);
|
||||
can.enable_interrupt(fdcan::interrupt::Interrupt::RxFifo1NewMsg);
|
||||
can.enable_interrupt(fdcan::interrupt::Interrupt::TxComplete);
|
||||
can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_0, true);
|
||||
can.enable_interrupt_line(fdcan::interrupt::InterruptLine::_1, true);
|
||||
|
||||
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(can.get_config().frame_transmit);
|
||||
Self { can, ns_per_timer_tick }
|
||||
}
|
||||
|
||||
/// Configures the bit timings calculated from supplied bitrate.
|
||||
pub fn set_bitrate(&mut self, bitrate: u32) {
|
||||
let bit_timing = util::calc_can_timings(T::frequency(), bitrate).unwrap();
|
||||
self.can.set_nominal_bit_timing(config::NominalBitTiming {
|
||||
sync_jump_width: bit_timing.sync_jump_width,
|
||||
prescaler: bit_timing.prescaler,
|
||||
seg1: bit_timing.seg1,
|
||||
seg2: bit_timing.seg2,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_transition {
|
||||
($from_mode:ident, $to_mode:ident, $name:ident, $func: ident) => {
|
||||
impl<'d, T: Instance> Fdcan<'d, T, fdcan::$from_mode> {
|
||||
/// Transition from $from_mode:ident mode to $to_mode:ident mode
|
||||
pub fn $name(self) -> Fdcan<'d, T, fdcan::$to_mode> {
|
||||
let ns_per_timer_tick = calc_ns_per_timer_tick::<T>(self.can.get_config().frame_transmit);
|
||||
Fdcan {
|
||||
can: self.can.$func(),
|
||||
ns_per_timer_tick,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_transition!(PoweredDownMode, ConfigMode, into_config_mode, into_config_mode);
|
||||
impl_transition!(InternalLoopbackMode, ConfigMode, into_config_mode, into_config_mode);
|
||||
|
||||
impl_transition!(ConfigMode, NormalOperationMode, into_normal_mode, into_normal);
|
||||
impl_transition!(
|
||||
ConfigMode,
|
||||
ExternalLoopbackMode,
|
||||
into_external_loopback_mode,
|
||||
into_external_loopback
|
||||
);
|
||||
impl_transition!(
|
||||
ConfigMode,
|
||||
InternalLoopbackMode,
|
||||
into_internal_loopback_mode,
|
||||
into_internal_loopback
|
||||
);
|
||||
|
||||
impl<'d, T: Instance, M: FdcanOperatingMode> Fdcan<'d, T, M>
|
||||
where
|
||||
M: fdcan::Transmit,
|
||||
M: fdcan::Receive,
|
||||
{
|
||||
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||
/// transmitted, then tries again.
|
||||
pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
if let Ok(dropped) = self
|
||||
.can
|
||||
.transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| {
|
||||
TxFrame::from_preserved(hdr, data32)
|
||||
})
|
||||
{
|
||||
return Poll::Ready(dropped.flatten());
|
||||
}
|
||||
|
||||
// Couldn't replace any lower priority frames. Need to wait for some mailboxes
|
||||
// to clear.
|
||||
Poll::Pending
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Flush one of the TX mailboxes.
|
||||
pub async fn flush(&self, mb: fdcan::Mailbox) {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
|
||||
let idx: u8 = mb.into();
|
||||
let idx = 1 << idx;
|
||||
if !T::regs().txbrp().read().trp(idx) {
|
||||
return Poll::Ready(());
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await;
|
||||
}
|
||||
|
||||
/// Returns the next received message frame
|
||||
pub async fn read(&mut self) -> Result<RxFrame, BusError> {
|
||||
poll_fn(|cx| {
|
||||
T::state().err_waker.register(cx.waker());
|
||||
T::state().rx_waker.register(cx.waker());
|
||||
|
||||
let mut buffer: [u8; 64] = [0; 64];
|
||||
if let Ok(rx) = self.can.receive0(&mut buffer) {
|
||||
// rx: fdcan::ReceiveOverrun<RxFrameInfo>
|
||||
// TODO: report overrun?
|
||||
// for now we just drop it
|
||||
|
||||
let frame: RxFrame = RxFrame::new(
|
||||
rx.unwrap(),
|
||||
&buffer,
|
||||
#[cfg(feature = "time")]
|
||||
calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
|
||||
);
|
||||
return Poll::Ready(Ok(frame));
|
||||
} else if let Ok(rx) = self.can.receive1(&mut buffer) {
|
||||
// rx: fdcan::ReceiveOverrun<RxFrameInfo>
|
||||
// TODO: report overrun?
|
||||
// for now we just drop it
|
||||
|
||||
let frame: RxFrame = RxFrame::new(
|
||||
rx.unwrap(),
|
||||
&buffer,
|
||||
#[cfg(feature = "time")]
|
||||
calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
|
||||
);
|
||||
return Poll::Ready(Ok(frame));
|
||||
} else if let Some(err) = curr_error::<T>() {
|
||||
// TODO: this is probably wrong
|
||||
return Poll::Ready(Err(err));
|
||||
}
|
||||
Poll::Pending
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
/// Split instance into separate Tx(write) and Rx(read) portions
|
||||
pub fn split<'c>(&'c mut self) -> (FdcanTx<'c, 'd, T, M>, FdcanRx<'c, 'd, T, M>) {
|
||||
let (mut _control, tx, rx0, rx1) = self.can.split_by_ref();
|
||||
(
|
||||
FdcanTx { _control, tx },
|
||||
FdcanRx {
|
||||
rx0,
|
||||
rx1,
|
||||
ns_per_timer_tick: self.ns_per_timer_tick,
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// FDCAN Tx only Instance
|
||||
pub struct FdcanTx<'c, 'd, T: Instance, M: fdcan::Transmit> {
|
||||
_control: &'c mut fdcan::FdCanControl<FdcanInstance<'d, T>, M>,
|
||||
tx: &'c mut fdcan::Tx<FdcanInstance<'d, T>, M>,
|
||||
}
|
||||
|
||||
impl<'c, 'd, T: Instance, M: fdcan::Transmit> FdcanTx<'c, 'd, T, M> {
|
||||
/// Queues the message to be sent but exerts backpressure. If a lower-priority
|
||||
/// frame is dropped from the mailbox, it is returned. If no lower-priority frames
|
||||
/// can be replaced, this call asynchronously waits for a frame to be successfully
|
||||
/// transmitted, then tries again.
|
||||
pub async fn write(&mut self, frame: &TxFrame) -> Option<TxFrame> {
|
||||
poll_fn(|cx| {
|
||||
T::state().tx_waker.register(cx.waker());
|
||||
if let Ok(dropped) = self
|
||||
.tx
|
||||
.transmit_preserve(frame.header, &frame.data.bytes, &mut |_, hdr, data32| {
|
||||
TxFrame::from_preserved(hdr, data32)
|
||||
})
|
||||
{
|
||||
return Poll::Ready(dropped.flatten());
|
||||
}
|
||||
|
||||
// Couldn't replace any lower priority frames. Need to wait for some mailboxes
|
||||
// to clear.
|
||||
Poll::Pending
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
/// FDCAN Rx only Instance
|
||||
#[allow(dead_code)]
|
||||
pub struct FdcanRx<'c, 'd, T: Instance, M: fdcan::Receive> {
|
||||
rx0: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo0>,
|
||||
rx1: &'c mut fdcan::Rx<FdcanInstance<'d, T>, M, fdcan::Fifo1>,
|
||||
ns_per_timer_tick: u64, // For FDCAN internal timer
|
||||
}
|
||||
|
||||
impl<'c, 'd, T: Instance, M: fdcan::Receive> FdcanRx<'c, 'd, T, M> {
|
||||
/// Returns the next received message frame
|
||||
pub async fn read(&mut self) -> Result<RxFrame, BusError> {
|
||||
poll_fn(|cx| {
|
||||
T::state().err_waker.register(cx.waker());
|
||||
T::state().rx_waker.register(cx.waker());
|
||||
|
||||
let mut buffer: [u8; 64] = [0; 64];
|
||||
if let Ok(rx) = self.rx0.receive(&mut buffer) {
|
||||
// rx: fdcan::ReceiveOverrun<RxFrameInfo>
|
||||
// TODO: report overrun?
|
||||
// for now we just drop it
|
||||
let frame: RxFrame = RxFrame::new(
|
||||
rx.unwrap(),
|
||||
&buffer,
|
||||
#[cfg(feature = "time")]
|
||||
calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
|
||||
);
|
||||
return Poll::Ready(Ok(frame));
|
||||
} else if let Ok(rx) = self.rx1.receive(&mut buffer) {
|
||||
// rx: fdcan::ReceiveOverrun<RxFrameInfo>
|
||||
// TODO: report overrun?
|
||||
// for now we just drop it
|
||||
let frame: RxFrame = RxFrame::new(
|
||||
rx.unwrap(),
|
||||
&buffer,
|
||||
#[cfg(feature = "time")]
|
||||
calc_timestamp::<T>(self.ns_per_timer_tick, rx.unwrap().time_stamp),
|
||||
);
|
||||
return Poll::Ready(Ok(frame));
|
||||
} else if let Some(err) = curr_error::<T>() {
|
||||
// TODO: this is probably wrong
|
||||
return Poll::Ready(Err(err));
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
impl<'d, T: Instance, M: FdcanOperatingMode> Deref for Fdcan<'d, T, M> {
|
||||
type Target = fdcan::FdCan<FdcanInstance<'d, T>, M>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.can
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, M: FdcanOperatingMode> DerefMut for Fdcan<'d, T, M> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.can
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) mod sealed {
|
||||
use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
|
||||
use embassy_sync::channel::Channel;
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
pub struct State {
|
||||
pub tx_waker: AtomicWaker,
|
||||
pub err_waker: AtomicWaker,
|
||||
pub rx_queue: Channel<CriticalSectionRawMutex, (u16, bxcan::Frame), 32>,
|
||||
pub rx_waker: AtomicWaker,
|
||||
}
|
||||
|
||||
impl State {
|
||||
@ -16,25 +579,122 @@ pub(crate) mod sealed {
|
||||
Self {
|
||||
tx_waker: AtomicWaker::new(),
|
||||
err_waker: AtomicWaker::new(),
|
||||
rx_queue: Channel::new(),
|
||||
rx_waker: AtomicWaker::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Instance {
|
||||
const REGISTERS: *mut fdcan::RegisterBlock;
|
||||
const MSG_RAM: *mut fdcan::message_ram::RegisterBlock;
|
||||
const MSG_RAM_OFFSET: usize;
|
||||
|
||||
fn regs() -> &'static crate::pac::can::Fdcan;
|
||||
fn state() -> &'static State;
|
||||
|
||||
#[cfg(not(stm32h7))]
|
||||
fn configure_msg_ram() {}
|
||||
|
||||
#[cfg(stm32h7)]
|
||||
fn configure_msg_ram() {
|
||||
let r = Self::regs();
|
||||
|
||||
use fdcan::message_ram::*;
|
||||
let mut offset_words = Self::MSG_RAM_OFFSET as u16;
|
||||
|
||||
// 11-bit filter
|
||||
r.sidfc().modify(|w| w.set_flssa(offset_words));
|
||||
offset_words += STANDARD_FILTER_MAX as u16;
|
||||
|
||||
// 29-bit filter
|
||||
r.xidfc().modify(|w| w.set_flesa(offset_words));
|
||||
offset_words += 2 * EXTENDED_FILTER_MAX as u16;
|
||||
|
||||
// Rx FIFO 0 and 1
|
||||
for i in 0..=1 {
|
||||
r.rxfc(i).modify(|w| {
|
||||
w.set_fsa(offset_words);
|
||||
w.set_fs(RX_FIFO_MAX);
|
||||
w.set_fwm(RX_FIFO_MAX);
|
||||
});
|
||||
offset_words += 18 * RX_FIFO_MAX as u16;
|
||||
}
|
||||
|
||||
// Rx buffer - see below
|
||||
// Tx event FIFO
|
||||
r.txefc().modify(|w| {
|
||||
w.set_efsa(offset_words);
|
||||
w.set_efs(TX_EVENT_MAX);
|
||||
w.set_efwm(TX_EVENT_MAX);
|
||||
});
|
||||
offset_words += 2 * TX_EVENT_MAX as u16;
|
||||
|
||||
// Tx buffers
|
||||
r.txbc().modify(|w| {
|
||||
w.set_tbsa(offset_words);
|
||||
w.set_tfqs(TX_FIFO_MAX);
|
||||
});
|
||||
offset_words += 18 * TX_FIFO_MAX as u16;
|
||||
|
||||
// Rx Buffer - not used
|
||||
r.rxbc().modify(|w| {
|
||||
w.set_rbsa(offset_words);
|
||||
});
|
||||
|
||||
// TX event FIFO?
|
||||
// Trigger memory?
|
||||
|
||||
// Set the element sizes to 16 bytes
|
||||
r.rxesc().modify(|w| {
|
||||
w.set_rbds(0b111);
|
||||
for i in 0..=1 {
|
||||
w.set_fds(i, 0b111);
|
||||
}
|
||||
});
|
||||
r.txesc().modify(|w| {
|
||||
w.set_tbds(0b111);
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Interruptable FDCAN instance.
|
||||
pub trait InterruptableInstance {}
|
||||
/// FDCAN instance.
|
||||
pub trait Instance: sealed::Instance + InterruptableInstance + 'static {}
|
||||
/// Trait for FDCAN interrupt channel 0
|
||||
pub trait IT0Instance {
|
||||
/// Type for FDCAN interrupt channel 0
|
||||
type IT0Interrupt: crate::interrupt::typelevel::Interrupt;
|
||||
}
|
||||
|
||||
foreach_peripheral!(
|
||||
(can, $inst:ident) => {
|
||||
/// Trait for FDCAN interrupt channel 1
|
||||
pub trait IT1Instance {
|
||||
/// Type for FDCAN interrupt channel 1
|
||||
type IT1Interrupt: crate::interrupt::typelevel::Interrupt;
|
||||
}
|
||||
|
||||
/// InterruptableInstance trait
|
||||
pub trait InterruptableInstance: IT0Instance + IT1Instance {}
|
||||
/// Instance trait
|
||||
pub trait Instance: sealed::Instance + RccPeripheral + InterruptableInstance + 'static {}
|
||||
/// Fdcan Instance struct
|
||||
pub struct FdcanInstance<'a, T>(PeripheralRef<'a, T>);
|
||||
|
||||
unsafe impl<'d, T: Instance> fdcan::message_ram::Instance for FdcanInstance<'d, T> {
|
||||
const MSG_RAM: *mut RegisterBlock = T::MSG_RAM;
|
||||
}
|
||||
|
||||
unsafe impl<'d, T: Instance> fdcan::Instance for FdcanInstance<'d, T>
|
||||
where
|
||||
FdcanInstance<'d, T>: fdcan::message_ram::Instance,
|
||||
{
|
||||
const REGISTERS: *mut fdcan::RegisterBlock = T::REGISTERS;
|
||||
}
|
||||
|
||||
macro_rules! impl_fdcan {
|
||||
($inst:ident, $msg_ram_inst:ident, $msg_ram_offset:literal) => {
|
||||
impl sealed::Instance for peripherals::$inst {
|
||||
const REGISTERS: *mut fdcan::RegisterBlock = crate::pac::$inst.as_ptr() as *mut _;
|
||||
const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = crate::pac::$msg_ram_inst.as_ptr() as *mut _;
|
||||
const MSG_RAM_OFFSET: usize = $msg_ram_offset;
|
||||
|
||||
fn regs() -> &'static crate::pac::can::Fdcan {
|
||||
&crate::pac::$inst
|
||||
}
|
||||
@ -47,8 +707,40 @@ foreach_peripheral!(
|
||||
|
||||
impl Instance for peripherals::$inst {}
|
||||
|
||||
foreach_interrupt!(
|
||||
($inst,can,FDCAN,IT0,$irq:ident) => {
|
||||
impl IT0Instance for peripherals::$inst {
|
||||
type IT0Interrupt = crate::interrupt::typelevel::$irq;
|
||||
}
|
||||
};
|
||||
($inst,can,FDCAN,IT1,$irq:ident) => {
|
||||
impl IT1Instance for peripherals::$inst {
|
||||
type IT1Interrupt = crate::interrupt::typelevel::$irq;
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
impl InterruptableInstance for peripherals::$inst {}
|
||||
};
|
||||
|
||||
($inst:ident, $msg_ram_inst:ident) => {
|
||||
impl_fdcan!($inst, $msg_ram_inst, 0);
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(stm32h7))]
|
||||
foreach_peripheral!(
|
||||
(can, FDCAN) => { impl_fdcan!(FDCAN, FDCANRAM); };
|
||||
(can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM1); };
|
||||
(can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM2); };
|
||||
(can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM3); };
|
||||
);
|
||||
|
||||
#[cfg(stm32h7)]
|
||||
foreach_peripheral!(
|
||||
(can, FDCAN1) => { impl_fdcan!(FDCAN1, FDCANRAM, 0x0000); };
|
||||
(can, FDCAN2) => { impl_fdcan!(FDCAN2, FDCANRAM, 0x0C00); };
|
||||
(can, FDCAN3) => { impl_fdcan!(FDCAN3, FDCANRAM, 0x1800); };
|
||||
);
|
||||
|
||||
pin_trait!(RxPin, Instance);
|
||||
|
117
embassy-stm32/src/can/util.rs
Normal file
117
embassy-stm32/src/can/util.rs
Normal file
@ -0,0 +1,117 @@
|
||||
//! Utility functions shared between CAN controller types.
|
||||
|
||||
use core::num::{NonZeroU16, NonZeroU8};
|
||||
|
||||
/// Shared struct to represent bit timings used by calc_can_timings.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct NominalBitTiming {
|
||||
/// Value by which the oscillator frequency is divided for generating the bit time quanta. The bit
|
||||
/// time is built up from a multiple of this quanta. Valid values are 1 to 512.
|
||||
pub prescaler: NonZeroU16,
|
||||
/// Valid values are 1 to 128.
|
||||
pub seg1: NonZeroU8,
|
||||
/// Valid values are 1 to 255.
|
||||
pub seg2: NonZeroU8,
|
||||
/// Valid values are 1 to 128.
|
||||
pub sync_jump_width: NonZeroU8,
|
||||
}
|
||||
|
||||
/// Calculate nominal CAN bit timing based on CAN bitrate and periphial clock frequency
|
||||
pub fn calc_can_timings(periph_clock: crate::time::Hertz, can_bitrate: u32) -> Option<NominalBitTiming> {
|
||||
const BS1_MAX: u8 = 16;
|
||||
const BS2_MAX: u8 = 8;
|
||||
const MAX_SAMPLE_POINT_PERMILL: u16 = 900;
|
||||
|
||||
let periph_clock = periph_clock.0;
|
||||
|
||||
if can_bitrate < 1000 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
|
||||
// CAN in Automation, 2003
|
||||
//
|
||||
// According to the source, optimal quanta per bit are:
|
||||
// Bitrate Optimal Maximum
|
||||
// 1000 kbps 8 10
|
||||
// 500 kbps 16 17
|
||||
// 250 kbps 16 17
|
||||
// 125 kbps 16 17
|
||||
let max_quanta_per_bit: u8 = if can_bitrate >= 1_000_000 { 10 } else { 17 };
|
||||
|
||||
// Computing (prescaler * BS):
|
||||
// BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
|
||||
// BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
|
||||
// let:
|
||||
// BS = 1 + BS1 + BS2 -- Number of time quanta per bit
|
||||
// PRESCALER_BS = PRESCALER * BS
|
||||
// ==>
|
||||
// PRESCALER_BS = PCLK / BITRATE
|
||||
let prescaler_bs = periph_clock / can_bitrate;
|
||||
|
||||
// Searching for such prescaler value so that the number of quanta per bit is highest.
|
||||
let mut bs1_bs2_sum = max_quanta_per_bit - 1;
|
||||
while (prescaler_bs % (1 + bs1_bs2_sum) as u32) != 0 {
|
||||
if bs1_bs2_sum <= 2 {
|
||||
return None; // No solution
|
||||
}
|
||||
bs1_bs2_sum -= 1;
|
||||
}
|
||||
|
||||
let prescaler = prescaler_bs / (1 + bs1_bs2_sum) as u32;
|
||||
if (prescaler < 1) || (prescaler > 1024) {
|
||||
return None; // No solution
|
||||
}
|
||||
|
||||
// Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
|
||||
// We need to find such values so that the sample point is as close as possible to the optimal value,
|
||||
// which is 87.5%, which is 7/8.
|
||||
//
|
||||
// Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
|
||||
// {{bs2 -> (1 + bs1)/7}}
|
||||
//
|
||||
// Hence:
|
||||
// bs2 = (1 + bs1) / 7
|
||||
// bs1 = (7 * bs1_bs2_sum - 1) / 8
|
||||
//
|
||||
// Sample point location can be computed as follows:
|
||||
// Sample point location = (1 + bs1) / (1 + bs1 + bs2)
|
||||
//
|
||||
// Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
|
||||
// - With rounding to nearest
|
||||
// - With rounding to zero
|
||||
let mut bs1 = ((7 * bs1_bs2_sum - 1) + 4) / 8; // Trying rounding to nearest first
|
||||
let mut bs2 = bs1_bs2_sum - bs1;
|
||||
core::assert!(bs1_bs2_sum > bs1);
|
||||
|
||||
let sample_point_permill = 1000 * ((1 + bs1) / (1 + bs1 + bs2)) as u16;
|
||||
if sample_point_permill > MAX_SAMPLE_POINT_PERMILL {
|
||||
// Nope, too far; now rounding to zero
|
||||
bs1 = (7 * bs1_bs2_sum - 1) / 8;
|
||||
bs2 = bs1_bs2_sum - bs1;
|
||||
}
|
||||
|
||||
// Check is BS1 and BS2 are in range
|
||||
if (bs1 < 1) || (bs1 > BS1_MAX) || (bs2 < 1) || (bs2 > BS2_MAX) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Check if final bitrate matches the requested
|
||||
if can_bitrate != (periph_clock / (prescaler * (1 + bs1 + bs2) as u32)) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// One is recommended by DS-015, CANOpen, and DeviceNet
|
||||
let sync_jump_width = core::num::NonZeroU8::new(1)?;
|
||||
|
||||
let seg1 = core::num::NonZeroU8::new(bs1)?;
|
||||
let seg2 = core::num::NonZeroU8::new(bs2)?;
|
||||
let nz_prescaler = core::num::NonZeroU16::new(prescaler as u16)?;
|
||||
|
||||
Some(NominalBitTiming {
|
||||
sync_jump_width,
|
||||
prescaler: nz_prescaler,
|
||||
seg1,
|
||||
seg2,
|
||||
})
|
||||
}
|
@ -504,29 +504,6 @@ pub trait DacPin<T: Instance, const C: u8>: crate::gpio::Pin + 'static {}
|
||||
|
||||
foreach_peripheral!(
|
||||
(dac, $inst:ident) => {
|
||||
// H7 uses single bit for both DAC1 and DAC2, this is a hack until a proper fix is implemented
|
||||
#[cfg(any(rcc_h7, rcc_h7rm0433))]
|
||||
impl crate::rcc::sealed::RccPeripheral for peripherals::$inst {
|
||||
fn frequency() -> crate::time::Hertz {
|
||||
critical_section::with(|_| unsafe { crate::rcc::get_freqs().pclk1 })
|
||||
}
|
||||
|
||||
fn enable_and_reset_with_cs(_cs: critical_section::CriticalSection) {
|
||||
// TODO: Increment refcount?
|
||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(true));
|
||||
crate::pac::RCC.apb1lrstr().modify(|w| w.set_dac12rst(false));
|
||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(true));
|
||||
}
|
||||
|
||||
fn disable_with_cs(_cs: critical_section::CriticalSection) {
|
||||
// TODO: Decrement refcount?
|
||||
crate::pac::RCC.apb1lenr().modify(|w| w.set_dac12en(false))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(rcc_h7, rcc_h7rm0433))]
|
||||
impl crate::rcc::RccPeripheral for peripherals::$inst {}
|
||||
|
||||
impl crate::dac::sealed::Instance for peripherals::$inst {
|
||||
fn regs() -> &'static crate::pac::dac::Dac {
|
||||
&crate::pac::$inst
|
||||
|
@ -13,6 +13,7 @@ use embassy_net_driver::{Capabilities, HardwareAddress, LinkState};
|
||||
use embassy_sync::waitqueue::AtomicWaker;
|
||||
|
||||
pub use self::_version::{InterruptHandler, *};
|
||||
use crate::rcc::RccPeripheral;
|
||||
|
||||
#[allow(unused)]
|
||||
const MTU: usize = 1514;
|
||||
@ -183,7 +184,7 @@ pub(crate) mod sealed {
|
||||
}
|
||||
|
||||
/// Ethernet instance.
|
||||
pub trait Instance: sealed::Instance + Send + 'static {}
|
||||
pub trait Instance: sealed::Instance + RccPeripheral + Send + 'static {}
|
||||
|
||||
impl sealed::Instance for crate::peripherals::ETH {
|
||||
fn regs() -> crate::pac::eth::Eth {
|
||||
@ -192,12 +193,19 @@ impl sealed::Instance for crate::peripherals::ETH {
|
||||
}
|
||||
impl Instance for crate::peripherals::ETH {}
|
||||
|
||||
pin_trait!(RXClkPin, Instance);
|
||||
pin_trait!(TXClkPin, Instance);
|
||||
pin_trait!(RefClkPin, Instance);
|
||||
pin_trait!(MDIOPin, Instance);
|
||||
pin_trait!(MDCPin, Instance);
|
||||
pin_trait!(RXDVPin, Instance);
|
||||
pin_trait!(CRSPin, Instance);
|
||||
pin_trait!(RXD0Pin, Instance);
|
||||
pin_trait!(RXD1Pin, Instance);
|
||||
pin_trait!(RXD2Pin, Instance);
|
||||
pin_trait!(RXD3Pin, Instance);
|
||||
pin_trait!(TXD0Pin, Instance);
|
||||
pin_trait!(TXD1Pin, Instance);
|
||||
pin_trait!(TXD2Pin, Instance);
|
||||
pin_trait!(TXD3Pin, Instance);
|
||||
pin_trait!(TXEnPin, Instance);
|
||||
|
@ -20,6 +20,7 @@ use crate::pac::AFIO;
|
||||
#[cfg(any(eth_v1b, eth_v1c))]
|
||||
use crate::pac::SYSCFG;
|
||||
use crate::pac::{ETH, RCC};
|
||||
use crate::rcc::sealed::RccPeripheral;
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
/// Interrupt handler.
|
||||
@ -191,8 +192,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
||||
|
||||
// TODO MTU size setting not found for v1 ethernet, check if correct
|
||||
|
||||
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
||||
let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
|
||||
let hclk = <T as RccPeripheral>::frequency();
|
||||
let hclk_mhz = hclk.0 / 1_000_000;
|
||||
|
||||
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
|
||||
|
@ -129,7 +129,7 @@ impl<'a> TDesRing<'a> {
|
||||
|
||||
/// Receive Descriptor representation
|
||||
///
|
||||
/// * rdes0: recieve buffer address
|
||||
/// * rdes0: receive buffer address
|
||||
/// * rdes1:
|
||||
/// * rdes2:
|
||||
/// * rdes3: OWN and Status
|
||||
|
@ -11,6 +11,7 @@ use crate::gpio::sealed::{AFType, Pin as _};
|
||||
use crate::gpio::{AnyPin, Speed};
|
||||
use crate::interrupt::InterruptExt;
|
||||
use crate::pac::ETH;
|
||||
use crate::rcc::sealed::RccPeripheral;
|
||||
use crate::{interrupt, Peripheral};
|
||||
|
||||
/// Interrupt handler.
|
||||
@ -39,12 +40,18 @@ pub struct Ethernet<'d, T: Instance, P: PHY> {
|
||||
_peri: PeripheralRef<'d, T>,
|
||||
pub(crate) tx: TDesRing<'d>,
|
||||
pub(crate) rx: RDesRing<'d>,
|
||||
pins: [PeripheralRef<'d, AnyPin>; 9],
|
||||
pins: Pins<'d>,
|
||||
pub(crate) phy: P,
|
||||
pub(crate) station_management: EthernetStationManagement<T>,
|
||||
pub(crate) mac_addr: [u8; 6],
|
||||
}
|
||||
|
||||
/// Pins of ethernet driver.
|
||||
enum Pins<'d> {
|
||||
Rmii([PeripheralRef<'d, AnyPin>; 9]),
|
||||
Mii([PeripheralRef<'d, AnyPin>; 14]),
|
||||
}
|
||||
|
||||
macro_rules! config_pins {
|
||||
($($pin:ident),*) => {
|
||||
critical_section::with(|_| {
|
||||
@ -57,11 +64,11 @@ macro_rules! config_pins {
|
||||
}
|
||||
|
||||
impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
||||
/// Create a new Ethernet driver.
|
||||
/// Create a new RMII ethernet driver using 9 pins.
|
||||
pub fn new<const TX: usize, const RX: usize>(
|
||||
queue: &'d mut PacketQueue<TX, RX>,
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
|
||||
irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
|
||||
ref_clk: impl Peripheral<P = impl RefClkPin<T>> + 'd,
|
||||
mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
|
||||
mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
|
||||
@ -74,8 +81,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
||||
phy: P,
|
||||
mac_addr: [u8; 6],
|
||||
) -> Self {
|
||||
into_ref!(peri, ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||
|
||||
// Enable the necessary Clocks
|
||||
#[cfg(not(rcc_h5))]
|
||||
critical_section::with(|_| {
|
||||
@ -85,7 +90,6 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
||||
w.set_eth1rxen(true);
|
||||
});
|
||||
|
||||
// RMII
|
||||
crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b100));
|
||||
});
|
||||
|
||||
@ -99,14 +103,110 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
||||
w.set_ethrxen(true);
|
||||
});
|
||||
|
||||
// RMII
|
||||
crate::pac::SYSCFG
|
||||
.pmcr()
|
||||
.modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4));
|
||||
});
|
||||
|
||||
into_ref!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||
config_pins!(ref_clk, mdio, mdc, crs, rx_d0, rx_d1, tx_d0, tx_d1, tx_en);
|
||||
|
||||
let pins = Pins::Rmii([
|
||||
ref_clk.map_into(),
|
||||
mdio.map_into(),
|
||||
mdc.map_into(),
|
||||
crs.map_into(),
|
||||
rx_d0.map_into(),
|
||||
rx_d1.map_into(),
|
||||
tx_d0.map_into(),
|
||||
tx_d1.map_into(),
|
||||
tx_en.map_into(),
|
||||
]);
|
||||
|
||||
Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
|
||||
}
|
||||
|
||||
/// Create a new MII ethernet driver using 14 pins.
|
||||
pub fn new_mii<const TX: usize, const RX: usize>(
|
||||
queue: &'d mut PacketQueue<TX, RX>,
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
|
||||
rx_clk: impl Peripheral<P = impl RXClkPin<T>> + 'd,
|
||||
tx_clk: impl Peripheral<P = impl TXClkPin<T>> + 'd,
|
||||
mdio: impl Peripheral<P = impl MDIOPin<T>> + 'd,
|
||||
mdc: impl Peripheral<P = impl MDCPin<T>> + 'd,
|
||||
rxdv: impl Peripheral<P = impl RXDVPin<T>> + 'd,
|
||||
rx_d0: impl Peripheral<P = impl RXD0Pin<T>> + 'd,
|
||||
rx_d1: impl Peripheral<P = impl RXD1Pin<T>> + 'd,
|
||||
rx_d2: impl Peripheral<P = impl RXD2Pin<T>> + 'd,
|
||||
rx_d3: impl Peripheral<P = impl RXD3Pin<T>> + 'd,
|
||||
tx_d0: impl Peripheral<P = impl TXD0Pin<T>> + 'd,
|
||||
tx_d1: impl Peripheral<P = impl TXD1Pin<T>> + 'd,
|
||||
tx_d2: impl Peripheral<P = impl TXD2Pin<T>> + 'd,
|
||||
tx_d3: impl Peripheral<P = impl TXD3Pin<T>> + 'd,
|
||||
tx_en: impl Peripheral<P = impl TXEnPin<T>> + 'd,
|
||||
phy: P,
|
||||
mac_addr: [u8; 6],
|
||||
) -> Self {
|
||||
// Enable necessary clocks.
|
||||
#[cfg(not(rcc_h5))]
|
||||
critical_section::with(|_| {
|
||||
crate::pac::RCC.ahb1enr().modify(|w| {
|
||||
w.set_eth1macen(true);
|
||||
w.set_eth1txen(true);
|
||||
w.set_eth1rxen(true);
|
||||
});
|
||||
|
||||
crate::pac::SYSCFG.pmcr().modify(|w| w.set_epis(0b000));
|
||||
});
|
||||
|
||||
#[cfg(rcc_h5)]
|
||||
critical_section::with(|_| {
|
||||
crate::pac::RCC.apb3enr().modify(|w| w.set_sbsen(true));
|
||||
|
||||
crate::pac::RCC.ahb1enr().modify(|w| {
|
||||
w.set_ethen(true);
|
||||
w.set_ethtxen(true);
|
||||
w.set_ethrxen(true);
|
||||
});
|
||||
|
||||
// TODO: This is for RMII - what would MII need here?
|
||||
crate::pac::SYSCFG
|
||||
.pmcr()
|
||||
.modify(|w| w.set_eth_sel_phy(crate::pac::syscfg::vals::EthSelPhy::B_0X4));
|
||||
});
|
||||
|
||||
into_ref!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
|
||||
config_pins!(rx_clk, tx_clk, mdio, mdc, rxdv, rx_d0, rx_d1, rx_d2, rx_d3, tx_d0, tx_d1, tx_d2, tx_d3, tx_en);
|
||||
|
||||
let pins = Pins::Mii([
|
||||
rx_clk.map_into(),
|
||||
tx_clk.map_into(),
|
||||
mdio.map_into(),
|
||||
mdc.map_into(),
|
||||
rxdv.map_into(),
|
||||
rx_d0.map_into(),
|
||||
rx_d1.map_into(),
|
||||
rx_d2.map_into(),
|
||||
rx_d3.map_into(),
|
||||
tx_d0.map_into(),
|
||||
tx_d1.map_into(),
|
||||
tx_d2.map_into(),
|
||||
tx_d3.map_into(),
|
||||
tx_en.map_into(),
|
||||
]);
|
||||
|
||||
Self::new_inner(queue, peri, irq, pins, phy, mac_addr)
|
||||
}
|
||||
|
||||
fn new_inner<const TX: usize, const RX: usize>(
|
||||
queue: &'d mut PacketQueue<TX, RX>,
|
||||
peri: impl Peripheral<P = T> + 'd,
|
||||
_irq: impl interrupt::typelevel::Binding<interrupt::typelevel::ETH, InterruptHandler> + 'd,
|
||||
pins: Pins<'d>,
|
||||
phy: P,
|
||||
mac_addr: [u8; 6],
|
||||
) -> Self {
|
||||
let dma = ETH.ethernet_dma();
|
||||
let mac = ETH.ethernet_mac();
|
||||
let mtl = ETH.ethernet_mtl();
|
||||
@ -165,8 +265,7 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
||||
w.set_rbsz(RX_BUFFER_SIZE as u16);
|
||||
});
|
||||
|
||||
// NOTE(unsafe) We got the peripheral singleton, which means that `rcc::init` was called
|
||||
let hclk = unsafe { crate::rcc::get_freqs() }.hclk1;
|
||||
let hclk = <T as RccPeripheral>::frequency();
|
||||
let hclk_mhz = hclk.0 / 1_000_000;
|
||||
|
||||
// Set the MDC clock frequency in the range 1MHz - 2.5MHz
|
||||
@ -182,24 +281,12 @@ impl<'d, T: Instance, P: PHY> Ethernet<'d, T, P> {
|
||||
}
|
||||
};
|
||||
|
||||
let pins = [
|
||||
ref_clk.map_into(),
|
||||
mdio.map_into(),
|
||||
mdc.map_into(),
|
||||
crs.map_into(),
|
||||
rx_d0.map_into(),
|
||||
rx_d1.map_into(),
|
||||
tx_d0.map_into(),
|
||||
tx_d1.map_into(),
|
||||
tx_en.map_into(),
|
||||
];
|
||||
|
||||
let mut this = Self {
|
||||
_peri: peri,
|
||||
_peri: peri.into_ref(),
|
||||
tx: TDesRing::new(&mut queue.tx_desc, &mut queue.tx_buf),
|
||||
rx: RDesRing::new(&mut queue.rx_desc, &mut queue.rx_buf),
|
||||
pins,
|
||||
phy: phy,
|
||||
phy,
|
||||
station_management: EthernetStationManagement {
|
||||
peri: PhantomData,
|
||||
clock_range: clock_range,
|
||||
@ -302,7 +389,10 @@ impl<'d, T: Instance, P: PHY> Drop for Ethernet<'d, T, P> {
|
||||
dma.dmacrx_cr().modify(|w| w.set_sr(false));
|
||||
|
||||
critical_section::with(|_| {
|
||||
for pin in self.pins.iter_mut() {
|
||||
for pin in match self.pins {
|
||||
Pins::Rmii(ref mut pins) => pins.iter_mut(),
|
||||
Pins::Mii(ref mut pins) => pins.iter_mut(),
|
||||
} {
|
||||
pin.set_as_disconnected();
|
||||
}
|
||||
})
|
||||
|
@ -10,8 +10,6 @@ pub use traits::Instance;
|
||||
#[allow(unused_imports)]
|
||||
use crate::gpio::sealed::{AFType, Pin};
|
||||
use crate::gpio::AnyPin;
|
||||
#[cfg(stm32f334)]
|
||||
use crate::rcc::get_freqs;
|
||||
use crate::time::Hertz;
|
||||
use crate::Peripheral;
|
||||
|
||||
@ -182,7 +180,7 @@ impl<'d, T: Instance> AdvancedPwm<'d, T> {
|
||||
T::enable_and_reset();
|
||||
|
||||
#[cfg(stm32f334)]
|
||||
if unsafe { get_freqs() }.hrtim.is_some() {
|
||||
if crate::pac::RCC.cfgr3().read().hrtim1sw() == crate::pac::rcc::vals::Timsw::PLL1_P {
|
||||
// Enable and and stabilize the DLL
|
||||
T::regs().dllcr().modify(|w| {
|
||||
w.set_cal(true);
|
||||
|
@ -80,10 +80,12 @@ pub(crate) mod sealed {
|
||||
|
||||
fn set_master_frequency(frequency: Hertz) {
|
||||
let f = frequency.0;
|
||||
#[cfg(not(stm32f334))]
|
||||
|
||||
// TODO: wire up HRTIM to the RCC mux infra.
|
||||
//#[cfg(stm32f334)]
|
||||
//let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
|
||||
//#[cfg(not(stm32f334))]
|
||||
let timer_f = Self::frequency().0;
|
||||
#[cfg(stm32f334)]
|
||||
let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
|
||||
|
||||
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
|
||||
let psc = if Self::regs().isr().read().dllrdy() {
|
||||
@ -103,10 +105,12 @@ pub(crate) mod sealed {
|
||||
|
||||
fn set_channel_frequency(channel: usize, frequency: Hertz) {
|
||||
let f = frequency.0;
|
||||
#[cfg(not(stm32f334))]
|
||||
|
||||
// TODO: wire up HRTIM to the RCC mux infra.
|
||||
//#[cfg(stm32f334)]
|
||||
//let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
|
||||
//#[cfg(not(stm32f334))]
|
||||
let timer_f = Self::frequency().0;
|
||||
#[cfg(stm32f334)]
|
||||
let timer_f = unsafe { crate::rcc::get_freqs() }.hrtim.unwrap_or(Self::frequency()).0;
|
||||
|
||||
let psc_min = (timer_f / f) / (u16::MAX as u32 / 32);
|
||||
let psc = if Self::regs().isr().read().dllrdy() {
|
||||
|
@ -4,7 +4,6 @@ use embassy_hal_internal::into_ref;
|
||||
use crate::gpio::sealed::{AFType, Pin as _};
|
||||
use crate::gpio::AnyPin;
|
||||
use crate::pac::spi::vals;
|
||||
use crate::rcc::get_freqs;
|
||||
use crate::spi::{Config as SpiConfig, *};
|
||||
use crate::time::Hertz;
|
||||
use crate::{Peripheral, PeripheralRef};
|
||||
@ -193,10 +192,10 @@ impl<'d, T: Instance, Tx, Rx> I2S<'d, T, Tx, Rx> {
|
||||
spi_cfg.frequency = freq;
|
||||
let spi = Spi::new_internal(peri, txdma, rxdma, spi_cfg);
|
||||
|
||||
#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
|
||||
|
||||
#[cfg(stm32f410)]
|
||||
// TODO move i2s to the new mux infra.
|
||||
//#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
//let pclk = unsafe { get_freqs() }.plli2s1_q.unwrap();
|
||||
//#[cfg(stm32f410)]
|
||||
let pclk = T::frequency();
|
||||
|
||||
let (odd, div) = compute_baud_rate(pclk, freq, config.master_clock, config.format);
|
||||
|
@ -2,7 +2,6 @@ use crate::pac::flash::vals::Latency;
|
||||
use crate::pac::rcc::vals::Sw;
|
||||
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Ppre as APBPrescaler};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
@ -133,13 +132,13 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
}
|
||||
};
|
||||
|
||||
set_freqs(Clocks {
|
||||
set_clocks!(
|
||||
hsi: None,
|
||||
lse: None,
|
||||
sys: sys_clk,
|
||||
hclk1: ahb_freq,
|
||||
pclk1: apb_freq,
|
||||
pclk1_tim: apb_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
sys: Some(sys_clk),
|
||||
hclk1: Some(ahb_freq),
|
||||
pclk1: Some(apb_freq),
|
||||
pclk1_tim: Some(apb_tim_freq),
|
||||
rtc: rtc,
|
||||
);
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ pub use crate::pac::rcc::vals::{
|
||||
#[cfg(any(stm32f4, stm32f7))]
|
||||
use crate::pac::PWR;
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
// TODO: on some F4s, PLLM is shared between all PLLs. Enforce that.
|
||||
@ -183,9 +182,9 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
};
|
||||
let pll = init_pll(PllInstance::Pll, config.pll, &pll_input);
|
||||
#[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
|
||||
let _plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input);
|
||||
let plli2s = init_pll(PllInstance::Plli2s, config.plli2s, &pll_input);
|
||||
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
|
||||
let _pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input);
|
||||
let pllsai = init_pll(PllInstance::Pllsai, config.pllsai, &pll_input);
|
||||
|
||||
// Configure sysclk
|
||||
let sys = match config.sys {
|
||||
@ -257,27 +256,41 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
});
|
||||
while RCC.cfgr().read().sws() != config.sys {}
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys,
|
||||
hclk1: hclk,
|
||||
hclk2: hclk,
|
||||
hclk3: hclk,
|
||||
pclk1,
|
||||
pclk2,
|
||||
pclk1_tim,
|
||||
pclk2_tim,
|
||||
rtc,
|
||||
set_clocks!(
|
||||
hsi: hsi,
|
||||
hse: hse,
|
||||
lse: None, // TODO
|
||||
lsi: None, // TODO
|
||||
sys: Some(sys),
|
||||
hclk1: Some(hclk),
|
||||
hclk2: Some(hclk),
|
||||
hclk3: Some(hclk),
|
||||
pclk1: Some(pclk1),
|
||||
pclk2: Some(pclk2),
|
||||
pclk1_tim: Some(pclk1_tim),
|
||||
pclk2_tim: Some(pclk2_tim),
|
||||
rtc: rtc,
|
||||
pll1_q: pll.q,
|
||||
#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
plli2s1_q: _plli2s.q,
|
||||
#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
plli2s1_r: _plli2s.r,
|
||||
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pllsai1_q: _pllsai.q,
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pllsai1_r: _pllsai.r,
|
||||
});
|
||||
#[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
|
||||
plli2s1_p: plli2s.p,
|
||||
#[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
|
||||
plli2s1_q: plli2s.q,
|
||||
#[cfg(any(stm32f2, all(stm32f4, not(stm32f410)), stm32f7))]
|
||||
plli2s1_r: plli2s.r,
|
||||
|
||||
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
|
||||
pllsai1_p: pllsai.p,
|
||||
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
|
||||
pllsai1_q: pllsai.q,
|
||||
#[cfg(any(stm32f446, stm32f427, stm32f437, stm32f4x9, stm32f7))]
|
||||
pllsai1_r: pllsai.r,
|
||||
|
||||
clk48: pll.q,
|
||||
|
||||
hsi_hse: None,
|
||||
afif: None,
|
||||
);
|
||||
}
|
||||
|
||||
struct PllInput {
|
||||
|
@ -1,6 +1,5 @@
|
||||
use stm32_metapac::flash::vals::Latency;
|
||||
|
||||
use super::{set_freqs, Clocks};
|
||||
use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Sw, Usbsw};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::time::Hertz;
|
||||
@ -160,13 +159,15 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: Hertz(real_sysclk),
|
||||
pclk1: Hertz(pclk),
|
||||
pclk2: Hertz(pclk),
|
||||
pclk1_tim: Hertz(pclk * timer_mul),
|
||||
pclk2_tim: Hertz(pclk * timer_mul),
|
||||
hclk1: Hertz(hclk),
|
||||
rtc,
|
||||
});
|
||||
set_clocks!(
|
||||
hsi: None,
|
||||
lse: None,
|
||||
sys: Some(Hertz(real_sysclk)),
|
||||
pclk1: Some(Hertz(pclk)),
|
||||
pclk2: Some(Hertz(pclk)),
|
||||
pclk1_tim: Some(Hertz(pclk * timer_mul)),
|
||||
pclk2_tim: Some(Hertz(pclk * timer_mul)),
|
||||
hclk1: Some(Hertz(hclk)),
|
||||
rtc: rtc,
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
use core::convert::TryFrom;
|
||||
|
||||
use super::{set_freqs, Clocks};
|
||||
use crate::pac::flash::vals::Latency;
|
||||
use crate::pac::rcc::vals::*;
|
||||
use crate::pac::{FLASH, RCC};
|
||||
@ -179,14 +178,14 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: Hertz(real_sysclk),
|
||||
pclk1: Hertz(pclk1),
|
||||
pclk2: Hertz(pclk2),
|
||||
pclk1_tim: Hertz(pclk1 * timer_mul1),
|
||||
pclk2_tim: Hertz(pclk2 * timer_mul2),
|
||||
hclk1: Hertz(hclk),
|
||||
set_clocks!(
|
||||
sys: Some(Hertz(real_sysclk)),
|
||||
pclk1: Some(Hertz(pclk1)),
|
||||
pclk2: Some(Hertz(pclk2)),
|
||||
pclk1_tim: Some(Hertz(pclk1 * timer_mul1)),
|
||||
pclk2_tim: Some(Hertz(pclk2 * timer_mul2)),
|
||||
hclk1: Some(Hertz(hclk)),
|
||||
adc: Some(Hertz(adcclk)),
|
||||
rtc,
|
||||
});
|
||||
rtc: rtc,
|
||||
);
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ use crate::pac::flash::vals::Latency;
|
||||
pub use crate::pac::rcc::vals::Adcpres;
|
||||
use crate::pac::rcc::vals::{Hpre, Pllmul, Pllsrc, Ppre, Prediv, Sw, Usbpre};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
@ -279,13 +278,16 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sysclk,
|
||||
pclk1: pclk1,
|
||||
pclk2: pclk2,
|
||||
pclk1_tim: pclk1 * timer_mul1,
|
||||
pclk2_tim: pclk2 * timer_mul2,
|
||||
hclk1: hclk,
|
||||
set_clocks!(
|
||||
hsi: None,
|
||||
lse: None,
|
||||
pll1_p: None,
|
||||
sys: Some(sysclk),
|
||||
pclk1: Some(pclk1),
|
||||
pclk2: Some(pclk2),
|
||||
pclk1_tim: Some(pclk1 * timer_mul1),
|
||||
pclk2_tim: Some(pclk2 * timer_mul2),
|
||||
hclk1: Some(hclk),
|
||||
#[cfg(rcc_f3)]
|
||||
adc: adc,
|
||||
#[cfg(all(rcc_f3, adc3_common))]
|
||||
@ -294,8 +296,8 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
adc34: None,
|
||||
#[cfg(stm32f334)]
|
||||
hrtim: hrtim,
|
||||
rtc,
|
||||
});
|
||||
rtc: rtc,
|
||||
);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -4,7 +4,6 @@ pub use crate::pac::rcc::vals::{
|
||||
Hpre as AHBPrescaler, Hsidiv as HSIPrescaler, Pllm, Plln, Pllp, Pllq, Pllr, Ppre as APBPrescaler,
|
||||
};
|
||||
use crate::pac::{FLASH, PWR, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
@ -352,11 +351,11 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
#[cfg(not(any(stm32g0b1, stm32g0c1, stm32g0b0)))]
|
||||
let hsi48_freq: Option<Hertz> = None;
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
hclk1: ahb_freq,
|
||||
pclk1: apb_freq,
|
||||
pclk1_tim: apb_tim_freq,
|
||||
set_clocks!(
|
||||
sys: Some(sys_clk),
|
||||
hclk1: Some(ahb_freq),
|
||||
pclk1: Some(apb_freq),
|
||||
pclk1_tim: Some(apb_tim_freq),
|
||||
hsi: hsi_freq,
|
||||
hsi48: hsi48_freq,
|
||||
hsi_div_8: hsi_div_8_freq,
|
||||
@ -365,6 +364,6 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
lsi: lsi_freq,
|
||||
pll1_q: pll1_q_freq,
|
||||
pll1_p: pll1_p_freq,
|
||||
rtc,
|
||||
});
|
||||
rtc: rtc,
|
||||
);
|
||||
}
|
||||
|
@ -3,11 +3,10 @@ use stm32_metapac::rcc::vals::{Adcsel, Pllsrc, Sw};
|
||||
use stm32_metapac::FLASH;
|
||||
|
||||
pub use crate::pac::rcc::vals::{
|
||||
Adcsel as AdcClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN, Pllp as PllP, Pllq as PllQ,
|
||||
Pllr as PllR, Ppre as APBPrescaler,
|
||||
Adcsel as AdcClockSource, Fdcansel as FdCanClockSource, Hpre as AHBPrescaler, Pllm as PllM, Plln as PllN,
|
||||
Pllp as PllP, Pllq as PllQ, Pllr as PllR, Ppre as APBPrescaler,
|
||||
};
|
||||
use crate::pac::{PWR, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
@ -87,6 +86,7 @@ pub struct Config {
|
||||
pub clock_48mhz_src: Option<Clock48MhzSrc>,
|
||||
pub adc12_clock_source: AdcClockSource,
|
||||
pub adc345_clock_source: AdcClockSource,
|
||||
pub fdcan_clock_source: FdCanClockSource,
|
||||
|
||||
pub ls: super::LsConfig,
|
||||
}
|
||||
@ -104,6 +104,7 @@ impl Default for Config {
|
||||
clock_48mhz_src: Some(Clock48MhzSrc::Hsi48(Default::default())),
|
||||
adc12_clock_source: Adcsel::DISABLE,
|
||||
adc345_clock_source: Adcsel::DISABLE,
|
||||
fdcan_clock_source: FdCanClockSource::PCLK1,
|
||||
ls: Default::default(),
|
||||
}
|
||||
}
|
||||
@ -282,6 +283,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
RCC.ccipr().modify(|w| w.set_adc12sel(config.adc12_clock_source));
|
||||
RCC.ccipr().modify(|w| w.set_adc345sel(config.adc345_clock_source));
|
||||
RCC.ccipr().modify(|w| w.set_fdcansel(config.fdcan_clock_source));
|
||||
|
||||
let adc12_ck = match config.adc12_clock_source {
|
||||
AdcClockSource::DISABLE => None,
|
||||
@ -304,20 +306,20 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
hclk1: ahb_freq,
|
||||
hclk2: ahb_freq,
|
||||
hclk3: ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
set_clocks!(
|
||||
sys: Some(sys_clk),
|
||||
hclk1: Some(ahb_freq),
|
||||
hclk2: Some(ahb_freq),
|
||||
hclk3: Some(ahb_freq),
|
||||
pclk1: Some(apb1_freq),
|
||||
pclk1_tim: Some(apb1_tim_freq),
|
||||
pclk2: Some(apb2_freq),
|
||||
pclk2_tim: Some(apb2_tim_freq),
|
||||
adc: adc12_ck,
|
||||
adc34: adc345_ck,
|
||||
pll1_p: None,
|
||||
pll1_q: None, // TODO
|
||||
hse: None, // TODO
|
||||
rtc,
|
||||
});
|
||||
rtc: rtc,
|
||||
);
|
||||
}
|
||||
|
@ -7,12 +7,11 @@ pub use crate::pac::rcc::vals::Adcdacsel as AdcClockSource;
|
||||
#[cfg(stm32h7)]
|
||||
pub use crate::pac::rcc::vals::Adcsel as AdcClockSource;
|
||||
pub use crate::pac::rcc::vals::{
|
||||
Ckpersel as PerClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv, Pllm as PllPreDiv, Plln as PllMul,
|
||||
Pllsrc as PllSource, Sw as Sysclk,
|
||||
Ckpersel as PerClockSource, Fdcansel as FdCanClockSource, Hsidiv as HSIPrescaler, Plldiv as PllDiv,
|
||||
Pllm as PllPreDiv, Plln as PllMul, Pllsrc as PllSource, Sw as Sysclk,
|
||||
};
|
||||
use crate::pac::rcc::vals::{Ckpersel, Pllrge, Pllvcosel, Timpre};
|
||||
use crate::pac::{FLASH, PWR, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
@ -212,6 +211,8 @@ pub struct Config {
|
||||
|
||||
pub per_clock_source: PerClockSource,
|
||||
pub adc_clock_source: AdcClockSource,
|
||||
pub fdcan_clock_source: FdCanClockSource,
|
||||
|
||||
pub timer_prescaler: TimerPrescaler,
|
||||
pub voltage_scale: VoltageScale,
|
||||
pub ls: super::LsConfig,
|
||||
@ -248,6 +249,8 @@ impl Default for Config {
|
||||
#[cfg(stm32h7)]
|
||||
adc_clock_source: AdcClockSource::PER,
|
||||
|
||||
fdcan_clock_source: FdCanClockSource::from_bits(0), // HSE
|
||||
|
||||
timer_prescaler: TimerPrescaler::DefaultX2,
|
||||
voltage_scale: VoltageScale::Scale0,
|
||||
ls: Default::default(),
|
||||
@ -426,7 +429,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
};
|
||||
|
||||
// Configure HSI48.
|
||||
let _hsi48 = config.hsi48.map(super::init_hsi48);
|
||||
let hsi48 = config.hsi48.map(super::init_hsi48);
|
||||
|
||||
// Configure CSI.
|
||||
RCC.cr().modify(|w| w.set_csion(config.csi));
|
||||
@ -585,7 +588,8 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
RCC.ccipr5().modify(|w| {
|
||||
w.set_ckpersel(config.per_clock_source);
|
||||
w.set_adcdacsel(config.adc_clock_source)
|
||||
w.set_adcdacsel(config.adc_clock_source);
|
||||
w.set_fdcan12sel(config.fdcan_clock_source)
|
||||
});
|
||||
}
|
||||
|
||||
@ -609,45 +613,33 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
while !pac::SYSCFG.cccsr().read().ready() {}
|
||||
}
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys,
|
||||
hclk1: hclk,
|
||||
hclk2: hclk,
|
||||
hclk3: hclk,
|
||||
hclk4: hclk,
|
||||
pclk1: apb1,
|
||||
pclk2: apb2,
|
||||
pclk3: apb3,
|
||||
set_clocks!(
|
||||
sys: Some(sys),
|
||||
hclk1: Some(hclk),
|
||||
hclk2: Some(hclk),
|
||||
hclk3: Some(hclk),
|
||||
hclk4: Some(hclk),
|
||||
pclk1: Some(apb1),
|
||||
pclk2: Some(apb2),
|
||||
pclk3: Some(apb3),
|
||||
#[cfg(stm32h7)]
|
||||
pclk4: apb4,
|
||||
#[cfg(stm32h5)]
|
||||
pclk4: Hertz(1),
|
||||
pclk1_tim: apb1_tim,
|
||||
pclk2_tim: apb2_tim,
|
||||
adc,
|
||||
rtc,
|
||||
pclk4: Some(apb4),
|
||||
pclk1_tim: Some(apb1_tim),
|
||||
pclk2_tim: Some(apb2_tim),
|
||||
adc: adc,
|
||||
rtc: rtc,
|
||||
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
hsi: None,
|
||||
#[cfg(stm32h5)]
|
||||
hsi48: None,
|
||||
#[cfg(stm32h5)]
|
||||
lsi: None,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
csi: None,
|
||||
hsi: hsi,
|
||||
hsi48: hsi48,
|
||||
csi: csi,
|
||||
hse: hse,
|
||||
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
lse: None,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
hse: None,
|
||||
lsi: None,
|
||||
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pll1_q: pll1.q,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pll2_p: pll2.p,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pll2_q: pll2.q,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pll2_r: pll2.r,
|
||||
#[cfg(any(rcc_h5, stm32h7))]
|
||||
pll3_p: pll3.p,
|
||||
@ -665,12 +657,8 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
#[cfg(stm32h5)]
|
||||
audioclk: None,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
per: None,
|
||||
|
||||
#[cfg(stm32h7)]
|
||||
rcc_pclk_d3: None,
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
struct PllInput {
|
||||
|
@ -9,7 +9,6 @@ pub use crate::pac::rcc::vals::Clk48sel as Clk48Src;
|
||||
pub use crate::pac::rcc::vals::Hsepre as HsePrescaler;
|
||||
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange as MSIRange, Ppre as APBPrescaler, Sw as ClockSrc};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
@ -262,7 +261,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb))]
|
||||
let pllsai1 = init_pll(PllInstance::Pllsai1, config.pllsai1, &pll_input);
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
let _pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input);
|
||||
let pllsai2 = init_pll(PllInstance::Pllsai2, config.pllsai2, &pll_input);
|
||||
|
||||
let sys_clk = match config.mux {
|
||||
ClockSrc::HSE => hse.unwrap(),
|
||||
@ -274,12 +273,12 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
|
||||
RCC.ccipr().modify(|w| w.set_clk48sel(config.clk48_src));
|
||||
#[cfg(any(rcc_l0_v2))]
|
||||
let _clk48 = match config.clk48_src {
|
||||
let clk48 = match config.clk48_src {
|
||||
Clk48Src::HSI48 => _hsi48,
|
||||
Clk48Src::PLL1_VCO_DIV_2 => pll.clk48,
|
||||
};
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb))]
|
||||
let _clk48 = match config.clk48_src {
|
||||
let clk48 = match config.clk48_src {
|
||||
Clk48Src::HSI48 => _hsi48,
|
||||
Clk48Src::MSI => msi,
|
||||
Clk48Src::PLLSAI1_Q => pllsai1.q,
|
||||
@ -376,37 +375,53 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
while !RCC.extcfgr().read().c2hpref() {}
|
||||
}
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
hclk1,
|
||||
set_clocks!(
|
||||
sys: Some(sys_clk),
|
||||
hclk1: Some(hclk1),
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
|
||||
hclk2,
|
||||
hclk2: Some(hclk2),
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb, stm32wl))]
|
||||
hclk3,
|
||||
pclk1,
|
||||
pclk2,
|
||||
pclk1_tim,
|
||||
pclk2_tim,
|
||||
hclk3: Some(hclk3),
|
||||
pclk1: Some(pclk1),
|
||||
pclk2: Some(pclk2),
|
||||
pclk1_tim: Some(pclk1_tim),
|
||||
pclk2_tim: Some(pclk2_tim),
|
||||
#[cfg(stm32wl)]
|
||||
pclk3: hclk3,
|
||||
#[cfg(rcc_l4)]
|
||||
hsi: None,
|
||||
#[cfg(rcc_l4)]
|
||||
lse: None,
|
||||
#[cfg(rcc_l4)]
|
||||
pllsai1_p: None,
|
||||
#[cfg(rcc_l4)]
|
||||
pllsai2_p: None,
|
||||
#[cfg(rcc_l4)]
|
||||
pll1_p: None,
|
||||
#[cfg(rcc_l4)]
|
||||
pll1_q: None,
|
||||
#[cfg(rcc_l4)]
|
||||
pclk3: Some(hclk3),
|
||||
hsi: hsi,
|
||||
hse: hse,
|
||||
msi: msi,
|
||||
#[cfg(any(rcc_l0_v2, stm32l4, stm32l5, stm32wb))]
|
||||
clk48: clk48,
|
||||
|
||||
#[cfg(not(any(stm32l0, stm32l1)))]
|
||||
pll1_p: pll.p,
|
||||
#[cfg(not(any(stm32l0, stm32l1)))]
|
||||
pll1_q: pll.q,
|
||||
pll1_r: pll.r,
|
||||
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb))]
|
||||
pllsai1_p: pllsai1.p,
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb))]
|
||||
pllsai1_q: pllsai1.q,
|
||||
#[cfg(any(stm32l4, stm32l5, stm32wb))]
|
||||
pllsai1_r: pllsai1.r,
|
||||
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
pllsai2_p: pllsai2.p,
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
pllsai2_q: pllsai2.q,
|
||||
#[cfg(any(stm32l47x, stm32l48x, stm32l49x, stm32l4ax, rcc_l4plus, stm32l5))]
|
||||
pllsai2_r: pllsai2.r,
|
||||
|
||||
rtc: rtc,
|
||||
|
||||
// TODO
|
||||
sai1_extclk: None,
|
||||
#[cfg(rcc_l4)]
|
||||
sai2_extclk: None,
|
||||
rtc,
|
||||
});
|
||||
lsi: None,
|
||||
lse: None,
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(any(stm32l0, stm32l1))]
|
||||
|
@ -5,8 +5,6 @@
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use crate::time::Hertz;
|
||||
|
||||
mod bd;
|
||||
mod mco;
|
||||
pub use bd::*;
|
||||
@ -32,162 +30,7 @@ mod _version;
|
||||
|
||||
pub use _version::*;
|
||||
|
||||
// Model Clock Configuration
|
||||
//
|
||||
// pub struct Clocks {
|
||||
// hse: Option<Hertz>,
|
||||
// hsi: bool,
|
||||
// lse: Option<Hertz>,
|
||||
// lsi: bool,
|
||||
// rtc: RtcSource,
|
||||
// }
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct Clocks {
|
||||
pub sys: Hertz,
|
||||
|
||||
// APB
|
||||
pub pclk1: Hertz,
|
||||
pub pclk1_tim: Hertz,
|
||||
#[cfg(not(any(rcc_c0, rcc_g0)))]
|
||||
pub pclk2: Hertz,
|
||||
#[cfg(not(any(rcc_c0, rcc_g0)))]
|
||||
pub pclk2_tim: Hertz,
|
||||
#[cfg(any(rcc_wl5, rcc_wle, rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_u5))]
|
||||
pub pclk3: Hertz,
|
||||
#[cfg(any(rcc_h7, rcc_h7rm0433, rcc_h7ab, stm32h5))]
|
||||
pub pclk4: Hertz,
|
||||
#[cfg(any(rcc_wba))]
|
||||
pub pclk7: Hertz,
|
||||
|
||||
// AHB
|
||||
pub hclk1: Hertz,
|
||||
#[cfg(any(
|
||||
rcc_l4,
|
||||
rcc_l4plus,
|
||||
rcc_l5,
|
||||
rcc_f2,
|
||||
rcc_f4,
|
||||
rcc_f410,
|
||||
rcc_f7,
|
||||
rcc_h5,
|
||||
rcc_h50,
|
||||
rcc_h7,
|
||||
rcc_h7rm0433,
|
||||
rcc_h7ab,
|
||||
rcc_g4,
|
||||
rcc_u5,
|
||||
rcc_wb,
|
||||
rcc_wba,
|
||||
rcc_wl5,
|
||||
rcc_wle
|
||||
))]
|
||||
pub hclk2: Hertz,
|
||||
#[cfg(any(
|
||||
rcc_l4,
|
||||
rcc_l4plus,
|
||||
rcc_l5,
|
||||
rcc_f2,
|
||||
rcc_f4,
|
||||
rcc_f410,
|
||||
rcc_f7,
|
||||
rcc_h5,
|
||||
rcc_h50,
|
||||
rcc_h7,
|
||||
rcc_h7rm0433,
|
||||
rcc_h7ab,
|
||||
rcc_u5,
|
||||
rcc_g4,
|
||||
rcc_wb,
|
||||
rcc_wl5,
|
||||
rcc_wle
|
||||
))]
|
||||
pub hclk3: Hertz,
|
||||
#[cfg(any(rcc_h5, rcc_h50, rcc_h7, rcc_h7rm0433, rcc_h7ab, rcc_wba))]
|
||||
pub hclk4: Hertz,
|
||||
|
||||
#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
pub plli2s1_q: Option<Hertz>,
|
||||
#[cfg(all(rcc_f4, not(stm32f410)))]
|
||||
pub plli2s1_r: Option<Hertz>,
|
||||
|
||||
#[cfg(rcc_l4)]
|
||||
pub pllsai1_p: Option<Hertz>,
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pub pllsai1_q: Option<Hertz>,
|
||||
#[cfg(any(stm32f427, stm32f429, stm32f437, stm32f439, stm32f446, stm32f469, stm32f479))]
|
||||
pub pllsai1_r: Option<Hertz>,
|
||||
#[cfg(rcc_l4)]
|
||||
pub pllsai2_p: Option<Hertz>,
|
||||
|
||||
#[cfg(any(stm32g0, stm32g4, rcc_l4))]
|
||||
pub pll1_p: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7, stm32f2, stm32f4, stm32f7, rcc_l4, stm32g0, stm32g4))]
|
||||
pub pll1_q: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll2_p: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll2_q: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll2_r: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll3_p: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll3_q: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub pll3_r: Option<Hertz>,
|
||||
|
||||
#[cfg(any(
|
||||
rcc_f1,
|
||||
rcc_f100,
|
||||
rcc_f1cl,
|
||||
rcc_h5,
|
||||
rcc_h50,
|
||||
rcc_h7,
|
||||
rcc_h7rm0433,
|
||||
rcc_h7ab,
|
||||
rcc_f3,
|
||||
rcc_g4
|
||||
))]
|
||||
pub adc: Option<Hertz>,
|
||||
|
||||
#[cfg(any(rcc_f3, rcc_g4))]
|
||||
pub adc34: Option<Hertz>,
|
||||
|
||||
#[cfg(stm32f334)]
|
||||
pub hrtim: Option<Hertz>,
|
||||
|
||||
pub rtc: Option<Hertz>,
|
||||
|
||||
#[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))]
|
||||
pub hsi: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32g0))]
|
||||
pub hsi48: Option<Hertz>,
|
||||
#[cfg(stm32g0)]
|
||||
pub hsi_div_8: Option<Hertz>,
|
||||
#[cfg(any(stm32g0, stm32h5))]
|
||||
pub lsi: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub csi: Option<Hertz>,
|
||||
|
||||
#[cfg(any(stm32h5, stm32h7, rcc_l4, rcc_c0, stm32g0))]
|
||||
pub lse: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7, stm32g0, stm32g4))]
|
||||
pub hse: Option<Hertz>,
|
||||
|
||||
#[cfg(stm32h5)]
|
||||
pub audioclk: Option<Hertz>,
|
||||
#[cfg(any(stm32h5, stm32h7))]
|
||||
pub per: Option<Hertz>,
|
||||
|
||||
#[cfg(stm32h7)]
|
||||
pub rcc_pclk_d3: Option<Hertz>,
|
||||
#[cfg(rcc_l4)]
|
||||
pub sai1_extclk: Option<Hertz>,
|
||||
#[cfg(rcc_l4)]
|
||||
pub sai2_extclk: Option<Hertz>,
|
||||
}
|
||||
pub use crate::_generated::Clocks;
|
||||
|
||||
#[cfg(feature = "low-power")]
|
||||
/// Must be written within a critical section
|
||||
|
@ -1,7 +1,6 @@
|
||||
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Msirange, Plldiv, Pllm, Plln, Ppre as APBPrescaler};
|
||||
use crate::pac::rcc::vals::{Msirgsel, Pllmboost, Pllrge, Pllsrc, Sw};
|
||||
use crate::pac::{FLASH, PWR, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
@ -338,7 +337,7 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
}
|
||||
};
|
||||
|
||||
let _hsi48 = config.hsi48.map(super::init_hsi48);
|
||||
let hsi48 = config.hsi48.map(super::init_hsi48);
|
||||
|
||||
// The clock source is ready
|
||||
// Calculate and set the flash wait states
|
||||
@ -448,18 +447,37 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
hclk1: ahb_freq,
|
||||
hclk2: ahb_freq,
|
||||
hclk3: ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk3: apb3_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
set_clocks!(
|
||||
sys: Some(sys_clk),
|
||||
hclk1: Some(ahb_freq),
|
||||
hclk2: Some(ahb_freq),
|
||||
hclk3: Some(ahb_freq),
|
||||
pclk1: Some(apb1_freq),
|
||||
pclk2: Some(apb2_freq),
|
||||
pclk3: Some(apb3_freq),
|
||||
pclk1_tim: Some(apb1_tim_freq),
|
||||
pclk2_tim: Some(apb2_tim_freq),
|
||||
hsi48: hsi48,
|
||||
rtc: rtc,
|
||||
|
||||
// TODO
|
||||
hse: None,
|
||||
hsi: None,
|
||||
audioclk: None,
|
||||
hsi48_div_2: None,
|
||||
lse: None,
|
||||
lsi: None,
|
||||
msik: None,
|
||||
pll1_p: None,
|
||||
pll1_q: None,
|
||||
pll1_r: None,
|
||||
pll2_p: None,
|
||||
pll2_q: None,
|
||||
pll2_r: None,
|
||||
pll3_p: None,
|
||||
pll3_q: None,
|
||||
pll3_r: None,
|
||||
);
|
||||
}
|
||||
|
||||
fn msirange_to_hertz(range: Msirange) -> Hertz {
|
||||
|
@ -1,88 +1,118 @@
|
||||
use stm32_metapac::rcc::vals::{Pllsrc, Sw};
|
||||
|
||||
pub use crate::pac::pwr::vals::Vos as VoltageScale;
|
||||
use crate::pac::rcc::regs::Cfgr1;
|
||||
pub use crate::pac::rcc::vals::{
|
||||
Adcsel as AdcClockSource, Hpre as AHBPrescaler, Hsepre as HsePrescaler, Ppre as APBPrescaler, Sw as ClockSrc,
|
||||
};
|
||||
use crate::pac::{FLASH, RCC};
|
||||
use crate::rcc::{set_freqs, Clocks};
|
||||
use crate::time::Hertz;
|
||||
|
||||
/// HSI speed
|
||||
pub const HSI_FREQ: Hertz = Hertz(16_000_000);
|
||||
// HSE speed
|
||||
pub const HSE_FREQ: Hertz = Hertz(32_000_000);
|
||||
|
||||
pub use crate::pac::pwr::vals::Vos as VoltageScale;
|
||||
pub use crate::pac::rcc::vals::{Hpre as AHBPrescaler, Ppre as APBPrescaler};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum ClockSrc {
|
||||
HSE(Hertz),
|
||||
HSI,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum PllSource {
|
||||
HSE(Hertz),
|
||||
HSI,
|
||||
}
|
||||
|
||||
impl Into<Pllsrc> for PllSource {
|
||||
fn into(self) -> Pllsrc {
|
||||
match self {
|
||||
PllSource::HSE(..) => Pllsrc::HSE,
|
||||
PllSource::HSI => Pllsrc::HSI,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Sw> for ClockSrc {
|
||||
fn into(self) -> Sw {
|
||||
match self {
|
||||
ClockSrc::HSE(..) => Sw::HSE,
|
||||
ClockSrc::HSI => Sw::HSI,
|
||||
}
|
||||
}
|
||||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
pub struct Hse {
|
||||
pub prescaler: HsePrescaler,
|
||||
}
|
||||
|
||||
/// Clocks configuration
|
||||
pub struct Config {
|
||||
// base clock sources
|
||||
pub hsi: bool,
|
||||
pub hse: Option<Hse>,
|
||||
|
||||
// sysclk, buses.
|
||||
pub mux: ClockSrc,
|
||||
pub ahb_pre: AHBPrescaler,
|
||||
pub apb1_pre: APBPrescaler,
|
||||
pub apb2_pre: APBPrescaler,
|
||||
pub apb7_pre: APBPrescaler,
|
||||
|
||||
// low speed LSI/LSE/RTC
|
||||
pub ls: super::LsConfig,
|
||||
|
||||
pub adc_clock_source: AdcClockSource,
|
||||
|
||||
pub voltage_scale: VoltageScale,
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
#[inline]
|
||||
fn default() -> Config {
|
||||
Config {
|
||||
hse: None,
|
||||
hsi: true,
|
||||
mux: ClockSrc::HSI,
|
||||
ahb_pre: AHBPrescaler::DIV1,
|
||||
apb1_pre: APBPrescaler::DIV1,
|
||||
apb2_pre: APBPrescaler::DIV1,
|
||||
apb7_pre: APBPrescaler::DIV1,
|
||||
ls: Default::default(),
|
||||
adc_clock_source: AdcClockSource::HCLK1,
|
||||
voltage_scale: VoltageScale::RANGE2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn hsi_enable() {
|
||||
RCC.cr().modify(|w| w.set_hsion(true));
|
||||
while !RCC.cr().read().hsirdy() {}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn init(config: Config) {
|
||||
// Switch to HSI to prevent problems with PLL configuration.
|
||||
if !RCC.cr().read().hsion() {
|
||||
hsi_enable()
|
||||
}
|
||||
if RCC.cfgr1().read().sws() != ClockSrc::HSI {
|
||||
// Set HSI as a clock source, reset prescalers.
|
||||
RCC.cfgr1().write_value(Cfgr1::default());
|
||||
// Wait for clock switch status bits to change.
|
||||
while RCC.cfgr1().read().sws() != ClockSrc::HSI {}
|
||||
}
|
||||
|
||||
// Set voltage scale
|
||||
crate::pac::PWR.vosr().write(|w| w.set_vos(config.voltage_scale));
|
||||
while !crate::pac::PWR.vosr().read().vosrdy() {}
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
let hsi = config.hsi.then(|| {
|
||||
hsi_enable();
|
||||
|
||||
HSI_FREQ
|
||||
});
|
||||
|
||||
let hse = config.hse.map(|hse| {
|
||||
RCC.cr().write(|w| {
|
||||
w.set_hseon(true);
|
||||
w.set_hsepre(hse.prescaler);
|
||||
});
|
||||
while !RCC.cr().read().hserdy() {}
|
||||
|
||||
HSE_FREQ
|
||||
});
|
||||
|
||||
let sys_clk = match config.mux {
|
||||
ClockSrc::HSE(freq) => {
|
||||
RCC.cr().write(|w| w.set_hseon(true));
|
||||
while !RCC.cr().read().hserdy() {}
|
||||
|
||||
freq
|
||||
}
|
||||
ClockSrc::HSI => {
|
||||
RCC.cr().write(|w| w.set_hsion(true));
|
||||
while !RCC.cr().read().hsirdy() {}
|
||||
|
||||
HSI_FREQ
|
||||
}
|
||||
ClockSrc::HSE => hse.unwrap(),
|
||||
ClockSrc::HSI => hsi.unwrap(),
|
||||
ClockSrc::_RESERVED_1 => unreachable!(),
|
||||
ClockSrc::PLL1_R => todo!(),
|
||||
};
|
||||
|
||||
// TODO make configurable
|
||||
let power_vos = VoltageScale::RANGE1;
|
||||
assert!(sys_clk.0 <= 100_000_000);
|
||||
|
||||
// states and programming delay
|
||||
let wait_states = match power_vos {
|
||||
let hclk1 = sys_clk / config.ahb_pre;
|
||||
let hclk2 = hclk1;
|
||||
let hclk4 = hclk1;
|
||||
// TODO: hclk5
|
||||
let (pclk1, pclk1_tim) = super::util::calc_pclk(hclk1, config.apb1_pre);
|
||||
let (pclk2, pclk2_tim) = super::util::calc_pclk(hclk1, config.apb2_pre);
|
||||
let (pclk7, _) = super::util::calc_pclk(hclk1, config.apb7_pre);
|
||||
|
||||
// Set flash wait states
|
||||
let flash_latency = match config.voltage_scale {
|
||||
VoltageScale::RANGE1 => match sys_clk.0 {
|
||||
..=32_000_000 => 0,
|
||||
..=64_000_000 => 1,
|
||||
@ -97,13 +127,24 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
},
|
||||
};
|
||||
|
||||
FLASH.acr().modify(|w| {
|
||||
w.set_latency(wait_states);
|
||||
});
|
||||
FLASH.acr().modify(|w| w.set_latency(flash_latency));
|
||||
while FLASH.acr().read().latency() != flash_latency {}
|
||||
|
||||
// Set sram wait states
|
||||
let _sram_latency = match config.voltage_scale {
|
||||
VoltageScale::RANGE1 => 0,
|
||||
VoltageScale::RANGE2 => match sys_clk.0 {
|
||||
..=12_000_000 => 0,
|
||||
..=16_000_000 => 1,
|
||||
_ => 2,
|
||||
},
|
||||
};
|
||||
// TODO: Set the SRAM wait states
|
||||
|
||||
RCC.cfgr1().modify(|w| {
|
||||
w.set_sw(config.mux.into());
|
||||
w.set_sw(config.mux);
|
||||
});
|
||||
while RCC.cfgr1().read().sws() != config.mux {}
|
||||
|
||||
RCC.cfgr2().modify(|w| {
|
||||
w.set_hpre(config.ahb_pre);
|
||||
@ -111,45 +152,25 @@ pub(crate) unsafe fn init(config: Config) {
|
||||
w.set_ppre2(config.apb2_pre);
|
||||
});
|
||||
|
||||
RCC.cfgr3().modify(|w| {
|
||||
w.set_ppre7(config.apb7_pre);
|
||||
});
|
||||
RCC.ccipr3().modify(|w| w.set_adcsel(config.adc_clock_source));
|
||||
|
||||
let ahb_freq = sys_clk / config.ahb_pre;
|
||||
let (apb1_freq, apb1_tim_freq) = match config.apb1_pre {
|
||||
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||
pre => {
|
||||
let freq = ahb_freq / pre;
|
||||
(freq, freq * 2u32)
|
||||
}
|
||||
};
|
||||
let (apb2_freq, apb2_tim_freq) = match config.apb2_pre {
|
||||
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||
pre => {
|
||||
let freq = ahb_freq / pre;
|
||||
(freq, freq * 2u32)
|
||||
}
|
||||
};
|
||||
let (apb7_freq, _apb7_tim_freq) = match config.apb7_pre {
|
||||
APBPrescaler::DIV1 => (ahb_freq, ahb_freq),
|
||||
pre => {
|
||||
let freq = ahb_freq / pre;
|
||||
(freq, freq * 2u32)
|
||||
}
|
||||
};
|
||||
set_clocks!(
|
||||
sys: Some(sys_clk),
|
||||
hclk1: Some(hclk1),
|
||||
hclk2: Some(hclk2),
|
||||
hclk4: Some(hclk4),
|
||||
pclk1: Some(pclk1),
|
||||
pclk2: Some(pclk2),
|
||||
pclk7: Some(pclk7),
|
||||
pclk1_tim: Some(pclk1_tim),
|
||||
pclk2_tim: Some(pclk2_tim),
|
||||
rtc: rtc,
|
||||
hse: hse,
|
||||
hsi: hsi,
|
||||
|
||||
let rtc = config.ls.init();
|
||||
|
||||
set_freqs(Clocks {
|
||||
sys: sys_clk,
|
||||
hclk1: ahb_freq,
|
||||
hclk2: ahb_freq,
|
||||
hclk4: ahb_freq,
|
||||
pclk1: apb1_freq,
|
||||
pclk2: apb2_freq,
|
||||
pclk7: apb7_freq,
|
||||
pclk1_tim: apb1_tim_freq,
|
||||
pclk2_tim: apb2_tim_freq,
|
||||
rtc,
|
||||
});
|
||||
// TODO
|
||||
lse: None,
|
||||
lsi: None,
|
||||
pll1_q: None,
|
||||
);
|
||||
}
|
||||
|
@ -670,7 +670,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
_ => panic!("Invalid Bus Width"),
|
||||
};
|
||||
|
||||
let ker_ck = T::kernel_clk();
|
||||
let ker_ck = T::frequency();
|
||||
let (_bypass, clkdiv, new_clock) = clk_div(ker_ck, freq)?;
|
||||
|
||||
// Enforce AHB and SDMMC_CK clock relation. See RM0433 Rev 7
|
||||
@ -1023,7 +1023,7 @@ impl<'d, T: Instance, Dma: SdmmcDma<T> + 'd> Sdmmc<'d, T, Dma> {
|
||||
/// specified frequency.
|
||||
pub async fn init_card(&mut self, freq: Hertz) -> Result<(), Error> {
|
||||
let regs = T::regs();
|
||||
let ker_ck = T::kernel_clk();
|
||||
let ker_ck = T::frequency();
|
||||
|
||||
let bus_width = match self.d3.is_some() {
|
||||
true => BusWidth::Four,
|
||||
@ -1429,7 +1429,6 @@ pub(crate) mod sealed {
|
||||
|
||||
fn regs() -> RegBlock;
|
||||
fn state() -> &'static AtomicWaker;
|
||||
fn kernel_clk() -> Hertz;
|
||||
}
|
||||
|
||||
pub trait Pins<T: Instance> {}
|
||||
@ -1461,61 +1460,6 @@ pub trait SdmmcDma<T: Instance> {}
|
||||
#[cfg(sdmmc_v2)]
|
||||
impl<T: Instance> SdmmcDma<T> for NoDma {}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
// TODO, these could not be implemented, because required clocks are not exposed in RCC:
|
||||
// - H7 uses pll1_q_ck or pll2_r_ck depending on SDMMCSEL
|
||||
// - L1 uses pll48
|
||||
// - L4 uses clk48(pll48)
|
||||
// - L4+, L5, U5 uses clk48(pll48) or PLLSAI3CLK(PLLP) depending on SDMMCSEL
|
||||
if #[cfg(stm32f1)] {
|
||||
// F1 uses AHB1(HCLK), which is correct in PAC
|
||||
macro_rules! kernel_clk {
|
||||
($inst:ident) => {
|
||||
<peripherals::$inst as crate::rcc::sealed::RccPeripheral>::frequency()
|
||||
}
|
||||
}
|
||||
} else if #[cfg(any(stm32f2, stm32f4))] {
|
||||
// F2, F4 always use pll48
|
||||
macro_rules! kernel_clk {
|
||||
($inst:ident) => {
|
||||
critical_section::with(|_| unsafe {
|
||||
unwrap!(crate::rcc::get_freqs().pll1_q)
|
||||
})
|
||||
}
|
||||
}
|
||||
} else if #[cfg(stm32f7)] {
|
||||
macro_rules! kernel_clk {
|
||||
(SDMMC1) => {
|
||||
critical_section::with(|_| unsafe {
|
||||
let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc1sel();
|
||||
if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYS {
|
||||
crate::rcc::get_freqs().sys
|
||||
} else {
|
||||
unwrap!(crate::rcc::get_freqs().pll1_q)
|
||||
}
|
||||
})
|
||||
};
|
||||
(SDMMC2) => {
|
||||
critical_section::with(|_| unsafe {
|
||||
let sdmmcsel = crate::pac::RCC.dckcfgr2().read().sdmmc2sel();
|
||||
if sdmmcsel == crate::pac::rcc::vals::Sdmmcsel::SYS {
|
||||
crate::rcc::get_freqs().sys
|
||||
} else {
|
||||
unwrap!(crate::rcc::get_freqs().pll1_q)
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// Use default peripheral clock and hope it works
|
||||
macro_rules! kernel_clk {
|
||||
($inst:ident) => {
|
||||
<peripherals::$inst as crate::rcc::sealed::RccPeripheral>::frequency()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach_peripheral!(
|
||||
(sdmmc, $inst:ident) => {
|
||||
impl sealed::Instance for peripherals::$inst {
|
||||
@ -1529,10 +1473,6 @@ foreach_peripheral!(
|
||||
static WAKER: ::embassy_sync::waitqueue::AtomicWaker = ::embassy_sync::waitqueue::AtomicWaker::new();
|
||||
&WAKER
|
||||
}
|
||||
|
||||
fn kernel_clk() -> Hertz {
|
||||
kernel_clk!($inst)
|
||||
}
|
||||
}
|
||||
|
||||
impl Instance for peripherals::$inst {}
|
||||
|
@ -54,6 +54,7 @@ pub struct ComplementaryPwm<'d, T> {
|
||||
|
||||
impl<'d, T: ComplementaryCaptureCompare16bitInstance> ComplementaryPwm<'d, T> {
|
||||
/// Create a new complementary PWM driver.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
tim: impl Peripheral<P = T> + 'd,
|
||||
_ch1: Option<PwmPin<'d, T, Ch1>>,
|
||||
@ -165,7 +166,7 @@ impl<'d, T: ComplementaryCaptureCompare16bitInstance> embedded_hal_02::Pwm for C
|
||||
}
|
||||
|
||||
fn get_period(&self) -> Self::Time {
|
||||
self.inner.get_frequency().into()
|
||||
self.inner.get_frequency()
|
||||
}
|
||||
|
||||
fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
|
||||
|
@ -311,6 +311,26 @@ pub(crate) mod sealed {
|
||||
.ccmr_output(channel_index / 2)
|
||||
.modify(|w| w.set_ocpe(channel_index % 2, preload));
|
||||
}
|
||||
|
||||
/// Get capture compare DMA selection
|
||||
fn get_cc_dma_selection(&self) -> super::vals::Ccds {
|
||||
Self::regs_gp16().cr2().read().ccds()
|
||||
}
|
||||
|
||||
/// Set capture compare DMA selection
|
||||
fn set_cc_dma_selection(&mut self, ccds: super::vals::Ccds) {
|
||||
Self::regs_gp16().cr2().modify(|w| w.set_ccds(ccds))
|
||||
}
|
||||
|
||||
/// Get capture compare DMA enable state
|
||||
fn get_cc_dma_enable_state(&self, channel: Channel) -> bool {
|
||||
Self::regs_gp16().dier().read().ccde(channel.index())
|
||||
}
|
||||
|
||||
/// Set capture compare DMA enable state
|
||||
fn set_cc_dma_enable_state(&mut self, channel: Channel, ccde: bool) {
|
||||
Self::regs_gp16().dier().modify(|w| w.set_ccde(channel.index(), ccde))
|
||||
}
|
||||
}
|
||||
|
||||
/// Capture/Compare 16-bit timer instance with complementary pin support.
|
||||
@ -450,20 +470,17 @@ pub enum CountingMode {
|
||||
impl CountingMode {
|
||||
/// Return whether this mode is edge-aligned (up or down).
|
||||
pub fn is_edge_aligned(&self) -> bool {
|
||||
match self {
|
||||
CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown => true,
|
||||
_ => false,
|
||||
}
|
||||
matches!(self, CountingMode::EdgeAlignedUp | CountingMode::EdgeAlignedDown)
|
||||
}
|
||||
|
||||
/// Return whether this mode is center-aligned.
|
||||
pub fn is_center_aligned(&self) -> bool {
|
||||
match self {
|
||||
matches!(
|
||||
self,
|
||||
CountingMode::CenterAlignedDownInterrupts
|
||||
| CountingMode::CenterAlignedUpInterrupts
|
||||
| CountingMode::CenterAlignedBothInterrupts => true,
|
||||
_ => false,
|
||||
}
|
||||
| CountingMode::CenterAlignedUpInterrupts
|
||||
| CountingMode::CenterAlignedBothInterrupts
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -705,3 +722,8 @@ foreach_interrupt! {
|
||||
|
||||
// Update Event trigger DMA for every timer
|
||||
dma_trait!(UpDma, Basic16bitInstance);
|
||||
|
||||
dma_trait!(Ch1Dma, CaptureCompare16bitInstance);
|
||||
dma_trait!(Ch2Dma, CaptureCompare16bitInstance);
|
||||
dma_trait!(Ch3Dma, CaptureCompare16bitInstance);
|
||||
dma_trait!(Ch4Dma, CaptureCompare16bitInstance);
|
||||
|
@ -160,7 +160,7 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
||||
///
|
||||
/// Note:
|
||||
/// you will need to provide corresponding TIMx_UP DMA channel to use this method.
|
||||
pub async fn gen_waveform(
|
||||
pub async fn waveform_up(
|
||||
&mut self,
|
||||
dma: impl Peripheral<P = impl super::UpDma<T>>,
|
||||
channel: Channel,
|
||||
@ -226,6 +226,95 @@ impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_waveform_chx {
|
||||
($fn_name:ident, $dma_ch:ident, $cc_ch:ident) => {
|
||||
impl<'d, T: CaptureCompare16bitInstance> SimplePwm<'d, T> {
|
||||
/// Generate a sequence of PWM waveform
|
||||
///
|
||||
/// Note:
|
||||
/// you will need to provide corresponding TIMx_CHy DMA channel to use this method.
|
||||
pub async fn $fn_name(&mut self, dma: impl Peripheral<P = impl super::$dma_ch<T>>, duty: &[u16]) {
|
||||
use super::vals::Ccds;
|
||||
|
||||
assert!(duty.iter().all(|v| *v <= self.get_max_duty()));
|
||||
|
||||
into_ref!(dma);
|
||||
|
||||
#[allow(clippy::let_unit_value)] // eg. stm32f334
|
||||
let req = dma.request();
|
||||
|
||||
let cc_channel = super::Channel::$cc_ch;
|
||||
|
||||
let original_duty_state = self.get_duty(cc_channel);
|
||||
let original_enable_state = self.is_enabled(cc_channel);
|
||||
let original_cc_dma_on_update = self.inner.get_cc_dma_selection() == Ccds::ONUPDATE;
|
||||
let original_cc_dma_enabled = self.inner.get_cc_dma_enable_state(cc_channel);
|
||||
|
||||
// redirect CC DMA request onto Update Event
|
||||
if !original_cc_dma_on_update {
|
||||
self.inner.set_cc_dma_selection(Ccds::ONUPDATE)
|
||||
}
|
||||
|
||||
if !original_cc_dma_enabled {
|
||||
self.inner.set_cc_dma_enable_state(cc_channel, true);
|
||||
}
|
||||
|
||||
if !original_enable_state {
|
||||
self.enable(cc_channel);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
#[cfg(not(any(bdma, gpdma)))]
|
||||
use crate::dma::{Burst, FifoThreshold};
|
||||
use crate::dma::{Transfer, TransferOptions};
|
||||
|
||||
let dma_transfer_option = TransferOptions {
|
||||
#[cfg(not(any(bdma, gpdma)))]
|
||||
fifo_threshold: Some(FifoThreshold::Full),
|
||||
#[cfg(not(any(bdma, gpdma)))]
|
||||
mburst: Burst::Incr8,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Transfer::new_write(
|
||||
&mut dma,
|
||||
req,
|
||||
duty,
|
||||
T::regs_gp16().ccr(cc_channel.index()).as_ptr() as *mut _,
|
||||
dma_transfer_option,
|
||||
)
|
||||
.await
|
||||
};
|
||||
|
||||
// restore output compare state
|
||||
if !original_enable_state {
|
||||
self.disable(cc_channel);
|
||||
}
|
||||
|
||||
self.set_duty(cc_channel, original_duty_state);
|
||||
|
||||
// Since DMA is closed before timer Capture Compare Event trigger DMA is turn off,
|
||||
// this can almost always trigger a DMA FIFO error.
|
||||
//
|
||||
// optional TODO:
|
||||
// clean FEIF after disable UDE
|
||||
if !original_cc_dma_enabled {
|
||||
self.inner.set_cc_dma_enable_state(cc_channel, false);
|
||||
}
|
||||
|
||||
if !original_cc_dma_on_update {
|
||||
self.inner.set_cc_dma_selection(Ccds::ONCOMPARE)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_waveform_chx!(waveform_ch1, Ch1Dma, Ch1);
|
||||
impl_waveform_chx!(waveform_ch2, Ch2Dma, Ch2);
|
||||
impl_waveform_chx!(waveform_ch3, Ch3Dma, Ch3);
|
||||
impl_waveform_chx!(waveform_ch4, Ch4Dma, Ch4);
|
||||
|
||||
impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d, T> {
|
||||
type Channel = Channel;
|
||||
type Time = Hertz;
|
||||
@ -240,7 +329,7 @@ impl<'d, T: CaptureCompare16bitInstance> embedded_hal_02::Pwm for SimplePwm<'d,
|
||||
}
|
||||
|
||||
fn get_period(&self) -> Self::Time {
|
||||
self.inner.get_frequency().into()
|
||||
self.inner.get_frequency()
|
||||
}
|
||||
|
||||
fn get_duty(&self, channel: Self::Channel) -> Self::Duty {
|
||||
|
@ -280,7 +280,7 @@ impl<'d, T: Instance> Driver<'d, T> {
|
||||
#[cfg(time)]
|
||||
embassy_time::block_for(embassy_time::Duration::from_millis(100));
|
||||
#[cfg(not(time))]
|
||||
cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.0 / 10);
|
||||
cortex_m::asm::delay(unsafe { crate::rcc::get_freqs() }.sys.unwrap().0 / 10);
|
||||
|
||||
#[cfg(not(usb_v4))]
|
||||
regs.btable().write(|w| w.set_btable(0));
|
||||
|
@ -325,7 +325,7 @@ where
|
||||
///
|
||||
/// Sent data may be reordered based on their priorty within the channel.
|
||||
/// For example, in a [`Max`](heapless::binary_heap::Max) [`PriorityChannel`]
|
||||
/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be recieved as `[3, 2, 1]`.
|
||||
/// containing `u32`'s, data sent in the following order `[1, 2, 3]` will be received as `[3, 2, 1]`.
|
||||
pub struct PriorityChannel<M, T, K, const N: usize>
|
||||
where
|
||||
T: Ord,
|
||||
|
@ -3,7 +3,7 @@ use core::ops::Range;
|
||||
pub struct RingBuffer<const N: usize> {
|
||||
start: usize,
|
||||
end: usize,
|
||||
empty: bool,
|
||||
full: bool,
|
||||
}
|
||||
|
||||
impl<const N: usize> RingBuffer<N> {
|
||||
@ -11,13 +11,13 @@ impl<const N: usize> RingBuffer<N> {
|
||||
Self {
|
||||
start: 0,
|
||||
end: 0,
|
||||
empty: true,
|
||||
full: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push_buf(&mut self) -> Range<usize> {
|
||||
if self.start == self.end && !self.empty {
|
||||
trace!(" ringbuf: push_buf empty");
|
||||
if self.is_full() {
|
||||
trace!(" ringbuf: push_buf full");
|
||||
return 0..0;
|
||||
}
|
||||
|
||||
@ -38,11 +38,11 @@ impl<const N: usize> RingBuffer<N> {
|
||||
}
|
||||
|
||||
self.end = self.wrap(self.end + n);
|
||||
self.empty = false;
|
||||
self.full = self.start == self.end;
|
||||
}
|
||||
|
||||
pub fn pop_buf(&mut self) -> Range<usize> {
|
||||
if self.empty {
|
||||
if self.is_empty() {
|
||||
trace!(" ringbuf: pop_buf empty");
|
||||
return 0..0;
|
||||
}
|
||||
@ -64,20 +64,20 @@ impl<const N: usize> RingBuffer<N> {
|
||||
}
|
||||
|
||||
self.start = self.wrap(self.start + n);
|
||||
self.empty = self.start == self.end;
|
||||
self.full = false;
|
||||
}
|
||||
|
||||
pub fn is_full(&self) -> bool {
|
||||
self.start == self.end && !self.empty
|
||||
self.full
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.empty
|
||||
self.start == self.end && !self.full
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn len(&self) -> usize {
|
||||
if self.empty {
|
||||
if self.is_empty() {
|
||||
0
|
||||
} else if self.start < self.end {
|
||||
self.end - self.start
|
||||
@ -89,7 +89,7 @@ impl<const N: usize> RingBuffer<N> {
|
||||
pub fn clear(&mut self) {
|
||||
self.start = 0;
|
||||
self.end = 0;
|
||||
self.empty = true;
|
||||
self.full = false;
|
||||
}
|
||||
|
||||
fn wrap(&self, n: usize) -> usize {
|
||||
|
@ -32,7 +32,7 @@ pub use delay::{block_for, Delay};
|
||||
pub use duration::Duration;
|
||||
pub use embassy_time_driver::TICK_HZ;
|
||||
pub use instant::Instant;
|
||||
pub use timer::{with_timeout, Ticker, TimeoutError, Timer};
|
||||
pub use timer::{with_deadline, with_timeout, Ticker, TimeoutError, Timer};
|
||||
|
||||
const fn gcd(a: u64, b: u64) -> u64 {
|
||||
if b == 0 {
|
||||
|
@ -8,7 +8,7 @@ use futures_util::{pin_mut, Stream};
|
||||
|
||||
use crate::{Duration, Instant};
|
||||
|
||||
/// Error returned by [`with_timeout`] on timeout.
|
||||
/// Error returned by [`with_timeout`] and [`with_deadline`] on timeout.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub struct TimeoutError;
|
||||
@ -26,6 +26,19 @@ pub async fn with_timeout<F: Future>(timeout: Duration, fut: F) -> Result<F::Out
|
||||
}
|
||||
}
|
||||
|
||||
/// Runs a given future with a deadline time.
|
||||
///
|
||||
/// If the future completes before the deadline, its output is returned. Otherwise, on timeout,
|
||||
/// work on the future is stopped (`poll` is no longer called), the future is dropped and `Err(TimeoutError)` is returned.
|
||||
pub async fn with_deadline<F: Future>(at: Instant, fut: F) -> Result<F::Output, TimeoutError> {
|
||||
let timeout_fut = Timer::at(at);
|
||||
pin_mut!(fut);
|
||||
match select(fut, timeout_fut).await {
|
||||
Either::Left((r, _)) => Ok(r),
|
||||
Either::Right(_) => Err(TimeoutError),
|
||||
}
|
||||
}
|
||||
|
||||
/// A future that completes at a specified [Instant](struct.Instant.html).
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
pub struct Timer {
|
||||
|
9
examples/nrf51/.cargo/config.toml
Normal file
9
examples/nrf51/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace nRF51422_xxAA with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip nRF51422_xxAA"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "trace"
|
20
examples/nrf51/Cargo.toml
Normal file
20
examples/nrf51/Cargo.toml
Normal file
@ -0,0 +1,20 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-nrf51-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
|
||||
embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time", "rt"] }
|
||||
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
|
||||
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7"
|
||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
35
examples/nrf51/build.rs
Normal file
35
examples/nrf51/build.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! This build script copies the `memory.x` file from the crate root into
|
||||
//! a directory where the linker can always find it at build time.
|
||||
//! For many projects this is optional, as the linker always searches the
|
||||
//! project root directory -- wherever `Cargo.toml` is. However, if you
|
||||
//! are using a workspace or have a more complicated build setup, this
|
||||
//! build script becomes required. Additionally, by requesting that
|
||||
//! Cargo re-run the build script whenever `memory.x` is changed,
|
||||
//! updating `memory.x` ensures a rebuild of the application with the
|
||||
//! new memory settings.
|
||||
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
// Put `memory.x` in our output directory and ensure it's
|
||||
// on the linker search path.
|
||||
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
File::create(out.join("memory.x"))
|
||||
.unwrap()
|
||||
.write_all(include_bytes!("memory.x"))
|
||||
.unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
|
||||
// By default, Cargo will re-run a build script whenever
|
||||
// any file in the project changes. By specifying `memory.x`
|
||||
// here, we ensure the build script is only re-run when
|
||||
// `memory.x` is changed.
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
5
examples/nrf51/memory.x
Normal file
5
examples/nrf51/memory.x
Normal file
@ -0,0 +1,5 @@
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x00000000, LENGTH = 128K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 16K
|
||||
}
|
20
examples/nrf51/src/bin/blinky.rs
Normal file
20
examples/nrf51/src/bin/blinky.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::gpio::{Level, Output, OutputDrive};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
let mut led = Output::new(p.P0_21, Level::Low, OutputDrive::Standard);
|
||||
|
||||
loop {
|
||||
led.set_high();
|
||||
Timer::after_millis(300).await;
|
||||
led.set_low();
|
||||
Timer::after_millis(300).await;
|
||||
}
|
||||
}
|
80
examples/rp/src/bin/debounce.rs
Normal file
80
examples/rp/src/bin/debounce.rs
Normal file
@ -0,0 +1,80 @@
|
||||
//! This example shows the ease of debouncing a button with async rust.
|
||||
//! Hook up a button or switch between pin 9 and ground.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::info;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_rp::gpio::{Input, Level, Pull};
|
||||
use embassy_time::{with_deadline, Duration, Instant, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
pub struct Debouncer<'a> {
|
||||
input: Input<'a>,
|
||||
debounce: Duration,
|
||||
}
|
||||
|
||||
impl<'a> Debouncer<'a> {
|
||||
pub fn new(input: Input<'a>, debounce: Duration) -> Self {
|
||||
Self { input, debounce }
|
||||
}
|
||||
|
||||
pub async fn debounce(&mut self) -> Level {
|
||||
loop {
|
||||
let l1 = self.input.get_level();
|
||||
|
||||
self.input.wait_for_any_edge().await;
|
||||
|
||||
Timer::after(self.debounce).await;
|
||||
|
||||
let l2 = self.input.get_level();
|
||||
if l1 != l2 {
|
||||
break l2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_rp::init(Default::default());
|
||||
let mut btn = Debouncer::new(Input::new(p.PIN_9, Pull::Up), Duration::from_millis(20));
|
||||
|
||||
info!("Debounce Demo");
|
||||
|
||||
loop {
|
||||
// button pressed
|
||||
btn.debounce().await;
|
||||
let start = Instant::now();
|
||||
info!("Button Press");
|
||||
|
||||
match with_deadline(start + Duration::from_secs(1), btn.debounce()).await {
|
||||
// Button Released < 1s
|
||||
Ok(_) => {
|
||||
info!("Button pressed for: {}ms", start.elapsed().as_millis());
|
||||
continue;
|
||||
}
|
||||
// button held for > 1s
|
||||
Err(_) => {
|
||||
info!("Button Held");
|
||||
}
|
||||
}
|
||||
|
||||
match with_deadline(start + Duration::from_secs(5), btn.debounce()).await {
|
||||
// Button released <5s
|
||||
Ok(_) => {
|
||||
info!("Button pressed for: {}ms", start.elapsed().as_millis());
|
||||
continue;
|
||||
}
|
||||
// button held for > >5s
|
||||
Err(_) => {
|
||||
info!("Button Long Held");
|
||||
}
|
||||
}
|
||||
|
||||
// wait for button release before handling another press
|
||||
btn.debounce().await;
|
||||
info!("Button pressed for: {}ms", start.elapsed().as_millis());
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
|
||||
loop {
|
||||
let mut buf = [0u8; 128];
|
||||
match dev.listen(&mut buf).await {
|
||||
Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device recieved general call write: {}", buf[..len]),
|
||||
Ok(i2c_slave::Command::GeneralCall(len)) => info!("Device received general call write: {}", buf[..len]),
|
||||
Ok(i2c_slave::Command::Read) => loop {
|
||||
match dev.respond_to_read(&[state]).await {
|
||||
Ok(x) => match x {
|
||||
@ -40,9 +40,9 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
|
||||
Err(e) => error!("error while responding {}", e),
|
||||
}
|
||||
},
|
||||
Ok(i2c_slave::Command::Write(len)) => info!("Device recieved write: {}", buf[..len]),
|
||||
Ok(i2c_slave::Command::Write(len)) => info!("Device received write: {}", buf[..len]),
|
||||
Ok(i2c_slave::Command::WriteRead(len)) => {
|
||||
info!("device recieved write read: {:x}", buf[..len]);
|
||||
info!("device received write read: {:x}", buf[..len]);
|
||||
match buf[0] {
|
||||
// Set the state
|
||||
0xC2 => {
|
||||
|
@ -91,7 +91,7 @@ async fn main(_spawner: Spawner) {
|
||||
loop {
|
||||
for &color in color_list {
|
||||
// with &mut, we can easily reuse same DMA channel multiple times
|
||||
ws2812_pwm.gen_waveform(&mut dp.DMA1_CH2, pwm_channel, color).await;
|
||||
ws2812_pwm.waveform_up(&mut dp.DMA1_CH2, pwm_channel, color).await;
|
||||
// ws2812 need at least 50 us low level input to confirm the input data and change it's state
|
||||
Timer::after_micros(50).await;
|
||||
// wait until ticker tick
|
||||
|
56
examples/stm32g4/src/bin/can.rs
Normal file
56
examples/stm32g4/src/bin/can.rs
Normal file
@ -0,0 +1,56 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::peripherals::*;
|
||||
use embassy_stm32::{bind_interrupts, can, Config};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
|
||||
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let config = Config::default();
|
||||
|
||||
let peripherals = embassy_stm32::init(config);
|
||||
|
||||
let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
|
||||
|
||||
// 250k bps
|
||||
can.set_bitrate(250_000);
|
||||
|
||||
info!("Configured");
|
||||
|
||||
//let mut can = can.into_external_loopback_mode();
|
||||
let mut can = can.into_normal_mode();
|
||||
|
||||
let mut i = 0;
|
||||
loop {
|
||||
let frame = can::TxFrame::new(
|
||||
can::TxFrameHeader {
|
||||
len: 1,
|
||||
frame_format: can::FrameFormat::Standard,
|
||||
id: can::StandardId::new(0x123).unwrap().into(),
|
||||
bit_rate_switching: false,
|
||||
marker: None,
|
||||
},
|
||||
&[i],
|
||||
)
|
||||
.unwrap();
|
||||
info!("Writing frame");
|
||||
_ = can.write(&frame).await;
|
||||
|
||||
match can.read().await {
|
||||
Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]),
|
||||
Err(_err) => error!("Error in frame"),
|
||||
}
|
||||
|
||||
Timer::after_millis(250).await;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
74
examples/stm32h5/src/bin/can.rs
Normal file
74
examples/stm32h5/src/bin/can.rs
Normal file
@ -0,0 +1,74 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::peripherals::*;
|
||||
use embassy_stm32::{bind_interrupts, can, rcc, Config};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
|
||||
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let mut config = Config::default();
|
||||
|
||||
// configure FDCAN to use PLL1_Q at 64 MHz
|
||||
config.rcc.pll1 = Some(rcc::Pll {
|
||||
source: rcc::PllSource::HSI,
|
||||
prediv: rcc::PllPreDiv::DIV4,
|
||||
mul: rcc::PllMul::MUL8,
|
||||
divp: None,
|
||||
divq: Some(rcc::PllDiv::DIV2),
|
||||
divr: None,
|
||||
});
|
||||
config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q;
|
||||
|
||||
let peripherals = embassy_stm32::init(config);
|
||||
|
||||
let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
|
||||
|
||||
can.can.apply_config(
|
||||
can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming {
|
||||
sync_jump_width: 1.try_into().unwrap(),
|
||||
prescaler: 8.try_into().unwrap(),
|
||||
seg1: 13.try_into().unwrap(),
|
||||
seg2: 2.try_into().unwrap(),
|
||||
}),
|
||||
);
|
||||
|
||||
info!("Configured");
|
||||
|
||||
let mut can = can.into_external_loopback_mode();
|
||||
//let mut can = can.into_normal_mode();
|
||||
|
||||
let mut i = 0;
|
||||
loop {
|
||||
let frame = can::TxFrame::new(
|
||||
can::TxFrameHeader {
|
||||
len: 1,
|
||||
frame_format: can::FrameFormat::Standard,
|
||||
id: can::StandardId::new(0x123).unwrap().into(),
|
||||
bit_rate_switching: false,
|
||||
marker: None,
|
||||
},
|
||||
&[i],
|
||||
)
|
||||
.unwrap();
|
||||
info!("Writing frame");
|
||||
_ = can.write(&frame).await;
|
||||
|
||||
match can.read().await {
|
||||
Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]),
|
||||
Err(_err) => error!("Error in frame"),
|
||||
}
|
||||
|
||||
Timer::after_millis(250).await;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
74
examples/stm32h7/src/bin/can.rs
Normal file
74
examples/stm32h7/src/bin/can.rs
Normal file
@ -0,0 +1,74 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::peripherals::*;
|
||||
use embassy_stm32::{bind_interrupts, can, rcc, Config};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
|
||||
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
|
||||
});
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let mut config = Config::default();
|
||||
|
||||
// configure FDCAN to use PLL1_Q at 64 MHz
|
||||
config.rcc.pll1 = Some(rcc::Pll {
|
||||
source: rcc::PllSource::HSI,
|
||||
prediv: rcc::PllPreDiv::DIV4,
|
||||
mul: rcc::PllMul::MUL8,
|
||||
divp: None,
|
||||
divq: Some(rcc::PllDiv::DIV2),
|
||||
divr: None,
|
||||
});
|
||||
config.rcc.fdcan_clock_source = rcc::FdCanClockSource::PLL1_Q;
|
||||
|
||||
let peripherals = embassy_stm32::init(config);
|
||||
|
||||
let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PA11, peripherals.PA12, Irqs);
|
||||
|
||||
can.can.apply_config(
|
||||
can::config::FdCanConfig::default().set_nominal_bit_timing(can::config::NominalBitTiming {
|
||||
sync_jump_width: 1.try_into().unwrap(),
|
||||
prescaler: 8.try_into().unwrap(),
|
||||
seg1: 13.try_into().unwrap(),
|
||||
seg2: 2.try_into().unwrap(),
|
||||
}),
|
||||
);
|
||||
|
||||
info!("Configured");
|
||||
|
||||
let mut can = can.into_external_loopback_mode();
|
||||
//let mut can = can.into_normal_mode();
|
||||
|
||||
let mut i = 0;
|
||||
loop {
|
||||
let frame = can::TxFrame::new(
|
||||
can::TxFrameHeader {
|
||||
len: 1,
|
||||
frame_format: can::FrameFormat::Standard,
|
||||
id: can::StandardId::new(0x123).unwrap().into(),
|
||||
bit_rate_switching: false,
|
||||
marker: None,
|
||||
},
|
||||
&[i],
|
||||
)
|
||||
.unwrap();
|
||||
info!("Writing frame");
|
||||
_ = can.write(&frame).await;
|
||||
|
||||
match can.read().await {
|
||||
Ok(rx_frame) => info!("Rx: {}", rx_frame.data()[0]),
|
||||
Err(_err) => error!("Error in frame"),
|
||||
}
|
||||
|
||||
Timer::after_millis(250).await;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
}
|
@ -65,6 +65,7 @@ async fn main(spawner: Spawner) -> ! {
|
||||
let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
|
||||
|
||||
static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new();
|
||||
|
||||
let device = Ethernet::new(
|
||||
PACKETS.init(PacketQueue::<16, 16>::new()),
|
||||
p.ETH,
|
||||
|
142
examples/stm32h7/src/bin/eth_client_mii.rs
Normal file
142
examples/stm32h7/src/bin/eth_client_mii.rs
Normal file
@ -0,0 +1,142 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_net::tcp::client::{TcpClient, TcpClientState};
|
||||
use embassy_net::{Stack, StackResources};
|
||||
use embassy_stm32::eth::generic_smi::GenericSMI;
|
||||
use embassy_stm32::eth::{Ethernet, PacketQueue};
|
||||
use embassy_stm32::peripherals::ETH;
|
||||
use embassy_stm32::rng::Rng;
|
||||
use embassy_stm32::{bind_interrupts, eth, peripherals, rng, Config};
|
||||
use embassy_time::Timer;
|
||||
use embedded_io_async::Write;
|
||||
use embedded_nal_async::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpConnect};
|
||||
use rand_core::RngCore;
|
||||
use static_cell::StaticCell;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
ETH => eth::InterruptHandler;
|
||||
RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||
});
|
||||
|
||||
type Device = Ethernet<'static, ETH, GenericSMI>;
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn net_task(stack: &'static Stack<Device>) -> ! {
|
||||
stack.run().await
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) -> ! {
|
||||
let mut config = Config::default();
|
||||
{
|
||||
use embassy_stm32::rcc::*;
|
||||
config.rcc.hsi = Some(HSIPrescaler::DIV1);
|
||||
config.rcc.csi = true;
|
||||
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
|
||||
config.rcc.pll1 = Some(Pll {
|
||||
source: PllSource::HSI,
|
||||
prediv: PllPreDiv::DIV4,
|
||||
mul: PllMul::MUL50,
|
||||
divp: Some(PllDiv::DIV2),
|
||||
divq: None,
|
||||
divr: None,
|
||||
});
|
||||
config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
|
||||
config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
|
||||
config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
|
||||
config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
|
||||
config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
|
||||
config.rcc.voltage_scale = VoltageScale::Scale1;
|
||||
}
|
||||
let p = embassy_stm32::init(config);
|
||||
info!("Hello World!");
|
||||
|
||||
// Generate random seed.
|
||||
let mut rng = Rng::new(p.RNG, Irqs);
|
||||
let mut seed = [0; 8];
|
||||
rng.fill_bytes(&mut seed);
|
||||
let seed = u64::from_le_bytes(seed);
|
||||
|
||||
let mac_addr = [0x00, 0x00, 0xDE, 0xAD, 0xBE, 0xEF];
|
||||
|
||||
static PACKETS: StaticCell<PacketQueue<16, 16>> = StaticCell::new();
|
||||
|
||||
let device = Ethernet::new_mii(
|
||||
PACKETS.init(PacketQueue::<16, 16>::new()),
|
||||
p.ETH,
|
||||
Irqs,
|
||||
p.PA1,
|
||||
p.PC3,
|
||||
p.PA2,
|
||||
p.PC1,
|
||||
p.PA7,
|
||||
p.PC4,
|
||||
p.PC5,
|
||||
p.PB0,
|
||||
p.PB1,
|
||||
p.PG13,
|
||||
p.PG12,
|
||||
p.PC2,
|
||||
p.PE2,
|
||||
p.PG11,
|
||||
GenericSMI::new(1),
|
||||
mac_addr,
|
||||
);
|
||||
info!("Device created");
|
||||
|
||||
let config = embassy_net::Config::dhcpv4(Default::default());
|
||||
//let config = embassy_net::Config::ipv4_static(embassy_net::StaticConfigV4 {
|
||||
// address: Ipv4Cidr::new(Ipv4Address::new(10, 42, 0, 61), 24),
|
||||
// dns_servers: Vec::new(),
|
||||
// gateway: Some(Ipv4Address::new(10, 42, 0, 1)),
|
||||
//});
|
||||
|
||||
// Init network stack
|
||||
static STACK: StaticCell<Stack<Device>> = StaticCell::new();
|
||||
static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
|
||||
let stack = &*STACK.init(Stack::new(
|
||||
device,
|
||||
config,
|
||||
RESOURCES.init(StackResources::<3>::new()),
|
||||
seed,
|
||||
));
|
||||
|
||||
// Launch network task
|
||||
unwrap!(spawner.spawn(net_task(stack)));
|
||||
|
||||
// Ensure DHCP configuration is up before trying connect
|
||||
stack.wait_config_up().await;
|
||||
|
||||
info!("Network task initialized");
|
||||
|
||||
let state: TcpClientState<1, 1024, 1024> = TcpClientState::new();
|
||||
let client = TcpClient::new(&stack, &state);
|
||||
|
||||
loop {
|
||||
// You need to start a server on the host machine, for example: `nc -l 8000`
|
||||
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 100, 1), 8000));
|
||||
|
||||
info!("connecting...");
|
||||
let r = client.connect(addr).await;
|
||||
if let Err(e) = r {
|
||||
info!("connect error: {:?}", e);
|
||||
Timer::after_secs(1).await;
|
||||
continue;
|
||||
}
|
||||
let mut connection = r.unwrap();
|
||||
info!("connected!");
|
||||
loop {
|
||||
let r = connection.write_all(b"Hello\n").await;
|
||||
if let Err(e) = r {
|
||||
info!("write error: {:?}", e);
|
||||
break;
|
||||
}
|
||||
Timer::after_secs(1).await;
|
||||
}
|
||||
}
|
||||
}
|
9
tests/nrf51422/.cargo/config.toml
Normal file
9
tests/nrf51422/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
#runner = "teleprobe local run --chip nRF51422_xxAA --elf"
|
||||
runner = "teleprobe client run"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "trace,embassy_hal_internal=debug"
|
22
tests/nrf51422/Cargo.toml
Normal file
22
tests/nrf51422/Cargo.toml
Normal file
@ -0,0 +1,22 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-nrf51-tests"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
teleprobe-meta = "1"
|
||||
|
||||
embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt", ] }
|
||||
embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "task-arena-size-128", "integrated-timers"] }
|
||||
embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] }
|
||||
embassy-nrf = { version = "0.1.0", path = "../../embassy-nrf", features = ["defmt", "nrf51", "time-driver-rtc1", "unstable-pac", "time"] }
|
||||
embedded-io-async = { version = "0.6.1", features = ["defmt-03"] }
|
||||
embedded-hal-async = { version = "1.0" }
|
||||
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
|
||||
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
|
||||
cortex-m-rt = "0.7.0"
|
||||
panic-probe = { version = "0.3", features = ["print-defmt"] }
|
17
tests/nrf51422/build.rs
Normal file
17
tests/nrf51422/build.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use std::error::Error;
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
fs::write(out.join("memory.x"), include_bytes!("memory.x")).unwrap();
|
||||
println!("cargo:rustc-link-search={}", out.display());
|
||||
println!("cargo:rerun-if-changed=memory.x");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tteleprobe.x");
|
||||
|
||||
Ok(())
|
||||
}
|
5
tests/nrf51422/memory.x
Normal file
5
tests/nrf51422/memory.x
Normal file
@ -0,0 +1,5 @@
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x00000000, LENGTH = 128K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 16K
|
||||
}
|
28
tests/nrf51422/src/bin/gpio.rs
Normal file
28
tests/nrf51422/src/bin/gpio.rs
Normal file
@ -0,0 +1,28 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
teleprobe_meta::target!(b"nrf51-dk");
|
||||
|
||||
use defmt::{assert, info};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull};
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let p = embassy_nrf::init(Default::default());
|
||||
|
||||
let input = Input::new(p.P0_13, Pull::Up);
|
||||
let mut output = Output::new(p.P0_14, Level::Low, OutputDrive::Standard);
|
||||
|
||||
output.set_low();
|
||||
Timer::after_millis(10).await;
|
||||
assert!(input.is_low());
|
||||
|
||||
output.set_high();
|
||||
Timer::after_millis(10).await;
|
||||
assert!(input.is_high());
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
}
|
24
tests/nrf51422/src/bin/timer.rs
Normal file
24
tests/nrf51422/src/bin/timer.rs
Normal file
@ -0,0 +1,24 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
teleprobe_meta::target!(b"nrf51-dk");
|
||||
|
||||
use defmt::{assert, info};
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_time::{Instant, Timer};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
let _p = embassy_nrf::init(Default::default());
|
||||
info!("Hello World!");
|
||||
|
||||
let start = Instant::now();
|
||||
Timer::after_millis(100).await;
|
||||
let end = Instant::now();
|
||||
let ms = (end - start).as_millis();
|
||||
info!("slept for {} ms", ms);
|
||||
assert!(ms >= 99);
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
}
|
@ -18,7 +18,6 @@ async fn main(_spawner: Spawner) {
|
||||
let ms = (end - start).as_millis();
|
||||
info!("slept for {} ms", ms);
|
||||
assert!(ms >= 99);
|
||||
assert!(ms < 110);
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
@ -80,7 +80,7 @@ async fn device_task(mut dev: i2c_slave::I2cSlave<'static, I2C1>) -> ! {
|
||||
_ => panic!("Invalid write length {}", len),
|
||||
},
|
||||
Ok(i2c_slave::Command::WriteRead(len)) => {
|
||||
info!("device recieved write read: {:x}", buf[..len]);
|
||||
info!("device received write read: {:x}", buf[..len]);
|
||||
match buf[0] {
|
||||
0xC2 => {
|
||||
let resp_buff = [0xD1, 0xD2, 0xD3, 0xD4];
|
||||
|
@ -14,11 +14,11 @@ stm32f429zi = ["embassy-stm32/stm32f429zi", "chrono", "eth", "stop", "can", "not
|
||||
stm32f446re = ["embassy-stm32/stm32f446re", "chrono", "stop", "can", "not-gpdma", "dac", "sdmmc"]
|
||||
stm32f767zi = ["embassy-stm32/stm32f767zi", "chrono", "not-gpdma", "eth", "rng"]
|
||||
stm32g071rb = ["embassy-stm32/stm32g071rb", "cm0", "not-gpdma", "dac"]
|
||||
stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng"]
|
||||
stm32g491re = ["embassy-stm32/stm32g491re", "chrono", "stop", "not-gpdma", "rng", "fdcan"]
|
||||
stm32h563zi = ["embassy-stm32/stm32h563zi", "chrono", "eth", "rng"]
|
||||
stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng"]
|
||||
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng"]
|
||||
stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng"]
|
||||
stm32h753zi = ["embassy-stm32/stm32h753zi", "chrono", "not-gpdma", "eth", "rng", "fdcan"]
|
||||
stm32h755zi = ["embassy-stm32/stm32h755zi-cm7", "chrono", "not-gpdma", "eth", "dac", "rng", "fdcan"]
|
||||
stm32h7a3zi = ["embassy-stm32/stm32h7a3zi", "not-gpdma", "rng", "fdcan"]
|
||||
stm32l073rz = ["embassy-stm32/stm32l073rz", "cm0", "not-gpdma", "rng"]
|
||||
stm32l152re = ["embassy-stm32/stm32l152re", "chrono", "not-gpdma"]
|
||||
stm32l496zg = ["embassy-stm32/stm32l496zg", "not-gpdma", "rng"]
|
||||
@ -37,6 +37,7 @@ sdmmc = []
|
||||
stop = ["embassy-stm32/low-power", "embassy-stm32/low-power-debug-with-sleep"]
|
||||
chrono = ["embassy-stm32/chrono", "dep:chrono"]
|
||||
can = []
|
||||
fdcan = []
|
||||
ble = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/ble"]
|
||||
mac = ["dep:embassy-stm32-wpan", "embassy-stm32-wpan/mac"]
|
||||
embassy-stm32-wpan = []
|
||||
@ -96,6 +97,11 @@ name = "eth"
|
||||
path = "src/bin/eth.rs"
|
||||
required-features = [ "eth",]
|
||||
|
||||
[[bin]]
|
||||
name = "fdcan"
|
||||
path = "src/bin/fdcan.rs"
|
||||
required-features = [ "fdcan",]
|
||||
|
||||
[[bin]]
|
||||
name = "gpio"
|
||||
path = "src/bin/gpio.rs"
|
||||
|
243
tests/stm32/src/bin/fdcan.rs
Normal file
243
tests/stm32/src/bin/fdcan.rs
Normal file
@ -0,0 +1,243 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
// required-features: fdcan
|
||||
|
||||
#[path = "../common.rs"]
|
||||
mod common;
|
||||
use common::*;
|
||||
use defmt::assert;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::peripherals::*;
|
||||
use embassy_stm32::{bind_interrupts, can, Config};
|
||||
use embassy_time::{Duration, Instant};
|
||||
use {defmt_rtt as _, panic_probe as _};
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
FDCAN1_IT0 => can::IT0InterruptHandler<FDCAN1>;
|
||||
FDCAN1_IT1 => can::IT1InterruptHandler<FDCAN1>;
|
||||
});
|
||||
|
||||
struct TestOptions {
|
||||
config: Config,
|
||||
max_latency: Duration,
|
||||
second_fifo_working: bool,
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "stm32h755zi", feature = "stm32h753zi", feature = "stm32h563zi"))]
|
||||
fn options() -> TestOptions {
|
||||
use embassy_stm32::rcc;
|
||||
info!("H75 config");
|
||||
let mut c = config();
|
||||
c.rcc.hse = Some(rcc::Hse {
|
||||
freq: embassy_stm32::time::Hertz(25_000_000),
|
||||
mode: rcc::HseMode::Oscillator,
|
||||
});
|
||||
c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
|
||||
TestOptions {
|
||||
config: c,
|
||||
max_latency: Duration::from_micros(3800),
|
||||
second_fifo_working: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "stm32h7a3zi"))]
|
||||
fn options() -> TestOptions {
|
||||
use embassy_stm32::rcc;
|
||||
info!("H7a config");
|
||||
let mut c = config();
|
||||
c.rcc.hse = Some(rcc::Hse {
|
||||
freq: embassy_stm32::time::Hertz(25_000_000),
|
||||
mode: rcc::HseMode::Oscillator,
|
||||
});
|
||||
c.rcc.fdcan_clock_source = rcc::FdCanClockSource::HSE;
|
||||
TestOptions {
|
||||
config: c,
|
||||
max_latency: Duration::from_micros(5500),
|
||||
second_fifo_working: false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "stm32g491re"))]
|
||||
fn options() -> TestOptions {
|
||||
info!("G4 config");
|
||||
TestOptions {
|
||||
config: config(),
|
||||
max_latency: Duration::from_micros(500),
|
||||
second_fifo_working: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) {
|
||||
//let peripherals = embassy_stm32::init(config());
|
||||
|
||||
let options = options();
|
||||
let peripherals = embassy_stm32::init(options.config);
|
||||
|
||||
let mut can = can::Fdcan::new(peripherals.FDCAN1, peripherals.PB8, peripherals.PB9, Irqs);
|
||||
|
||||
// 250k bps
|
||||
can.set_bitrate(250_000);
|
||||
|
||||
can.can.set_extended_filter(
|
||||
can::filter::ExtendedFilterSlot::_0,
|
||||
can::filter::ExtendedFilter::accept_all_into_fifo1(),
|
||||
);
|
||||
|
||||
let mut can = can.into_internal_loopback_mode();
|
||||
|
||||
info!("CAN Configured");
|
||||
|
||||
let mut i: u8 = 0;
|
||||
loop {
|
||||
let tx_frame = can::TxFrame::new(
|
||||
can::TxFrameHeader {
|
||||
len: 1,
|
||||
frame_format: can::FrameFormat::Standard,
|
||||
id: can::StandardId::new(0x123).unwrap().into(),
|
||||
bit_rate_switching: false,
|
||||
marker: None,
|
||||
},
|
||||
&[i],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
info!("Transmitting frame...");
|
||||
let tx_ts = Instant::now();
|
||||
can.write(&tx_frame).await;
|
||||
|
||||
let envelope = can.read().await.unwrap();
|
||||
info!("Frame received!");
|
||||
|
||||
// Check data.
|
||||
assert!(i == envelope.data()[0], "{} == {}", i, envelope.data()[0]);
|
||||
|
||||
info!("loopback time {}", envelope.header.time_stamp);
|
||||
info!("loopback frame {=u8}", envelope.data()[0]);
|
||||
let latency = envelope.timestamp.saturating_duration_since(tx_ts);
|
||||
info!("loopback latency {} us", latency.as_micros());
|
||||
|
||||
// Theoretical minimum latency is 55us, actual is usually ~80us
|
||||
const MIN_LATENCY: Duration = Duration::from_micros(50);
|
||||
// Was failing at 150 but we are not getting a real time stamp. I'm not
|
||||
// sure if there are other delays
|
||||
assert!(
|
||||
MIN_LATENCY <= latency && latency <= options.max_latency,
|
||||
"{} <= {} <= {}",
|
||||
MIN_LATENCY,
|
||||
latency,
|
||||
options.max_latency
|
||||
);
|
||||
|
||||
i += 1;
|
||||
if i > 10 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let max_buffered = if options.second_fifo_working { 6 } else { 3 };
|
||||
|
||||
// Below here, check that we can receive from both FIFO0 and FIFO0
|
||||
// Above we configured FIFO1 for extended ID packets. There are only 3 slots
|
||||
// in each FIFO so make sure we write enough to fill them both up before reading.
|
||||
for i in 0..3 {
|
||||
// Try filling up the RX FIFO0 buffers with standard packets
|
||||
let tx_frame = can::TxFrame::new(
|
||||
can::TxFrameHeader {
|
||||
len: 1,
|
||||
frame_format: can::FrameFormat::Standard,
|
||||
id: can::StandardId::new(0x123).unwrap().into(),
|
||||
bit_rate_switching: false,
|
||||
marker: None,
|
||||
},
|
||||
&[i],
|
||||
)
|
||||
.unwrap();
|
||||
info!("Transmitting frame {}", i);
|
||||
can.write(&tx_frame).await;
|
||||
}
|
||||
for i in 3..max_buffered {
|
||||
// Try filling up the RX FIFO0 buffers with extended packets
|
||||
let tx_frame = can::TxFrame::new(
|
||||
can::TxFrameHeader {
|
||||
len: 1,
|
||||
frame_format: can::FrameFormat::Standard,
|
||||
id: can::ExtendedId::new(0x1232344).unwrap().into(),
|
||||
bit_rate_switching: false,
|
||||
marker: None,
|
||||
},
|
||||
&[i],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
info!("Transmitting frame {}", i);
|
||||
can.write(&tx_frame).await;
|
||||
}
|
||||
|
||||
// Try and receive all 6 packets
|
||||
for i in 0..max_buffered {
|
||||
let envelope = can.read().await.unwrap();
|
||||
match envelope.header.id {
|
||||
can::Id::Extended(id) => {
|
||||
info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
|
||||
}
|
||||
can::Id::Standard(id) => {
|
||||
info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test again with a split
|
||||
let (mut tx, mut rx) = can.split();
|
||||
for i in 0..3 {
|
||||
// Try filling up the RX FIFO0 buffers with standard packets
|
||||
let tx_frame = can::TxFrame::new(
|
||||
can::TxFrameHeader {
|
||||
len: 1,
|
||||
frame_format: can::FrameFormat::Standard,
|
||||
id: can::StandardId::new(0x123).unwrap().into(),
|
||||
bit_rate_switching: false,
|
||||
marker: None,
|
||||
},
|
||||
&[i],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
info!("Transmitting frame {}", i);
|
||||
tx.write(&tx_frame).await;
|
||||
}
|
||||
for i in 3..max_buffered {
|
||||
// Try filling up the RX FIFO0 buffers with extended packets
|
||||
let tx_frame = can::TxFrame::new(
|
||||
can::TxFrameHeader {
|
||||
len: 1,
|
||||
frame_format: can::FrameFormat::Standard,
|
||||
id: can::ExtendedId::new(0x1232344).unwrap().into(),
|
||||
bit_rate_switching: false,
|
||||
marker: None,
|
||||
},
|
||||
&[i],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
info!("Transmitting frame {}", i);
|
||||
tx.write(&tx_frame).await;
|
||||
}
|
||||
|
||||
// Try and receive all 6 packets
|
||||
for i in 0..max_buffered {
|
||||
let envelope = rx.read().await.unwrap();
|
||||
match envelope.header.id {
|
||||
can::Id::Extended(id) => {
|
||||
info!("Extended received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
|
||||
}
|
||||
can::Id::Standard(id) => {
|
||||
info!("Standard received! {:x} {} {}", id.as_raw(), envelope.data()[0], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info!("Test OK");
|
||||
cortex_m::asm::bkpt();
|
||||
}
|
Loading…
Reference in New Issue
Block a user