nrf52840dk_lib/
lib.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//! Tock kernel for the Nordic Semiconductor nRF52840 development kit (DK).
6//!
7//! It is based on nRF52840 SoC (Cortex M4 core with a BLE transceiver) with
8//! many exported I/O and peripherals.
9//!
10//! Pin Configuration
11//! -------------------
12//!
13//! ### `GPIO`
14//!
15//! | #  | Pin   | Ix | Header | Arduino |
16//! |----|-------|----|--------|---------|
17//! | 0  | P1.01 | 33 | P3 1   | D0      |
18//! | 1  | P1.02 | 34 | P3 2   | D1      |
19//! | 2  | P1.03 | 35 | P3 3   | D2      |
20//! | 3  | P1.04 | 36 | P3 4   | D3      |
21//! | 4  | P1.05 | 37 | P3 5   | D4      |
22//! | 5  | P1.06 | 38 | P3 6   | D5      |
23//! | 6  | P1.07 | 39 | P3 7   | D6      |
24//! | 7  | P1.08 | 40 | P3 8   | D7      |
25//! | 8  | P1.10 | 42 | P4 1   | D8      |
26//! | 9  | P1.11 | 43 | P4 2   | D9      |
27//! | 10 | P1.12 | 44 | P4 3   | D10     |
28//! | 11 | P1.13 | 45 | P4 4   | D11     |
29//! | 12 | P1.14 | 46 | P4 5   | D12     |
30//! | 13 | P1.15 | 47 | P4 6   | D13     |
31//! | 14 | P0.26 | 26 | P4 9   | D14     |
32//! | 15 | P0.27 | 27 | P4 10  | D15     |
33//!
34//! ### `GPIO` / Analog Inputs
35//!
36//! | #  | Pin        | Header | Arduino |
37//! |----|------------|--------|---------|
38//! | 16 | P0.03 AIN1 | P2 1   | A0      |
39//! | 17 | P0.04 AIN2 | P2 2   | A1      |
40//! | 18 | P0.28 AIN4 | P2 3   | A2      |
41//! | 19 | P0.29 AIN5 | P2 4   | A3      |
42//! | 20 | P0.30 AIN6 | P2 5   | A4      |
43//! | 21 | P0.31 AIN7 | P2 6   | A5      |
44//! | 22 | P0.02 AIN0 | P4 8   | AVDD    |
45//!
46//! ### Onboard Functions
47//!
48//! | Pin   | Header | Function |
49//! |-------|--------|----------|
50//! | P0.05 | P6 3   | UART RTS |
51//! | P0.06 | P6 4   | UART TXD |
52//! | P0.07 | P6 5   | UART CTS |
53//! | P0.08 | P6 6   | UART RXT |
54//! | P0.11 | P24 1  | Button 1 |
55//! | P0.12 | P24 2  | Button 2 |
56//! | P0.13 | P24 3  | LED 1    |
57//! | P0.14 | P24 4  | LED 2    |
58//! | P0.15 | P24 5  | LED 3    |
59//! | P0.16 | P24 6  | LED 4    |
60//! | P0.18 | P24 8  | Reset    |
61//! | P0.19 | P24 9  | SPI CLK  |
62//! | P0.20 | P24 10 | SPI MOSI |
63//! | P0.21 | P24 11 | SPI MISO |
64//! | P0.22 | P24 12 | SPI CS   |
65//! | P0.24 | P24 14 | Button 3 |
66//! | P0.25 | P24 15 | Button 4 |
67//! | P0.26 | P24 16 | I2C SDA  |
68//! | P0.27 | P24 17 | I2C SCL  |
69
70#![no_std]
71#![deny(missing_docs)]
72
73use core::ptr::addr_of;
74
75use capsules_core::virtualizers::virtual_alarm::{MuxAlarm, VirtualMuxAlarm};
76use capsules_extra::net::ieee802154::MacAddress;
77use capsules_extra::net::ipv6::ip_utils::IPAddr;
78use kernel::component::Component;
79use kernel::hil::led::LedLow;
80use kernel::hil::time::Counter;
81#[allow(unused_imports)]
82use kernel::hil::usb::Client;
83use kernel::platform::{KernelResources, SyscallDriverLookup};
84use kernel::scheduler::round_robin::RoundRobinSched;
85#[allow(unused_imports)]
86use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
87use nrf52840::gpio::Pin;
88use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
89use nrf52_components::{UartChannel, UartPins};
90
91// The nRF52840DK LEDs (see back of board)
92const LED1_PIN: Pin = Pin::P0_13;
93const LED2_PIN: Pin = Pin::P0_14;
94const LED3_PIN: Pin = Pin::P0_15;
95const LED4_PIN: Pin = Pin::P0_16;
96
97// The nRF52840DK buttons (see back of board)
98const BUTTON1_PIN: Pin = Pin::P0_11;
99const BUTTON2_PIN: Pin = Pin::P0_12;
100const BUTTON3_PIN: Pin = Pin::P0_24;
101const BUTTON4_PIN: Pin = Pin::P0_25;
102const BUTTON_RST_PIN: Pin = Pin::P0_18;
103
104const UART_RTS: Option<Pin> = Some(Pin::P0_05);
105const UART_TXD: Pin = Pin::P0_06;
106const UART_CTS: Option<Pin> = Some(Pin::P0_07);
107const UART_RXD: Pin = Pin::P0_08;
108
109const SPI_MOSI: Pin = Pin::P0_20;
110const SPI_MISO: Pin = Pin::P0_21;
111const SPI_CLK: Pin = Pin::P0_19;
112const SPI_CS: Pin = Pin::P0_22;
113
114const SPI_MX25R6435F_CHIP_SELECT: Pin = Pin::P0_17;
115const SPI_MX25R6435F_WRITE_PROTECT_PIN: Pin = Pin::P0_22;
116const SPI_MX25R6435F_HOLD_PIN: Pin = Pin::P0_23;
117
118/// I2C pins
119const I2C_SDA_PIN: Pin = Pin::P0_26;
120const I2C_SCL_PIN: Pin = Pin::P0_27;
121
122// Constants related to the configuration of the 15.4 network stack
123const PAN_ID: u16 = 0xABCD;
124const DST_MAC_ADDR: capsules_extra::net::ieee802154::MacAddress =
125    capsules_extra::net::ieee802154::MacAddress::Short(49138);
126const DEFAULT_CTX_PREFIX_LEN: u8 = 8; //Length of context for 6LoWPAN compression
127const DEFAULT_CTX_PREFIX: [u8; 16] = [0x0_u8; 16]; //Context for 6LoWPAN Compression
128
129/// Debug Writer
130pub mod io;
131
132// Whether to use UART debugging or Segger RTT (USB) debugging.
133// - Set to false to use UART.
134// - Set to true to use Segger RTT over USB.
135const USB_DEBUGGING: bool = false;
136
137/// This platform's chip type:
138pub type Chip = nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>;
139
140/// Number of concurrent processes this platform supports.
141pub const NUM_PROCS: usize = 8;
142
143/// Process array of this platform.
144pub static mut PROCESSES: [Option<&'static dyn kernel::process::Process>; NUM_PROCS] =
145    [None; NUM_PROCS];
146
147static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
148static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
149    None;
150
151/// Dummy buffer that causes the linker to reserve enough space for the stack.
152#[no_mangle]
153#[link_section = ".stack_buffer"]
154pub static mut STACK_MEMORY: [u8; 0x2000] = [0; 0x2000];
155
156//------------------------------------------------------------------------------
157// SYSCALL DRIVER TYPE DEFINITIONS
158//------------------------------------------------------------------------------
159
160type AlarmDriver = components::alarm::AlarmDriverComponentType<nrf52840::rtc::Rtc<'static>>;
161type RngDriver = components::rng::RngComponentType<nrf52840::trng::Trng<'static>>;
162
163// TicKV
164type Mx25r6435f = components::mx25r6435f::Mx25r6435fComponentType<
165    nrf52840::spi::SPIM<'static>,
166    nrf52840::gpio::GPIOPin<'static>,
167    nrf52840::rtc::Rtc<'static>,
168>;
169const TICKV_PAGE_SIZE: usize =
170    core::mem::size_of::<<Mx25r6435f as kernel::hil::flash::Flash>::Page>();
171type Siphasher24 = components::siphash::Siphasher24ComponentType;
172type TicKVDedicatedFlash =
173    components::tickv::TicKVDedicatedFlashComponentType<Mx25r6435f, Siphasher24, TICKV_PAGE_SIZE>;
174type TicKVKVStore = components::kv::TicKVKVStoreComponentType<
175    TicKVDedicatedFlash,
176    capsules_extra::tickv::TicKVKeyType,
177>;
178type KVStorePermissions = components::kv::KVStorePermissionsComponentType<TicKVKVStore>;
179type VirtualKVPermissions = components::kv::VirtualKVPermissionsComponentType<KVStorePermissions>;
180type KVDriver = components::kv::KVDriverComponentType<VirtualKVPermissions>;
181
182// Temperature
183type TemperatureDriver =
184    components::temperature::TemperatureComponentType<nrf52840::temperature::Temp<'static>>;
185
186// IEEE 802.15.4
187type Ieee802154MacDevice = components::ieee802154::Ieee802154ComponentMacDeviceType<
188    nrf52840::ieee802154_radio::Radio<'static>,
189    nrf52840::aes::AesECB<'static>,
190>;
191/// Userspace 802.15.4 driver with in-kernel packet framing and MAC layer.
192pub type Ieee802154Driver = components::ieee802154::Ieee802154ComponentType<
193    nrf52840::ieee802154_radio::Radio<'static>,
194    nrf52840::aes::AesECB<'static>,
195>;
196
197// EUI64
198/// Userspace EUI64 driver.
199pub type Eui64Driver = components::eui64::Eui64ComponentType;
200
201/// Supported drivers by the platform
202pub struct Platform {
203    ble_radio: &'static capsules_extra::ble_advertising_driver::BLE<
204        'static,
205        nrf52840::ble_radio::Radio<'static>,
206        VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
207    >,
208    button: &'static capsules_core::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>,
209    pconsole: &'static capsules_core::process_console::ProcessConsole<
210        'static,
211        { capsules_core::process_console::DEFAULT_COMMAND_HISTORY_LEN },
212        VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
213        components::process_console::Capability,
214    >,
215    console: &'static capsules_core::console::Console<'static>,
216    gpio: &'static capsules_core::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>,
217    led: &'static capsules_core::led::LedDriver<
218        'static,
219        kernel::hil::led::LedLow<'static, nrf52840::gpio::GPIOPin<'static>>,
220        4,
221    >,
222    rng: &'static RngDriver,
223    adc: &'static capsules_core::adc::AdcDedicated<'static, nrf52840::adc::Adc<'static>>,
224    temp: &'static TemperatureDriver,
225    /// The IPC driver.
226    pub ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
227    analog_comparator: &'static capsules_extra::analog_comparator::AnalogComparator<
228        'static,
229        nrf52840::acomp::Comparator<'static>,
230    >,
231    alarm: &'static AlarmDriver,
232    i2c_master_slave: &'static capsules_core::i2c_master_slave_driver::I2CMasterSlaveDriver<
233        'static,
234        nrf52840::i2c::TWI<'static>,
235    >,
236    spi_controller: &'static capsules_core::spi_controller::Spi<
237        'static,
238        capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<
239            'static,
240            nrf52840::spi::SPIM<'static>,
241        >,
242    >,
243    kv_driver: &'static KVDriver,
244    scheduler: &'static RoundRobinSched<'static>,
245    systick: cortexm4::systick::SysTick,
246}
247
248impl SyscallDriverLookup for Platform {
249    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
250    where
251        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
252    {
253        match driver_num {
254            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
255            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
256            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
257            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
258            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
259            capsules_core::rng::DRIVER_NUM => f(Some(self.rng)),
260            capsules_core::adc::DRIVER_NUM => f(Some(self.adc)),
261            capsules_extra::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)),
262            capsules_extra::temperature::DRIVER_NUM => f(Some(self.temp)),
263            capsules_extra::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
264            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
265            capsules_core::i2c_master_slave_driver::DRIVER_NUM => f(Some(self.i2c_master_slave)),
266            capsules_core::spi_controller::DRIVER_NUM => f(Some(self.spi_controller)),
267            capsules_extra::kv_driver::DRIVER_NUM => f(Some(self.kv_driver)),
268            _ => f(None),
269        }
270    }
271}
272
273impl KernelResources<Chip> for Platform {
274    type SyscallDriverLookup = Self;
275    type SyscallFilter = ();
276    type ProcessFault = ();
277    type Scheduler = RoundRobinSched<'static>;
278    type SchedulerTimer = cortexm4::systick::SysTick;
279    type WatchDog = ();
280    type ContextSwitchCallback = ();
281
282    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
283        self
284    }
285    fn syscall_filter(&self) -> &Self::SyscallFilter {
286        &()
287    }
288    fn process_fault(&self) -> &Self::ProcessFault {
289        &()
290    }
291    fn scheduler(&self) -> &Self::Scheduler {
292        self.scheduler
293    }
294    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
295        &self.systick
296    }
297    fn watchdog(&self) -> &Self::WatchDog {
298        &()
299    }
300    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
301        &()
302    }
303}
304
305/// Create the capsules needed for the in-kernel UDP and 15.4 stack.
306pub unsafe fn ieee802154_udp(
307    board_kernel: &'static kernel::Kernel,
308    nrf52840_peripherals: &'static Nrf52840DefaultPeripherals<'static>,
309    mux_alarm: &'static MuxAlarm<nrf52840::rtc::Rtc>,
310) -> (
311    &'static Eui64Driver,
312    &'static Ieee802154Driver,
313    &'static capsules_extra::net::udp::UDPDriver<'static>,
314) {
315    //--------------------------------------------------------------------------
316    // AES
317    //--------------------------------------------------------------------------
318
319    let aes_mux =
320        components::ieee802154::MuxAes128ccmComponent::new(&nrf52840_peripherals.nrf52.ecb)
321            .finalize(components::mux_aes128ccm_component_static!(
322                nrf52840::aes::AesECB
323            ));
324
325    //--------------------------------------------------------------------------
326    // 802.15.4
327    //--------------------------------------------------------------------------
328
329    let device_id = (*addr_of!(nrf52840::ficr::FICR_INSTANCE)).id();
330    let device_id_bottom_16: u16 = u16::from_le_bytes([device_id[0], device_id[1]]);
331
332    let eui64_driver = components::eui64::Eui64Component::new(u64::from_le_bytes(device_id))
333        .finalize(components::eui64_component_static!());
334
335    let (ieee802154_driver, mux_mac) = components::ieee802154::Ieee802154Component::new(
336        board_kernel,
337        capsules_extra::ieee802154::DRIVER_NUM,
338        &nrf52840_peripherals.ieee802154_radio,
339        aes_mux,
340        PAN_ID,
341        device_id_bottom_16,
342        device_id,
343    )
344    .finalize(components::ieee802154_component_static!(
345        nrf52840::ieee802154_radio::Radio,
346        nrf52840::aes::AesECB<'static>
347    ));
348
349    //--------------------------------------------------------------------------
350    // UDP
351    //--------------------------------------------------------------------------
352
353    let local_ip_ifaces = static_init!(
354        [IPAddr; 3],
355        [
356            IPAddr::generate_from_mac(capsules_extra::net::ieee802154::MacAddress::Long(device_id)),
357            IPAddr([
358                0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
359                0x1e, 0x1f,
360            ]),
361            IPAddr::generate_from_mac(capsules_extra::net::ieee802154::MacAddress::Short(
362                device_id_bottom_16
363            )),
364        ]
365    );
366
367    let (udp_send_mux, udp_recv_mux, udp_port_table) = components::udp_mux::UDPMuxComponent::new(
368        mux_mac,
369        DEFAULT_CTX_PREFIX_LEN,
370        DEFAULT_CTX_PREFIX,
371        DST_MAC_ADDR,
372        MacAddress::Long(device_id),
373        local_ip_ifaces,
374        mux_alarm,
375    )
376    .finalize(components::udp_mux_component_static!(
377        nrf52840::rtc::Rtc,
378        Ieee802154MacDevice
379    ));
380
381    // UDP driver initialization happens here
382    let udp_driver = components::udp_driver::UDPDriverComponent::new(
383        board_kernel,
384        capsules_extra::net::udp::driver::DRIVER_NUM,
385        udp_send_mux,
386        udp_recv_mux,
387        udp_port_table,
388        local_ip_ifaces,
389    )
390    .finalize(components::udp_driver_component_static!(nrf52840::rtc::Rtc));
391
392    (eui64_driver, ieee802154_driver, udp_driver)
393}
394
395/// This is in a separate, inline(never) function so that its stack frame is
396/// removed when this function returns. Otherwise, the stack space used for
397/// these static_inits is wasted.
398#[inline(never)]
399pub unsafe fn start() -> (
400    &'static kernel::Kernel,
401    Platform,
402    &'static Chip,
403    &'static Nrf52840DefaultPeripherals<'static>,
404    &'static MuxAlarm<'static, nrf52840::rtc::Rtc<'static>>,
405) {
406    //--------------------------------------------------------------------------
407    // INITIAL SETUP
408    //--------------------------------------------------------------------------
409
410    // Apply errata fixes and enable interrupts.
411    nrf52840::init();
412
413    // Set up peripheral drivers. Called in separate function to reduce stack
414    // usage.
415    let ieee802154_ack_buf = static_init!(
416        [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE],
417        [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE]
418    );
419    // Initialize chip peripheral drivers
420    let nrf52840_peripherals = static_init!(
421        Nrf52840DefaultPeripherals,
422        Nrf52840DefaultPeripherals::new(ieee802154_ack_buf)
423    );
424
425    // Set up circular peripheral dependencies.
426    nrf52840_peripherals.init();
427    let base_peripherals = &nrf52840_peripherals.nrf52;
428
429    // Configure kernel debug GPIOs as early as possible.
430    kernel::debug::assign_gpios(
431        Some(&nrf52840_peripherals.gpio_port[LED1_PIN]),
432        Some(&nrf52840_peripherals.gpio_port[LED2_PIN]),
433        Some(&nrf52840_peripherals.gpio_port[LED3_PIN]),
434    );
435
436    // Choose the channel for serial output. This board can be configured to use
437    // either the Segger RTT channel or via UART with traditional TX/RX GPIO
438    // pins.
439    let uart_channel = if USB_DEBUGGING {
440        // Initialize early so any panic beyond this point can use the RTT
441        // memory object.
442        let mut rtt_memory_refs = components::segger_rtt::SeggerRttMemoryComponent::new()
443            .finalize(components::segger_rtt_memory_component_static!());
444
445        // XXX: This is inherently unsafe as it aliases the mutable reference to
446        // rtt_memory. This aliases reference is only used inside a panic
447        // handler, which should be OK, but maybe we should use a const
448        // reference to rtt_memory and leverage interior mutability instead.
449        self::io::set_rtt_memory(&*rtt_memory_refs.get_rtt_memory_ptr());
450
451        UartChannel::Rtt(rtt_memory_refs)
452    } else {
453        UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD))
454    };
455
456    // Setup space to store the core kernel data structure.
457    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&*addr_of!(PROCESSES)));
458
459    // Create (and save for panic debugging) a chip object to setup low-level
460    // resources (e.g. MPU, systick).
461    let chip = static_init!(Chip, nrf52840::chip::NRF52::new(nrf52840_peripherals));
462    CHIP = Some(chip);
463
464    // Do nRF configuration and setup. This is shared code with other nRF-based
465    // platforms.
466    nrf52_components::startup::NrfStartupComponent::new(
467        false,
468        BUTTON_RST_PIN,
469        nrf52840::uicr::Regulator0Output::DEFAULT,
470        &base_peripherals.nvmc,
471    )
472    .finalize(());
473
474    //--------------------------------------------------------------------------
475    // CAPABILITIES
476    //--------------------------------------------------------------------------
477
478    // Create capabilities that the board needs to call certain protected kernel
479    // functions.
480    let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
481    let gpio_port = &nrf52840_peripherals.gpio_port;
482
483    //--------------------------------------------------------------------------
484    // GPIO
485    //--------------------------------------------------------------------------
486
487    // Expose the D0-D13 Arduino GPIO pins to userspace.
488    let gpio = components::gpio::GpioComponent::new(
489        board_kernel,
490        capsules_core::gpio::DRIVER_NUM,
491        components::gpio_component_helper!(
492            nrf52840::gpio::GPIOPin,
493            0 => &nrf52840_peripherals.gpio_port[Pin::P1_01],
494            1 => &nrf52840_peripherals.gpio_port[Pin::P1_02],
495            2 => &nrf52840_peripherals.gpio_port[Pin::P1_03],
496            3 => &nrf52840_peripherals.gpio_port[Pin::P1_04],
497            4 => &nrf52840_peripherals.gpio_port[Pin::P1_05],
498            5 => &nrf52840_peripherals.gpio_port[Pin::P1_06],
499            6 => &nrf52840_peripherals.gpio_port[Pin::P1_07],
500            7 => &nrf52840_peripherals.gpio_port[Pin::P1_08],
501            // Avoid exposing the I2C pins to userspace, as these are used in
502            // some tutorials (e.g., `nrf52840dk-thread-tutorial`).
503            //
504            // In the future we might want to make this configurable.
505            //
506            // 8 => &nrf52840_peripherals.gpio_port[Pin::P1_10],
507            // 9 => &nrf52840_peripherals.gpio_port[Pin::P1_11],
508            10 => &nrf52840_peripherals.gpio_port[Pin::P1_12],
509            11 => &nrf52840_peripherals.gpio_port[Pin::P1_13],
510            12 => &nrf52840_peripherals.gpio_port[Pin::P1_14],
511            13 => &nrf52840_peripherals.gpio_port[Pin::P1_15],
512        ),
513    )
514    .finalize(components::gpio_component_static!(nrf52840::gpio::GPIOPin));
515
516    //--------------------------------------------------------------------------
517    // BUTTONS
518    //--------------------------------------------------------------------------
519
520    let button = components::button::ButtonComponent::new(
521        board_kernel,
522        capsules_core::button::DRIVER_NUM,
523        components::button_component_helper!(
524            nrf52840::gpio::GPIOPin,
525            (
526                &nrf52840_peripherals.gpio_port[BUTTON1_PIN],
527                kernel::hil::gpio::ActivationMode::ActiveLow,
528                kernel::hil::gpio::FloatingState::PullUp
529            ),
530            (
531                &nrf52840_peripherals.gpio_port[BUTTON2_PIN],
532                kernel::hil::gpio::ActivationMode::ActiveLow,
533                kernel::hil::gpio::FloatingState::PullUp
534            ),
535            (
536                &nrf52840_peripherals.gpio_port[BUTTON3_PIN],
537                kernel::hil::gpio::ActivationMode::ActiveLow,
538                kernel::hil::gpio::FloatingState::PullUp
539            ),
540            (
541                &nrf52840_peripherals.gpio_port[BUTTON4_PIN],
542                kernel::hil::gpio::ActivationMode::ActiveLow,
543                kernel::hil::gpio::FloatingState::PullUp
544            )
545        ),
546    )
547    .finalize(components::button_component_static!(
548        nrf52840::gpio::GPIOPin
549    ));
550
551    //--------------------------------------------------------------------------
552    // LEDs
553    //--------------------------------------------------------------------------
554
555    let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
556        LedLow<'static, nrf52840::gpio::GPIOPin>,
557        LedLow::new(&nrf52840_peripherals.gpio_port[LED1_PIN]),
558        LedLow::new(&nrf52840_peripherals.gpio_port[LED2_PIN]),
559        LedLow::new(&nrf52840_peripherals.gpio_port[LED3_PIN]),
560        LedLow::new(&nrf52840_peripherals.gpio_port[LED4_PIN]),
561    ));
562
563    //--------------------------------------------------------------------------
564    // TIMER
565    //--------------------------------------------------------------------------
566
567    let rtc = &base_peripherals.rtc;
568    let _ = rtc.start();
569    let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
570        .finalize(components::alarm_mux_component_static!(nrf52840::rtc::Rtc));
571    let alarm = components::alarm::AlarmDriverComponent::new(
572        board_kernel,
573        capsules_core::alarm::DRIVER_NUM,
574        mux_alarm,
575    )
576    .finalize(components::alarm_component_static!(nrf52840::rtc::Rtc));
577
578    //--------------------------------------------------------------------------
579    // UART & CONSOLE & DEBUG
580    //--------------------------------------------------------------------------
581
582    let uart_channel = nrf52_components::UartChannelComponent::new(
583        uart_channel,
584        mux_alarm,
585        &base_peripherals.uarte0,
586    )
587    .finalize(nrf52_components::uart_channel_component_static!(
588        nrf52840::rtc::Rtc
589    ));
590
591    // Tool for displaying information about processes.
592    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
593        .finalize(components::process_printer_text_component_static!());
594    PROCESS_PRINTER = Some(process_printer);
595
596    // Virtualize the UART channel for the console and for kernel debug.
597    let uart_mux = components::console::UartMuxComponent::new(uart_channel, 115200)
598        .finalize(components::uart_mux_component_static!());
599
600    // Create the process console, an interactive terminal for managing
601    // processes.
602    let pconsole = components::process_console::ProcessConsoleComponent::new(
603        board_kernel,
604        uart_mux,
605        mux_alarm,
606        process_printer,
607        Some(cortexm4::support::reset),
608    )
609    .finalize(components::process_console_component_static!(
610        nrf52840::rtc::Rtc<'static>
611    ));
612
613    // Setup the serial console for userspace.
614    let console = components::console::ConsoleComponent::new(
615        board_kernel,
616        capsules_core::console::DRIVER_NUM,
617        uart_mux,
618    )
619    .finalize(components::console_component_static!());
620
621    // Create the debugger object that handles calls to `debug!()`.
622    components::debug_writer::DebugWriterComponent::new(uart_mux)
623        .finalize(components::debug_writer_component_static!());
624
625    //--------------------------------------------------------------------------
626    // BLE
627    //--------------------------------------------------------------------------
628
629    let ble_radio = components::ble::BLEComponent::new(
630        board_kernel,
631        capsules_extra::ble_advertising_driver::DRIVER_NUM,
632        &base_peripherals.ble_radio,
633        mux_alarm,
634    )
635    .finalize(components::ble_component_static!(
636        nrf52840::rtc::Rtc,
637        nrf52840::ble_radio::Radio
638    ));
639
640    //--------------------------------------------------------------------------
641    // TEMPERATURE (internal)
642    //--------------------------------------------------------------------------
643
644    let temp = components::temperature::TemperatureComponent::new(
645        board_kernel,
646        capsules_extra::temperature::DRIVER_NUM,
647        &base_peripherals.temp,
648    )
649    .finalize(components::temperature_component_static!(
650        nrf52840::temperature::Temp
651    ));
652
653    //--------------------------------------------------------------------------
654    // RANDOM NUMBER GENERATOR
655    //--------------------------------------------------------------------------
656
657    let rng = components::rng::RngComponent::new(
658        board_kernel,
659        capsules_core::rng::DRIVER_NUM,
660        &base_peripherals.trng,
661    )
662    .finalize(components::rng_component_static!(nrf52840::trng::Trng));
663
664    //--------------------------------------------------------------------------
665    // ADC
666    //--------------------------------------------------------------------------
667
668    let adc_channels = static_init!(
669        [nrf52840::adc::AdcChannelSetup; 6],
670        [
671            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput1),
672            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput2),
673            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput4),
674            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput5),
675            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput6),
676            nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput7),
677        ]
678    );
679    let adc = components::adc::AdcDedicatedComponent::new(
680        &base_peripherals.adc,
681        adc_channels,
682        board_kernel,
683        capsules_core::adc::DRIVER_NUM,
684    )
685    .finalize(components::adc_dedicated_component_static!(
686        nrf52840::adc::Adc
687    ));
688
689    //--------------------------------------------------------------------------
690    // SPI
691    //--------------------------------------------------------------------------
692
693    let mux_spi = components::spi::SpiMuxComponent::new(&base_peripherals.spim0)
694        .finalize(components::spi_mux_component_static!(nrf52840::spi::SPIM));
695
696    // Create the SPI system call capsule.
697    let spi_controller = components::spi::SpiSyscallComponent::new(
698        board_kernel,
699        mux_spi,
700        kernel::hil::spi::cs::IntoChipSelect::<_, kernel::hil::spi::cs::ActiveLow>::into_cs(
701            &gpio_port[SPI_CS],
702        ),
703        capsules_core::spi_controller::DRIVER_NUM,
704    )
705    .finalize(components::spi_syscall_component_static!(
706        nrf52840::spi::SPIM
707    ));
708
709    base_peripherals.spim0.configure(
710        nrf52840::pinmux::Pinmux::new(SPI_MOSI as u32),
711        nrf52840::pinmux::Pinmux::new(SPI_MISO as u32),
712        nrf52840::pinmux::Pinmux::new(SPI_CLK as u32),
713    );
714
715    //--------------------------------------------------------------------------
716    // ONBOARD EXTERNAL FLASH
717    //--------------------------------------------------------------------------
718
719    let mx25r6435f = components::mx25r6435f::Mx25r6435fComponent::new(
720        Some(&gpio_port[SPI_MX25R6435F_WRITE_PROTECT_PIN]),
721        Some(&gpio_port[SPI_MX25R6435F_HOLD_PIN]),
722        &gpio_port[SPI_MX25R6435F_CHIP_SELECT],
723        mux_alarm,
724        mux_spi,
725    )
726    .finalize(components::mx25r6435f_component_static!(
727        nrf52840::spi::SPIM,
728        nrf52840::gpio::GPIOPin,
729        nrf52840::rtc::Rtc
730    ));
731
732    //--------------------------------------------------------------------------
733    // TICKV
734    //--------------------------------------------------------------------------
735
736    // Static buffer to use when reading/writing flash for TicKV.
737    let page_buffer = static_init!(
738        <Mx25r6435f as kernel::hil::flash::Flash>::Page,
739        <Mx25r6435f as kernel::hil::flash::Flash>::Page::default()
740    );
741
742    // SipHash for creating TicKV hashed keys.
743    let sip_hash = components::siphash::Siphasher24Component::new()
744        .finalize(components::siphasher24_component_static!());
745
746    // TicKV with Tock wrapper/interface.
747    let tickv = components::tickv::TicKVDedicatedFlashComponent::new(
748        sip_hash,
749        mx25r6435f,
750        0, // start at the beginning of the flash chip
751        (capsules_extra::mx25r6435f::SECTOR_SIZE as usize) * 32, // arbitrary size of 32 pages
752        page_buffer,
753    )
754    .finalize(components::tickv_dedicated_flash_component_static!(
755        Mx25r6435f,
756        Siphasher24,
757        TICKV_PAGE_SIZE,
758    ));
759
760    // KVSystem interface to KV (built on TicKV).
761    let tickv_kv_store = components::kv::TicKVKVStoreComponent::new(tickv).finalize(
762        components::tickv_kv_store_component_static!(
763            TicKVDedicatedFlash,
764            capsules_extra::tickv::TicKVKeyType,
765        ),
766    );
767
768    let kv_store_permissions = components::kv::KVStorePermissionsComponent::new(tickv_kv_store)
769        .finalize(components::kv_store_permissions_component_static!(
770            TicKVKVStore
771        ));
772
773    // Share the KV stack with a mux.
774    let mux_kv = components::kv::KVPermissionsMuxComponent::new(kv_store_permissions).finalize(
775        components::kv_permissions_mux_component_static!(KVStorePermissions),
776    );
777
778    // Create a virtual component for the userspace driver.
779    let virtual_kv_driver = components::kv::VirtualKVPermissionsComponent::new(mux_kv).finalize(
780        components::virtual_kv_permissions_component_static!(KVStorePermissions),
781    );
782
783    // Userspace driver for KV.
784    let kv_driver = components::kv::KVDriverComponent::new(
785        virtual_kv_driver,
786        board_kernel,
787        capsules_extra::kv_driver::DRIVER_NUM,
788    )
789    .finalize(components::kv_driver_component_static!(
790        VirtualKVPermissions
791    ));
792
793    //--------------------------------------------------------------------------
794    // I2C CONTROLLER/TARGET
795    //--------------------------------------------------------------------------
796
797    let i2c_master_slave = components::i2c::I2CMasterSlaveDriverComponent::new(
798        board_kernel,
799        capsules_core::i2c_master_slave_driver::DRIVER_NUM,
800        &base_peripherals.twi1,
801    )
802    .finalize(components::i2c_master_slave_component_static!(
803        nrf52840::i2c::TWI
804    ));
805
806    base_peripherals.twi1.configure(
807        nrf52840::pinmux::Pinmux::new(I2C_SCL_PIN as u32),
808        nrf52840::pinmux::Pinmux::new(I2C_SDA_PIN as u32),
809    );
810    base_peripherals.twi1.set_speed(nrf52840::i2c::Speed::K400);
811
812    //--------------------------------------------------------------------------
813    // ANALOG COMPARATOR
814    //--------------------------------------------------------------------------
815
816    // Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02)
817    // These are hardcoded pin assignments specified in the driver
818    let analog_comparator = components::analog_comparator::AnalogComparatorComponent::new(
819        &base_peripherals.acomp,
820        components::analog_comparator_component_helper!(
821            nrf52840::acomp::Channel,
822            &*addr_of!(nrf52840::acomp::CHANNEL_AC0)
823        ),
824        board_kernel,
825        capsules_extra::analog_comparator::DRIVER_NUM,
826    )
827    .finalize(components::analog_comparator_component_static!(
828        nrf52840::acomp::Comparator
829    ));
830
831    //--------------------------------------------------------------------------
832    // NRF CLOCK SETUP
833    //--------------------------------------------------------------------------
834
835    nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
836
837    //--------------------------------------------------------------------------
838    // USB EXAMPLES
839    //--------------------------------------------------------------------------
840    // Uncomment to experiment with this.
841
842    // // Create the strings we include in the USB descriptor.
843    // let strings = static_init!(
844    //     [&str; 3],
845    //     [
846    //         "Nordic Semiconductor", // Manufacturer
847    //         "nRF52840dk - TockOS",  // Product
848    //         "serial0001",           // Serial number
849    //     ]
850    // );
851
852    // CTAP Example
853    //
854    // let (ctap, _ctap_driver) = components::ctap::CtapComponent::new(
855    //     board_kernel,
856    //     capsules_extra::ctap::DRIVER_NUM,
857    //     &nrf52840_peripherals.usbd,
858    //     0x1915, // Nordic Semiconductor
859    //     0x503a, // lowRISC generic FS USB
860    //     strings,
861    // )
862    // .finalize(components::ctap_component_static!(nrf52840::usbd::Usbd));
863
864    // ctap.enable();
865    // ctap.attach();
866
867    // // Keyboard HID Example
868    // type UsbHw = nrf52840::usbd::Usbd<'static>;
869    // let usb_device = &nrf52840_peripherals.usbd;
870
871    // let (keyboard_hid, keyboard_hid_driver) = components::keyboard_hid::KeyboardHidComponent::new(
872    //     board_kernel,
873    //     capsules_core::driver::NUM::KeyboardHid as usize,
874    //     usb_device,
875    //     0x1915, // Nordic Semiconductor
876    //     0x503a,
877    //     strings,
878    // )
879    // .finalize(components::keyboard_hid_component_static!(UsbHw));
880
881    // keyboard_hid.enable();
882    // keyboard_hid.attach();
883
884    //--------------------------------------------------------------------------
885    // PLATFORM SETUP, SCHEDULER, AND START KERNEL LOOP
886    //--------------------------------------------------------------------------
887
888    let scheduler = components::sched::round_robin::RoundRobinComponent::new(&*addr_of!(PROCESSES))
889        .finalize(components::round_robin_component_static!(NUM_PROCS));
890
891    let platform = Platform {
892        button,
893        ble_radio,
894        pconsole,
895        console,
896        led,
897        gpio,
898        rng,
899        adc,
900        temp,
901        alarm,
902        analog_comparator,
903        ipc: kernel::ipc::IPC::new(
904            board_kernel,
905            kernel::ipc::DRIVER_NUM,
906            &memory_allocation_capability,
907        ),
908        i2c_master_slave,
909        spi_controller,
910        kv_driver,
911        scheduler,
912        systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
913    };
914
915    let _ = platform.pconsole.start();
916    base_peripherals.adc.calibrate();
917
918    debug!("Initialization complete. Entering main loop\r");
919    debug!("{}", &*addr_of!(nrf52840::ficr::FICR_INSTANCE));
920
921    (
922        board_kernel,
923        platform,
924        chip,
925        nrf52840_peripherals,
926        mux_alarm,
927    )
928}