nrf52840dk_thread_tutorial/
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//! Tock kernel for the Nordic Semiconductor nRF52840 development kit (DK).
6
7#![no_std]
8// Disable this attribute when documenting, as a workaround for
9// https://github.com/rust-lang/rust/issues/62184.
10#![cfg_attr(not(doc), no_main)]
11#![deny(missing_docs)]
12
13use core::ptr::{addr_of, addr_of_mut};
14
15use kernel::component::Component;
16use kernel::platform::{KernelResources, SyscallDriverLookup};
17use kernel::{capabilities, create_capability};
18use nrf52840::gpio::Pin;
19use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
20use nrf52840dk_lib::{self, NUM_PROCS, PROCESSES};
21
22type ScreenDriver = components::screen::ScreenComponentType;
23
24// State for loading and holding applications.
25// How should the kernel respond when a process faults.
26const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
27    capsules_system::process_policies::PanicFaultPolicy {};
28
29type Ieee802154RawDriver =
30    components::ieee802154::Ieee802154RawComponentType<nrf52840::ieee802154_radio::Radio<'static>>;
31
32struct Platform {
33    base: nrf52840dk_lib::Platform,
34    ieee802154: &'static Ieee802154RawDriver,
35    eui64: &'static nrf52840dk_lib::Eui64Driver,
36    screen: &'static ScreenDriver,
37    nonvolatile_storage:
38        &'static capsules_extra::isolated_nonvolatile_storage_driver::IsolatedNonvolatileStorage<
39            'static,
40            {
41                components::isolated_nonvolatile_storage::ISOLATED_NONVOLATILE_STORAGE_APP_REGION_SIZE_DEFAULT
42            },
43        >,
44}
45
46impl SyscallDriverLookup for Platform {
47    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
48    where
49        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
50    {
51        match driver_num {
52            capsules_extra::eui64::DRIVER_NUM => f(Some(self.eui64)),
53            capsules_extra::ieee802154::DRIVER_NUM => f(Some(self.ieee802154)),
54            capsules_extra::screen::DRIVER_NUM => f(Some(self.screen)),
55            capsules_extra::isolated_nonvolatile_storage_driver::DRIVER_NUM => {
56                f(Some(self.nonvolatile_storage))
57            }
58            _ => self.base.with_driver(driver_num, f),
59        }
60    }
61}
62
63type Chip = nrf52840dk_lib::Chip;
64
65impl KernelResources<Chip> for Platform {
66    type SyscallDriverLookup = Self;
67    type SyscallFilter = <nrf52840dk_lib::Platform as KernelResources<Chip>>::SyscallFilter;
68    type ProcessFault = <nrf52840dk_lib::Platform as KernelResources<Chip>>::ProcessFault;
69    type Scheduler = <nrf52840dk_lib::Platform as KernelResources<Chip>>::Scheduler;
70    type SchedulerTimer = <nrf52840dk_lib::Platform as KernelResources<Chip>>::SchedulerTimer;
71    type WatchDog = <nrf52840dk_lib::Platform as KernelResources<Chip>>::WatchDog;
72    type ContextSwitchCallback =
73        <nrf52840dk_lib::Platform as KernelResources<Chip>>::ContextSwitchCallback;
74
75    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
76        self
77    }
78    fn syscall_filter(&self) -> &Self::SyscallFilter {
79        self.base.syscall_filter()
80    }
81    fn process_fault(&self) -> &Self::ProcessFault {
82        self.base.process_fault()
83    }
84    fn scheduler(&self) -> &Self::Scheduler {
85        self.base.scheduler()
86    }
87    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
88        self.base.scheduler_timer()
89    }
90    fn watchdog(&self) -> &Self::WatchDog {
91        self.base.watchdog()
92    }
93    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
94        self.base.context_switch_callback()
95    }
96}
97
98/// Main function called after RAM initialized.
99#[no_mangle]
100pub unsafe fn main() {
101    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
102
103    // Create the base board:
104    let (board_kernel, base_platform, chip, nrf52840_peripherals, _mux_alarm) =
105        nrf52840dk_lib::start();
106
107    //--------------------------------------------------------------------------
108    // RAW 802.15.4
109    //--------------------------------------------------------------------------
110
111    let device_id = (*addr_of!(nrf52840::ficr::FICR_INSTANCE)).id();
112
113    let eui64 = components::eui64::Eui64Component::new(u64::from_le_bytes(device_id))
114        .finalize(components::eui64_component_static!());
115
116    let ieee802154 = components::ieee802154::Ieee802154RawComponent::new(
117        board_kernel,
118        capsules_extra::ieee802154::DRIVER_NUM,
119        &nrf52840_peripherals.ieee802154_radio,
120    )
121    .finalize(components::ieee802154_raw_component_static!(
122        nrf52840::ieee802154_radio::Radio,
123    ));
124
125    //--------------------------------------------------------------------------
126    // SCREEN
127    //--------------------------------------------------------------------------
128
129    const SCREEN_I2C_SDA_PIN: Pin = Pin::P1_10;
130    const SCREEN_I2C_SCL_PIN: Pin = Pin::P1_11;
131
132    let i2c_bus = components::i2c::I2CMuxComponent::new(&nrf52840_peripherals.nrf52.twi1, None)
133        .finalize(components::i2c_mux_component_static!(nrf52840::i2c::TWI));
134    nrf52840_peripherals.nrf52.twi1.configure(
135        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SCL_PIN as u32),
136        nrf52840::pinmux::Pinmux::new(SCREEN_I2C_SDA_PIN as u32),
137    );
138    nrf52840_peripherals
139        .nrf52
140        .twi1
141        .set_speed(nrf52840::i2c::Speed::K400);
142
143    // I2C address is b011110X, and on this board D/C̅ is GND.
144    let ssd1306_sh1106_i2c = components::i2c::I2CComponent::new(i2c_bus, 0x3c)
145        .finalize(components::i2c_component_static!(nrf52840::i2c::TWI));
146
147    // Create the ssd1306 object for the actual screen driver.
148    #[cfg(feature = "screen_ssd1306")]
149    let ssd1306_sh1106 = components::ssd1306::Ssd1306Component::new(ssd1306_sh1106_i2c, true)
150        .finalize(components::ssd1306_component_static!(nrf52840::i2c::TWI));
151
152    #[cfg(feature = "screen_sh1106")]
153    let ssd1306_sh1106 = components::sh1106::Sh1106Component::new(ssd1306_sh1106_i2c, true)
154        .finalize(components::sh1106_component_static!(nrf52840::i2c::TWI));
155
156    let screen = components::screen::ScreenComponent::new(
157        board_kernel,
158        capsules_extra::screen::DRIVER_NUM,
159        ssd1306_sh1106,
160        None,
161    )
162    .finalize(components::screen_component_static!(1032));
163
164    ssd1306_sh1106.init_screen();
165
166    //--------------------------------------------------------------------------
167    // NONVOLATILE STORAGE
168    //--------------------------------------------------------------------------
169
170    // 32kB of userspace-accessible storage, page aligned:
171    kernel::storage_volume!(APP_STORAGE, 32);
172
173    let nonvolatile_storage = components::isolated_nonvolatile_storage::IsolatedNonvolatileStorageComponent::new(
174        board_kernel,
175        capsules_extra::isolated_nonvolatile_storage_driver::DRIVER_NUM,
176        &nrf52840_peripherals.nrf52.nvmc,
177        core::ptr::addr_of!(APP_STORAGE) as usize,
178        APP_STORAGE.len()
179    )
180    .finalize(components::isolated_nonvolatile_storage_component_static!(
181        nrf52840::nvmc::Nvmc,
182        { components::isolated_nonvolatile_storage::ISOLATED_NONVOLATILE_STORAGE_APP_REGION_SIZE_DEFAULT }
183    ));
184
185    //--------------------------------------------------------------------------
186    // PLATFORM SETUP, SCHEDULER, AND START KERNEL LOOP
187    //--------------------------------------------------------------------------
188
189    let platform = Platform {
190        base: base_platform,
191        eui64,
192        ieee802154,
193        screen,
194        nonvolatile_storage,
195    };
196
197    // These symbols are defined in the linker script.
198    extern "C" {
199        /// Beginning of the ROM region containing app images.
200        static _sapps: u8;
201        /// End of the ROM region containing app images.
202        static _eapps: u8;
203        /// Beginning of the RAM region for app memory.
204        static mut _sappmem: u8;
205        /// End of the RAM region for app memory.
206        static _eappmem: u8;
207    }
208
209    //--------------------------------------------------------------------------
210    // CREDENTIAL CHECKING
211    //--------------------------------------------------------------------------
212
213    // Create the credential checker.
214    let checking_policy = components::appid::checker_null::AppCheckerNullComponent::new()
215        .finalize(components::app_checker_null_component_static!());
216
217    // Create the AppID assigner.
218    let assigner = components::appid::assigner_name::AppIdAssignerNamesComponent::new()
219        .finalize(components::appid_assigner_names_component_static!());
220
221    // Create the process checking machine.
222    let checker = components::appid::checker::ProcessCheckerMachineComponent::new(checking_policy)
223        .finalize(components::process_checker_machine_component_static!());
224
225    //--------------------------------------------------------------------------
226    // STORAGE PERMISSIONS
227    //--------------------------------------------------------------------------
228
229    let storage_permissions_policy =
230        components::storage_permissions::individual::StoragePermissionsIndividualComponent::new()
231            .finalize(
232                components::storage_permissions_individual_component_static!(
233                    nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
234                    kernel::process::ProcessStandardDebugFull,
235                ),
236            );
237
238    //--------------------------------------------------------------------------
239    // PROCESS LOADING
240    //--------------------------------------------------------------------------
241    // Create and start the asynchronous process loader.
242    let _loader = components::loader::sequential::ProcessLoaderSequentialComponent::new(
243        checker,
244        &mut *addr_of_mut!(PROCESSES),
245        board_kernel,
246        chip,
247        &FAULT_RESPONSE,
248        assigner,
249        storage_permissions_policy,
250    )
251    .finalize(components::process_loader_sequential_component_static!(
252        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
253        kernel::process::ProcessStandardDebugFull,
254        NUM_PROCS
255    ));
256
257    board_kernel.kernel_loop(
258        &platform,
259        chip,
260        Some(&platform.base.ipc),
261        &main_loop_capability,
262    );
263}