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