From bb2685ca94d45522fbb301bda07d4cb6f205e5f2 Mon Sep 17 00:00:00 2001 From: Jean-Michel Picod Date: Wed, 16 Sep 2020 10:38:36 +0200 Subject: [PATCH] Update out-of-tree board to new kernel --- boards/nordic/nrf52840_dongle_dfu/Cargo.toml | 2 +- boards/nordic/nrf52840_mdk_dfu/Cargo.toml | 2 +- boards/nordic/nrf52840_mdk_dfu/src/main.rs | 373 ++++++++++++++++--- 3 files changed, 332 insertions(+), 45 deletions(-) diff --git a/boards/nordic/nrf52840_dongle_dfu/Cargo.toml b/boards/nordic/nrf52840_dongle_dfu/Cargo.toml index 35eab8a..10b387c 100644 --- a/boards/nordic/nrf52840_dongle_dfu/Cargo.toml +++ b/boards/nordic/nrf52840_dongle_dfu/Cargo.toml @@ -15,4 +15,4 @@ cortexm4 = { path = "../../../arch/cortex-m4" } capsules = { path = "../../../capsules" } kernel = { path = "../../../kernel" } nrf52840 = { path = "../../../chips/nrf52840" } -nrf52dk_base = { path = "../nrf52dk_base" } +nrf52_components = { path = "../nrf52_components" } diff --git a/boards/nordic/nrf52840_mdk_dfu/Cargo.toml b/boards/nordic/nrf52840_mdk_dfu/Cargo.toml index c0cb7af..03733b8 100644 --- a/boards/nordic/nrf52840_mdk_dfu/Cargo.toml +++ b/boards/nordic/nrf52840_mdk_dfu/Cargo.toml @@ -11,4 +11,4 @@ cortexm4 = { path = "../../../arch/cortex-m4" } capsules = { path = "../../../capsules" } kernel = { path = "../../../kernel" } nrf52840 = { path = "../../../chips/nrf52840" } -nrf52dk_base = { path = "../nrf52dk_base" } +nrf52_components = { path = "../nrf52_components" } diff --git a/boards/nordic/nrf52840_mdk_dfu/src/main.rs b/boards/nordic/nrf52840_mdk_dfu/src/main.rs index 24dc42f..a346da5 100644 --- a/boards/nordic/nrf52840_mdk_dfu/src/main.rs +++ b/boards/nordic/nrf52840_mdk_dfu/src/main.rs @@ -4,14 +4,20 @@ //! many exported I/O and peripherals. #![no_std] -#![no_main] +// Disable this attribute when documenting, as a workaround for +// https://github.com/rust-lang/rust/issues/62184. +#![cfg_attr(not(doc), no_main)] +#![feature(const_in_array_repeat_expressions)] #![deny(missing_docs)] +use capsules::virtual_alarm::VirtualMuxAlarm; +use kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState}; use kernel::component::Component; #[allow(unused_imports)] -use kernel::{debug, debug_gpio, debug_verbose, static_init}; +use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init}; +use kernel::hil::usb::UsbController; use nrf52840::gpio::Pin; -use nrf52dk_base::{SpiPins, UartChannel, UartPins}; +use nrf52_components::{self, UartChannel, UartPins}; // The nRF52840 MDK USB Dongle LEDs const LED1_R_PIN: Pin = Pin::P0_23; @@ -27,13 +33,24 @@ const UART_TXD: Pin = Pin::P0_20; const UART_CTS: Option = Some(Pin::P0_03); const UART_RXD: Pin = Pin::P0_19; -const SPI_MOSI: Pin = Pin::P0_05; -const SPI_MISO: Pin = Pin::P0_06; -const SPI_CLK: Pin = Pin::P0_07; +// Constants related to the configuration of the 15.4 network stack +const SRC_MAC: u16 = 0xf00f; +const PAN_ID: u16 = 0xABCD; /// UART Writer pub mod io; +const VENDOR_ID: u16 = 0x1915; // Nordic Semiconductor +const PRODUCT_ID: u16 = 0x521f; // nRF52840 Dongle (PCA10059) +static STRINGS: &'static [&'static str] = &[ + // Manufacturer + "Nordic Semiconductor ASA", + // Product + "OpenSK", + // Serial number + "v0.1", +]; + // State for loading and holding applications. // How should the kernel respond when a process faults. const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultResponse::Panic; @@ -41,12 +58,8 @@ const FAULT_RESPONSE: kernel::procs::FaultResponse = kernel::procs::FaultRespons // Number of concurrent processes this platform supports. const NUM_PROCS: usize = 8; -// RAM to be shared by all application processes. -#[link_section = ".app_memory"] -static mut APP_MEMORY: [u8; 0x3C000] = [0; 0x3C000]; - static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] = - [None, None, None, None, None, None, None, None]; + [None; NUM_PROCS]; static mut STORAGE_LOCATIONS: [kernel::StorageLocation; 1] = [kernel::StorageLocation { address: 0xC0000, @@ -61,6 +74,84 @@ static mut CHIP: Option<&'static nrf52840::chip::Chip> = None; #[link_section = ".stack_buffer"] pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000]; +/// Supported drivers by the platform +pub struct Platform { + ble_radio: &'static capsules::ble_advertising_driver::BLE< + 'static, + nrf52840::ble_radio::Radio<'static>, + VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>, + >, + ieee802154_radio: &'static capsules::ieee802154::RadioDriver<'static>, + button: &'static capsules::button::Button<'static, nrf52840::gpio::GPIOPin<'static>>, + pconsole: &'static capsules::process_console::ProcessConsole< + 'static, + components::process_console::Capability, + >, + console: &'static capsules::console::Console<'static>, + gpio: &'static capsules::gpio::GPIO<'static, nrf52840::gpio::GPIOPin<'static>>, + led: &'static capsules::led::LED<'static, nrf52840::gpio::GPIOPin<'static>>, + rng: &'static capsules::rng::RngDriver<'static>, + temp: &'static capsules::temperature::TemperatureSensor<'static>, + ipc: kernel::ipc::IPC, + analog_comparator: &'static capsules::analog_comparator::AnalogComparator< + 'static, + nrf52840::acomp::Comparator<'static>, + >, + alarm: &'static capsules::alarm::AlarmDriver< + 'static, + capsules::virtual_alarm::VirtualMuxAlarm<'static, nrf52840::rtc::Rtc<'static>>, + >, + nvmc: &'static nrf52840::nvmc::SyscallDriver, + usb: &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver< + 'static, + 'static, + nrf52840::usbd::Usbd<'static>, + >, +} + +impl kernel::Platform for Platform { + fn with_driver(&self, driver_num: usize, f: F) -> R + where + F: FnOnce(Option<&dyn kernel::Driver>) -> R, + { + match driver_num { + capsules::console::DRIVER_NUM => f(Some(self.console)), + capsules::gpio::DRIVER_NUM => f(Some(self.gpio)), + capsules::alarm::DRIVER_NUM => f(Some(self.alarm)), + capsules::led::DRIVER_NUM => f(Some(self.led)), + capsules::button::DRIVER_NUM => f(Some(self.button)), + capsules::rng::DRIVER_NUM => f(Some(self.rng)), + capsules::ble_advertising_driver::DRIVER_NUM => f(Some(self.ble_radio)), + capsules::ieee802154::DRIVER_NUM => f(Some(self.ieee802154_radio)), + capsules::temperature::DRIVER_NUM => f(Some(self.temp)), + capsules::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)), + nrf52840::nvmc::DRIVER_NUM => f(Some(self.nvmc)), + capsules::usb::usb_ctap::DRIVER_NUM => f(Some(self.usb)), + kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)), + _ => f(None), + } + } + + fn filter_syscall( + &self, + process: &dyn kernel::procs::ProcessType, + syscall: &kernel::syscall::Syscall, + ) -> Result<(), kernel::ReturnCode> { + use kernel::syscall::Syscall; + match *syscall { + Syscall::COMMAND { + driver_number: nrf52840::nvmc::DRIVER_NUM, + subdriver_number: cmd, + arg0: ptr, + arg1: len, + } if (cmd == 2 || cmd == 3) && !process.fits_in_storage_location(ptr, len) => { + Err(kernel::ReturnCode::EINVAL) + } + _ => Ok(()), + } + } +} + /// Entry point in the vector table called on hard reset. #[no_mangle] pub unsafe fn reset_handler() { @@ -72,24 +163,34 @@ pub unsafe fn reset_handler() { kernel::Kernel::new_with_storage(&PROCESSES, &STORAGE_LOCATIONS) ); // GPIOs - let gpio = components::gpio::GpioComponent::new(board_kernel).finalize( + let gpio = components::gpio::GpioComponent::new( + board_kernel, components::gpio_component_helper!( - &nrf52840::gpio::PORT[Pin::P0_04], - &nrf52840::gpio::PORT[Pin::P0_05], - &nrf52840::gpio::PORT[Pin::P0_06], - &nrf52840::gpio::PORT[Pin::P0_07], - &nrf52840::gpio::PORT[Pin::P0_08] + nrf52840::gpio::GPIOPin, + // left side of the USB plug. Right side is used for UART + 0 => &nrf52840::gpio::PORT[Pin::P0_04], + 1 => &nrf52840::gpio::PORT[Pin::P0_05], + 2 => &nrf52840::gpio::PORT[Pin::P0_06], + 3 => &nrf52840::gpio::PORT[Pin::P0_07], + 4 => &nrf52840::gpio::PORT[Pin::P0_08] ), - ); - let button = components::button::ButtonComponent::new(board_kernel).finalize( - components::button_component_helper!(( - &nrf52840::gpio::PORT[BUTTON_PIN], - kernel::hil::gpio::ActivationMode::ActiveLow, - kernel::hil::gpio::FloatingState::PullUp - )), - ); + ).finalize(components::gpio_component_buf!(nrf52840::gpio::GPIOPin)); - let led = components::led::LedsComponent::new().finalize(components::led_component_helper!( + let button = components::button::ButtonComponent::new( + board_kernel, + components::button_component_helper!( + nrf52840::gpio::GPIOPin, + ( + &nrf52840::gpio::PORT[BUTTON_PIN], + kernel::hil::gpio::ActivationMode::ActiveLow, + kernel::hil::gpio::FloatingState::PullUp + ) + ), + ) + .finalize(components::button_component_buf!(nrf52840::gpio::GPIOPin)); + + let led = components::led::LedsComponent::new(components::led_component_helper!( + nrf52840::gpio::GPIOPin, ( &nrf52840::gpio::PORT[LED1_R_PIN], kernel::hil::gpio::ActivationMode::ActiveLow @@ -102,30 +203,216 @@ pub unsafe fn reset_handler() { &nrf52840::gpio::PORT[LED1_B_PIN], kernel::hil::gpio::ActivationMode::ActiveLow ) - )); + )) + .finalize(components::led_component_buf!(nrf52840::gpio::GPIOPin)); + let chip = static_init!(nrf52840::chip::Chip, nrf52840::chip::new()); CHIP = Some(chip); - nrf52dk_base::setup_board( - board_kernel, + nrf52_components::startup::NrfStartupComponent::new( + false, BUTTON_RST_PIN, - &nrf52840::gpio::PORT, - gpio, - LED1_R_PIN, - LED1_G_PIN, - LED1_B_PIN, - led, - UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD)), - &SpiPins::new(SPI_MOSI, SPI_MISO, SPI_CLK), - &None, + nrf52840::uicr::Regulator0Output::V3_0, + ) + .finalize(()); + + // Create capabilities that the board needs to call certain protected kernel + // functions. + let process_management_capability = + create_capability!(capabilities::ProcessManagementCapability); + let main_loop_capability = create_capability!(capabilities::MainLoopCapability); + let memory_allocation_capability = create_capability!(capabilities::MemoryAllocationCapability); + + let gpio_port = &nrf52840::gpio::PORT; + + // Configure kernel debug gpios as early as possible + kernel::debug::assign_gpios( + Some(&gpio_port[LED1_R_PIN]), + Some(&gpio_port[LED1_G_PIN]), + Some(&gpio_port[LED1_B_PIN]), + ); + + let rtc = &nrf52840::rtc::RTC; + rtc.start(); + let mux_alarm = components::alarm::AlarmMuxComponent::new(rtc) + .finalize(components::alarm_mux_component_helper!(nrf52840::rtc::Rtc)); + let alarm = components::alarm::AlarmDriverComponent::new(board_kernel, mux_alarm) + .finalize(components::alarm_component_helper!(nrf52840::rtc::Rtc)); + let uart_channel = UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD)); + let channel = nrf52_components::UartChannelComponent::new(uart_channel, mux_alarm).finalize(()); + + let dynamic_deferred_call_clients = + static_init!([DynamicDeferredCallClientState; 2], Default::default()); + let dynamic_deferred_caller = static_init!( + DynamicDeferredCall, + DynamicDeferredCall::new(dynamic_deferred_call_clients) + ); + DynamicDeferredCall::set_global_instance(dynamic_deferred_caller); + + // Create a shared UART channel for the console and for kernel debug. + let uart_mux = + components::console::UartMuxComponent::new(channel, 115200, dynamic_deferred_caller) + .finalize(()); + + let pconsole = + components::process_console::ProcessConsoleComponent::new(board_kernel, uart_mux) + .finalize(()); + + // Setup the console. + let console = components::console::ConsoleComponent::new(board_kernel, uart_mux).finalize(()); + // Create the debugger object that handles calls to `debug!()`. + components::debug_writer::DebugWriterComponent::new(uart_mux).finalize(()); + + let ble_radio = + nrf52_components::BLEComponent::new(board_kernel, &nrf52840::ble_radio::RADIO, mux_alarm) + .finalize(()); + + let (ieee802154_radio, _mux_mac) = components::ieee802154::Ieee802154Component::new( + board_kernel, + &nrf52840::ieee802154_radio::RADIO, + &nrf52840::aes::AESECB, + PAN_ID, + SRC_MAC, + ) + .finalize(components::ieee802154_component_helper!( + nrf52840::ieee802154_radio::Radio, + nrf52840::aes::AesECB<'static> + )); + + let temp = components::temperature::TemperatureComponent::new( + board_kernel, + &nrf52840::temperature::TEMP, + ) + .finalize(()); + + let rng = components::rng::RngComponent::new(board_kernel, &nrf52840::trng::TRNG).finalize(()); + + // Initialize AC using AIN5 (P0.29) as VIN+ and VIN- as AIN0 (P0.02) + // These are hardcoded pin assignments specified in the driver + let analog_comparator = components::analog_comparator::AcComponent::new( + &nrf52840::acomp::ACOMP, + components::acomp_component_helper!( + nrf52840::acomp::Channel, + &nrf52840::acomp::CHANNEL_AC0 + ), + ) + .finalize(components::acomp_component_buf!( + nrf52840::acomp::Comparator + )); + + let nvmc = static_init!( + nrf52840::nvmc::SyscallDriver, + nrf52840::nvmc::SyscallDriver::new( + &nrf52840::nvmc::NVMC, + board_kernel.create_grant(&memory_allocation_capability), + ) + ); + + // Configure USB controller + let usb: + &'static capsules::usb::usb_ctap::CtapUsbSyscallDriver< + 'static, + 'static, + nrf52840::usbd::Usbd<'static>, + > = { + let usb_ctap = static_init!( + capsules::usb::usbc_ctap_hid::ClientCtapHID< + 'static, + 'static, + nrf52840::usbd::Usbd<'static>, + >, + capsules::usb::usbc_ctap_hid::ClientCtapHID::new( + &nrf52840::usbd::USBD, + capsules::usb::usbc_client::MAX_CTRL_PACKET_SIZE_NRF52840, + VENDOR_ID, + PRODUCT_ID, + STRINGS, + ) + ); + nrf52840::usbd::USBD.set_client(usb_ctap); + + // Enable power events to be sent to USB controller + nrf52840::power::POWER.set_usb_client(&nrf52840::usbd::USBD); + nrf52840::power::POWER.enable_interrupts(); + + // Configure the USB userspace driver + let usb_driver = static_init!( + capsules::usb::usb_ctap::CtapUsbSyscallDriver< + 'static, + 'static, + nrf52840::usbd::Usbd<'static>, + >, + capsules::usb::usb_ctap::CtapUsbSyscallDriver::new( + usb_ctap, + board_kernel.create_grant(&memory_allocation_capability) + ) + ); + usb_ctap.set_client(usb_driver); + usb_driver as &'static _ + }; + + nrf52_components::NrfClockComponent::new().finalize(()); + + let platform = Platform { button, - true, - &mut APP_MEMORY, + ble_radio, + ieee802154_radio, + pconsole, + console, + led, + gpio, + rng, + temp, + alarm, + analog_comparator, + nvmc, + usb, + ipc: kernel::ipc::IPC::new(board_kernel, &memory_allocation_capability), + }; + + platform.pconsole.start(); + debug!("Initialization complete. Entering main loop\r"); + debug!("{}", &nrf52840::ficr::FICR_INSTANCE); + + /// These symbols are defined in the linker script. + extern "C" { + /// Beginning of the ROM region containing app images. + static _sapps: u8; + /// End of the ROM region containing app images. + static _eapps: u8; + /// Beginning of the RAM region for app memory. + static mut _sappmem: u8; + /// End of the RAM region for app memory. + static _eappmem: u8; + } + + kernel::procs::load_processes( + board_kernel, + chip, + core::slice::from_raw_parts( + &_sapps as *const u8, + &_eapps as *const u8 as usize - &_sapps as *const u8 as usize, + ), + core::slice::from_raw_parts_mut( + &mut _sappmem as *mut u8, + &_eappmem as *const u8 as usize - &_sappmem as *const u8 as usize, + ), &mut PROCESSES, FAULT_RESPONSE, - nrf52840::uicr::Regulator0Output::V3_0, - false, - &Some(&nrf52840::usbd::USBD), + &process_management_capability, + ) + .unwrap_or_else(|err| { + debug!("Error loading processes!"); + debug!("{:?}", err); + }); + + let scheduler = components::sched::round_robin::RoundRobinComponent::new(&PROCESSES) + .finalize(components::rr_component_helper!(NUM_PROCS)); + board_kernel.kernel_loop( + &platform, chip, + Some(&platform.ipc), + scheduler, + &main_loop_capability, ); }