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