nrf52_components/
startup.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//! Component for starting up nrf52 platforms.
6//! Contains 3 components, NrfStartupComponent, NrfClockComponent,
7//! and UartChannelComponent, as well as two helper structs for
8//! intializing Uart on Nordic boards.
9
10use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
11use core::mem::MaybeUninit;
12use kernel::component::Component;
13use nrf52::gpio::Pin;
14use nrf52::uicr::Regulator0Output;
15use segger::rtt::SeggerRtt;
16
17pub struct NrfStartupComponent<'a> {
18    nfc_as_gpios: bool,
19    button_rst_pin: Pin,
20    reg_vout: Regulator0Output,
21    nvmc: &'a nrf52::nvmc::Nvmc,
22}
23
24impl<'a> NrfStartupComponent<'a> {
25    pub fn new(
26        nfc_as_gpios: bool,
27        button_rst_pin: Pin,
28        reg_vout: Regulator0Output,
29        nvmc: &'a nrf52::nvmc::Nvmc,
30    ) -> Self {
31        Self {
32            nfc_as_gpios,
33            button_rst_pin,
34            reg_vout,
35            nvmc,
36        }
37    }
38}
39
40impl Component for NrfStartupComponent<'_> {
41    type StaticInput = ();
42    type Output = ();
43    fn finalize(self, _s: Self::StaticInput) -> Self::Output {
44        // Disable APPROTECT in software. This is required as of newer nRF52
45        // hardware revisions. See
46        // https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/working-with-the-nrf52-series-improved-approtect.
47        // If run on older HW revisions this function will do nothing.
48        let approtect = nrf52::approtect::Approtect::new();
49        approtect.sw_disable_approtect();
50
51        // Make non-volatile memory writable and activate the reset button
52        let uicr = nrf52::uicr::Uicr::new();
53
54        // Check if we need to erase UICR memory to re-program it
55        // This only needs to be done when a bit needs to be flipped from 0 to 1.
56        let psel0_reset: u32 = uicr.get_psel0_reset_pin().map_or(0, |pin| pin as u32);
57        let psel1_reset: u32 = uicr.get_psel1_reset_pin().map_or(0, |pin| pin as u32);
58        let mut erase_uicr = ((!psel0_reset & (self.button_rst_pin as u32))
59            | (!psel1_reset & (self.button_rst_pin as u32))
60            | (!(uicr.get_vout() as u32) & (self.reg_vout as u32)))
61            != 0;
62
63        // Only enabling the NFC pin protection requires an erase.
64        if self.nfc_as_gpios {
65            erase_uicr |= !uicr.is_nfc_pins_protection_enabled();
66        }
67
68        // On new nRF52 variants we need to ensure that the APPROTECT field in UICR is
69        // set to `HwDisable`.
70        if uicr.is_ap_protect_enabled() {
71            erase_uicr = true;
72        }
73
74        if erase_uicr {
75            self.nvmc.erase_uicr();
76        }
77
78        self.nvmc.configure_writeable();
79        while !self.nvmc.is_ready() {}
80
81        let mut needs_soft_reset: bool = false;
82
83        // Configure reset pins
84        if uicr
85            .get_psel0_reset_pin()
86            .is_none_or(|pin| pin != self.button_rst_pin)
87        {
88            uicr.set_psel0_reset_pin(self.button_rst_pin);
89            while !self.nvmc.is_ready() {}
90            needs_soft_reset = true;
91        }
92        if uicr
93            .get_psel1_reset_pin()
94            .is_none_or(|pin| pin != self.button_rst_pin)
95        {
96            uicr.set_psel1_reset_pin(self.button_rst_pin);
97            while !self.nvmc.is_ready() {}
98            needs_soft_reset = true;
99        }
100
101        // Configure voltage regulator output
102        if uicr.get_vout() != self.reg_vout {
103            uicr.set_vout(self.reg_vout);
104            while !self.nvmc.is_ready() {}
105            needs_soft_reset = true;
106        }
107
108        // Check if we need to free the NFC pins for GPIO
109        if self.nfc_as_gpios {
110            uicr.set_nfc_pins_protection(true);
111            while !self.nvmc.is_ready() {}
112            needs_soft_reset = true;
113        }
114
115        // If APPROTECT was not already disabled, ensure it is set to disabled.
116        if uicr.is_ap_protect_enabled() {
117            uicr.disable_ap_protect();
118            while !self.nvmc.is_ready() {}
119            needs_soft_reset = true;
120        }
121
122        // Any modification of UICR needs a soft reset for the changes to be taken into account.
123        if needs_soft_reset {
124            unsafe {
125                cortexm4::scb::reset();
126            }
127        }
128    }
129}
130
131pub struct NrfClockComponent<'a> {
132    clock: &'a nrf52::clock::Clock,
133}
134
135impl<'a> NrfClockComponent<'a> {
136    pub fn new(clock: &'a nrf52::clock::Clock) -> Self {
137        Self { clock }
138    }
139}
140
141impl Component for NrfClockComponent<'_> {
142    type StaticInput = ();
143    type Output = ();
144    fn finalize(self, _s: Self::StaticInput) -> Self::Output {
145        // Start all of the clocks. Low power operation will require a better
146        // approach than this.
147        self.clock.low_stop();
148        self.clock.high_stop();
149
150        self.clock
151            .low_set_source(nrf52::clock::LowClockSource::XTAL);
152        self.clock.low_start();
153        self.clock.high_start();
154        while !self.clock.low_started() {}
155        while !self.clock.high_started() {}
156    }
157}
158
159#[macro_export]
160macro_rules! uart_channel_component_static {
161    ($A:ty $(,)?) => {{
162        components::segger_rtt_component_static!($A)
163    };};
164}
165
166/// Pins for the UART
167#[derive(Debug)]
168pub struct UartPins {
169    rts: Option<Pin>,
170    txd: Pin,
171    cts: Option<Pin>,
172    rxd: Pin,
173}
174
175impl UartPins {
176    pub fn new(rts: Option<Pin>, txd: Pin, cts: Option<Pin>, rxd: Pin) -> Self {
177        Self { rts, txd, cts, rxd }
178    }
179}
180
181/// Uart chanel representation depends on whether USB debugging is
182/// enabled.
183pub enum UartChannel<'a> {
184    Pins(UartPins),
185    Rtt(components::segger_rtt::SeggerRttMemoryRefs<'a>),
186}
187
188pub struct UartChannelComponent {
189    uart_channel: UartChannel<'static>,
190    mux_alarm: &'static MuxAlarm<'static, nrf52::rtc::Rtc<'static>>,
191    uarte0: &'static nrf52::uart::Uarte<'static>,
192}
193
194impl UartChannelComponent {
195    pub fn new(
196        uart_channel: UartChannel<'static>,
197        mux_alarm: &'static MuxAlarm<'static, nrf52::rtc::Rtc<'static>>,
198        uarte0: &'static nrf52::uart::Uarte<'static>,
199    ) -> Self {
200        Self {
201            uart_channel,
202            mux_alarm,
203            uarte0,
204        }
205    }
206}
207
208impl Component for UartChannelComponent {
209    type StaticInput = (
210        &'static mut MaybeUninit<VirtualMuxAlarm<'static, nrf52::rtc::Rtc<'static>>>,
211        &'static mut MaybeUninit<
212            SeggerRtt<'static, VirtualMuxAlarm<'static, nrf52::rtc::Rtc<'static>>>,
213        >,
214    );
215    type Output = &'static dyn kernel::hil::uart::Uart<'static>;
216
217    fn finalize(self, s: Self::StaticInput) -> Self::Output {
218        match self.uart_channel {
219            UartChannel::Pins(uart_pins) => {
220                unsafe {
221                    self.uarte0.initialize(
222                        nrf52::pinmux::Pinmux::new(uart_pins.txd as u32),
223                        nrf52::pinmux::Pinmux::new(uart_pins.rxd as u32),
224                        uart_pins.cts.map(|x| nrf52::pinmux::Pinmux::new(x as u32)),
225                        uart_pins.rts.map(|x| nrf52::pinmux::Pinmux::new(x as u32)),
226                    )
227                };
228                self.uarte0
229            }
230            UartChannel::Rtt(rtt_memory) => {
231                let rtt =
232                    components::segger_rtt::SeggerRttComponent::new(self.mux_alarm, rtt_memory)
233                        .finalize(s);
234                rtt
235            }
236        }
237    }
238}