boards/kakute-f7-mini-v3: add imu core infra

Signed-off-by: Onur Özkan <work@onurozkan.dev>
This commit is contained in:
Onur Özkan committed 2026-07-18 15:24:35 +03:00
1 parent e0065f8963
commit b90948870b
4 files changed
+202 -12

No files matched your search

+6
View File
@@ -11,3 +11,9 @@ edition = "2024"
license = "AGPL-3.0-only"
repository = "https://github.com/Orkavian/kaptan"
rust-version = "1.90"
[workspace.lints.rust]
unsafe_op_in_unsafe_fn = "deny"
[workspace.lints.clippy]
undocumented_unsafe_blocks = "deny"
+3
View File
@@ -6,6 +6,9 @@ repository.workspace = true
rust-version.workspace = true
version.workspace = true
[lints]
workspace = true
[features]
firmware = []
+190 -12
View File
@@ -8,14 +8,18 @@ use panic_halt as _;
mod app {
#[shared]
struct Shared {
// TODO
imu_data_ready_count: u32,
}
#[local]
struct Local {
// TODO
led: stm32f7::stm32f722::GPIOD,
led_output_high: bool,
heartbeat_timer: stm32f7::stm32f722::TIM2,
last_data_ready_count: u32,
imu_spi: stm32f7::stm32f722::SPI1,
imu_chip_select: stm32f7::stm32f722::GPIOB,
data_ready_interrupt: stm32f7::stm32f722::EXTI,
}
#[init]
@@ -31,23 +35,167 @@ mod app {
.moder()
.modify(|_, write| write.moder2().output());
device
.RCC
.ahb1enr()
.modify(|_, write| write.gpioaen().set_bit());
device.GPIOA.moder().modify(|_, write| {
write
.moder5()
.alternate()
.moder6()
.alternate()
.moder7()
.alternate()
.moder4()
.input()
});
device.GPIOA.afrl().modify(|_, write| {
// SAFETY: AF5 selects SPI1 for PA5, PA6, and PA7.
unsafe {
write
.afrl5()
.bits(0b0101)
.afrl6()
.bits(0b0101)
.afrl7()
.bits(0b0101)
}
});
device
.RCC
.ahb1enr()
.modify(|_, write| write.gpioben().set_bit());
device
.GPIOB
.moder()
.modify(|_, write| write.moder2().output());
device.GPIOB.bsrr().write(|write| write.bs2().set_bit());
device
.RCC
.apb2enr()
.modify(|_, write| write.spi1en().set_bit());
device.SPI1.cr1().write(|write| {
write
.mstr()
.master()
.br()
.div64()
.ssm()
.set_bit()
.ssi()
.set_bit()
});
device.SPI1.cr2().modify(|_, write| write.frxth().set_bit());
device.SPI1.cr1().modify(|_, write| write.spe().set_bit());
let mpu6000_detected = is_mpu6000(&device.SPI1, &device.GPIOB);
if mpu6000_detected {
write_mpu_register(&device.SPI1, &device.GPIOB, 0x6B, 0x01);
write_mpu_register(&device.SPI1, &device.GPIOB, 0x37, 0);
write_mpu_register(&device.SPI1, &device.GPIOB, 0x38, 0x01);
device
.RCC
.apb2enr()
.modify(|_, write| write.syscfgen().set_bit());
device.SYSCFG.exticr2().modify(|_, write| {
// SAFETY: EXTI4 source 0 selects GPIOA.
unsafe { write.exti4().bits(0) }
});
device.EXTI.imr().modify(|_, write| write.im4().clear_bit());
device.EXTI.rtsr().modify(|_, write| write.tr4().set_bit());
device
.EXTI
.ftsr()
.modify(|_, write| write.tr4().clear_bit());
device.EXTI.pr().write(|write| write.pr4().clear());
device.EXTI.imr().modify(|_, write| write.im4().set_bit());
}
device
.RCC
.apb1enr()
.modify(|_, write| write.tim2en().set_bit());
device.TIM2.cr1().modify(|_, write| write.cen().clear_bit());
device.TIM2.psc().write(|write| {
// SAFETY: 15_999 fits in TIM2's 16-bit prescaler field.
unsafe { write.psc().bits(15_999) }
});
device.TIM2.arr().write(|write| {
// SAFETY: 999 fits in TIM2's 32-bit auto-reload field.
unsafe { write.arr().bits(999) }
});
device.TIM2.egr().write(|write| write.ug().set_bit());
device.TIM2.sr().modify(|_, write| write.uif().clear_bit());
if mpu6000_detected {
device.TIM2.dier().modify(|_, write| write.uie().set_bit());
device.TIM2.cr1().modify(|_, write| write.cen().set_bit());
}
(
Shared {},
Shared {
imu_data_ready_count: 0,
},
Local {
led: device.GPIOD,
led_output_high: false,
heartbeat_timer: device.TIM2,
last_data_ready_count: 0,
imu_spi: device.SPI1,
imu_chip_select: device.GPIOB,
data_ready_interrupt: device.EXTI,
},
)
}
#[task(binds = EXTI4, priority = 15)]
fn imu_data_ready(_context: imu_data_ready::Context) {
// TODO
#[idle]
fn idle(_context: idle::Context) -> ! {
loop {
cortex_m::asm::wfi();
}
}
#[task(
binds = EXTI4,
priority = 15,
shared = [imu_data_ready_count],
local = [imu_spi, imu_chip_select, data_ready_interrupt]
)]
fn imu_data_ready(mut context: imu_data_ready::Context) {
context
.local
.data_ready_interrupt
.pr()
.write(|write| write.pr4().clear());
context.shared.imu_data_ready_count.lock(|count| {
*count = count.wrapping_add(1);
});
}
#[task(
binds = TIM2,
priority = 1,
shared = [imu_data_ready_count],
local = [led, led_output_high, heartbeat_timer, last_data_ready_count]
)]
fn led_heartbeat(mut context: led_heartbeat::Context) {
context
.local
.heartbeat_timer
.sr()
.modify(|_, write| write.uif().clear_bit());
let imu_data_ready_count = context.shared.imu_data_ready_count.lock(|count| *count);
if imu_data_ready_count == *context.local.last_data_ready_count {
*context.local.led_output_high = false;
} else {
*context.local.led_output_high = !*context.local.led_output_high;
*context.local.last_data_ready_count = imu_data_ready_count;
}
#[idle(local = [led, led_output_high])]
fn idle(context: idle::Context) -> ! {
loop {
if *context.local.led_output_high {
context
.local
@@ -61,9 +209,39 @@ mod app {
.bsrr()
.write(|write| write.bs2().set_bit());
}
*context.local.led_output_high = !*context.local.led_output_high;
cortex_m::asm::delay(8_000_000);
}
fn is_mpu6000(spi: &stm32f7::stm32f722::SPI1, chip_select: &stm32f7::stm32f722::GPIOB) -> bool {
chip_select.bsrr().write(|write| write.br2().set_bit());
let _ = spi_transfer(spi, 0xF5);
let identity = spi_transfer(spi, 0);
while spi.sr().read().bsy().is_busy() {}
chip_select.bsrr().write(|write| write.bs2().set_bit());
identity == 0x68
}
fn spi_transfer(spi: &stm32f7::stm32f722::SPI1, byte: u8) -> u8 {
while spi.sr().read().txe().is_not_empty() {}
spi.dr8().write(|write| {
// SAFETY: `byte` is an 8-bit SPI frame and fits DR8 exactly.
unsafe { write.dr().bits(byte) }
});
while spi.sr().read().rxne().is_empty() {}
spi.dr8().read().dr().bits()
}
fn write_mpu_register(
spi: &stm32f7::stm32f722::SPI1,
chip_select: &stm32f7::stm32f722::GPIOB,
register: u8,
value: u8,
) {
chip_select.bsrr().write(|write| write.br2().set_bit());
let _ = spi_transfer(spi, register);
let _ = spi_transfer(spi, value);
while spi.sr().read().bsy().is_busy() {}
chip_select.bsrr().write(|write| write.bs2().set_bit());
}
}
+3
View File
@@ -6,6 +6,9 @@ repository.workspace = true
rust-version.workspace = true
version.workspace = true
[lints]
workspace = true
[features]
std = ["dep:syn"]