boards/kakute-f7-mini-v3: add imu core infra
Signed-off-by: Onur Özkan <work@onurozkan.dev>
This commit is contained in:
1 parent
e0065f8963
commit
b90948870b
4 files changed
+202
-12
No files matched your search
@@ -11,3 +11,9 @@ edition = "2024"
|
|||||||
license = "AGPL-3.0-only"
|
license = "AGPL-3.0-only"
|
||||||
repository = "https://github.com/Orkavian/kaptan"
|
repository = "https://github.com/Orkavian/kaptan"
|
||||||
rust-version = "1.90"
|
rust-version = "1.90"
|
||||||
|
|
||||||
|
[workspace.lints.rust]
|
||||||
|
unsafe_op_in_unsafe_fn = "deny"
|
||||||
|
|
||||||
|
[workspace.lints.clippy]
|
||||||
|
undocumented_unsafe_blocks = "deny"
|
||||||
@@ -6,6 +6,9 @@ repository.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
firmware = []
|
firmware = []
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,18 @@ use panic_halt as _;
|
|||||||
mod app {
|
mod app {
|
||||||
#[shared]
|
#[shared]
|
||||||
struct Shared {
|
struct Shared {
|
||||||
// TODO
|
imu_data_ready_count: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[local]
|
#[local]
|
||||||
struct Local {
|
struct Local {
|
||||||
// TODO
|
|
||||||
led: stm32f7::stm32f722::GPIOD,
|
led: stm32f7::stm32f722::GPIOD,
|
||||||
led_output_high: bool,
|
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]
|
#[init]
|
||||||
@@ -31,23 +35,167 @@ mod app {
|
|||||||
.moder()
|
.moder()
|
||||||
.modify(|_, write| write.moder2().output());
|
.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 {
|
Local {
|
||||||
led: device.GPIOD,
|
led: device.GPIOD,
|
||||||
led_output_high: false,
|
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)]
|
#[idle]
|
||||||
fn imu_data_ready(_context: imu_data_ready::Context) {
|
fn idle(_context: idle::Context) -> ! {
|
||||||
// TODO
|
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 {
|
if *context.local.led_output_high {
|
||||||
context
|
context
|
||||||
.local
|
.local
|
||||||
@@ -61,9 +209,39 @@ mod app {
|
|||||||
.bsrr()
|
.bsrr()
|
||||||
.write(|write| write.bs2().set_bit());
|
.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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,9 @@ repository.workspace = true
|
|||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
std = ["dep:syn"]
|
std = ["dep:syn"]
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user