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