clue_nrf52840/
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 Adafruit CLUE nRF52480 Express.
6//!
7//! It is based on nRF52840 Express SoC (Cortex M4 core with a BLE + IEEE 802.15.4 transceiver).
8
9#![no_std]
10#![no_main]
11#![deny(missing_docs)]
12
13use core::ptr::addr_of;
14
15use capsules_core::virtualizers::virtual_aes_ccm::MuxAES128CCM;
16
17use kernel::capabilities;
18use kernel::component::Component;
19use kernel::hil;
20use kernel::hil::buzzer::Buzzer;
21use kernel::hil::i2c::I2CMaster;
22use kernel::hil::led::LedHigh;
23use kernel::hil::symmetric_encryption::AES128;
24use kernel::hil::time::Alarm;
25use kernel::hil::time::Counter;
26use kernel::hil::usb::Client;
27use kernel::platform::chip::Chip;
28use kernel::platform::{KernelResources, SyscallDriverLookup};
29use kernel::process::ProcessArray;
30use kernel::scheduler::round_robin::RoundRobinSched;
31#[allow(unused_imports)]
32use kernel::{create_capability, debug, debug_gpio, debug_verbose, static_init};
33
34use nrf52840::gpio::Pin;
35use nrf52840::interrupt_service::Nrf52840DefaultPeripherals;
36
37// LEDs.
38const LED_RED_PIN: Pin = Pin::P1_01;
39const LED_WHITE_PIN: Pin = Pin::P0_10;
40
41const LED_KERNEL_PIN: Pin = Pin::P1_01;
42
43// Speaker
44const SPEAKER_PIN: Pin = Pin::P1_00;
45
46// Buttons
47const BUTTON_LEFT: Pin = Pin::P1_02;
48const BUTTON_RIGHT: Pin = Pin::P1_10;
49
50#[allow(dead_code)]
51const GPIO_D0: Pin = Pin::P0_04;
52#[allow(dead_code)]
53const GPIO_D1: Pin = Pin::P0_05;
54#[allow(dead_code)]
55const GPIO_D2: Pin = Pin::P0_03;
56#[allow(dead_code)]
57const GPIO_D3: Pin = Pin::P0_28;
58#[allow(dead_code)]
59const GPIO_D4: Pin = Pin::P0_02;
60
61const GPIO_D6: Pin = Pin::P1_09;
62const GPIO_D7: Pin = Pin::P0_07;
63const GPIO_D8: Pin = Pin::P1_07;
64const GPIO_D9: Pin = Pin::P0_27;
65
66#[allow(dead_code)]
67const GPIO_D10: Pin = Pin::P0_30;
68#[allow(dead_code)]
69const GPIO_D12: Pin = Pin::P0_31;
70
71const GPIO_D13: Pin = Pin::P0_08;
72const GPIO_D14: Pin = Pin::P0_06;
73const GPIO_D15: Pin = Pin::P0_26;
74const GPIO_D16: Pin = Pin::P0_29;
75
76const _UART_TX_PIN: Pin = Pin::P0_05;
77const _UART_RX_PIN: Pin = Pin::P0_04;
78
79/// I2C pins for all of the sensors.
80const I2C_SDA_PIN: Pin = Pin::P0_24;
81const I2C_SCL_PIN: Pin = Pin::P0_25;
82
83/// Interrupt pin for the APDS9960 sensor.
84const APDS9960_PIN: Pin = Pin::P0_09;
85
86/// Personal Area Network ID for the IEEE 802.15.4 radio
87const PAN_ID: u16 = 0xABCD;
88
89/// TFT ST7789H2
90const ST7789H2_SCK: Pin = Pin::P0_14;
91const ST7789H2_MOSI: Pin = Pin::P0_15;
92const ST7789H2_MISO: Pin = Pin::P0_26; // ST7789H2 has no MISO Pin, but SPI requires a MISO Pin
93const ST7789H2_CS: Pin = Pin::P0_12;
94const ST7789H2_DC: Pin = Pin::P0_13;
95const ST7789H2_RESET: Pin = Pin::P1_03;
96
97/// TFT backlight
98const _ST7789H2_LITE: Pin = Pin::P1_05;
99
100/// UART Writer for panic!()s.
101pub mod io;
102
103// State for loading and holding applications.
104// How should the kernel respond when a process faults.
105const FAULT_RESPONSE: capsules_system::process_policies::StopWithDebugFaultPolicy =
106    capsules_system::process_policies::StopWithDebugFaultPolicy {};
107
108// Number of concurrent processes this platform supports.
109const NUM_PROCS: usize = 8;
110
111/// Static variables used by io.rs.
112static mut PROCESSES: Option<&'static ProcessArray<NUM_PROCS>> = None;
113static mut CHIP: Option<&'static nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>> = None;
114static mut PROCESS_PRINTER: Option<&'static capsules_system::process_printer::ProcessPrinterText> =
115    None;
116static mut CDC_REF_FOR_PANIC: Option<
117    &'static capsules_extra::usb::cdc::CdcAcm<
118        'static,
119        nrf52::usbd::Usbd,
120        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, nrf52::rtc::Rtc>,
121    >,
122> = None;
123static mut NRF52_POWER: Option<&'static nrf52840::power::Power> = None;
124
125kernel::stack_size! {0x1000}
126
127// Function for the CDC/USB stack to use to enter the Adafruit nRF52 Bootloader
128fn baud_rate_reset_bootloader_enter() {
129    unsafe {
130        // 0x4e is the magic value the Adafruit nRF52 Bootloader expects
131        // as defined by https://github.com/adafruit/Adafruit_nRF52_Bootloader/blob/master/src/main.c
132        NRF52_POWER.unwrap().set_gpregret(0x90);
133        // uncomment to use with Adafruit nRF52 Bootloader
134        // NRF52_POWER.unwrap().set_gpregret(0x4e);
135        cortexm4::scb::reset();
136    }
137}
138
139type SHT3xSensor = components::sht3x::SHT3xComponentType<
140    capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, nrf52::rtc::Rtc<'static>>,
141    capsules_core::virtualizers::virtual_i2c::I2CDevice<'static, nrf52840::i2c::TWI<'static>>,
142>;
143type TemperatureDriver = components::temperature::TemperatureComponentType<SHT3xSensor>;
144type HumidityDriver = components::humidity::HumidityComponentType<SHT3xSensor>;
145type RngDriver = components::rng::RngComponentType<nrf52840::trng::Trng<'static>>;
146
147type Ieee802154Driver = components::ieee802154::Ieee802154ComponentType<
148    nrf52840::ieee802154_radio::Radio<'static>,
149    nrf52840::aes::AesECB<'static>,
150>;
151
152/// Supported drivers by the platform
153pub struct Platform {
154    ble_radio: &'static capsules_extra::ble_advertising_driver::BLE<
155        'static,
156        nrf52::ble_radio::Radio<'static>,
157        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
158            'static,
159            nrf52::rtc::Rtc<'static>,
160        >,
161    >,
162    ieee802154_radio: &'static Ieee802154Driver,
163    console: &'static capsules_core::console::Console<'static>,
164    proximity: &'static capsules_extra::proximity::ProximitySensor<'static>,
165    gpio: &'static capsules_core::gpio::GPIO<'static, nrf52::gpio::GPIOPin<'static>>,
166    led: &'static capsules_core::led::LedDriver<
167        'static,
168        LedHigh<'static, nrf52::gpio::GPIOPin<'static>>,
169        2,
170    >,
171    button: &'static capsules_core::button::Button<'static, nrf52::gpio::GPIOPin<'static>>,
172    screen: &'static capsules_extra::screen::screen::Screen<'static>,
173    rng: &'static RngDriver,
174    ipc: kernel::ipc::IPC<{ NUM_PROCS as u8 }>,
175    alarm: &'static capsules_core::alarm::AlarmDriver<
176        'static,
177        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
178            'static,
179            nrf52::rtc::Rtc<'static>,
180        >,
181    >,
182    buzzer: &'static capsules_extra::buzzer_driver::Buzzer<
183        'static,
184        capsules_extra::buzzer_pwm::PwmBuzzer<
185            'static,
186            capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
187                'static,
188                nrf52840::rtc::Rtc<'static>,
189            >,
190            capsules_core::virtualizers::virtual_pwm::PwmPinUser<'static, nrf52840::pwm::Pwm>,
191        >,
192    >,
193    adc: &'static capsules_core::adc::AdcVirtualized<'static>,
194    temperature: &'static TemperatureDriver,
195    humidity: &'static HumidityDriver,
196    scheduler: &'static RoundRobinSched<'static>,
197    systick: cortexm4::systick::SysTick,
198}
199
200impl SyscallDriverLookup for Platform {
201    fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
202    where
203        F: FnOnce(Option<&dyn kernel::syscall::SyscallDriver>) -> R,
204    {
205        match driver_num {
206            capsules_core::console::DRIVER_NUM => f(Some(self.console)),
207            capsules_extra::proximity::DRIVER_NUM => f(Some(self.proximity)),
208            capsules_core::gpio::DRIVER_NUM => f(Some(self.gpio)),
209            capsules_core::alarm::DRIVER_NUM => f(Some(self.alarm)),
210            capsules_core::led::DRIVER_NUM => f(Some(self.led)),
211            capsules_core::button::DRIVER_NUM => f(Some(self.button)),
212            capsules_core::adc::DRIVER_NUM => f(Some(self.adc)),
213            capsules_extra::screen::screen::DRIVER_NUM => f(Some(self.screen)),
214            capsules_core::rng::DRIVER_NUM => f(Some(self.rng)),
215            capsules_extra::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)),
216            capsules_extra::ieee802154::DRIVER_NUM => f(Some(self.ieee802154_radio)),
217            capsules_extra::buzzer_driver::DRIVER_NUM => f(Some(self.buzzer)),
218            kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
219            capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)),
220            capsules_extra::humidity::DRIVER_NUM => f(Some(self.humidity)),
221            _ => f(None),
222        }
223    }
224}
225
226impl KernelResources<nrf52::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>>
227    for Platform
228{
229    type SyscallDriverLookup = Self;
230    type SyscallFilter = ();
231    type ProcessFault = ();
232    type Scheduler = RoundRobinSched<'static>;
233    type SchedulerTimer = cortexm4::systick::SysTick;
234    type WatchDog = ();
235    type ContextSwitchCallback = ();
236
237    fn syscall_driver_lookup(&self) -> &Self::SyscallDriverLookup {
238        self
239    }
240    fn syscall_filter(&self) -> &Self::SyscallFilter {
241        &()
242    }
243    fn process_fault(&self) -> &Self::ProcessFault {
244        &()
245    }
246    fn scheduler(&self) -> &Self::Scheduler {
247        self.scheduler
248    }
249    fn scheduler_timer(&self) -> &Self::SchedulerTimer {
250        &self.systick
251    }
252    fn watchdog(&self) -> &Self::WatchDog {
253        &()
254    }
255    fn context_switch_callback(&self) -> &Self::ContextSwitchCallback {
256        &()
257    }
258}
259
260/// This is in a separate, inline(never) function so that its stack frame is
261/// removed when this function returns. Otherwise, the stack space used for
262/// these static_inits is wasted.
263#[inline(never)]
264unsafe fn start() -> (
265    &'static kernel::Kernel,
266    Platform,
267    &'static nrf52840::chip::NRF52<'static, Nrf52840DefaultPeripherals<'static>>,
268) {
269    nrf52840::init();
270
271    let ieee802154_ack_buf = static_init!(
272        [u8; nrf52840::ieee802154_radio::ACK_BUF_SIZE],
273        [0; nrf52840::ieee802154_radio::ACK_BUF_SIZE]
274    );
275    // Initialize chip peripheral drivers
276    let nrf52840_peripherals = static_init!(
277        Nrf52840DefaultPeripherals,
278        Nrf52840DefaultPeripherals::new(ieee802154_ack_buf)
279    );
280
281    // set up circular peripheral dependencies
282    nrf52840_peripherals.init();
283
284    let base_peripherals = &nrf52840_peripherals.nrf52;
285
286    // Save a reference to the power module for resetting the board into the
287    // bootloader.
288    NRF52_POWER = Some(&base_peripherals.pwr_clk);
289
290    // Create an array to hold process references.
291    let processes = components::process_array::ProcessArrayComponent::new()
292        .finalize(components::process_array_component_static!(NUM_PROCS));
293    PROCESSES = Some(processes);
294
295    // Setup space to store the core kernel data structure.
296    let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(processes.as_slice()));
297
298    //--------------------------------------------------------------------------
299    // CAPABILITIES
300    //--------------------------------------------------------------------------
301
302    // Create capabilities that the board needs to call certain protected kernel
303    // functions.
304    let process_management_capability =
305        create_capability!(capabilities::ProcessManagementCapability);
306    let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability);
307
308    //--------------------------------------------------------------------------
309    // DEBUG GPIO
310    //--------------------------------------------------------------------------
311
312    // Configure kernel debug GPIOs as early as possible. These are used by the
313    // `debug_gpio!(0, toggle)` macro. We configure these early so that the
314    // macro is available during most of the setup code and kernel execution.
315    kernel::debug::assign_gpios(
316        Some(&nrf52840_peripherals.gpio_port[LED_KERNEL_PIN]),
317        None,
318        None,
319    );
320
321    //--------------------------------------------------------------------------
322    // GPIO
323    //--------------------------------------------------------------------------
324
325    let gpio = components::gpio::GpioComponent::new(
326        board_kernel,
327        capsules_core::gpio::DRIVER_NUM,
328        components::gpio_component_helper!(
329            nrf52840::gpio::GPIOPin,
330            // uncomment the following to use pins D0, D1, D2, D3 and D4 as gpio
331            // instead of A2, A3, A4, A5 and A6
332            // 0 => &nrf52840_peripherals.gpio_port[GPIO_D0],
333            // 1 => &nrf52840_peripherals.gpio_port[GPIO_D1],
334            // 2 => &nrf52840_peripherals.gpio_port[GPIO_D2],
335            // 3 => &nrf52840_peripherals.gpio_port[GPIO_D3],
336            // 4 => &nrf52840_peripherals.gpio_port[GPIO_D4],
337
338            6 => &nrf52840_peripherals.gpio_port[GPIO_D6],
339            7 => &nrf52840_peripherals.gpio_port[GPIO_D7],
340            8 => &nrf52840_peripherals.gpio_port[GPIO_D8],
341            9 => &nrf52840_peripherals.gpio_port[GPIO_D9],
342
343            // uncomment the following to use pins D10 as gpio instead of A7
344            // 10 => &nrf52840_peripherals.gpio_port[GPIO_D10],
345
346            // uncomment the following to use pins D12 as gpio instead of A0
347            // 12 => &nrf52840_peripherals.gpio_port[GPIO_D12],
348
349            13 => &nrf52840_peripherals.gpio_port[GPIO_D13],
350            14 => &nrf52840_peripherals.gpio_port[GPIO_D14],
351            15 => &nrf52840_peripherals.gpio_port[GPIO_D15],
352            16 => &nrf52840_peripherals.gpio_port[GPIO_D16]
353        ),
354    )
355    .finalize(components::gpio_component_static!(nrf52840::gpio::GPIOPin));
356
357    //--------------------------------------------------------------------------
358    // LEDs
359    //--------------------------------------------------------------------------
360
361    let led = components::led::LedsComponent::new().finalize(components::led_component_static!(
362        LedHigh<'static, nrf52840::gpio::GPIOPin>,
363        LedHigh::new(&nrf52840_peripherals.gpio_port[LED_RED_PIN]),
364        LedHigh::new(&nrf52840_peripherals.gpio_port[LED_WHITE_PIN])
365    ));
366
367    //--------------------------------------------------------------------------
368    // Buttons
369    //--------------------------------------------------------------------------
370    let button = components::button::ButtonComponent::new(
371        board_kernel,
372        capsules_core::button::DRIVER_NUM,
373        components::button_component_helper!(
374            nrf52840::gpio::GPIOPin,
375            (
376                &nrf52840_peripherals.gpio_port[BUTTON_LEFT],
377                kernel::hil::gpio::ActivationMode::ActiveLow,
378                kernel::hil::gpio::FloatingState::PullUp
379            ), // Left
380            (
381                &nrf52840_peripherals.gpio_port[BUTTON_RIGHT],
382                kernel::hil::gpio::ActivationMode::ActiveLow,
383                kernel::hil::gpio::FloatingState::PullUp
384            ) // Right
385        ),
386    )
387    .finalize(components::button_component_static!(
388        nrf52840::gpio::GPIOPin
389    ));
390
391    //--------------------------------------------------------------------------
392    // ALARM & TIMER
393    //--------------------------------------------------------------------------
394
395    let rtc = &base_peripherals.rtc;
396    let _ = rtc.start();
397
398    let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc)
399        .finalize(components::alarm_mux_component_static!(nrf52::rtc::Rtc));
400    let alarm = components::alarm::AlarmDriverComponent::new(
401        board_kernel,
402        capsules_core::alarm::DRIVER_NUM,
403        mux_alarm,
404    )
405    .finalize(components::alarm_component_static!(nrf52::rtc::Rtc));
406
407    //--------------------------------------------------------------------------
408    // PWM & BUZZER
409    //--------------------------------------------------------------------------
410
411    let mux_pwm = static_init!(
412        capsules_core::virtualizers::virtual_pwm::MuxPwm<'static, nrf52840::pwm::Pwm>,
413        capsules_core::virtualizers::virtual_pwm::MuxPwm::new(&base_peripherals.pwm0)
414    );
415    let virtual_pwm_buzzer = static_init!(
416        capsules_core::virtualizers::virtual_pwm::PwmPinUser<'static, nrf52840::pwm::Pwm>,
417        capsules_core::virtualizers::virtual_pwm::PwmPinUser::new(
418            mux_pwm,
419            nrf52840::pinmux::Pinmux::new(SPEAKER_PIN as u32)
420        )
421    );
422    virtual_pwm_buzzer.add_to_mux();
423
424    let virtual_alarm_buzzer = static_init!(
425        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc>,
426        capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm::new(mux_alarm)
427    );
428    virtual_alarm_buzzer.setup();
429
430    let pwm_buzzer = static_init!(
431        capsules_extra::buzzer_pwm::PwmBuzzer<
432            'static,
433            capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
434                'static,
435                nrf52840::rtc::Rtc,
436            >,
437            capsules_core::virtualizers::virtual_pwm::PwmPinUser<'static, nrf52840::pwm::Pwm>,
438        >,
439        capsules_extra::buzzer_pwm::PwmBuzzer::new(
440            virtual_pwm_buzzer,
441            virtual_alarm_buzzer,
442            capsules_extra::buzzer_pwm::DEFAULT_MAX_BUZZ_TIME_MS,
443        )
444    );
445
446    let buzzer = static_init!(
447        capsules_extra::buzzer_driver::Buzzer<
448            'static,
449            capsules_extra::buzzer_pwm::PwmBuzzer<
450                'static,
451                capsules_core::virtualizers::virtual_alarm::VirtualMuxAlarm<
452                    'static,
453                    nrf52840::rtc::Rtc,
454                >,
455                capsules_core::virtualizers::virtual_pwm::PwmPinUser<'static, nrf52840::pwm::Pwm>,
456            >,
457        >,
458        capsules_extra::buzzer_driver::Buzzer::new(
459            pwm_buzzer,
460            capsules_extra::buzzer_driver::DEFAULT_MAX_BUZZ_TIME_MS,
461            board_kernel.create_grant(
462                capsules_extra::buzzer_driver::DRIVER_NUM,
463                &memory_allocation_capability
464            )
465        )
466    );
467
468    pwm_buzzer.set_client(buzzer);
469
470    virtual_alarm_buzzer.set_alarm_client(pwm_buzzer);
471
472    //--------------------------------------------------------------------------
473    // UART & CONSOLE & DEBUG
474    //--------------------------------------------------------------------------
475
476    // Setup the CDC-ACM over USB driver that we will use for UART.
477    // We use the Adafruit Vendor ID and Product ID since the device is the same.
478
479    // Create the strings we include in the USB descriptor. We use the hardcoded
480    // DEVICEADDR register on the nRF52 to set the serial number.
481    let serial_number_buf = static_init!([u8; 17], [0; 17]);
482    let serial_number_string: &'static str =
483        (*addr_of!(nrf52::ficr::FICR_INSTANCE)).address_str(serial_number_buf);
484    let strings = static_init!(
485        [&str; 3],
486        [
487            "Adafruit",               // Manufacturer
488            "CLUE nRF52840 - TockOS", // Product
489            serial_number_string,     // Serial number
490        ]
491    );
492
493    let cdc = components::cdc::CdcAcmComponent::new(
494        &nrf52840_peripherals.usbd,
495        capsules_extra::usb::cdc::MAX_CTRL_PACKET_SIZE_NRF52840,
496        0x239a,
497        0x8071,
498        strings,
499        mux_alarm,
500        Some(&baud_rate_reset_bootloader_enter),
501    )
502    .finalize(components::cdc_acm_component_static!(
503        nrf52::usbd::Usbd,
504        nrf52::rtc::Rtc
505    ));
506    CDC_REF_FOR_PANIC = Some(cdc); //for use by panic handler
507
508    // Create a shared UART channel for the console and for kernel debug.
509    let uart_mux = components::console::UartMuxComponent::new(cdc, 115200)
510        .finalize(components::uart_mux_component_static!());
511
512    // Setup the console.
513    let console = components::console::ConsoleComponent::new(
514        board_kernel,
515        capsules_core::console::DRIVER_NUM,
516        uart_mux,
517    )
518    .finalize(components::console_component_static!());
519    // Create the debugger object that handles calls to `debug!()`.
520    components::debug_writer::DebugWriterComponent::new(
521        uart_mux,
522        create_capability!(capabilities::SetDebugWriterCapability),
523    )
524    .finalize(components::debug_writer_component_static!());
525
526    //--------------------------------------------------------------------------
527    // RANDOM NUMBERS
528    //--------------------------------------------------------------------------
529
530    let rng = components::rng::RngComponent::new(
531        board_kernel,
532        capsules_core::rng::DRIVER_NUM,
533        &base_peripherals.trng,
534    )
535    .finalize(components::rng_component_static!(nrf52840::trng::Trng));
536
537    //--------------------------------------------------------------------------
538    // ADC
539    //--------------------------------------------------------------------------
540    base_peripherals.adc.calibrate();
541
542    let adc_mux = components::adc::AdcMuxComponent::new(&base_peripherals.adc)
543        .finalize(components::adc_mux_component_static!(nrf52840::adc::Adc));
544
545    let adc_syscall =
546        components::adc::AdcVirtualComponent::new(board_kernel, capsules_core::adc::DRIVER_NUM)
547            .finalize(components::adc_syscall_component_helper!(
548                // A0
549                components::adc::AdcComponent::new(
550                    adc_mux,
551                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput7)
552                )
553                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
554                // A1
555                components::adc::AdcComponent::new(
556                    adc_mux,
557                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput5)
558                )
559                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
560                // A2
561                components::adc::AdcComponent::new(
562                    adc_mux,
563                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput2)
564                )
565                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
566                // A3
567                components::adc::AdcComponent::new(
568                    adc_mux,
569                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput3)
570                )
571                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
572                // A4
573                components::adc::AdcComponent::new(
574                    adc_mux,
575                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput1)
576                )
577                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
578                // A5
579                components::adc::AdcComponent::new(
580                    adc_mux,
581                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput4)
582                )
583                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
584                // A6
585                components::adc::AdcComponent::new(
586                    adc_mux,
587                    nrf52840::adc::AdcChannelSetup::new(nrf52840::adc::AdcChannel::AnalogInput0)
588                )
589                .finalize(components::adc_component_static!(nrf52840::adc::Adc)),
590            ));
591
592    //--------------------------------------------------------------------------
593    // SENSORS
594    //--------------------------------------------------------------------------
595
596    let sensors_i2c_bus = static_init!(
597        capsules_core::virtualizers::virtual_i2c::MuxI2C<'static, nrf52840::i2c::TWI>,
598        capsules_core::virtualizers::virtual_i2c::MuxI2C::new(&base_peripherals.twi1, None,)
599    );
600    kernel::deferred_call::DeferredCallClient::register(sensors_i2c_bus);
601    base_peripherals.twi1.configure(
602        nrf52840::pinmux::Pinmux::new(I2C_SCL_PIN as u32),
603        nrf52840::pinmux::Pinmux::new(I2C_SDA_PIN as u32),
604    );
605    base_peripherals.twi1.set_master_client(sensors_i2c_bus);
606
607    let apds9960 = components::apds9960::Apds9960Component::new(
608        sensors_i2c_bus,
609        0x39,
610        &nrf52840_peripherals.gpio_port[APDS9960_PIN],
611    )
612    .finalize(components::apds9960_component_static!(nrf52840::i2c::TWI));
613    let proximity = components::proximity::ProximityComponent::new(
614        apds9960,
615        board_kernel,
616        capsules_extra::proximity::DRIVER_NUM,
617    )
618    .finalize(components::proximity_component_static!());
619
620    let sht3x = components::sht3x::SHT3xComponent::new(
621        sensors_i2c_bus,
622        capsules_extra::sht3x::BASE_ADDR,
623        mux_alarm,
624    )
625    .finalize(components::sht3x_component_static!(
626        nrf52::rtc::Rtc<'static>,
627        nrf52840::i2c::TWI
628    ));
629
630    let temperature = components::temperature::TemperatureComponent::new(
631        board_kernel,
632        capsules_extra::temperature::DRIVER_NUM,
633        sht3x,
634    )
635    .finalize(components::temperature_component_static!(SHT3xSensor));
636
637    let humidity = components::humidity::HumidityComponent::new(
638        board_kernel,
639        capsules_extra::humidity::DRIVER_NUM,
640        sht3x,
641    )
642    .finalize(components::humidity_component_static!(SHT3xSensor));
643
644    //--------------------------------------------------------------------------
645    // TFT
646    //--------------------------------------------------------------------------
647
648    let spi_mux = components::spi::SpiMuxComponent::new(&base_peripherals.spim0)
649        .finalize(components::spi_mux_component_static!(nrf52840::spi::SPIM));
650
651    base_peripherals.spim0.configure(
652        nrf52840::pinmux::Pinmux::new(ST7789H2_MOSI as u32),
653        nrf52840::pinmux::Pinmux::new(ST7789H2_MISO as u32),
654        nrf52840::pinmux::Pinmux::new(ST7789H2_SCK as u32),
655    );
656
657    let bus = components::bus::SpiMasterBusComponent::new(
658        spi_mux,
659        hil::spi::cs::IntoChipSelect::<_, hil::spi::cs::ActiveLow>::into_cs(
660            &nrf52840_peripherals.gpio_port[ST7789H2_CS],
661        ),
662        20_000_000,
663        kernel::hil::spi::ClockPhase::SampleLeading,
664        kernel::hil::spi::ClockPolarity::IdleLow,
665    )
666    .finalize(components::spi_bus_component_static!(nrf52840::spi::SPIM));
667
668    let tft = components::st77xx::ST77XXComponent::new(
669        mux_alarm,
670        bus,
671        Some(&nrf52840_peripherals.gpio_port[ST7789H2_DC]),
672        Some(&nrf52840_peripherals.gpio_port[ST7789H2_RESET]),
673        &capsules_extra::st77xx::ST7789H2,
674    )
675    .finalize(components::st77xx_component_static!(
676        // bus type
677        capsules_extra::bus::SpiMasterBus<
678            'static,
679            capsules_core::virtualizers::virtual_spi::VirtualSpiMasterDevice<
680                'static,
681                nrf52840::spi::SPIM,
682            >,
683        >,
684        // timer type
685        nrf52840::rtc::Rtc,
686        // pin type
687        nrf52::gpio::GPIOPin<'static>
688    ));
689
690    let _ = tft.init();
691
692    let screen = components::screen::ScreenComponent::new(
693        board_kernel,
694        capsules_extra::screen::screen::DRIVER_NUM,
695        tft,
696        Some(tft),
697    )
698    .finalize(components::screen_component_static!(57600));
699
700    //--------------------------------------------------------------------------
701    // WIRELESS
702    //--------------------------------------------------------------------------
703
704    let ble_radio = components::ble::BLEComponent::new(
705        board_kernel,
706        capsules_extra::ble_advertising_driver::DRIVER_NUM,
707        &base_peripherals.ble_radio,
708        mux_alarm,
709    )
710    .finalize(components::ble_component_static!(
711        nrf52840::rtc::Rtc,
712        nrf52840::ble_radio::Radio
713    ));
714
715    let aes_mux = static_init!(
716        MuxAES128CCM<'static, nrf52840::aes::AesECB>,
717        MuxAES128CCM::new(&base_peripherals.ecb,)
718    );
719    kernel::deferred_call::DeferredCallClient::register(aes_mux);
720    base_peripherals.ecb.set_client(aes_mux);
721
722    let device_id = (*addr_of!(nrf52840::ficr::FICR_INSTANCE)).id();
723
724    let device_id_bottom_16 = u16::from_le_bytes([device_id[0], device_id[1]]);
725
726    let (ieee802154_radio, _mux_mac) = components::ieee802154::Ieee802154Component::new(
727        board_kernel,
728        capsules_extra::ieee802154::DRIVER_NUM,
729        &nrf52840_peripherals.ieee802154_radio,
730        aes_mux,
731        PAN_ID,
732        device_id_bottom_16,
733        device_id,
734    )
735    .finalize(components::ieee802154_component_static!(
736        nrf52840::ieee802154_radio::Radio,
737        nrf52840::aes::AesECB<'static>
738    ));
739
740    let process_printer = components::process_printer::ProcessPrinterTextComponent::new()
741        .finalize(components::process_printer_text_component_static!());
742    PROCESS_PRINTER = Some(process_printer);
743
744    let pconsole = components::process_console::ProcessConsoleComponent::new(
745        board_kernel,
746        uart_mux,
747        mux_alarm,
748        process_printer,
749        Some(cortexm4::support::reset),
750    )
751    .finalize(components::process_console_component_static!(
752        nrf52840::rtc::Rtc
753    ));
754    let _ = pconsole.start();
755
756    //--------------------------------------------------------------------------
757    // FINAL SETUP AND BOARD BOOT
758    //--------------------------------------------------------------------------
759
760    // Start all of the clocks. Low power operation will require a better
761    // approach than this.
762    nrf52_components::NrfClockComponent::new(&base_peripherals.clock).finalize(());
763
764    let scheduler = components::sched::round_robin::RoundRobinComponent::new(processes)
765        .finalize(components::round_robin_component_static!(NUM_PROCS));
766
767    let platform = Platform {
768        ble_radio,
769        ieee802154_radio,
770        console,
771        proximity,
772        led,
773        gpio,
774        adc: adc_syscall,
775        screen,
776        button,
777        rng,
778        buzzer,
779        alarm,
780        ipc: kernel::ipc::IPC::new(
781            board_kernel,
782            kernel::ipc::DRIVER_NUM,
783            &memory_allocation_capability,
784        ),
785        temperature,
786        humidity,
787        scheduler,
788        systick: cortexm4::systick::SysTick::new_with_calibration(64000000),
789    };
790
791    let chip = static_init!(
792        nrf52840::chip::NRF52<Nrf52840DefaultPeripherals>,
793        nrf52840::chip::NRF52::new(nrf52840_peripherals)
794    );
795    CHIP = Some(chip);
796
797    // Need to disable the MPU because the bootloader seems to set it up.
798    chip.mpu().clear_mpu();
799
800    // Configure the USB stack to enable a serial port over CDC-ACM.
801    cdc.enable();
802    cdc.attach();
803
804    debug!("Initialization complete. Entering main loop.");
805
806    //--------------------------------------------------------------------------
807    // PROCESSES AND MAIN LOOP
808    //--------------------------------------------------------------------------
809
810    // These symbols are defined in the linker script.
811    extern "C" {
812        /// Beginning of the ROM region containing app images.
813        static _sapps: u8;
814        /// End of the ROM region containing app images.
815        static _eapps: u8;
816        /// Beginning of the RAM region for app memory.
817        static mut _sappmem: u8;
818        /// End of the RAM region for app memory.
819        static _eappmem: u8;
820    }
821
822    kernel::process::load_processes(
823        board_kernel,
824        chip,
825        core::slice::from_raw_parts(
826            core::ptr::addr_of!(_sapps),
827            core::ptr::addr_of!(_eapps) as usize - core::ptr::addr_of!(_sapps) as usize,
828        ),
829        core::slice::from_raw_parts_mut(
830            core::ptr::addr_of_mut!(_sappmem),
831            core::ptr::addr_of!(_eappmem) as usize - core::ptr::addr_of!(_sappmem) as usize,
832        ),
833        &FAULT_RESPONSE,
834        &process_management_capability,
835    )
836    .unwrap_or_else(|err| {
837        debug!("Error loading processes!");
838        debug!("{:?}", err);
839    });
840
841    (board_kernel, platform, chip)
842}
843
844/// Main function called after RAM initialized.
845#[no_mangle]
846pub unsafe fn main() {
847    let main_loop_capability = create_capability!(capabilities::MainLoopCapability);
848
849    let (board_kernel, board, chip) = start();
850    board_kernel.kernel_loop(&board, chip, Some(&board.ipc), &main_loop_capability);
851}