msp_exp432p401r/
main.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Board file for the MSP-EXP432P401R evaluation board from TI.
6//!
7//! - <https://www.ti.com/tool/MSP-EXP432P401R>
8
9#![no_std]
10#![no_main]
11#![deny(missing_docs)]
12
13use components::gpio::GpioComponent;
14use kernel::capabilities;
15use kernel::component::Component;
16use kernel::hil::gpio::Configure;
17use kernel::platform::{KernelResources, SyscallDriverLookup};
18use kernel::process::ProcessArray;
19use kernel::scheduler::round_robin::RoundRobinSched;
20use kernel::{create_capability, debug, static_init};
21
22/// Support routines for debugging I/O.
23pub mod io;
24
25/// Number of concurrent processes this platform supports.
26const NUM_PROCS: usize = 4;
27
28/// Static variables used by io.rs.
29static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
30
31/// Static reference to chip for panic dumps.
32static mut CHIP: Option<&'static msp432::chip::Msp432<msp432::chip::Msp432DefaultPeripherals>> =
33    None;
34// Static reference to process printer for panic dumps.
35static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
36    None;
37
38/// How should the kernel respond when a process faults.
39const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
40    capsules_system::process_policies::PanicFaultPolicy {};
41
42kernel::stack_size! {0x1000}
43
44/// A structure representing this platform that holds references to all
45/// capsules for this platform.
46struct MspExp432P401R {
47    led: &'static capsules_core::led::LedDriver<
48        'static,
49        kernel::hil::led::LedHigh<'static, msp432::gpio::IntPin<'static>>,
50        3,
51    >,
52    console: &'static capsules_core::console::Console<'static>,
53    button: &'static capsules_core::button::Button<'static, msp432::gpio::IntPin<'static>>,
54    gpio: &'static capsules_core::gpio::GPIO<'static, msp432::gpio::IntPin<'static>>,
55    alarm: &'static capsules_core::alarm::AlarmDriver<
56        'static,
57        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
58            'static,
59            msp432::timer::TimerA<'static>,
60        >,
61    >,
62    ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
63    adc: &'static capsules_core::adc::AdcDedicated<'static, msp432::adc::Adc<'static>>,
64    wdt: &'static msp432::wdt::Wdt,
65    scheduler: &'static RoundRobinSched<'static>,
66    systick: cortexm4::systick::SysTick,
67}
68
69impl KernelResources<msp432::chip::Msp432<'static, msp432::chip::Msp432DefaultPeripherals<'static>>>
70    for MspExp432P401R
71{
72    type SyscallDriverLookup = Self;
73    type SyscallFilter = ();
74    type ProcessFault = ();
75    type Scheduler = RoundRobinSched<'static>;
76    type SchedulerTimer = cortexm4::systick::SysTick;
77    type WatchDog = msp432::wdt::Wdt;
78    type ContextSwitchCallback = ();
79
80    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
81        self
82    }
83    fn syscall_filter(&self) -> &Self::SyscallFilter {
84        &()
85    }
86    fn process_fault(&self) -> &Self::ProcessFault {
87        &()
88    }
89    fn scheduler(&self) -> &Self::Scheduler {
90        self.scheduler
91    }
92    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
93        &self.systick
94    }
95    fn watchdog(&self) -> &Self::WatchDog {
96        self.wdt
97    }
98    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
99        &()
100    }
101}
102
103/// Mapping of integer syscalls to objects that implement syscalls.
104impl SyscallDriverLookup for MspExp432P401R {
105    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
106    where
107        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
108    {
109        match driver_num {
110            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
111            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
112            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
113            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
114            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
115            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
116            capsules_core::adc::DRIVER_NUM => f(Some(self.adc)),
117            _ => f(None),
118        }
119    }
120}
121
122/// Startup initialisation
123///
124/// This code was more or less copied from the code examples of Texas instruments.
125/// It disables the watchdog, enables all RAM banks, configures the chip to the high-power mode
126/// (which is necessary for 48MHz operation) and enables waitstates and buffering in a way that
127/// the flash returns valid data with 48MHz CPU frequency.
128unsafe fn startup_intilialisation() {
129    msp432::init();
130
131    // For now, these peripherals are only used at startup, so we do not
132    // allocate them for the life of the program. If these are later used by the
133    // chip crate (such as for handling interrupts), they will need to be
134    // added to Msp432DefaultPeripherals
135    let wdt = msp432::wdt::Wdt::new();
136    let sysctl = msp432::sysctl::SysCtl::new();
137    let flctl = msp432::flctl::FlCtl::new();
138    let pcm = msp432::pcm::Pcm::new();
139
140    // The watchdog must be disabled, because it is enabled by default on reset and has a
141    // interval of approximately 10ms. See datasheet p. 759, section 17.2.2.
142    // Do this in a separate function which is executed before the kernel is started in order to
143    // make sure that not more than 1 watchdog instances exist at the same time.
144    wdt.disable();
145    sysctl.enable_all_sram_banks();
146    pcm.set_high_power();
147    flctl.set_waitstates(msp432::flctl::WaitStates::_1);
148    flctl.set_buffering(true);
149}
150
151/// Function to setup all ADC-capaable pins
152/// Since the chips has 100 pins, we really setup all capable pins to work as ADC-pins.
153unsafe fn setup_adc_pins(gpio: &msp432::gpio::GpioManager) {
154    use msp432::gpio::{IntPinNr, PinNr};
155    gpio.int_pins[IntPinNr::P05_5 as usize].enable_tertiary_function(); // A0
156    gpio.int_pins[IntPinNr::P05_4 as usize].enable_tertiary_function(); // A1
157    gpio.int_pins[IntPinNr::P05_3 as usize].enable_tertiary_function(); // A2
158    gpio.int_pins[IntPinNr::P05_2 as usize].enable_tertiary_function(); // A3
159    gpio.int_pins[IntPinNr::P05_1 as usize].enable_tertiary_function(); // A4
160    gpio.int_pins[IntPinNr::P05_0 as usize].enable_tertiary_function(); // A5
161    gpio.int_pins[IntPinNr::P04_7 as usize].enable_tertiary_function(); // A6
162    gpio.int_pins[IntPinNr::P04_6 as usize].enable_tertiary_function(); // A7
163    gpio.int_pins[IntPinNr::P04_5 as usize].enable_tertiary_function(); // A8
164    gpio.int_pins[IntPinNr::P04_4 as usize].enable_tertiary_function(); // A9
165    gpio.int_pins[IntPinNr::P04_3 as usize].enable_tertiary_function(); // A10
166    gpio.int_pins[IntPinNr::P04_2 as usize].enable_tertiary_function(); // A11
167    gpio.int_pins[IntPinNr::P04_1 as usize].enable_tertiary_function(); // A12
168    gpio.int_pins[IntPinNr::P04_0 as usize].enable_tertiary_function(); // A13
169    gpio.int_pins[IntPinNr::P06_1 as usize].enable_tertiary_function(); // A14
170    gpio.int_pins[IntPinNr::P06_0 as usize].enable_tertiary_function(); // A15
171    gpio.pins[PinNr::P09_1 as usize].enable_tertiary_function(); // A16
172    gpio.pins[PinNr::P09_0 as usize].enable_tertiary_function(); // A17
173    gpio.pins[PinNr::P08_7 as usize].enable_tertiary_function(); // A18
174    gpio.pins[PinNr::P08_6 as usize].enable_tertiary_function(); // A19
175    gpio.pins[PinNr::P08_5 as usize].enable_tertiary_function(); // A20
176    gpio.pins[PinNr::P08_4 as usize].enable_tertiary_function(); // A21
177
178    // Don't configure these pins since their channels are used for the internal
179    // temperature sensor (Channel 22) and the Battery Monitor (A23)
180    // gpio.pins[PinNr::P08_3 as usize].enable_tertiary_function(); // A22
181    // gpio.pins[PinNr::P08_2 as usize].enable_tertiary_function(); // A23
182}
183
184/// This is in a separate, inline(never) function so that its stack frame is
185/// removed when this function returns. Otherwise, the stack space used for
186/// these static_inits is wasted.
187#[inline(never)]
188unsafe fn start() -> (
189    &'static kernel::Kernel,
190    MspExp432P401R,
191    &'static msp432::chip::Msp432<'static, msp432::chip::Msp432DefaultPeripherals<'static>>,
192) {
193    startup_intilialisation();
194
195    let peripherals = static_init!(
196        msp432::chip::Msp432DefaultPeripherals,
197        msp432::chip::Msp432DefaultPeripherals::new()
198    );
199    peripherals.init();
200
201    // Setup the GPIO pins to use the HFXT (high frequency external) oscillator (48MHz)
202    peripherals.gpio.pins[msp432::gpio::PinNr::PJ_2 as usize].enable_primary_function();
203    peripherals.gpio.pins[msp432::gpio::PinNr::PJ_3 as usize].enable_primary_function();
204
205    // Setup the GPIO pins to use the LFXT (low frequency external) oscillator (32.768kHz)
206    peripherals.gpio.pins[msp432::gpio::PinNr::PJ_0 as usize].enable_primary_function();
207    peripherals.gpio.pins[msp432::gpio::PinNr::PJ_1 as usize].enable_primary_function();
208
209    // Setup the clocks: MCLK: 48MHz, HSMCLK: 12MHz, SMCLK: 1.5MHz, ACLK: 32.768kHz
210    peripherals.cs.setup_clocks();
211
212    // Setup the debug GPIOs
213    let dbg_gpio0 = &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_0 as usize];
214    let dbg_gpio1 = &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_5 as usize];
215    let dbg_gpio2 = &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_7 as usize];
216    dbg_gpio0.make_output();
217    dbg_gpio1.make_output();
218    dbg_gpio2.make_output();
219    debug::assign_gpios(
220        Some(dbg_gpio0), // Red LED
221        Some(dbg_gpio1),
222        Some(dbg_gpio2),
223    );
224
225    // Setup pins for UART0
226    peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_2 as usize].enable_primary_function();
227    peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_3 as usize].enable_primary_function();
228
229    // Create an array to hold process references.
230    let processes = components::process_array::ProcessArrayComponent::new()
231        .finalize(components::process_array_component_static!(NUM_PROCS));
232    PROCESSES = Some(processes);
233
234    // Setup space to store the core kernel data structure.
235    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
236
237    let chip = static_init!(
238        msp432::chip::Msp432<msp432::chip::Msp432DefaultPeripherals>,
239        msp432::chip::Msp432::new(peripherals)
240    );
241    CHIP = Some(chip);
242
243    // Setup buttons
244    let button = components::button::ButtonComponent::new(
245        board_kernel,
246        capsules_core::button::DRIVER_NUM,
247        components::button_component_helper!(
248            msp432::gpio::IntPin,
249            (
250                &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_1 as usize],
251                kernel::hil::gpio::ActivationMode::ActiveLow,
252                kernel::hil::gpio::FloatingState::PullUp
253            ),
254            (
255                &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_4 as usize],
256                kernel::hil::gpio::ActivationMode::ActiveLow,
257                kernel::hil::gpio::FloatingState::PullUp
258            )
259        ),
260    )
261    .finalize(components::button_component_static!(msp432::gpio::IntPin));
262
263    // Setup LEDs
264    let leds = components::led::LedsComponent::new().finalize(components::led_component_static!(
265        kernel::hil::led::LedHigh<'static, msp432::gpio::IntPin>,
266        kernel::hil::led::LedHigh::new(
267            &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P02_0 as usize]
268        ),
269        kernel::hil::led::LedHigh::new(
270            &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P02_1 as usize]
271        ),
272        kernel::hil::led::LedHigh::new(
273            &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P02_2 as usize]
274        ),
275    ));
276
277    // Setup user-GPIOs
278    let gpio = GpioComponent::new(
279        board_kernel,
280        capsules_core::gpio::DRIVER_NUM,
281        components::gpio_component_helper!(
282            msp432::gpio::IntPin<'static>,
283            // Left outer connector, top to bottom
284            // 0 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P06_0 as usize], // A15
285            1 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_2 as usize],
286            2 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_3 as usize],
287            // 3 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P04_1 as usize], // A12
288            // 4 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P04_3 as usize], // A10
289            5 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_5 as usize],
290            // 6 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P04_6 as usize], // A7
291            7 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P06_5 as usize],
292            8 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P06_4 as usize],
293            // Left inner connector, top to bottom
294            // 9 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P06_1 as usize], // A14
295            // 10 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P04_0 as usize], // A13
296            // 11 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P04_2 as usize], // A11
297            // 12 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P04_4 as usize], // A9
298            // 13 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P04_5 as usize], // A8
299            // 14 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P04_7 as usize], // A6
300            // 15 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P05_4 as usize], // A1
301            // 16 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P05_5 as usize], // A0
302            // Right inner connector, top to bottom
303            17 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P02_7 as usize],
304            18 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P02_6 as usize],
305            19 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P02_4 as usize],
306            20 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P05_6 as usize],
307            21 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P06_6 as usize],
308            22 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P06_7 as usize],
309            23 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P02_3 as usize],
310            // 24 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P05_1 as usize], // A4
311            // 25 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_5 as usize], // debug-gpio
312            // 26 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_7 as usize], // debug-gpio
313            // Right outer connector, top to bottom
314            27 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P02_5 as usize],
315            28 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_0 as usize],
316            29 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P05_7 as usize],
317            30 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_6 as usize],
318            31 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_7 as usize],
319            // 32 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P05_0 as usize], // A5
320            // 33 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P05_2 as usize], // A3
321            34 => &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_6 as usize]
322        ),
323    )
324    .finalize(components::gpio_component_static!(
325        msp432::gpio::IntPin<'static>
326    ));
327
328    let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
329    let process_management_capability =
330        create_capability!(capabilities::ProcessManagementCapability);
331
332    // Setup UART0
333    let uart_mux = components::console::UartMuxComponent::new(&peripherals.uart0, 115200)
334        .finalize(components::uart_mux_component_static!());
335
336    // Setup the console.
337    let console = components::console::ConsoleComponent::new(
338        board_kernel,
339        capsules_core::console::DRIVER_NUM,
340        uart_mux,
341    )
342    .finalize(components::console_component_static!());
343    // Create the debugger object that handles calls to `debug!()`.
344    components::debug_writer::DebugWriterComponent::new(
345        uart_mux,
346        create_capability!(capabilities::SetDebugWriterCapability),
347    )
348    .finalize(components::debug_writer_component_static!());
349
350    // Setup alarm
351    let timer0 = &peripherals.timer_a0;
352    let mux_alarm = components::alarm::AlarmMuxComponent::new(timer0).finalize(
353        components::alarm_mux_component_static!(msp432::timer::TimerA),
354    );
355    let alarm = components::alarm::AlarmDriverComponent::new(
356        board_kernel,
357        capsules_core::alarm::DRIVER_NUM,
358        mux_alarm,
359    )
360    .finalize(components::alarm_component_static!(msp432::timer::TimerA));
361
362    // Setup ADC
363    setup_adc_pins(&peripherals.gpio);
364
365    let adc_channels = static_init!(
366        [msp432::adc::Channel; 24],
367        [
368            msp432::adc::Channel::Channel0,  // A0
369            msp432::adc::Channel::Channel1,  // A1
370            msp432::adc::Channel::Channel2,  // A2
371            msp432::adc::Channel::Channel3,  // A3
372            msp432::adc::Channel::Channel4,  // A4
373            msp432::adc::Channel::Channel5,  // A5
374            msp432::adc::Channel::Channel6,  // A6
375            msp432::adc::Channel::Channel7,  // A7
376            msp432::adc::Channel::Channel8,  // A8
377            msp432::adc::Channel::Channel9,  // A9
378            msp432::adc::Channel::Channel10, // A10
379            msp432::adc::Channel::Channel11, // A11
380            msp432::adc::Channel::Channel12, // A12
381            msp432::adc::Channel::Channel13, // A13
382            msp432::adc::Channel::Channel14, // A14
383            msp432::adc::Channel::Channel15, // A15
384            msp432::adc::Channel::Channel16, // A16
385            msp432::adc::Channel::Channel17, // A17
386            msp432::adc::Channel::Channel18, // A18
387            msp432::adc::Channel::Channel19, // A19
388            msp432::adc::Channel::Channel20, // A20
389            msp432::adc::Channel::Channel21, // A21
390            msp432::adc::Channel::Channel22, // A22
391            msp432::adc::Channel::Channel23, // A23
392        ]
393    );
394    let adc = components::adc::AdcDedicatedComponent::new(
395        &peripherals.adc,
396        adc_channels,
397        board_kernel,
398        capsules_core::adc::DRIVER_NUM,
399    )
400    .finalize(components::adc_dedicated_component_static!(
401        msp432::adc::Adc
402    ));
403
404    // Set the reference voltage for the ADC to 2.5V
405    peripherals
406        .adc_ref
407        .select_ref_voltage(msp432::ref_module::ReferenceVoltage::Volt2_5);
408    // Enable the internal temperature sensor on ADC Channel 22
409    peripherals.adc_ref.enable_temp_sensor(true);
410
411    let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
412        .finalize(components::round_robin_component_static!(NUM_PROCS));
413
414    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
415        .finalize(components::process_printer_text_component_static!());
416    PROCESS_PRINTER = Some(process_printer);
417
418    let msp_exp432p4014 = MspExp432P401R {
419        led: leds,
420        console,
421        button,
422        gpio,
423        alarm,
424        ipc: kernel::ipc::IPC::new(
425            board_kernel,
426            kernel::ipc::DRIVER_NUM,
427            &memory_allocation_capability,
428        ),
429        adc,
430        scheduler,
431        systick: cortexm4::systick::SysTick::new_with_calibration(48_000_000),
432        wdt: &peripherals.wdt,
433    };
434
435    debug!("Initialization complete. Entering main loop");
436
437    // These symbols are defined in the linker script.
438    extern "C" {
439        /// Beginning of the ROM region containing app images.
440        static _sapps: u8;
441        /// End of the ROM region containing app images.
442        static _eapps: u8;
443        /// Beginning of the RAM region for app memory.
444        static mut _sappmem: u8;
445        /// End of the RAM region for app memory.
446        static _eappmem: u8;
447    }
448
449    kernel::process::load_processes(
450        board_kernel,
451        chip,
452        core::slice::from_raw_parts(
453            core::ptr::addr_of!(_sapps),
454            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
455        ),
456        core::slice::from_raw_parts_mut(
457            core::ptr::addr_of_mut!(_sappmem),
458            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
459        ),
460        &FAULT_RESPONSE,
461        &process_management_capability,
462    )
463    .unwrap();
464
465    //Uncomment to run multi alarm test
466    /*components::test::multi_alarm_test::MultiAlarmTestComponent::new(mux_alarm)
467    .finalize(components::multi_alarm_test_component_buf!(msp432::timer::TimerA))
468    .run();*/
469
470    (board_kernel, msp_exp432p4014, chip)
471}
472
473/// Main function called after RAM initialized.
474#[no_mangle]
475pub unsafe fn main() {
476    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
477
478    let (board_kernel, board, chip) = start();
479    board_kernel.kernel_loop(&board, chip, Some(&board.ipc), &main_loop_capability);
480}