msp432/
chip.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
5use core::fmt::Write;
6use cortexm4::{CortexM4, CortexMVariant};
7use kernel::platform::chip::Chip;
8
9use crate::nvic;
10use crate::wdt;
11use kernel::platform::chip::InterruptService;
12
13pub struct Msp432<'a, I: InterruptService + 'a> {
14    mpu: cortexm4::mpu::MPU,
15    userspace_kernel_boundary: cortexm4::syscall::SysCall,
16    interrupt_service: &'a I,
17}
18
19pub struct Msp432DefaultPeripherals<'a> {
20    pub adc: crate::adc::Adc<'a>,
21    pub uart0: crate::uart::Uart<'a>,
22    pub cs: crate::cs::ClockSystem,
23    pub dma_channels: crate::dma::DmaChannels<'a>,
24    pub adc_ref: crate::ref_module::Ref,
25    pub timer_a0: crate::timer::TimerA<'a>,
26    pub timer_a1: crate::timer::TimerA<'a>,
27    pub timer_a2: crate::timer::TimerA<'a>,
28    pub timer_a3: crate::timer::TimerA<'a>,
29    pub gpio: crate::gpio::GpioManager<'a>,
30    pub i2c0: crate::i2c::I2c<'a>,
31    pub wdt: wdt::Wdt,
32}
33
34impl<'a> Msp432DefaultPeripherals<'a> {
35    pub fn new() -> Self {
36        Self {
37            adc: crate::adc::Adc::new(),
38            uart0: crate::uart::Uart::new(crate::usci::USCI_A0_BASE, 0, 1, 1, 1),
39            cs: crate::cs::ClockSystem::new(),
40            dma_channels: crate::dma::DmaChannels::new(),
41            adc_ref: crate::ref_module::Ref::new(),
42            timer_a0: crate::timer::TimerA::new(crate::timer::TIMER_A0_BASE),
43            timer_a1: crate::timer::TimerA::new(crate::timer::TIMER_A1_BASE),
44            timer_a2: crate::timer::TimerA::new(crate::timer::TIMER_A2_BASE),
45            timer_a3: crate::timer::TimerA::new(crate::timer::TIMER_A3_BASE),
46            gpio: crate::gpio::GpioManager::new(),
47            i2c0: crate::i2c::I2c::new(crate::usci::USCI_B0_BASE),
48            wdt: wdt::Wdt::new(),
49        }
50    }
51
52    pub unsafe fn init(&'a self) {
53        // Setup DMA channels for the UART
54        self.uart0.set_dma(
55            &self.dma_channels[self.uart0.tx_dma_chan],
56            &self.dma_channels[self.uart0.rx_dma_chan],
57        );
58        self.dma_channels[self.uart0.tx_dma_chan].set_client(&self.uart0);
59        self.dma_channels[self.uart0.rx_dma_chan].set_client(&self.uart0);
60
61        // Setup Reference Module, Timer and DMA for ADC
62        self.adc.set_modules(
63            &self.adc_ref,
64            &self.timer_a3,
65            &self.dma_channels[self.adc.dma_chan],
66        );
67        self.dma_channels[self.adc.dma_chan].set_client(&self.adc);
68    }
69}
70
71impl kernel::platform::chip::InterruptService for Msp432DefaultPeripherals<'_> {
72    unsafe fn service_interrupt(&self, interrupt: u32) -> bool {
73        match interrupt {
74            nvic::ADC => self.adc.handle_interrupt(),
75            nvic::DMA_INT0 => self.dma_channels.handle_interrupt(0),
76            nvic::DMA_INT1 => self.dma_channels.handle_interrupt(1),
77            nvic::DMA_INT2 => self.dma_channels.handle_interrupt(2),
78            nvic::DMA_INT3 => self.dma_channels.handle_interrupt(3),
79            nvic::DMA_ERR => self.dma_channels.handle_interrupt(-1),
80            nvic::IO_PORT1 => self.gpio.handle_interrupt(0),
81            nvic::IO_PORT2 => self.gpio.handle_interrupt(1),
82            nvic::IO_PORT3 => self.gpio.handle_interrupt(2),
83            nvic::IO_PORT4 => self.gpio.handle_interrupt(3),
84            nvic::IO_PORT5 => self.gpio.handle_interrupt(4),
85            nvic::IO_PORT6 => self.gpio.handle_interrupt(5),
86            nvic::TIMER_A0_0 | nvic::TIMER_A0_1 => self.timer_a0.handle_interrupt(),
87            nvic::TIMER_A1_0 | nvic::TIMER_A1_1 => self.timer_a1.handle_interrupt(),
88            nvic::TIMER_A2_0 | nvic::TIMER_A2_1 => self.timer_a2.handle_interrupt(),
89            nvic::TIMER_A3_0 | nvic::TIMER_A3_1 => self.timer_a3.handle_interrupt(),
90            nvic::USCI_B0 => self.i2c0.handle_interrupt(),
91            _ => return false,
92        }
93        true
94    }
95}
96
97impl<'a, I: InterruptService + 'a> Msp432<'a, I> {
98    pub unsafe fn new(interrupt_service: &'a I) -> Self {
99        Self {
100            mpu: cortexm4::mpu::MPU::new(),
101            userspace_kernel_boundary: cortexm4::syscall::SysCall::new(),
102            interrupt_service,
103        }
104    }
105}
106
107impl<'a, I: InterruptService + 'a> Chip for Msp432<'a, I> {
108    type MPU = cortexm4::mpu::MPU;
109    type UserspaceKernelBoundary = cortexm4::syscall::SysCall;
110
111    fn service_pending_interrupts(&self) {
112        unsafe {
113            loop {
114                if let Some(interrupt) = cortexm4::nvic::next_pending() {
115                    if !self.interrupt_service.service_interrupt(interrupt) {
116                        panic!("unhandled interrupt {}", interrupt);
117                    }
118
119                    let n = cortexm4::nvic::Nvic::new(interrupt);
120                    n.clear_pending();
121                    n.enable();
122                } else {
123                    break;
124                }
125            }
126        }
127    }
128
129    fn has_pending_interrupts(&self) -> bool {
130        unsafe { cortexm4::nvic::has_pending() }
131    }
132
133    fn mpu(&self) -> &cortexm4::mpu::MPU {
134        &self.mpu
135    }
136
137    fn userspace_kernel_boundary(&self) -> &cortexm4::syscall::SysCall {
138        &self.userspace_kernel_boundary
139    }
140
141    fn sleep(&self) {
142        unsafe {
143            cortexm4::support::wfi();
144        }
145    }
146
147    unsafe fn atomic<F, R>(&self, f: F) -> R
148    where
149        F: FnOnce() -> R,
150    {
151        cortexm4::support::atomic(f)
152    }
153
154    unsafe fn print_state(&self, write: &mut dyn Write) {
155        CortexM4::print_cortexm_state(write);
156    }
157}