1#![no_std]
10#![no_main]
11#![deny(missing_docs)]
12
13use core::ptr::addr_of_mut;
14
15use capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm;
16use components::gpio::GpioComponent;
17use kernel::capabilities;
18use kernel::component::Component;
19use kernel::debug::PanicResources;
20use kernel::hil::gpio::Configure;
21use kernel::hil::led::LedHigh;
22use kernel::platform::{KernelResources, SyscallDriverLookup};
23use kernel::scheduler::round_robin::RoundRobinSched;
24use kernel::utilities::single_thread_value::SingleThreadValue;
25use kernel::{create_capability, debug, static_init};
26use stm32f446re::chip_specs::Stm32f446Specs;
27use stm32f446re::clocks::hsi::HSI_FREQUENCY_MHZ;
28use stm32f446re::gpio::{AlternateFunction, Mode, PinId, PortId};
29use stm32f446re::interrupt_service::Stm32f446reDefaultPeripherals;
30
31pub mod io;
33
34#[allow(dead_code)]
36mod virtual_uart_rx_test;
37
38const NUM_PROCS: usize = 4;
40
41type ChipHw = stm32f446re::chip::Stm32f4xx<'static, Stm32f446reDefaultPeripherals<'static>>;
42type ProcessPrinterInUse = capsules_system::process_printer::ProcessPrinterText;
43
44static PANIC_RESOURCES: SingleThreadValue<PanicResources<ChipHw, ProcessPrinterInUse>> =
46 SingleThreadValue::new(PanicResources::new());
47
48const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
50 capsules_system::process_policies::PanicFaultPolicy {};
51
52kernel::stack_size! {0x2000}
53
54type TemperatureSTMSensor = components::temperature_stm::TemperatureSTMComponentType<
55 capsules_core::virtualizers::virtual_adc::AdcDevice<'static, stm32f446re::adc::Adc<'static>>,
56>;
57type TemperatureDriver = components::temperature::TemperatureComponentType<TemperatureSTMSensor>;
58
59struct NucleoF446RE {
62 console: &'static capsules_core::console::Console<'static>,
63 ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
64 led: &'static capsules_core::led::LedDriver<
65 'static,
66 LedHigh<'static, stm32f446re::gpio::Pin<'static>>,
67 1,
68 >,
69 button: &'static capsules_core::button::Button<'static, stm32f446re::gpio::Pin<'static>>,
70 adc: &'static capsules_core::adc::AdcVirtualized<'static>,
71 alarm: &'static capsules_core::alarm::AlarmDriver<
72 'static,
73 VirtualMuxAlarm<'static, stm32f446re::tim2::Tim2<'static>>,
74 >,
75
76 temperature: &'static TemperatureDriver,
77 gpio: &'static capsules_core::gpio::GPIO<'static, stm32f446re::gpio::Pin<'static>>,
78
79 scheduler: &'static RoundRobinSched<'static>,
80 systick: cortexm4::systick::SysTick,
81}
82
83impl SyscallDriverLookup for NucleoF446RE {
85 fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
86 where
87 F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
88 {
89 match driver_num {
90 capsules_core::console::DRIVER_NUM => f(Some(self.console)),
91 capsules_core::led::DRIVER_NUM => f(Some(self.led)),
92 capsules_core::button::DRIVER_NUM => f(Some(self.button)),
93 capsules_core::adc::DRIVER_NUM => f(Some(self.adc)),
94 capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
95 capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)),
96 capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
97 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
98 _ => f(None),
99 }
100 }
101}
102
103impl
104 KernelResources<
105 stm32f446re::chip::Stm32f4xx<
106 'static,
107 stm32f446re::interrupt_service::Stm32f446reDefaultPeripherals<'static>,
108 >,
109 > for NucleoF446RE
110{
111 type SyscallDriverLookup = Self;
112 type SyscallFilter = ();
113 type ProcessFault = ();
114 type Scheduler = RoundRobinSched<'static>;
115 type SchedulerTimer = cortexm4::systick::SysTick;
116 type WatchDog = ();
117 type ContextSwitchCallback = ();
118
119 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
120 self
121 }
122 fn syscall_filter(&self) -> &Self::SyscallFilter {
123 &()
124 }
125 fn process_fault(&self) -> &Self::ProcessFault {
126 &()
127 }
128 fn scheduler(&self) -> &Self::Scheduler {
129 self.scheduler
130 }
131 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
132 &self.systick
133 }
134 fn watchdog(&self) -> &Self::WatchDog {
135 &()
136 }
137 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
138 &()
139 }
140}
141
142unsafe fn setup_dma(
144 dma: &stm32f446re::dma::Dma1,
145 dma_streams: &'static [stm32f446re::dma::Stream<stm32f446re::dma::Dma1>; 8],
146 usart2: &'static stm32f446re::usart::Usart<stm32f446re::dma::Dma1>,
147) {
148 use stm32f446re::dma::Dma1Peripheral;
149 use stm32f446re::usart;
150
151 dma.enable_clock();
152
153 let usart2_tx_stream = &dma_streams[Dma1Peripheral::USART2_TX.get_stream_idx()];
154 let usart2_rx_stream = &dma_streams[Dma1Peripheral::USART2_RX.get_stream_idx()];
155
156 usart2.set_dma(
157 usart::TxDMA(usart2_tx_stream),
158 usart::RxDMA(usart2_rx_stream),
159 );
160
161 usart2_tx_stream.set_client(usart2);
162 usart2_rx_stream.set_client(usart2);
163
164 usart2_tx_stream.setup(Dma1Peripheral::USART2_TX);
165 usart2_rx_stream.setup(Dma1Peripheral::USART2_RX);
166
167 cortexm4::nvic::Nvic::new(Dma1Peripheral::USART2_TX.get_stream_irqn()).enable();
168 cortexm4::nvic::Nvic::new(Dma1Peripheral::USART2_RX.get_stream_irqn()).enable();
169}
170
171unsafe fn set_pin_primary_functions(
173 syscfg: &stm32f446re::syscfg::Syscfg,
174 gpio_ports: &'static stm32f446re::gpio::GpioPorts<'static>,
175) {
176 syscfg.enable_clock();
177
178 gpio_ports.get_port_from_port_id(PortId::A).enable_clock();
179 gpio_ports.get_port_from_port_id(PortId::B).enable_clock();
180
181 gpio_ports.get_pin(PinId::PA05).map(|pin| {
183 pin.make_output();
184
185 let debug_gpios = static_init!([&'static dyn kernel::hil::gpio::Pin; 1], [pin]);
187 kernel::debug::initialize_debug_gpio::<
188 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
189 >();
190 kernel::debug::assign_gpios(debug_gpios);
191 });
192
193 gpio_ports.get_pin(PinId::PA02).map(|pin| {
195 pin.set_mode(Mode::AlternateFunctionMode);
196 pin.set_alternate_function(AlternateFunction::AF7);
198 });
199 gpio_ports.get_pin(PinId::PA03).map(|pin| {
200 pin.set_mode(Mode::AlternateFunctionMode);
201 pin.set_alternate_function(AlternateFunction::AF7);
203 });
204
205 gpio_ports.get_port_from_port_id(PortId::C).enable_clock();
206
207 gpio_ports.get_pin(PinId::PC13).map(|pin| {
209 pin.enable_interrupt();
210 });
211
212 gpio_ports.get_pin(PinId::PA10).map(|pin| {
214 pin.enable_interrupt();
215 });
216
217 gpio_ports.get_pin(PinId::PA00).map(|pin| {
219 pin.set_mode(stm32f446re::gpio::Mode::AnalogMode);
220 });
221
222 gpio_ports.get_pin(PinId::PA01).map(|pin| {
224 pin.set_mode(stm32f446re::gpio::Mode::AnalogMode);
225 });
226
227 gpio_ports.get_pin(PinId::PA04).map(|pin| {
229 pin.set_mode(stm32f446re::gpio::Mode::AnalogMode);
230 });
231
232 gpio_ports.get_pin(PinId::PB00).map(|pin| {
234 pin.set_mode(stm32f446re::gpio::Mode::AnalogMode);
235 });
236
237 gpio_ports.get_pin(PinId::PC01).map(|pin| {
239 pin.set_mode(stm32f446re::gpio::Mode::AnalogMode);
240 });
241
242 gpio_ports.get_pin(PinId::PC00).map(|pin| {
244 pin.set_mode(stm32f446re::gpio::Mode::AnalogMode);
245 });
246}
247
248unsafe fn setup_peripherals(tim2: &stm32f446re::tim2::Tim2) {
250 cortexm4::nvic::Nvic::new(stm32f446re::nvic::USART2).enable();
252
253 tim2.enable_clock();
255 tim2.start();
256 cortexm4::nvic::Nvic::new(stm32f446re::nvic::TIM2).enable();
257}
258
259#[inline(never)]
263unsafe fn start() -> (
264 &'static kernel::Kernel,
265 NucleoF446RE,
266 &'static stm32f446re::chip::Stm32f4xx<'static, Stm32f446reDefaultPeripherals<'static>>,
267) {
268 stm32f446re::init();
269
270 kernel::deferred_call::initialize_deferred_call_state::<
272 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
273 >();
274
275 PANIC_RESOURCES.bind_to_thread::<<ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider>();
277
278 let rcc = static_init!(stm32f446re::rcc::Rcc, stm32f446re::rcc::Rcc::new());
280 let clocks = static_init!(
281 stm32f446re::clocks::Clocks<Stm32f446Specs>,
282 stm32f446re::clocks::Clocks::new(rcc)
283 );
284
285 let syscfg = static_init!(
286 stm32f446re::syscfg::Syscfg,
287 stm32f446re::syscfg::Syscfg::new(clocks)
288 );
289 let exti = static_init!(
290 stm32f446re::exti::Exti,
291 stm32f446re::exti::Exti::new(syscfg)
292 );
293 let dma1 = static_init!(stm32f446re::dma::Dma1, stm32f446re::dma::Dma1::new(clocks));
294 let dma2 = static_init!(stm32f446re::dma::Dma2, stm32f446re::dma::Dma2::new(clocks));
295
296 let peripherals = static_init!(
297 Stm32f446reDefaultPeripherals,
298 Stm32f446reDefaultPeripherals::new(clocks, exti, dma1, dma2)
299 );
300 peripherals.init();
301 let base_peripherals = &peripherals.stm32f4;
302
303 setup_peripherals(&base_peripherals.tim2);
304
305 set_pin_primary_functions(syscfg, &base_peripherals.gpio_ports);
306
307 setup_dma(
308 dma1,
309 &base_peripherals.dma1_streams,
310 &base_peripherals.usart2,
311 );
312
313 let processes = components::process_array::ProcessArrayComponent::new()
315 .finalize(components::process_array_component_static!(NUM_PROCS));
316 PANIC_RESOURCES.get().map(|resources| {
317 resources.processes.put(processes.as_slice());
318 });
319
320 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
322
323 let chip = static_init!(
324 stm32f446re::chip::Stm32f4xx<Stm32f446reDefaultPeripherals>,
325 stm32f446re::chip::Stm32f4xx::new(peripherals)
326 );
327 PANIC_RESOURCES.get().map(|resources| {
328 resources.chip.put(chip);
329 });
330
331 base_peripherals.usart2.enable_clock();
335 let uart_mux = components::console::UartMuxComponent::new(&base_peripherals.usart2, 115200)
336 .finalize(components::uart_mux_component_static!());
337
338 (*addr_of_mut!(io::WRITER)).set_initialized();
341
342 let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
345 let process_management_capability =
346 create_capability!(capabilities::ProcessManagementCapability);
347
348 let console = components::console::ConsoleComponent::new(
350 board_kernel,
351 capsules_core::console::DRIVER_NUM,
352 uart_mux,
353 )
354 .finalize(components::console_component_static!());
355 components::debug_writer::DebugWriterComponent::new::<
357 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
358 >(
359 uart_mux,
360 create_capability!(capabilities::SetDebugWriterCapability),
361 )
362 .finalize(components::debug_writer_component_static!());
363
364 let gpio_ports = &base_peripherals.gpio_ports;
366
367 let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
369 LedHigh<'static, stm32f446re::gpio::Pin>,
370 LedHigh::new(gpio_ports.get_pin(stm32f446re::gpio::PinId::PA05).unwrap()),
371 ));
372
373 let button = components::button::ButtonComponent::new(
375 board_kernel,
376 capsules_core::button::DRIVER_NUM,
377 components::button_component_helper!(
378 stm32f446re::gpio::Pin,
379 (
380 gpio_ports.get_pin(stm32f446re::gpio::PinId::PC13).unwrap(),
381 kernel::hil::gpio::ActivationMode::ActiveLow,
382 kernel::hil::gpio::FloatingState::PullNone
383 )
384 ),
385 )
386 .finalize(components::button_component_static!(stm32f446re::gpio::Pin));
387
388 let tim2 = &base_peripherals.tim2;
390 let mux_alarm = components::alarm::AlarmMuxComponent::new(tim2).finalize(
391 components::alarm_mux_component_static!(stm32f446re::tim2::Tim2),
392 );
393
394 let alarm = components::alarm::AlarmDriverComponent::new(
395 board_kernel,
396 capsules_core::alarm::DRIVER_NUM,
397 mux_alarm,
398 )
399 .finalize(components::alarm_component_static!(stm32f446re::tim2::Tim2));
400
401 let adc_mux = components::adc::AdcMuxComponent::new(&base_peripherals.adc1)
403 .finalize(components::adc_mux_component_static!(stm32f446re::adc::Adc));
404
405 let temp_sensor = components::temperature_stm::TemperatureSTMComponent::new(
406 adc_mux,
407 stm32f446re::adc::Channel::Channel18,
408 2.5,
409 0.76,
410 )
411 .finalize(components::temperature_stm_adc_component_static!(
412 stm32f446re::adc::Adc
413 ));
414
415 let temp = components::temperature::TemperatureComponent::new(
416 board_kernel,
417 capsules_extra::temperature::DRIVER_NUM,
418 temp_sensor,
419 )
420 .finalize(components::temperature_component_static!(
421 TemperatureSTMSensor
422 ));
423
424 let adc_channel_0 =
425 components::adc::AdcComponent::new(adc_mux, stm32f446re::adc::Channel::Channel0)
426 .finalize(components::adc_component_static!(stm32f446re::adc::Adc));
427
428 let adc_channel_1 =
429 components::adc::AdcComponent::new(adc_mux, stm32f446re::adc::Channel::Channel1)
430 .finalize(components::adc_component_static!(stm32f446re::adc::Adc));
431
432 let adc_channel_2 =
433 components::adc::AdcComponent::new(adc_mux, stm32f446re::adc::Channel::Channel4)
434 .finalize(components::adc_component_static!(stm32f446re::adc::Adc));
435
436 let adc_channel_3 =
437 components::adc::AdcComponent::new(adc_mux, stm32f446re::adc::Channel::Channel8)
438 .finalize(components::adc_component_static!(stm32f446re::adc::Adc));
439
440 let adc_channel_4 =
441 components::adc::AdcComponent::new(adc_mux, stm32f446re::adc::Channel::Channel11)
442 .finalize(components::adc_component_static!(stm32f446re::adc::Adc));
443
444 let adc_channel_5 =
445 components::adc::AdcComponent::new(adc_mux, stm32f446re::adc::Channel::Channel10)
446 .finalize(components::adc_component_static!(stm32f446re::adc::Adc));
447
448 let adc_syscall =
449 components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM)
450 .finalize(components::adc_syscall_component_helper!(
451 adc_channel_0,
452 adc_channel_1,
453 adc_channel_2,
454 adc_channel_3,
455 adc_channel_4,
456 adc_channel_5
457 ));
458
459 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
460 .finalize(components::process_printer_text_component_static!());
461 PANIC_RESOURCES.get().map(|resources| {
462 resources.printer.put(process_printer);
463 });
464
465 let gpio = GpioComponent::new(
467 board_kernel,
468 capsules_core::gpio::DRIVER_NUM,
469 components::gpio_component_helper!(
470 stm32f446re::gpio::Pin,
471 2 => gpio_ports.get_pin(PinId::PA10).unwrap(), 3 => gpio_ports.get_pin(PinId::PB03).unwrap(), 4 => gpio_ports.get_pin(PinId::PB05).unwrap(), 5 => gpio_ports.get_pin(PinId::PB04).unwrap(), 6 => gpio_ports.get_pin(PinId::PB10).unwrap(), 7 => gpio_ports.get_pin(PinId::PA08).unwrap(), 8 => gpio_ports.get_pin(PinId::PA09).unwrap(), 9 => gpio_ports.get_pin(PinId::PC07).unwrap(), 10 => gpio_ports.get_pin(PinId::PB06).unwrap(), 11 => gpio_ports.get_pin(PinId::PA07).unwrap(), 12 => gpio_ports.get_pin(PinId::PA06).unwrap(), 13 => gpio_ports.get_pin(PinId::PA05).unwrap(), 14 => gpio_ports.get_pin(PinId::PB09).unwrap(), 15 => gpio_ports.get_pin(PinId::PB08).unwrap(), ),
498 )
499 .finalize(components::gpio_component_static!(stm32f446re::gpio::Pin));
500
501 let process_console = components::process_console::ProcessConsoleComponent::new(
503 board_kernel,
504 uart_mux,
505 mux_alarm,
506 process_printer,
507 Some(cortexm4::support::reset),
508 )
509 .finalize(components::process_console_component_static!(
510 stm32f446re::tim2::Tim2
511 ));
512 let _ = process_console.start();
513
514 let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
515 .finalize(components::round_robin_component_static!(NUM_PROCS));
516
517 let nucleo_f446re = NucleoF446RE {
518 console,
519 ipc: kernel::ipc::IPC::new(
520 board_kernel,
521 kernel::ipc::DRIVER_NUM,
522 &memory_allocation_capability,
523 ),
524 led,
525 button,
526 adc: adc_syscall,
527 alarm,
528
529 temperature: temp,
530 gpio,
531
532 scheduler,
533 systick: cortexm4::systick::SysTick::new_with_calibration(
534 (HSI_FREQUENCY_MHZ * 1_000_000) as u32,
535 ),
536 };
537
538 debug!("Initialization complete. Entering main loop");
544
545 extern "C" {
547 static _sapps: u8;
549 static _eapps: u8;
551 static mut _sappmem: u8;
553 static _eappmem: u8;
555 }
556
557 kernel::process::load_processes(
558 board_kernel,
559 chip,
560 core::slice::from_raw_parts(
561 core::ptr::addr_of!(_sapps),
562 core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
563 ),
564 core::slice::from_raw_parts_mut(
565 core::ptr::addr_of_mut!(_sappmem),
566 core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
567 ),
568 &FAULT_RESPONSE,
569 &process_management_capability,
570 )
571 .unwrap_or_else(|err| {
572 debug!("Error loading processes!");
573 debug!("{:?}", err);
574 });
575
576 (board_kernel, nucleo_f446re, chip)
582}
583
584#[no_mangle]
586pub unsafe fn main() {
587 let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
588
589 let (board_kernel, platform, chip) = start();
590 board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
591}