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