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// Disable this attribute when documenting, as a workaround for
11// https://github.com/rust-lang/rust/issues/62184.
12#![cfg_attr(not(doc), no_main)]
13#![deny(missing_docs)]
14
15use core::ptr::{addr_of, addr_of_mut};
16
17use components::gpio::GpioComponent;
18use kernel::capabilities;
19use kernel::component::Component;
20use kernel::hil::gpio::Configure;
21use kernel::platform::{KernelResources, SyscallDriverLookup};
22use kernel::scheduler::round_robin::RoundRobinSched;
23use kernel::{create_capability, debug, static_init};
24
25/// Support routines for debugging I/O.
26pub mod io;
27
28/// Number of concurrent processes this platform supports.
29const NUM_PROCS: usize = 4;
30
31/// Actual memory for holding the active process structures.
32static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
33    [None; NUM_PROCS];
34
35/// Static reference to chip for panic dumps.
36static mut CHIP: Option<&'static msp432::chip::Msp432<msp432::chip::Msp432DefaultPeripherals>> =
37    None;
38// Static reference to process printer for panic dumps.
39static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
40    None;
41
42/// How should the kernel respond when a process faults.
43const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
44    capsules_system::process_policies::PanicFaultPolicy {};
45
46/// Dummy buffer that causes the linker to reserve enough space for the stack.
47#[no_mangle]
48#[link_section = ".stack_buffer"]
49pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
50
51/// A structure representing this platform that holds references to all
52/// capsules for this platform.
53struct MspExp432P401R {
54    led: &'static capsules_core::led::LedDriver<
55        'static,
56        kernel::hil::led::LedHigh<'static, msp432::gpio::IntPin<'static>>,
57        3,
58    >,
59    console: &'static capsules_core::console::Console<'static>,
60    button: &'static capsules_core::button::Button<'static, msp432::gpio::IntPin<'static>>,
61    gpio: &'static capsules_core::gpio::GPIO<'static, msp432::gpio::IntPin<'static>>,
62    alarm: &'static capsules_core::alarm::AlarmDriver<
63        'static,
64        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
65            'static,
66            msp432::timer::TimerA<'static>,
67        >,
68    >,
69    ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
70    adc: &'static capsules_core::adc::AdcDedicated<'static, msp432::adc::Adc<'static>>,
71    wdt: &'static msp432::wdt::Wdt,
72    scheduler: &'static RoundRobinSched<'static>,
73    systick: cortexm4::systick::SysTick,
74}
75
76impl KernelResources<msp432::chip::Msp432<'static, msp432::chip::Msp432DefaultPeripherals<'static>>>
77    for MspExp432P401R
78{
79    type SyscallDriverLookup = Self;
80    type SyscallFilter = ();
81    type ProcessFault = ();
82    type Scheduler = RoundRobinSched<'static>;
83    type SchedulerTimer = cortexm4::systick::SysTick;
84    type WatchDog = msp432::wdt::Wdt;
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        self.wdt
104    }
105    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
106        &()
107    }
108}
109
110/// Mapping of integer syscalls to objects that implement syscalls.
111impl SyscallDriverLookup for MspExp432P401R {
112    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
113    where
114        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
115    {
116        match driver_num {
117            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
118            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
119            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
120            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
121            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
122            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
123            capsules_core::adc::DRIVER_NUM => f(Some(self.adc)),
124            _ => f(None),
125        }
126    }
127}
128
129/// Startup initialisation
130///
131/// This code was more or less copied from the code examples of Texas instruments.
132/// It disables the watchdog, enables all RAM banks, configures the chip to the high-power mode
133/// (which is necessary for 48MHz operation) and enables waitstates and buffering in a way that
134/// the flash returns valid data with 48MHz CPU frequency.
135unsafe fn startup_intilialisation() {
136    msp432::init();
137
138    // For now, these peripherals are only used at startup, so we do not
139    // allocate them for the life of the program. If these are later used by the
140    // chip crate (such as for handling interrupts), they will need to be
141    // added to Msp432DefaultPeripherals
142    let wdt = msp432::wdt::Wdt::new();
143    let sysctl = msp432::sysctl::SysCtl::new();
144    let flctl = msp432::flctl::FlCtl::new();
145    let pcm = msp432::pcm::Pcm::new();
146
147    // The watchdog must be disabled, because it is enabled by default on reset and has a
148    // interval of approximately 10ms. See datasheet p. 759, section 17.2.2.
149    // Do this in a separate function which is executed before the kernel is started in order to
150    // make sure that not more than 1 watchdog instances exist at the same time.
151    wdt.disable();
152    sysctl.enable_all_sram_banks();
153    pcm.set_high_power();
154    flctl.set_waitstates(msp432::flctl::WaitStates::_1);
155    flctl.set_buffering(true);
156}
157
158/// Function to setup all ADC-capaable pins
159/// Since the chips has 100 pins, we really setup all capable pins to work as ADC-pins.
160unsafe fn setup_adc_pins(gpio: &msp432::gpio::GpioManager) {
161    use msp432::gpio::{IntPinNr, PinNr};
162    gpio.int_pins[IntPinNr::P05_5 as usize].enable_tertiary_function(); // A0
163    gpio.int_pins[IntPinNr::P05_4 as usize].enable_tertiary_function(); // A1
164    gpio.int_pins[IntPinNr::P05_3 as usize].enable_tertiary_function(); // A2
165    gpio.int_pins[IntPinNr::P05_2 as usize].enable_tertiary_function(); // A3
166    gpio.int_pins[IntPinNr::P05_1 as usize].enable_tertiary_function(); // A4
167    gpio.int_pins[IntPinNr::P05_0 as usize].enable_tertiary_function(); // A5
168    gpio.int_pins[IntPinNr::P04_7 as usize].enable_tertiary_function(); // A6
169    gpio.int_pins[IntPinNr::P04_6 as usize].enable_tertiary_function(); // A7
170    gpio.int_pins[IntPinNr::P04_5 as usize].enable_tertiary_function(); // A8
171    gpio.int_pins[IntPinNr::P04_4 as usize].enable_tertiary_function(); // A9
172    gpio.int_pins[IntPinNr::P04_3 as usize].enable_tertiary_function(); // A10
173    gpio.int_pins[IntPinNr::P04_2 as usize].enable_tertiary_function(); // A11
174    gpio.int_pins[IntPinNr::P04_1 as usize].enable_tertiary_function(); // A12
175    gpio.int_pins[IntPinNr::P04_0 as usize].enable_tertiary_function(); // A13
176    gpio.int_pins[IntPinNr::P06_1 as usize].enable_tertiary_function(); // A14
177    gpio.int_pins[IntPinNr::P06_0 as usize].enable_tertiary_function(); // A15
178    gpio.pins[PinNr::P09_1 as usize].enable_tertiary_function(); // A16
179    gpio.pins[PinNr::P09_0 as usize].enable_tertiary_function(); // A17
180    gpio.pins[PinNr::P08_7 as usize].enable_tertiary_function(); // A18
181    gpio.pins[PinNr::P08_6 as usize].enable_tertiary_function(); // A19
182    gpio.pins[PinNr::P08_5 as usize].enable_tertiary_function(); // A20
183    gpio.pins[PinNr::P08_4 as usize].enable_tertiary_function(); // A21
184
185    // Don't configure these pins since their channels are used for the internal
186    // temperature sensor (Channel 22) and the Battery Monitor (A23)
187    // gpio.pins[PinNr::P08_3 as usize].enable_tertiary_function(); // A22
188    // gpio.pins[PinNr::P08_2 as usize].enable_tertiary_function(); // A23
189}
190
191/// This is in a separate, inline(never) function so that its stack frame is
192/// removed when this function returns. Otherwise, the stack space used for
193/// these static_inits is wasted.
194#[inline(never)]
195unsafe fn start() -> (
196    &'static kernel::Kernel,
197    MspExp432P401R,
198    &'static msp432::chip::Msp432<'static, msp432::chip::Msp432DefaultPeripherals<'static>>,
199) {
200    startup_intilialisation();
201
202    let peripherals = static_init!(
203        msp432::chip::Msp432DefaultPeripherals,
204        msp432::chip::Msp432DefaultPeripherals::new()
205    );
206    peripherals.init();
207
208    // Setup the GPIO pins to use the HFXT (high frequency external) oscillator (48MHz)
209    peripherals.gpio.pins[msp432::gpio::PinNr::PJ_2 as usize].enable_primary_function();
210    peripherals.gpio.pins[msp432::gpio::PinNr::PJ_3 as usize].enable_primary_function();
211
212    // Setup the GPIO pins to use the LFXT (low frequency external) oscillator (32.768kHz)
213    peripherals.gpio.pins[msp432::gpio::PinNr::PJ_0 as usize].enable_primary_function();
214    peripherals.gpio.pins[msp432::gpio::PinNr::PJ_1 as usize].enable_primary_function();
215
216    // Setup the clocks: MCLK: 48MHz, HSMCLK: 12MHz, SMCLK: 1.5MHz, ACLK: 32.768kHz
217    peripherals.cs.setup_clocks();
218
219    // Setup the debug GPIOs
220    let dbg_gpio0 = &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_0 as usize];
221    let dbg_gpio1 = &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_5 as usize];
222    let dbg_gpio2 = &peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P03_7 as usize];
223    dbg_gpio0.make_output();
224    dbg_gpio1.make_output();
225    dbg_gpio2.make_output();
226    debug::assign_gpios(
227        Some(dbg_gpio0), // Red LED
228        Some(dbg_gpio1),
229        Some(dbg_gpio2),
230    );
231
232    // Setup pins for UART0
233    peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_2 as usize].enable_primary_function();
234    peripherals.gpio.int_pins[msp432::gpio::IntPinNr::P01_3 as usize].enable_primary_function();
235
236    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
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(uart_mux)
345        .finalize(components::debug_writer_component_static!());
346
347    // Setup alarm
348    let timer0 = &peripherals.timer_a0;
349    let mux_alarm = components::alarm::AlarmMuxComponent::new(timer0).finalize(
350        components::alarm_mux_component_static!(msp432::timer::TimerA),
351    );
352    let alarm = components::alarm::AlarmDriverComponent::new(
353        board_kernel,
354        capsules_core::alarm::DRIVER_NUM,
355        mux_alarm,
356    )
357    .finalize(components::alarm_component_static!(msp432::timer::TimerA));
358
359    // Setup ADC
360    setup_adc_pins(&peripherals.gpio);
361
362    let adc_channels = static_init!(
363        [msp432::adc::Channel; 24],
364        [
365            msp432::adc::Channel::Channel0,  // A0
366            msp432::adc::Channel::Channel1,  // A1
367            msp432::adc::Channel::Channel2,  // A2
368            msp432::adc::Channel::Channel3,  // A3
369            msp432::adc::Channel::Channel4,  // A4
370            msp432::adc::Channel::Channel5,  // A5
371            msp432::adc::Channel::Channel6,  // A6
372            msp432::adc::Channel::Channel7,  // A7
373            msp432::adc::Channel::Channel8,  // A8
374            msp432::adc::Channel::Channel9,  // A9
375            msp432::adc::Channel::Channel10, // A10
376            msp432::adc::Channel::Channel11, // A11
377            msp432::adc::Channel::Channel12, // A12
378            msp432::adc::Channel::Channel13, // A13
379            msp432::adc::Channel::Channel14, // A14
380            msp432::adc::Channel::Channel15, // A15
381            msp432::adc::Channel::Channel16, // A16
382            msp432::adc::Channel::Channel17, // A17
383            msp432::adc::Channel::Channel18, // A18
384            msp432::adc::Channel::Channel19, // A19
385            msp432::adc::Channel::Channel20, // A20
386            msp432::adc::Channel::Channel21, // A21
387            msp432::adc::Channel::Channel22, // A22
388            msp432::adc::Channel::Channel23, // A23
389        ]
390    );
391    let adc = components::adc::AdcDedicatedComponent::new(
392        &peripherals.adc,
393        adc_channels,
394        board_kernel,
395        capsules_core::adc::DRIVER_NUM,
396    )
397    .finalize(components::adc_dedicated_component_static!(
398        msp432::adc::Adc
399    ));
400
401    // Set the reference voltage for the ADC to 2.5V
402    peripherals
403        .adc_ref
404        .select_ref_voltage(msp432::ref_module::ReferenceVoltage::Volt2_5);
405    // Enable the internal temperature sensor on ADC Channel 22
406    peripherals.adc_ref.enable_temp_sensor(true);
407
408    let scheduler = components::sched::round_robin::RoundRobinComponent::new(&*addr_of!(PROCESSES))
409        .finalize(components::round_robin_component_static!(NUM_PROCS));
410
411    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
412        .finalize(components::process_printer_text_component_static!());
413    PROCESS_PRINTER = Some(process_printer);
414
415    let msp_exp432p4014 = MspExp432P401R {
416        led: leds,
417        console,
418        button,
419        gpio,
420        alarm,
421        ipc: kernel::ipc::IPC::new(
422            board_kernel,
423            kernel::ipc::DRIVER_NUM,
424            &memory_allocation_capability,
425        ),
426        adc,
427        scheduler,
428        systick: cortexm4::systick::SysTick::new_with_calibration(48_000_000),
429        wdt: &peripherals.wdt,
430    };
431
432    debug!("Initialization complete. Entering main loop");
433
434    // These symbols are defined in the linker script.
435    extern "C" {
436        /// Beginning of the ROM region containing app images.
437        static _sapps: u8;
438        /// End of the ROM region containing app images.
439        static _eapps: u8;
440        /// Beginning of the RAM region for app memory.
441        static mut _sappmem: u8;
442        /// End of the RAM region for app memory.
443        static _eappmem: u8;
444    }
445
446    kernel::process::load_processes(
447        board_kernel,
448        chip,
449        core::slice::from_raw_parts(
450            core::ptr::addr_of!(_sapps),
451            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
452        ),
453        core::slice::from_raw_parts_mut(
454            core::ptr::addr_of_mut!(_sappmem),
455            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
456        ),
457        &mut *addr_of_mut!(PROCESSES),
458        &FAULT_RESPONSE,
459        &process_management_capability,
460    )
461    .unwrap();
462
463    //Uncomment to run multi alarm test
464    /*components::test::multi_alarm_test::MultiAlarmTestComponent::new(mux_alarm)
465    .finalize(components::multi_alarm_test_component_buf!(msp432::timer::TimerA))
466    .run();*/
467
468    (board_kernel, msp_exp432p4014, chip)
469}
470
471/// Main function called after RAM initialized.
472#[no_mangle]
473pub unsafe fn main() {
474    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
475
476    let (board_kernel, board, chip) = start();
477    board_kernel.kernel_loop(&board, chip, Some(&board.ipc), &main_loop_capability);
478}