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