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