1#![no_std]
14#![no_main]
15
16mod fcb;
17mod io;
18
19use imxrt1060::gpio::PinId;
20use imxrt1060::iomuxc::{MuxMode, PadId, Sion};
21use imxrt10xx as imxrt1060;
22use kernel::capabilities;
23use kernel::component::Component;
24use kernel::hil::{gpio::Configure, led::LedHigh};
25use kernel::platform::chip::ClockInterface;
26use kernel::platform::{KernelResources, SyscallDriverLookup};
27use kernel::process::ProcessArray;
28use kernel::scheduler::round_robin::RoundRobinSched;
29use kernel::{create_capability, static_init};
30
31const NUM_PROCS: usize = 4;
33
34static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
36const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
38 capsules_system::process_policies::PanicFaultPolicy {};
39
40struct Teensy40 {
42 led: &'static capsules_core::led::LedDriver<
43 'static,
44 LedHigh<'static, imxrt1060::gpio::Pin<'static>>,
45 1,
46 >,
47 console: &'static capsules_core::console::Console<'static>,
48 ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
49 alarm: &'static capsules_core::alarm::AlarmDriver<
50 'static,
51 capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
52 'static,
53 imxrt1060::gpt::Gpt1<'static>,
54 >,
55 >,
56
57 scheduler: &'static RoundRobinSched<'static>,
58 systick: cortexm7::systick::SysTick,
59}
60
61impl SyscallDriverLookup for Teensy40 {
62 fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
63 where
64 F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
65 {
66 match driver_num {
67 capsules_core::led::DRIVER_NUM => f(Some(self.led)),
68 capsules_core::console::DRIVER_NUM => f(Some(self.console)),
69 kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
70 capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
71 _ => f(None),
72 }
73 }
74}
75
76impl KernelResources<imxrt1060::chip::Imxrt10xx<imxrt1060::chip::Imxrt10xxDefaultPeripherals>>
77 for Teensy40
78{
79 type SyscallDriverLookup = Self;
80 type SyscallFilter = ();
81 type ProcessFault = ();
82 type Scheduler = RoundRobinSched<'static>;
83 type SchedulerTimer = cortexm7::systick::SysTick;
84 type WatchDog = ();
85 type ContextSwitchCallback = ();
86
87 fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
88 self
89 }
90 fn syscall_filter(&self) -> &Self::SyscallFilter {
91 &()
92 }
93 fn process_fault(&self) -> &Self::ProcessFault {
94 &()
95 }
96 fn scheduler(&self) -> &Self::Scheduler {
97 self.scheduler
98 }
99 fn scheduler_timer(&self) -> &Self::SchedulerTimer {
100 &self.systick
101 }
102 fn watchdog(&self) -> &Self::WatchDog {
103 &()
104 }
105 fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
106 &()
107 }
108}
109
110mod dma_config {
114 use super::imxrt1060::nvic;
115
116 pub const LPUART2_RX: usize = 7;
118 pub const LPUART2_TX: usize = 8;
120
121 const DMA_INTERRUPTS: &[u32] = &[nvic::DMA7_23, nvic::DMA8_24];
123
124 #[inline(always)]
126 pub fn enable_interrupts() {
127 DMA_INTERRUPTS
128 .iter()
129 .copied()
130 .map(|vector| unsafe { cortexm7::nvic::Nvic::new(vector) })
132 .for_each(|intr| intr.enable());
133 }
134}
135
136type ChipHw = imxrt1060::chip::Imxrt10xx<imxrt1060::chip::Imxrt10xxDefaultPeripherals>;
137static mut CHIP: Option<&'static ChipHw> = None;
138static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
139 None;
140
141fn set_arm_clock(ccm: &imxrt1060::ccm::Ccm, ccm_analog: &imxrt1060::ccm_analog::CcmAnalog) {
146 use imxrt1060::ccm::{
147 PeripheralClock2Selection, PeripheralClockSelection, PrePeripheralClockSelection,
148 };
149
150 ccm.set_peripheral_clock2_divider(1);
152 ccm.set_peripheral_clock2_selection(PeripheralClock2Selection::Oscillator);
153 ccm.set_peripheral_clock_selection(PeripheralClockSelection::PeripheralClock2Divided);
154
155 ccm_analog.restart_pll1(100);
162
163 ccm.set_arm_divider(2);
166
167 ccm.set_ahb_divider(1);
169
170 ccm.set_pre_peripheral_clock_selection(PrePeripheralClockSelection::Pll1);
172 ccm.set_peripheral_clock_selection(PeripheralClockSelection::PrePeripheralClock);
173}
174
175#[inline(never)]
179unsafe fn start() -> (&'static kernel::Kernel, Teensy40, &'static ChipHw) {
180 imxrt1060::init();
181
182 kernel::deferred_call::initialize_deferred_call_state::<
184 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
185 >();
186
187 let ccm = static_init!(imxrt1060::ccm::Ccm, imxrt1060::ccm::Ccm::new());
188 let peripherals = static_init!(
189 imxrt1060::chip::Imxrt10xxDefaultPeripherals,
190 imxrt1060::chip::Imxrt10xxDefaultPeripherals::new(ccm)
191 );
192
193 peripherals.ccm.set_low_power_mode();
194
195 peripherals.dcdc.clock().enable();
196 peripherals.dcdc.set_target_vdd_soc(1250);
197 set_arm_clock(peripherals.ccm, &peripherals.ccm_analog);
198 peripherals.ccm.set_ipg_divider(4);
200
201 peripherals.lpuart1.disable_clock();
202 peripherals.lpuart2.disable_clock();
203 peripherals
204 .ccm
205 .set_uart_clock_sel(imxrt1060::ccm::UartClockSelection::PLL3);
206 peripherals.ccm.set_uart_clock_podf(1);
207
208 peripherals.ccm.enable_iomuxc_clock();
209 peripherals.ccm.enable_iomuxc_snvs_clock();
210
211 peripherals
212 .ccm
213 .set_perclk_sel(imxrt1060::ccm::PerclkClockSel::Oscillator);
214 peripherals.ccm.set_perclk_divider(8);
215
216 peripherals.ports.pin(PinId::B0_03).make_output();
217
218 peripherals
220 .iomuxc
221 .enable_sw_mux_ctl_pad_gpio(PadId::B0, MuxMode::ALT5, Sion::Disabled, 3);
222
223 peripherals
225 .iomuxc
226 .enable_sw_mux_ctl_pad_gpio(PadId::AdB1, MuxMode::ALT2, Sion::Disabled, 2);
227 peripherals
228 .iomuxc
229 .enable_sw_mux_ctl_pad_gpio(PadId::AdB1, MuxMode::ALT2, Sion::Disabled, 3);
230
231 peripherals.iomuxc.enable_lpuart2_tx_select_input();
232 peripherals.iomuxc.enable_lpuart2_rx_select_input();
233
234 peripherals.lpuart2.enable_clock();
235 peripherals.lpuart2.set_baud();
236
237 peripherals.gpt1.enable_clock();
238 peripherals.gpt1.start(
239 peripherals.ccm.perclk_sel(),
240 peripherals.ccm.perclk_divider(),
241 );
242
243 peripherals.dma.clock().enable();
244 peripherals.dma.reset_tcds();
245 peripherals
246 .lpuart2
247 .set_rx_dma_channel(&peripherals.dma.channels[dma_config::LPUART2_RX]);
248 peripherals
249 .lpuart2
250 .set_tx_dma_channel(&peripherals.dma.channels[dma_config::LPUART2_TX]);
251
252 cortexm7::nvic::Nvic::new(imxrt1060::nvic::GPT1).enable();
253 dma_config::enable_interrupts();
254
255 let chip = static_init!(ChipHw, ChipHw::new(peripherals));
256 CHIP = Some(chip);
257
258 let processes = components::process_array::ProcessArrayComponent::new()
262 .finalize(components::process_array_component_static!(NUM_PROCS));
263 PROCESSES = Some(processes);
264
265 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
267
268 let uart_mux = components::console::UartMuxComponent::new(&peripherals.lpuart2, 115_200)
271 .finalize(components::uart_mux_component_static!());
272 components::debug_writer::DebugWriterComponent::new::<
274 <ChipHw as kernel::platform::chip::Chip>::ThreadIdProvider,
275 >(
276 uart_mux,
277 create_capability!(capabilities::SetDebugWriterCapability),
278 )
279 .finalize(components::debug_writer_component_static!());
280
281 let console = components::console::ConsoleComponent::new(
283 board_kernel,
284 capsules_core::console::DRIVER_NUM,
285 uart_mux,
286 )
287 .finalize(components::console_component_static!());
288
289 let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
291 LedHigh<imxrt1060::gpio::Pin>,
292 LedHigh::new(peripherals.ports.pin(PinId::B0_03))
293 ));
294
295 let mux_alarm = components::alarm::AlarmMuxComponent::new(&peripherals.gpt1).finalize(
297 components::alarm_mux_component_static!(imxrt1060::gpt::Gpt1),
298 );
299 let alarm = components::alarm::AlarmDriverComponent::new(
300 board_kernel,
301 capsules_core::alarm::DRIVER_NUM,
302 mux_alarm,
303 )
304 .finalize(components::alarm_component_static!(imxrt1060::gpt::Gpt1));
305
306 let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
310 let process_management_capability =
311 create_capability!(capabilities::ProcessManagementCapability);
312
313 let ipc = kernel::ipc::IPC::new(
314 board_kernel,
315 kernel::ipc::DRIVER_NUM,
316 &memory_allocation_capability,
317 );
318
319 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
320 .finalize(components::process_printer_text_component_static!());
321 PROCESS_PRINTER = Some(process_printer);
322
323 let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
324 .finalize(components::round_robin_component_static!(NUM_PROCS));
325
326 let teensy40 = Teensy40 {
330 led,
331 console,
332 ipc,
333 alarm,
334
335 scheduler,
336 systick: cortexm7::systick::SysTick::new_with_calibration(792_000_000),
337 };
338
339 extern "C" {
343 static _sapps: u8;
347 static _eapps: u8;
351 static mut _sappmem: u8;
353 static _eappmem: u8;
355 }
356
357 kernel::process::load_processes(
358 board_kernel,
359 chip,
360 core::slice::from_raw_parts(
361 core::ptr::addr_of!(_sapps),
362 core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
363 ),
364 core::slice::from_raw_parts_mut(
365 core::ptr::addr_of_mut!(_sappmem),
366 core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
367 ),
368 &FAULT_RESPONSE,
369 &process_management_capability,
370 )
371 .unwrap();
372
373 (board_kernel, teensy40, chip)
374}
375
376#[no_mangle]
378pub unsafe fn main() {
379 let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
380
381 let (board_kernel, platform, chip) = start();
382 board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
383}
384
385kernel::stack_size! {0x2000}
386
387const FCB_SIZE: usize = core::mem::size_of::<fcb::FCB>();
388
389#[cfg_attr(not(target_os = "macos"), link_section = ".fcb_buffer")]
401#[no_mangle]
402#[used]
403static mut FCB_BUFFER: [u8; 0x1000 - FCB_SIZE] = [0xFF; 0x1000 - FCB_SIZE];