Validate configuration through its owning schemas and keep board declarations separate from shared F722 resource ownership. Bound USB transitions, isolate transport failures and retain restart-only activation. Migrate navigation and flight consumers with the sensor and schema contracts. Require explicit installation data and synchronous output authority; board motor outputs remain inhibited. Validation: assembled-prefix host tests, strict Clippy, platform/USB tests and both ARM release builds. Final-source coverage and scoped Miri/Kani evidence are retained separately from hardware qualification.
54 lines
1.8 KiB
Rust
54 lines
1.8 KiB
Rust
use kaptan_spi::{CompletionError, SpiCompletion};
|
|
use stm32f7::stm32f722::{dma2, spi1};
|
|
|
|
const QUIESCE_POLLS: usize = 1024;
|
|
|
|
pub(super) fn bus_finished(spi: &spi1::RegisterBlock) -> bool {
|
|
let status = spi.sr().read();
|
|
status.ftlvl().is_empty() && status.bsy().is_not_busy()
|
|
}
|
|
|
|
pub(super) fn complete_transfer(
|
|
spi: &spi1::RegisterBlock,
|
|
rx: &dma2::ST,
|
|
tx: &dma2::ST,
|
|
completion: SpiCompletion,
|
|
has_fault: impl FnOnce() -> bool,
|
|
) -> Result<SpiCompletion, CompletionError> {
|
|
spi.cr2()
|
|
.modify(|_, write| write.rxdmaen().clear_bit().txdmaen().clear_bit());
|
|
rx.cr().modify(|_, write| write.en().clear_bit());
|
|
tx.cr().modify(|_, write| write.en().clear_bit());
|
|
// Leave SPI enabled while queued frames drain. Writing EN=0 does not
|
|
// establish that DMA stopped or that the final SPI clock completed.
|
|
let quiescent = (0..QUIESCE_POLLS).any(|_| {
|
|
rx.cr().read().en().is_disabled() && tx.cr().read().en().is_disabled() && bus_finished(spi)
|
|
});
|
|
spi.cr1().modify(|_, write| write.spe().clear_bit());
|
|
cortex_m::asm::dsb();
|
|
if !quiescent {
|
|
return Err(CompletionError::Quarantined);
|
|
}
|
|
let complete = completion == SpiCompletion::Complete
|
|
&& rx.ndtr().read().bits() == 0
|
|
&& tx.ndtr().read().bits() == 0
|
|
&& spi.sr().read().frlvl().is_empty()
|
|
&& !has_fault();
|
|
// Cancellation can leave old frames in the four-byte RX FIFO. Check
|
|
// faults before draining: the DR/SR reads can clear an overrun.
|
|
for _ in 0..4 {
|
|
if spi.sr().read().frlvl().is_empty() {
|
|
break;
|
|
}
|
|
let _ = spi.dr().read().bits();
|
|
}
|
|
if !spi.sr().read().frlvl().is_empty() {
|
|
return Err(CompletionError::Quarantined);
|
|
}
|
|
Ok(if complete {
|
|
SpiCompletion::Complete
|
|
} else {
|
|
SpiCompletion::TransferFault
|
|
})
|
|
}
|