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 Chip = imxrt1060::chip::Imxrt10xx<imxrt1060::chip::Imxrt10xxDefaultPeripherals>;
137static mut CHIP: Option<&'static Chip> = 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 Chip) {
180 imxrt1060::init();
181
182 let ccm = static_init!(imxrt1060::ccm::Ccm, imxrt1060::ccm::Ccm::new());
183 let peripherals = static_init!(
184 imxrt1060::chip::Imxrt10xxDefaultPeripherals,
185 imxrt1060::chip::Imxrt10xxDefaultPeripherals::new(ccm)
186 );
187
188 peripherals.ccm.set_low_power_mode();
189
190 peripherals.dcdc.clock().enable();
191 peripherals.dcdc.set_target_vdd_soc(1250);
192 set_arm_clock(peripherals.ccm, &peripherals.ccm_analog);
193 peripherals.ccm.set_ipg_divider(4);
195
196 peripherals.lpuart1.disable_clock();
197 peripherals.lpuart2.disable_clock();
198 peripherals
199 .ccm
200 .set_uart_clock_sel(imxrt1060::ccm::UartClockSelection::PLL3);
201 peripherals.ccm.set_uart_clock_podf(1);
202
203 peripherals.ccm.enable_iomuxc_clock();
204 peripherals.ccm.enable_iomuxc_snvs_clock();
205
206 peripherals
207 .ccm
208 .set_perclk_sel(imxrt1060::ccm::PerclkClockSel::Oscillator);
209 peripherals.ccm.set_perclk_divider(8);
210
211 peripherals.ports.pin(PinId::B0_03).make_output();
212
213 peripherals
215 .iomuxc
216 .enable_sw_mux_ctl_pad_gpio(PadId::B0, MuxMode::ALT5, Sion::Disabled, 3);
217
218 peripherals
220 .iomuxc
221 .enable_sw_mux_ctl_pad_gpio(PadId::AdB1, MuxMode::ALT2, Sion::Disabled, 2);
222 peripherals
223 .iomuxc
224 .enable_sw_mux_ctl_pad_gpio(PadId::AdB1, MuxMode::ALT2, Sion::Disabled, 3);
225
226 peripherals.iomuxc.enable_lpuart2_tx_select_input();
227 peripherals.iomuxc.enable_lpuart2_rx_select_input();
228
229 peripherals.lpuart2.enable_clock();
230 peripherals.lpuart2.set_baud();
231
232 peripherals.gpt1.enable_clock();
233 peripherals.gpt1.start(
234 peripherals.ccm.perclk_sel(),
235 peripherals.ccm.perclk_divider(),
236 );
237
238 peripherals.dma.clock().enable();
239 peripherals.dma.reset_tcds();
240 peripherals
241 .lpuart2
242 .set_rx_dma_channel(&peripherals.dma.channels[dma_config::LPUART2_RX]);
243 peripherals
244 .lpuart2
245 .set_tx_dma_channel(&peripherals.dma.channels[dma_config::LPUART2_TX]);
246
247 cortexm7::nvic::Nvic::new(imxrt1060::nvic::GPT1).enable();
248 dma_config::enable_interrupts();
249
250 let chip = static_init!(Chip, Chip::new(peripherals));
251 CHIP = Some(chip);
252
253 let processes = components::process_array::ProcessArrayComponent::new()
257 .finalize(components::process_array_component_static!(NUM_PROCS));
258 PROCESSES = Some(processes);
259
260 let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
262
263 let uart_mux = components::console::UartMuxComponent::new(&peripherals.lpuart2, 115_200)
266 .finalize(components::uart_mux_component_static!());
267 components::debug_writer::DebugWriterComponent::new(
269 uart_mux,
270 create_capability!(capabilities::SetDebugWriterCapability),
271 )
272 .finalize(components::debug_writer_component_static!());
273
274 let console = components::console::ConsoleComponent::new(
276 board_kernel,
277 capsules_core::console::DRIVER_NUM,
278 uart_mux,
279 )
280 .finalize(components::console_component_static!());
281
282 let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
284 LedHigh<imxrt1060::gpio::Pin>,
285 LedHigh::new(peripherals.ports.pin(PinId::B0_03))
286 ));
287
288 let mux_alarm = components::alarm::AlarmMuxComponent::new(&peripherals.gpt1).finalize(
290 components::alarm_mux_component_static!(imxrt1060::gpt::Gpt1),
291 );
292 let alarm = components::alarm::AlarmDriverComponent::new(
293 board_kernel,
294 capsules_core::alarm::DRIVER_NUM,
295 mux_alarm,
296 )
297 .finalize(components::alarm_component_static!(imxrt1060::gpt::Gpt1));
298
299 let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
303 let process_management_capability =
304 create_capability!(capabilities::ProcessManagementCapability);
305
306 let ipc = kernel::ipc::IPC::new(
307 board_kernel,
308 kernel::ipc::DRIVER_NUM,
309 &memory_allocation_capability,
310 );
311
312 let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
313 .finalize(components::process_printer_text_component_static!());
314 PROCESS_PRINTER = Some(process_printer);
315
316 let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
317 .finalize(components::round_robin_component_static!(NUM_PROCS));
318
319 let teensy40 = Teensy40 {
323 led,
324 console,
325 ipc,
326 alarm,
327
328 scheduler,
329 systick: cortexm7::systick::SysTick::new_with_calibration(792_000_000),
330 };
331
332 extern "C" {
336 static _sapps: u8;
340 static _eapps: u8;
344 static mut _sappmem: u8;
346 static _eappmem: u8;
348 }
349
350 kernel::process::load_processes(
351 board_kernel,
352 chip,
353 core::slice::from_raw_parts(
354 core::ptr::addr_of!(_sapps),
355 core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
356 ),
357 core::slice::from_raw_parts_mut(
358 core::ptr::addr_of_mut!(_sappmem),
359 core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
360 ),
361 &FAULT_RESPONSE,
362 &process_management_capability,
363 )
364 .unwrap();
365
366 (board_kernel, teensy40, chip)
367}
368
369#[no_mangle]
371pub unsafe fn main() {
372 let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
373
374 let (board_kernel, platform, chip) = start();
375 board_kernel.kernel_loop(&platform, chip, Some(&platform.ipc), &main_loop_capability);
376}
377
378#[no_mangle]
382#[link_section = ".stack_buffer"]
383#[used]
384static mut STACK_BUFFER: [u8; 0x2000] = [0; 0x2000];
385
386const FCB_SIZE: usize = core::mem::size_of::<fcb::FCB>();
387
388#[no_mangle]
396#[link_section = ".fcb_buffer"]
397#[used]
398static mut FCB_BUFFER: [u8; 0x1000 - FCB_SIZE] = [0xFF; 0x1000 - FCB_SIZE];