feat(f722): add usb mavlink transport
This commit is contained in:
1 parent
7dc3ccb619
commit
604a7aba86
18 files changed
+1087
-208
No files matched your search
@@ -3,7 +3,10 @@
|
||||
use kaptan_err_reportable::KaptanError;
|
||||
use stm32f7::stm32f722;
|
||||
|
||||
const CLOCK_SWITCH_POLL_LIMIT: u16 = 1_024;
|
||||
const CLOCK_SWITCH_POLL_LIMIT: u32 = 1_024;
|
||||
// Crystal startup is slower than a clock-tree state transition. This remains
|
||||
// bounded so an absent oscillator reaches safe-idle instead of hanging boot.
|
||||
const HSE_STARTUP_POLL_LIMIT: u32 = 1_000_000;
|
||||
|
||||
/// Failure to establish the 216 MHz PLL clock profile.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, KaptanError)]
|
||||
@@ -22,30 +25,44 @@ pub enum ClockProfileError {
|
||||
OverDriveSwitchNotReady,
|
||||
#[kaptan_error(id = 11007)]
|
||||
SystemClockNotPll,
|
||||
#[kaptan_error(id = 11008)]
|
||||
HseNotReady,
|
||||
}
|
||||
|
||||
/// Selects the F722 platform's HSI PLL profile.
|
||||
/// Selects the F722 platform's 8 MHz HSE PLL profile.
|
||||
///
|
||||
/// SYSCLK/HCLK run at 216 MHz; APB1 is 54 MHz (timers run at 108 MHz), and
|
||||
/// APB2 is 108 MHz. HSI is the PLL source, so no external-crystal assumption
|
||||
/// is introduced.
|
||||
/// APB2 is 108 MHz. Both supported flight-controller boards have an 8 MHz
|
||||
/// external oscillator; using it as the PLL source gives USB an accurate
|
||||
/// 48 MHz clock through PLLQ.
|
||||
pub fn select_pll216_profile(
|
||||
rcc: &stm32f722::RCC,
|
||||
pwr: &stm32f722::PWR,
|
||||
flash: &stm32f722::FLASH,
|
||||
) -> Result<(), ClockProfileError> {
|
||||
rcc.cr().modify(|_, write| write.hsion().on());
|
||||
if !wait_until(|| rcc.cr().read().hsirdy().is_ready()) {
|
||||
if !wait_until(CLOCK_SWITCH_POLL_LIMIT, || {
|
||||
rcc.cr().read().hsirdy().is_ready()
|
||||
}) {
|
||||
return Err(ClockProfileError::HsiNotReady);
|
||||
}
|
||||
|
||||
// Return to HSI before changing a PLL left configured by an earlier boot stage.
|
||||
rcc.cfgr().modify(|_, write| write.sw().hsi());
|
||||
if !wait_until(|| rcc.cfgr().read().sws().is_hsi()) {
|
||||
if !wait_until(CLOCK_SWITCH_POLL_LIMIT, || rcc.cfgr().read().sws().is_hsi()) {
|
||||
return Err(ClockProfileError::SystemClockNotHsi);
|
||||
}
|
||||
|
||||
rcc.cr().modify(|_, write| write.hseon().on());
|
||||
if !wait_until(HSE_STARTUP_POLL_LIMIT, || {
|
||||
rcc.cr().read().hserdy().is_ready()
|
||||
}) {
|
||||
return Err(ClockProfileError::HseNotReady);
|
||||
}
|
||||
rcc.cr().modify(|_, write| write.pllon().off());
|
||||
if !wait_until(|| !rcc.cr().read().pllrdy().is_ready()) {
|
||||
if !wait_until(CLOCK_SWITCH_POLL_LIMIT, || {
|
||||
!rcc.cr().read().pllrdy().is_ready()
|
||||
}) {
|
||||
return Err(ClockProfileError::PllNotStopped);
|
||||
}
|
||||
|
||||
@@ -56,11 +73,15 @@ pub fn select_pll216_profile(
|
||||
// over-drive-enable fields; it preserves every other PWR_CR1 bit owned by boot.
|
||||
unsafe { write.bits((read.bits() & !(0b11 << 14)) | (0b11 << 14) | (1 << 16)) }
|
||||
});
|
||||
if !wait_until(|| pwr.csr1().read().odrdy().bit_is_set()) {
|
||||
if !wait_until(CLOCK_SWITCH_POLL_LIMIT, || {
|
||||
pwr.csr1().read().odrdy().bit_is_set()
|
||||
}) {
|
||||
return Err(ClockProfileError::OverDriveNotReady);
|
||||
}
|
||||
pwr.cr1().modify(|_, write| write.odswen().set_bit());
|
||||
if !wait_until(|| pwr.csr1().read().odswrdy().bit_is_set()) {
|
||||
if !wait_until(CLOCK_SWITCH_POLL_LIMIT, || {
|
||||
pwr.csr1().read().odswrdy().bit_is_set()
|
||||
}) {
|
||||
return Err(ClockProfileError::OverDriveSwitchNotReady);
|
||||
}
|
||||
flash.acr().modify(|read, write| {
|
||||
@@ -69,14 +90,16 @@ pub fn select_pll216_profile(
|
||||
unsafe { write.bits((read.bits() & !0x0f) | 7 | (1 << 8) | (1 << 9)) }
|
||||
});
|
||||
|
||||
// HSI / 16 * 432 / 2 = 216 MHz; Q=9 supplies a 48 MHz domain.
|
||||
// HSE / 8 * 432 / 2 = 216 MHz; Q=9 supplies the exact 48 MHz USB domain.
|
||||
rcc.pllcfgr().write(|write| {
|
||||
// SAFETY: 16, 432, P=/2 (the reset encoding), and Q=9 are the valid PLL
|
||||
// divisors described above; the PLL is disabled before this full-register write.
|
||||
unsafe { write.bits(16 | (432 << 6) | (9 << 24)) }
|
||||
// SAFETY: M=8, N=432, P=/2 (the reset encoding), Q=9, and the HSE source
|
||||
// are valid for the 8 MHz board oscillator; the PLL is disabled first.
|
||||
unsafe { write.bits(8 | (432 << 6) | (1 << 22) | (9 << 24)) }
|
||||
});
|
||||
rcc.cr().modify(|_, write| write.pllon().on());
|
||||
if !wait_until(|| rcc.cr().read().pllrdy().is_ready()) {
|
||||
if !wait_until(CLOCK_SWITCH_POLL_LIMIT, || {
|
||||
rcc.cr().read().pllrdy().is_ready()
|
||||
}) {
|
||||
return Err(ClockProfileError::PllNotReady);
|
||||
}
|
||||
rcc.cfgr().modify(|read, write| {
|
||||
@@ -92,14 +115,14 @@ pub fn select_pll216_profile(
|
||||
)
|
||||
}
|
||||
});
|
||||
if !wait_until(|| rcc.cfgr().read().sws().is_pll()) {
|
||||
if !wait_until(CLOCK_SWITCH_POLL_LIMIT, || rcc.cfgr().read().sws().is_pll()) {
|
||||
return Err(ClockProfileError::SystemClockNotPll);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn wait_until(mut ready: impl FnMut() -> bool) -> bool {
|
||||
for _ in 0..CLOCK_SWITCH_POLL_LIMIT {
|
||||
fn wait_until(limit: u32, mut ready: impl FnMut() -> bool) -> bool {
|
||||
for _ in 0..limit {
|
||||
if ready() {
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user