1#![no_std]
2#![doc = include_str!("../README.md")]
3
4use cortex_m::peripheral::DWT;
5use cu_bdshot::{Stm32H7Board, Stm32H7BoardResources, register_stm32h7_board};
6use cu_sdlogger::{EMMCLogger, EMMCSectionStorage, ForceSyncSend, find_copper_partition};
7use cu29::resource::{ResourceBundle, ResourceManager};
8use cu29::{CuError, CuResult, bundle_resources};
9use embedded_hal::adc::OneShot;
10use embedded_hal::blocking::delay::DelayMs;
11use embedded_hal::blocking::spi::Transfer;
12use embedded_hal::digital::v2::OutputPin;
13use spin::Mutex;
14use stm32h7xx_hal::{
15 adc,
16 delay::Delay,
17 gpio::{Analog, Output, PushPull, Speed},
18 nb, pac,
19 prelude::*,
20 rcc::{self, rec::AdcClkSel},
21 sdmmc::{self, SdCard, Sdmmc, SdmmcBlockDevice},
22 serial::{Error as UartError, Serial, config::Config},
23 spi::{Config as SpiConfig, Mode, Phase, Polarity, SpiExt},
24};
25
26const UART_OVERRUN_LOG_PERIOD_SECS: u32 = 1;
28const UART6_BAUD: u32 = 420_000;
29const UART2_BAUD: u32 = 115_200;
30const UART4_BAUD: u32 = 115_200;
31
32pub type SerialPortError = embedded_io::ErrorKind;
33
34pub struct SerialWrapper<U> {
36 inner: Serial<U>,
37 label: &'static str,
38 last_overrun_cycle: Option<u32>,
39 overrun_period_cycles: u32,
40}
41
42unsafe impl<U> Send for SerialWrapper<U> {}
44unsafe impl<U> Sync for SerialWrapper<U> {}
46
47impl<U> SerialWrapper<U> {
48 fn new(inner: Serial<U>, label: &'static str, overrun_period_cycles: u32) -> Self {
49 Self {
50 inner,
51 label,
52 last_overrun_cycle: None,
53 overrun_period_cycles,
54 }
55 }
56
57 fn should_warn_overrun(&mut self) -> bool {
58 if self.overrun_period_cycles == 0 {
59 return true;
60 }
61 let now = DWT::cycle_count();
62 match self.last_overrun_cycle {
63 Some(prev) if now.wrapping_sub(prev) < self.overrun_period_cycles => false,
64 _ => {
65 self.last_overrun_cycle = Some(now);
66 true
67 }
68 }
69 }
70}
71
72macro_rules! impl_serial_wrapper_io {
73 ($usart:ty) => {
74 impl embedded_io::ErrorType for SerialWrapper<$usart> {
75 type Error = SerialPortError;
76 }
77
78 impl embedded_io::Read for SerialWrapper<$usart> {
79 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
80 let mut read = 0;
81 for b in buf.iter_mut() {
82 match self.inner.read() {
83 Ok(byte) => {
84 *b = byte;
85 read += 1;
86 }
87 Err(nb::Error::WouldBlock) => break, Err(nb::Error::Other(e)) => match e {
89 UartError::Overrun => {
90 if self.should_warn_overrun() {
91 defmt::warn!("{} overrun, data lost", self.label);
92 }
93 break;
95 }
96 _ => {
97 defmt::error!("{} read err: {:?}", self.label, e);
98 return Err(SerialPortError::Other);
99 }
100 },
101 }
102 }
103 Ok(read)
104 }
105 }
106
107 impl embedded_io::Write for SerialWrapper<$usart> {
108 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
109 let mut written = 0;
110 for &b in buf {
111 match nb::block!(self.inner.write(b)) {
112 Ok(()) => written += 1,
113 Err(e) => {
114 defmt::error!("{} write err: {:?}", self.label, e);
115 return Err(SerialPortError::Other);
116 }
117 }
118 }
119 Ok(written)
120 }
121
122 fn flush(&mut self) -> Result<(), Self::Error> {
123 Ok(())
124 }
125 }
126 };
127}
128
129impl_serial_wrapper_io!(pac::USART6);
130impl_serial_wrapper_io!(pac::USART2);
131impl_serial_wrapper_io!(pac::UART4);
132
133pub type Uart6Port = SerialWrapper<pac::USART6>;
135pub type Uart2Port = SerialWrapper<pac::USART2>;
136pub type Uart4Port = SerialWrapper<pac::UART4>;
137
138pub struct SingleThreaded<T>(T);
140
141impl<T> SingleThreaded<T> {
142 pub fn new(inner: T) -> Self {
143 Self(inner)
144 }
145}
146
147unsafe impl<T> Send for SingleThreaded<T> {}
149unsafe impl<T> Sync for SingleThreaded<T> {}
151
152impl<T> Transfer<u8> for SingleThreaded<T>
153where
154 T: Transfer<u8>,
155{
156 type Error = T::Error;
157
158 fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
159 self.0.transfer(words)
160 }
161}
162
163impl<T> OutputPin for SingleThreaded<T>
164where
165 T: OutputPin,
166{
167 type Error = T::Error;
168
169 fn set_low(&mut self) -> Result<(), Self::Error> {
170 self.0.set_low()
171 }
172
173 fn set_high(&mut self) -> Result<(), Self::Error> {
174 self.0.set_high()
175 }
176}
177
178impl<T> DelayMs<u32> for SingleThreaded<T>
179where
180 T: DelayMs<u32>,
181{
182 fn delay_ms(&mut self, ms: u32) {
183 self.0.delay_ms(ms);
184 }
185}
186
187pub type GreenLed =
188 stm32h7xx_hal::gpio::gpioe::PE6<stm32h7xx_hal::gpio::Output<stm32h7xx_hal::gpio::PushPull>>;
189
190pub type Bmi088Spi =
191 SingleThreaded<stm32h7xx_hal::spi::Spi<pac::SPI2, stm32h7xx_hal::spi::Enabled, u8>>;
192pub type Bmi088AccCs = SingleThreaded<stm32h7xx_hal::gpio::gpiod::PD4<Output<PushPull>>>;
193pub type Bmi088GyrCs = SingleThreaded<stm32h7xx_hal::gpio::gpiod::PD5<Output<PushPull>>>;
194pub type Bmi088Delay = SingleThreaded<Delay>;
195pub type BatterySensePin = stm32h7xx_hal::gpio::gpioc::PC0<Analog>;
196
197pub struct BatteryAdc {
198 adc: adc::Adc<pac::ADC1, adc::Enabled>,
199 pin: BatterySensePin,
200}
201
202unsafe impl Send for BatteryAdc {}
204unsafe impl Sync for BatteryAdc {}
206
207impl BatteryAdc {
208 fn new(adc: adc::Adc<pac::ADC1, adc::Enabled>, pin: BatterySensePin) -> Self {
209 Self { adc, pin }
210 }
211
212 pub fn read_raw_blocking(&mut self) -> u32 {
213 nb::block!(self.adc.read(&mut self.pin)).unwrap_or(0)
214 }
215
216 pub fn slope(&self) -> u32 {
217 self.adc.slope()
218 }
219}
220
221type SdBlockDev = ForceSyncSend<SdmmcBlockDevice<Sdmmc<pac::SDMMC1, SdCard>>>;
222pub type LogStorage = EMMCSectionStorage<SdBlockDev>;
223pub type Logger = EMMCLogger<SdBlockDev>;
224
225fn init_sd_logger(
226 sdmmc1: pac::SDMMC1,
227 sdmmc1_rec: rcc::rec::Sdmmc1,
228 clocks: &rcc::CoreClocks,
229 pins: (
230 impl sdmmc::PinClk<pac::SDMMC1>,
231 impl sdmmc::PinCmd<pac::SDMMC1>,
232 impl sdmmc::PinD0<pac::SDMMC1>,
233 impl sdmmc::PinD1<pac::SDMMC1>,
234 impl sdmmc::PinD2<pac::SDMMC1>,
235 impl sdmmc::PinD3<pac::SDMMC1>,
236 ),
237) -> CuResult<Logger> {
238 defmt::info!("Basic Init done, creating sdmmc...");
239 let mut sdmmc: Sdmmc<_, SdCard> = sdmmc1.sdmmc(pins, sdmmc1_rec, clocks);
240
241 defmt::info!("Init()... ");
242 sdmmc
243 .init(25.MHz())
244 .map_err(|_| CuError::from("SDMMC init failed"))?;
245 defmt::info!("Init passed ... ");
246 sdmmc.card().map_err(|_| CuError::from("no sd card"))?;
247 defmt::info!("Card detected!!");
248
249 let bd = ForceSyncSend::new(sdmmc.sdmmc_block_device());
250
251 let (start, count) = match find_copper_partition(&bd) {
252 Ok(Some((s, c))) => (s, c),
253 Ok(None) => {
254 defmt::warn!("Copper partition not found on SD");
255 return Err(CuError::from("copper partition missing"));
256 }
257 Err(_) => {
258 defmt::warn!("SD read error during partition scan");
259 return Err(CuError::from("sd read error during partition scan"));
260 }
261 };
262
263 Logger::new(bd, start, count)
264}
265
266pub struct MicoAirH743;
268
269bundle_resources!(
270 MicoAirH743: Uart6, Uart2, Uart4, GreenLed, Logger, Bmi088Spi, Bmi088AccCs, Bmi088GyrCs, Bmi088Delay, BatteryAdc
271);
272
273impl ResourceBundle for MicoAirH743 {
274 fn build(
275 bundle: cu29::resource::BundleContext<Self>,
276 _config: Option<&cu29::config::ComponentConfig>,
277 manager: &mut ResourceManager,
278 ) -> CuResult<()> {
279 let mut cp = cortex_m::Peripherals::take()
282 .ok_or_else(|| CuError::from("cortex-m peripherals already taken"))?;
283 #[cfg(all(target_arch = "arm", target_abi = "eabihf"))]
284 cp.SCB.enable_fpu();
285 cp.DCB.enable_trace();
286 DWT::unlock();
287 let mut dwt = cp.DWT;
288 dwt.enable_cycle_counter();
289 let syst = cp.SYST;
290
291 let dp = pac::Peripherals::take()
292 .ok_or_else(|| CuError::from("stm32 peripherals already taken"))?;
293
294 let pwr = dp.PWR.constrain();
296 let vos = pwr.freeze();
297 let rcc = dp.RCC.constrain();
298 let mut ccdr = rcc
299 .sys_ck(400.MHz())
300 .pll1_q_ck(100.MHz())
301 .freeze(vos, &dp.SYSCFG);
302 ccdr.peripheral.kernel_adc_clk_mux(AdcClkSel::Per);
303 let sysclk_hz = ccdr.clocks.sys_ck().raw();
304 let sdmmc1_rec = ccdr.peripheral.SDMMC1;
305 let mut delay = Delay::new(syst, ccdr.clocks);
306
307 let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
308 let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
309 let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
310 let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
311 let battery_pin = gpioc.pc0.into_analog();
312
313 let green_led = gpioe.pe6.into_push_pull_output();
314 let mut adc1 = adc::Adc::adc1(
315 dp.ADC1,
316 4.MHz(),
317 &mut delay,
318 ccdr.peripheral.ADC12,
319 &ccdr.clocks,
320 )
321 .enable();
322 adc1.set_resolution(adc::Resolution::TwelveBit);
323 adc1.set_sample_time(adc::AdcSampleTime::T_64);
324 let battery_adc = BatteryAdc::new(adc1, battery_pin);
325
326 let overrun_period_cycles = sysclk_hz.saturating_mul(UART_OVERRUN_LOG_PERIOD_SECS);
327 let uart6_config = Config::default().baudrate(UART6_BAUD.bps());
328 let uart6 = SerialWrapper::new(
329 dp.USART6
330 .serial(
331 (gpioc.pc6.into_alternate(), gpioc.pc7.into_alternate()),
332 uart6_config,
333 ccdr.peripheral.USART6,
334 &ccdr.clocks,
335 )
336 .map_err(|_| CuError::from("uart6 init failed"))?,
337 "UART6",
338 overrun_period_cycles,
339 );
340
341 let uart2_baud = match _config {
342 Some(cfg) => cfg.get::<u32>("uart2_baud")?.unwrap_or(UART2_BAUD),
343 None => UART2_BAUD,
344 };
345 let uart2_config = Config::default().baudrate(uart2_baud.bps());
346 let uart2 = SerialWrapper::new(
347 dp.USART2
348 .serial(
349 (gpioa.pa2.into_alternate(), gpioa.pa3.into_alternate()),
350 uart2_config,
351 ccdr.peripheral.USART2,
352 &ccdr.clocks,
353 )
354 .map_err(|_| CuError::from("uart2 init failed"))?,
355 "UART2",
356 overrun_period_cycles,
357 );
358
359 let uart4_baud = match _config {
360 Some(cfg) => cfg.get::<u32>("uart4_baud")?.unwrap_or(UART4_BAUD),
361 None => UART4_BAUD,
362 };
363 let uart4_config = Config::default().baudrate(uart4_baud.bps());
364 let uart4 = SerialWrapper::new(
365 dp.UART4
366 .serial(
367 (gpioa.pa0.into_alternate(), gpioa.pa1.into_alternate()),
368 uart4_config,
369 ccdr.peripheral.UART4,
370 &ccdr.clocks,
371 )
372 .map_err(|_| CuError::from("uart4 init failed"))?,
373 "UART4",
374 overrun_period_cycles,
375 );
376
377 let logger = init_sd_logger(
378 dp.SDMMC1,
379 sdmmc1_rec,
380 &ccdr.clocks,
381 (
382 gpioc.pc12.into_alternate::<12>().speed(Speed::VeryHigh),
383 gpiod.pd2.into_alternate::<12>().speed(Speed::VeryHigh),
384 gpioc.pc8.into_alternate::<12>().speed(Speed::VeryHigh),
385 gpioc.pc9.into_alternate::<12>().speed(Speed::VeryHigh),
386 gpioc.pc10.into_alternate::<12>().speed(Speed::VeryHigh),
387 gpioc.pc11.into_alternate::<12>().speed(Speed::VeryHigh),
388 ),
389 )?;
390
391 let sck = gpiod.pd3.into_alternate::<5>().speed(Speed::VeryHigh);
392 let miso = gpioc.pc2.into_alternate::<5>().speed(Speed::VeryHigh);
393 let mosi = gpioc.pc3.into_alternate::<5>().speed(Speed::VeryHigh);
394 let mut bmi088_acc_cs = gpiod.pd4.into_push_pull_output();
395 let mut bmi088_gyr_cs = gpiod.pd5.into_push_pull_output();
396 bmi088_acc_cs.set_high();
397 bmi088_gyr_cs.set_high();
398
399 let spi_cfg = SpiConfig::new(Mode {
400 polarity: Polarity::IdleHigh,
401 phase: Phase::CaptureOnSecondTransition,
402 });
403 let bmi088_spi: stm32h7xx_hal::spi::Spi<pac::SPI2, stm32h7xx_hal::spi::Enabled, u8> =
404 dp.SPI2.spi(
405 (sck, miso, mosi),
406 spi_cfg,
407 10.MHz(),
408 ccdr.peripheral.SPI2,
409 &ccdr.clocks,
410 );
411
412 let bmi088_spi = SingleThreaded::new(bmi088_spi);
413 let bmi088_acc_cs = SingleThreaded::new(bmi088_acc_cs);
414 let bmi088_gyr_cs = SingleThreaded::new(bmi088_gyr_cs);
415 let bmi088_delay = SingleThreaded::new(delay);
416
417 let bdshot_resources = Stm32H7BoardResources {
418 m1: gpioe.pe14,
419 m2: gpioe.pe13,
420 m3: gpioe.pe11,
421 m4: gpioe.pe9,
422 dwt,
423 sysclk_hz,
424 };
425 let bdshot_board = Stm32H7Board::new(bdshot_resources)?;
426 register_stm32h7_board(bdshot_board)?;
427
428 let uart6_key = bundle.key(MicoAirH743Id::Uart6);
429 let uart2_key = bundle.key(MicoAirH743Id::Uart2);
430 let uart4_key = bundle.key(MicoAirH743Id::Uart4);
431 let led_key = bundle.key(MicoAirH743Id::GreenLed);
432 let logger_key = bundle.key(MicoAirH743Id::Logger);
433 let bmi088_spi_key = bundle.key(MicoAirH743Id::Bmi088Spi);
434 let bmi088_acc_cs_key = bundle.key(MicoAirH743Id::Bmi088AccCs);
435 let bmi088_gyr_cs_key = bundle.key(MicoAirH743Id::Bmi088GyrCs);
436 let bmi088_delay_key = bundle.key(MicoAirH743Id::Bmi088Delay);
437 let battery_adc_key = bundle.key(MicoAirH743Id::BatteryAdc);
438
439 manager.add_owned(uart6_key, uart6)?;
440 manager.add_owned(uart2_key, uart2)?;
441 manager.add_owned(uart4_key, uart4)?;
442 manager.add_owned(led_key, Mutex::new(green_led))?;
443 manager.add_owned(logger_key, logger)?;
444 manager.add_owned(bmi088_spi_key, bmi088_spi)?;
445 manager.add_owned(bmi088_acc_cs_key, bmi088_acc_cs)?;
446 manager.add_owned(bmi088_gyr_cs_key, bmi088_gyr_cs)?;
447 manager.add_owned(bmi088_delay_key, bmi088_delay)?;
448 manager.add_owned(battery_adc_key, battery_adc)?;
449 Ok(())
450 }
451}