Files
kaptan/firmware/platforms/stm32f7/src/f722/peripherals/spi_dma.rs
T
Onur Özkan f9a61a086f feat(firmware): validate configuration and migrate sensor-driven flight APIs
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.
2026-11-07 18:12:11 +03:00

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
})
}