Kernel minimization (#334)

* adds patch to remove unused kernel components

* new boards, rebase patches to match

* rename boards for deployment
This commit is contained in:
kaczmarczyck
2021-06-28 14:55:20 +02:00
committed by GitHub
parent 5f20ba544b
commit ce0ee6c054
32 changed files with 1234 additions and 155 deletions

View File

@@ -0,0 +1,14 @@
[package]
name = "nrf52840_dongle_opensk"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
build = "build.rs"
edition = "2018"
[dependencies]
components = { path = "../../components" }
cortexm4 = { path = "../../../arch/cortex-m4" }
capsules = { path = "../../../capsules" }
kernel = { path = "../../../kernel" }
nrf52840 = { path = "../../../chips/nrf52840" }
nrf52_components = { path = "../nrf52_components" }

View File

@@ -0,0 +1,28 @@
# Makefile for building the tock kernel for the nRF development kit
TARGET=thumbv7em-none-eabi
PLATFORM=nrf52840_dongle_opensk
include ../../Makefile.common
TOCKLOADER=tockloader
# Where in the nrf52 flash to load the kernel with `tockloader`
KERNEL_ADDRESS=0x00000
# Upload programs over uart with tockloader
ifdef PORT
TOCKLOADER_GENERAL_FLAGS += --port $(PORT)
endif
TOCKLOADER_JTAG_FLAGS = --jlink --board nrf52dk
# Upload the kernel over JTAG
.PHONY: flash
flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) $(TOCKLOADER_JTAG_FLAGS) $<
# Upload the kernel over serial/bootloader
.PHONY: program
program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).hex
$(error Cannot program nRF52840-Dongle over USB. Use \`make flash\` and JTAG)

View File

@@ -0,0 +1,41 @@
Platform-Specific Instructions: nRF52840-Dongle
===================================
This is an adapted nrf52840\_dongle made to work with OpenSK.
The [nRF52840 Dongle](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-Dongle)
is a platform based around the nRF52840, an SoC with an ARM Cortex-M4 and a BLE radio.
The kit is uses a USB key form factor and includes 1 button, 1 red LED and 1 RGB LED.
## Getting Started
To program the nRF52840 Dongle with Tock, you will need a JLink JTAG device and the
appropriate cables. An example setup is:
- [JLink JTAG Device](https://www.digikey.com/product-detail/en/segger-microcontroller-systems/8.08.90-J-LINK-EDU/899-1008-ND/2263130)
- [ARM to TagConnect Adapter](https://www.digikey.com/product-detail/en/tag-connect-llc/TC2050-ARM2010/TC2050-ARM2010-ND/3528170)
- [10pin TagConnect Cable](https://www.digikey.com/product-detail/en/tag-connect-llc/TC2050-IDC-NL/TC2050-IDC-NL-ND/2605367)
Then, follow the [Tock Getting Started guide](../../../doc/Getting_Started.md)
JTAG is the preferred method to program. The development kit has the JTAG pins exposed either
through the half-moons pads or, below the PCB, on a Tag-Connect TC2050 connector footprint.
You need to [install JTAG software](../../../doc/Getting_Started.md#optional-requirements).
## Programming the kernel
Once you have all software installed, you should be able to simply run
make flash in this directory to install a fresh kernel.
## Programming user-level applications
You can program an application via JTAG using `tockloader`:
```shell
$ cd libtock-c/examples/<app>
$ make
$ tockloader install --jlink --board nrf52dk
```
## Debugging
See the [nrf52dk README](../nrf52dk/README.md) for information about debugging
the nRF52840 Dongle.

View File

@@ -0,0 +1,4 @@
fn main() {
println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=../../kernel_layout.ld");
}

View File

@@ -0,0 +1,25 @@
#
#
#
# J-LINK GDB SERVER initialization
#
# This connects to a GDB Server listening
# for commands on localhost at tcp port 2331
target remote localhost:2331
monitor speed 30
file ../../../../target/thumbv7em-none-eabi/release/nrf52840_dongle
monitor reset
#
# CPU core initialization (to be done by user)
#
# Set the processor mode
# monitor reg cpsr = 0xd3
# Set auto JTAG speed
monitor speed auto
# Setup GDB FOR FASTER DOWNLOADS
set remote memory-write-packet-size 1024
set remote memory-write-packet-size fixed
# tui enable
# layout split
# layout service_pending_interrupts
b reset_handler

View File

@@ -0,0 +1 @@
JLinkGDBServer -device nRF52840_xxAA -speed 1200 -if swd -AutoConnect 1 -port 2331

View File

@@ -0,0 +1,2 @@
INCLUDE ../nrf52840_chip_layout.ld
INCLUDE ../../kernel_layout.ld

View File

@@ -0,0 +1,65 @@
use core::fmt::Write;
use core::panic::PanicInfo;
use cortexm4;
use kernel::debug;
use kernel::debug::IoWrite;
use kernel::hil::led;
use kernel::hil::uart::{self, Configure};
use nrf52840::gpio::Pin;
use crate::CHIP;
use crate::PROCESSES;
struct Writer {
initialized: bool,
}
static mut WRITER: Writer = Writer { initialized: false };
impl Write for Writer {
fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
self.write(s.as_bytes());
Ok(())
}
}
impl IoWrite for Writer {
fn write(&mut self, buf: &[u8]) {
let uart = unsafe { &mut nrf52840::uart::UARTE0 };
if !self.initialized {
self.initialized = true;
uart.configure(uart::Parameters {
baud_rate: 115200,
stop_bits: uart::StopBits::One,
parity: uart::Parity::None,
hw_flow_control: false,
width: uart::Width::Eight,
});
}
for &c in buf {
unsafe {
uart.send_byte(c);
}
while !uart.tx_ready() {}
}
}
}
#[cfg(not(test))]
#[no_mangle]
#[panic_handler]
/// Panic handler
pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
// The nRF52840 Dongle LEDs (see back of board)
const LED1_PIN: Pin = Pin::P0_06;
let led = &mut led::LedLow::new(&mut nrf52840::gpio::PORT[LED1_PIN]);
let writer = &mut WRITER;
debug::panic(
&mut [led],
writer,
pi,
&cortexm4::support::nop,
&PROCESSES,
&CHIP,
)
}

View File

@@ -0,0 +1,311 @@
//! Tock kernel for the Nordic Semiconductor nRF52840 dongle.
//!
//! It is based on nRF52840 SoC (Cortex M4 core with a BLE transceiver) with
//! many exported I/O and peripherals.
#![no_std]
// 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 kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::component::Component;
#[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use nrf52840::gpio::Pin;
use nrf52_components::{self, UartChannel, UartPins};
// The nRF52840 Dongle LEDs
const LED1_PIN: Pin = Pin::P0_06;
const LED2_R_PIN: Pin = Pin::P0_08;
const LED2_G_PIN: Pin = Pin::P1_09;
const LED2_B_PIN: Pin = Pin::P0_12;
// The nRF52840 Dongle button
const BUTTON_PIN: Pin = Pin::P1_06;
const BUTTON_RST_PIN: Pin = Pin::P0_18;
const UART_RTS: Option<Pin> = Some(Pin::P0_13);
const UART_TXD: Pin = Pin::P0_15;
const UART_CTS: Option<Pin> = Some(Pin::P0_17);
const UART_RXD: Pin = Pin::P0_20;
// SPI pins not currently in use, but left here for convenience
const _SPI_MOSI: Pin = Pin::P1_01;
const _SPI_MISO: Pin = Pin::P1_02;
const _SPI_CLK: Pin = Pin::P1_04;
/// UART Writer
pub mod io;
// 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;
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] =
[None; NUM_PROCS];
// Static reference to chip for panic dumps
static mut CHIP: Option<&'static nrf52840::chip::Chip> = None;
/// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle]
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
/// Supported drivers by the platform
pub struct Platform {
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>,
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>>,
>,
}
impl kernel::Platform for Platform {
fn with_driver<F, R>(&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::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None),
}
}
}
/// Entry point in the vector table called on hard reset.
#[no_mangle]
pub unsafe fn reset_handler() {
// Loads relocations and clears BSS
nrf52840::init();
let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES));
// GPIOs
let gpio = components::gpio::GpioComponent::new(
board_kernel,
components::gpio_component_helper!(
nrf52840::gpio::GPIOPin,
// left side of the USB plug
0 => &nrf52840::gpio::PORT[Pin::P0_13],
1 => &nrf52840::gpio::PORT[Pin::P0_15],
2 => &nrf52840::gpio::PORT[Pin::P0_17],
3 => &nrf52840::gpio::PORT[Pin::P0_20],
4 => &nrf52840::gpio::PORT[Pin::P0_22],
5 => &nrf52840::gpio::PORT[Pin::P0_24],
6 => &nrf52840::gpio::PORT[Pin::P1_00],
7 => &nrf52840::gpio::PORT[Pin::P0_09],
8 => &nrf52840::gpio::PORT[Pin::P0_10],
// right side of the USB plug
9 => &nrf52840::gpio::PORT[Pin::P0_31],
10 => &nrf52840::gpio::PORT[Pin::P0_29],
11 => &nrf52840::gpio::PORT[Pin::P0_02],
12 => &nrf52840::gpio::PORT[Pin::P1_15],
13 => &nrf52840::gpio::PORT[Pin::P1_13],
14 => &nrf52840::gpio::PORT[Pin::P1_10],
// Below the PCB
15 => &nrf52840::gpio::PORT[Pin::P0_26],
16 => &nrf52840::gpio::PORT[Pin::P0_04],
17 => &nrf52840::gpio::PORT[Pin::P0_11],
18 => &nrf52840::gpio::PORT[Pin::P0_14],
19 => &nrf52840::gpio::PORT[Pin::P1_11],
20 => &nrf52840::gpio::PORT[Pin::P1_07],
21 => &nrf52840::gpio::PORT[Pin::P1_01],
22 => &nrf52840::gpio::PORT[Pin::P1_04],
23 => &nrf52840::gpio::PORT[Pin::P1_02]
),
)
.finalize(components::gpio_component_buf!(nrf52840::gpio::GPIOPin));
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_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED2_R_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED2_G_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED2_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);
nrf52_components::startup::NrfStartupComponent::new(
false,
BUTTON_RST_PIN,
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[LED2_R_PIN]),
Some(&gpio_port[LED2_G_PIN]),
Some(&gpio_port[LED2_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 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
));
nrf52_components::NrfClockComponent::new().finalize(());
let platform = Platform {
button,
pconsole,
console,
led,
gpio,
rng,
alarm,
analog_comparator,
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,
&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,
);
}

View File

@@ -10,7 +10,6 @@
#![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)]
@@ -33,10 +32,6 @@ const UART_TXD: Pin = Pin::P0_20;
const UART_CTS: Option<Pin> = Some(Pin::P0_03);
const UART_RXD: Pin = Pin::P0_19;
// 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;
@@ -76,12 +71,6 @@ 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,
@@ -91,7 +80,6 @@ pub struct Platform {
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,
@@ -121,9 +109,6 @@ impl kernel::Platform for Platform {
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)),
@@ -263,28 +248,6 @@ pub unsafe fn reset_handler() {
// 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)
@@ -355,14 +318,11 @@ pub unsafe fn reset_handler() {
let platform = Platform {
button,
ble_radio,
ieee802154_radio,
pconsole,
console,
led,
gpio,
rng,
temp,
alarm,
analog_comparator,
nvmc,

View File

@@ -0,0 +1,14 @@
[package]
name = "nrf52840dk_opensk"
version = "0.1.0"
authors = ["Tock Project Developers <tock-dev@googlegroups.com>"]
build = "build.rs"
edition = "2018"
[dependencies]
components = { path = "../../components" }
cortexm4 = { path = "../../../arch/cortex-m4" }
capsules = { path = "../../../capsules" }
kernel = { path = "../../../kernel" }
nrf52840 = { path = "../../../chips/nrf52840" }
nrf52_components = { path = "../nrf52_components" }

View File

@@ -0,0 +1,31 @@
# Makefile for building the tock kernel for the nRF development kit
TARGET=thumbv7em-none-eabi
PLATFORM=nrf52840dk_opensk
include ../../Makefile.common
TOCKLOADER=tockloader
# Where in the SAM4L flash to load the kernel with `tockloader`
KERNEL_ADDRESS=0x00000
# Upload programs over uart with tockloader
ifdef PORT
TOCKLOADER_GENERAL_FLAGS += --port $(PORT)
endif
# Upload the kernel over JTAG
.PHONY: flash
flash: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) --board nrf52dk --jlink $<
# Upload the kernel over JTAG using OpenOCD
.PHONY: flash-openocd
flash-openocd: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).bin
$(TOCKLOADER) $(TOCKLOADER_GENERAL_FLAGS) flash --address $(KERNEL_ADDRESS) --board nrf52dk --openocd $<
# Upload the kernel over serial/bootloader
.PHONY: program
program: $(TOCK_ROOT_DIRECTORY)target/$(TARGET)/release/$(PLATFORM).hex
$(error Cannot program nRF52840DK over USB. Use \`make flash\` and JTAG)

View File

@@ -0,0 +1,65 @@
Platform-Specific Instructions: nRF52840-DK
===================================
This is an adapted nrf52840dk made to work with OpenSK.
The [nRF52840 Development
Kit](https://www.nordicsemi.com/Software-and-Tools/Development-Kits/nRF52840-DK) is a platform
based around the nRF52840, an SoC with an ARM Cortex-M4 and a BLE
radio. The kit is Arduino shield compatible and includes several
buttons.
## Getting Started
First, follow the [Tock Getting Started guide](../../../doc/Getting_Started.md)
JTAG is the preferred method to program. The development kit has an
integrated JTAG debugger, you simply need to [install JTAG
software](../../../doc/Getting_Started.md#loading-the-kernel-onto-a-board).
## Programming the kernel
Once you have all software installed, you should be able to simply run
make flash in this directory to install a fresh kernel.
## Programming user-level applications
You can program an application over USB using the integrated JTAG and `tockloader`:
```bash
$ cd libtock-c/examples/<app>
$ make
$ tockloader install --jlink --board nrf52dk
```
The same options (`--jlink --board nrf52dk`) must be passed for other tockloader commands
such as `erase-apps` or `list`.
Viewing console output on the nrf52840dk is slightly different from other boards. You must use
```bash
$ tockloader listen
```
**followed by a press of the reset button** in order to view console output starting from the boot
sequence. Notably, you should not
pass the `--jlink` option to `tockloader listen`.
## Console output
This board supports two methods for writing messages to a console interface
(console driver for applications as well as debug statements in the kernel).
By default, messages are written to a UART interface over the GPIO pins `P0.05`
to `P0.08` (see the [main.rs](src/main.rs) file).
If you don't have any UART cables or want to use a different interface, there is
also a console over the Segger RTT protocol. This only requires a micro-USB
cable on the USB debugging port (the same used to flash Tock on the board), and
is enabled by setting the `USB_DEBUGGING` constant to `true` in the
[main.rs](src/main.rs) file.
This disables the UART interface.
For instructions about how to receive RTT messages on the host, see the
[corresponding capsule](../../../capsules/src/segger_rtt.rs).
## Debugging
See the [nrf52dk README](../nrf52dk/README.md) for information about debugging
the nRF52840dk.

View File

@@ -0,0 +1,4 @@
fn main() {
println!("cargo:rerun-if-changed=layout.ld");
println!("cargo:rerun-if-changed=../../kernel_layout.ld");
}

View File

@@ -0,0 +1,25 @@
#
#
#
# J-LINK GDB SERVER initialization
#
# This connects to a GDB Server listening
# for commands on localhost at tcp port 2331
target remote localhost:2331
monitor speed 30
file ../../../../target/thumbv7em-none-eabi/release/nrf52dk
monitor reset
#
# CPU core initialization (to be done by user)
#
# Set the processor mode
# monitor reg cpsr = 0xd3
# Set auto JTAG speed
monitor speed auto
# Setup GDB FOR FASTER DOWNLOADS
set remote memory-write-packet-size 1024
set remote memory-write-packet-size fixed
# tui enable
# layout split
# layout service_pending_interrupts
b reset_handler

View File

@@ -0,0 +1 @@
JLinkGDBServer -device nrf52 -speed 1200 -if swd -AutoConnect 1 -port 2331

View File

@@ -0,0 +1,2 @@
INCLUDE ../nrf52840_chip_layout.ld
INCLUDE ../../kernel_layout.ld

View File

@@ -0,0 +1,102 @@
use core::fmt::Write;
use core::panic::PanicInfo;
use cortexm4;
use kernel::debug;
use kernel::debug::IoWrite;
use kernel::hil::led;
use kernel::hil::uart::{self, Configure};
use nrf52840::gpio::Pin;
use crate::CHIP;
use crate::PROCESSES;
enum Writer {
WriterUart(/* initialized */ bool),
WriterRtt(&'static capsules::segger_rtt::SeggerRttMemory<'static>),
}
static mut WRITER: Writer = Writer::WriterUart(false);
fn wait() {
for _ in 0..100 {
cortexm4::support::nop();
}
}
/// Set the RTT memory buffer used to output panic messages.
pub unsafe fn set_rtt_memory(
rtt_memory: &'static mut capsules::segger_rtt::SeggerRttMemory<'static>,
) {
WRITER = Writer::WriterRtt(rtt_memory);
}
impl Write for Writer {
fn write_str(&mut self, s: &str) -> ::core::fmt::Result {
self.write(s.as_bytes());
Ok(())
}
}
impl IoWrite for Writer {
fn write(&mut self, buf: &[u8]) {
match self {
Writer::WriterUart(ref mut initialized) => {
let uart = unsafe { &mut nrf52840::uart::UARTE0 };
if !*initialized {
*initialized = true;
uart.configure(uart::Parameters {
baud_rate: 115200,
stop_bits: uart::StopBits::One,
parity: uart::Parity::None,
hw_flow_control: false,
width: uart::Width::Eight,
});
}
for &c in buf {
unsafe {
uart.send_byte(c);
}
while !uart.tx_ready() {}
}
}
Writer::WriterRtt(rtt_memory) => {
let up_buffer = unsafe { &*rtt_memory.get_up_buffer_ptr() };
let buffer_len = up_buffer.length.get();
let buffer = unsafe {
core::slice::from_raw_parts_mut(
up_buffer.buffer.get() as *mut u8,
buffer_len as usize,
)
};
let mut write_position = up_buffer.write_position.get();
for &c in buf {
buffer[write_position as usize] = c;
write_position = (write_position + 1) % buffer_len;
up_buffer.write_position.set(write_position);
wait();
}
}
};
}
}
#[cfg(not(test))]
#[no_mangle]
#[panic_handler]
/// Panic handler
pub unsafe extern "C" fn panic_fmt(pi: &PanicInfo) -> ! {
// The nRF52840DK LEDs (see back of board)
const LED1_PIN: Pin = Pin::P0_13;
let led = &mut led::LedLow::new(&mut nrf52840::gpio::PORT[LED1_PIN]);
let writer = &mut WRITER;
debug::panic(
&mut [led],
writer,
pi,
&cortexm4::support::nop,
&PROCESSES,
&CHIP,
)
}

View File

@@ -0,0 +1,396 @@
//! Tock kernel for the Nordic Semiconductor nRF52840 development kit (DK).
//!
//! It is based on nRF52840 SoC (Cortex M4 core with a BLE transceiver) with
//! many exported I/O and peripherals.
//!
//! Pin Configuration
//! -------------------
//!
//! ### `GPIO`
//!
//! | # | Pin | Ix | Header | Arduino |
//! |----|-------|----|--------|---------|
//! | 0 | P1.01 | 33 | P3 1 | D0 |
//! | 1 | P1.02 | 34 | P3 2 | D1 |
//! | 2 | P1.03 | 35 | P3 3 | D2 |
//! | 3 | P1.04 | 36 | P3 4 | D3 |
//! | 4 | P1.05 | 37 | P3 5 | D4 |
//! | 5 | P1.06 | 38 | P3 6 | D5 |
//! | 6 | P1.07 | 39 | P3 7 | D6 |
//! | 7 | P1.08 | 40 | P3 8 | D7 |
//! | 8 | P1.10 | 42 | P4 1 | D8 |
//! | 9 | P1.11 | 43 | P4 2 | D9 |
//! | 10 | P1.12 | 44 | P4 3 | D10 |
//! | 11 | P1.13 | 45 | P4 4 | D11 |
//! | 12 | P1.14 | 46 | P4 5 | D12 |
//! | 13 | P1.15 | 47 | P4 6 | D13 |
//! | 14 | P0.26 | 26 | P4 9 | D14 |
//! | 15 | P0.27 | 27 | P4 10 | D15 |
//!
//! ### `GPIO` / Analog Inputs
//!
//! | # | Pin | Header | Arduino |
//! |----|------------|--------|---------|
//! | 16 | P0.03 AIN1 | P2 1 | A0 |
//! | 17 | P0.04 AIN2 | P2 2 | A1 |
//! | 18 | P0.28 AIN4 | P2 3 | A2 |
//! | 19 | P0.29 AIN5 | P2 4 | A3 |
//! | 20 | P0.30 AIN6 | P2 5 | A4 |
//! | 21 | P0.31 AIN7 | P2 6 | A5 |
//! | 22 | P0.02 AIN0 | P4 8 | AVDD |
//!
//! ### Onboard Functions
//!
//! | Pin | Header | Function |
//! |-------|--------|----------|
//! | P0.05 | P6 3 | UART RTS |
//! | P0.06 | P6 4 | UART TXD |
//! | P0.07 | P6 5 | UART CTS |
//! | P0.08 | P6 6 | UART RXT |
//! | P0.11 | P24 1 | Button 1 |
//! | P0.12 | P24 2 | Button 2 |
//! | P0.13 | P24 3 | LED 1 |
//! | P0.14 | P24 4 | LED 2 |
//! | P0.15 | P24 5 | LED 3 |
//! | P0.16 | P24 6 | LED 4 |
//! | P0.18 | P24 8 | Reset |
//! | P0.19 | P24 9 | SPI CLK |
//! | P0.20 | P24 10 | SPI MOSI |
//! | P0.21 | P24 11 | SPI MISO |
//! | P0.24 | P24 14 | Button 3 |
//! | P0.25 | P24 15 | Button 4 |
#![no_std]
// 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 kernel::common::dynamic_deferred_call::{DynamicDeferredCall, DynamicDeferredCallClientState};
use kernel::component::Component;
#[allow(unused_imports)]
use kernel::{capabilities, create_capability, debug, debug_gpio, debug_verbose, static_init};
use nrf52840::gpio::Pin;
use nrf52_components::{self, UartChannel, UartPins};
// The nRF52840DK LEDs (see back of board)
const LED1_PIN: Pin = Pin::P0_13;
const LED2_PIN: Pin = Pin::P0_14;
const LED3_PIN: Pin = Pin::P0_15;
const LED4_PIN: Pin = Pin::P0_16;
// The nRF52840DK buttons (see back of board)
const BUTTON1_PIN: Pin = Pin::P0_11;
const BUTTON2_PIN: Pin = Pin::P0_12;
const BUTTON3_PIN: Pin = Pin::P0_24;
const BUTTON4_PIN: Pin = Pin::P0_25;
const BUTTON_RST_PIN: Pin = Pin::P0_18;
const UART_RTS: Option<Pin> = Some(Pin::P0_05);
const UART_TXD: Pin = Pin::P0_06;
const UART_CTS: Option<Pin> = Some(Pin::P0_07);
const UART_RXD: Pin = Pin::P0_08;
const SPI_MOSI: Pin = Pin::P0_20;
const SPI_MISO: Pin = Pin::P0_21;
const SPI_CLK: Pin = Pin::P0_19;
/// Debug Writer
pub mod io;
// Whether to use UART debugging or Segger RTT (USB) debugging.
// - Set to false to use UART.
// - Set to true to use Segger RTT over USB.
const USB_DEBUGGING: bool = true;
// 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;
// Number of concurrent processes this platform supports.
const NUM_PROCS: usize = 8;
static mut PROCESSES: [Option<&'static dyn kernel::procs::ProcessType>; NUM_PROCS] =
[None; NUM_PROCS];
static mut CHIP: Option<&'static nrf52840::chip::Chip> = None;
/// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle]
#[link_section = ".stack_buffer"]
pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000];
/// Supported drivers by the platform
pub struct Platform {
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>,
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>>,
>,
}
impl kernel::Platform for Platform {
fn with_driver<F, R>(&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::analog_comparator::DRIVER_NUM => f(Some(self.analog_comparator)),
kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
_ => f(None),
}
}
}
/// Entry point in the vector table called on hard reset.
#[no_mangle]
pub unsafe fn reset_handler() {
// Loads relocations and clears BSS
nrf52840::init();
let uart_channel = if USB_DEBUGGING {
// Initialize early so any panic beyond this point can use the RTT memory object.
let mut rtt_memory_refs =
components::segger_rtt::SeggerRttMemoryComponent::new().finalize(());
// XXX: This is inherently unsafe as it aliases the mutable reference to rtt_memory. This
// aliases reference is only used inside a panic handler, which should be OK, but maybe we
// should use a const reference to rtt_memory and leverage interior mutability instead.
self::io::set_rtt_memory(&mut *rtt_memory_refs.get_rtt_memory_ptr());
UartChannel::Rtt(rtt_memory_refs)
} else {
UartChannel::Pins(UartPins::new(UART_RTS, UART_TXD, UART_CTS, UART_RXD))
};
let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new(&PROCESSES));
let gpio = components::gpio::GpioComponent::new(
board_kernel,
components::gpio_component_helper!(
nrf52840::gpio::GPIOPin,
0 => &nrf52840::gpio::PORT[Pin::P1_01],
1 => &nrf52840::gpio::PORT[Pin::P1_02],
2 => &nrf52840::gpio::PORT[Pin::P1_03],
3 => &nrf52840::gpio::PORT[Pin::P1_04],
4 => &nrf52840::gpio::PORT[Pin::P1_05],
5 => &nrf52840::gpio::PORT[Pin::P1_06],
6 => &nrf52840::gpio::PORT[Pin::P1_07],
7 => &nrf52840::gpio::PORT[Pin::P1_08],
8 => &nrf52840::gpio::PORT[Pin::P1_10],
9 => &nrf52840::gpio::PORT[Pin::P1_11],
10 => &nrf52840::gpio::PORT[Pin::P1_12],
11 => &nrf52840::gpio::PORT[Pin::P1_13],
12 => &nrf52840::gpio::PORT[Pin::P1_14],
13 => &nrf52840::gpio::PORT[Pin::P1_15],
14 => &nrf52840::gpio::PORT[Pin::P0_26],
15 => &nrf52840::gpio::PORT[Pin::P0_27]
),
)
.finalize(components::gpio_component_buf!(nrf52840::gpio::GPIOPin));
let button = components::button::ButtonComponent::new(
board_kernel,
components::button_component_helper!(
nrf52840::gpio::GPIOPin,
(
&nrf52840::gpio::PORT[BUTTON1_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp
), //13
(
&nrf52840::gpio::PORT[BUTTON2_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp
), //14
(
&nrf52840::gpio::PORT[BUTTON3_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp
), //15
(
&nrf52840::gpio::PORT[BUTTON4_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow,
kernel::hil::gpio::FloatingState::PullUp
) //16
),
)
.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_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED2_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED3_PIN],
kernel::hil::gpio::ActivationMode::ActiveLow
),
(
&nrf52840::gpio::PORT[LED4_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);
nrf52_components::startup::NrfStartupComponent::new(
false,
BUTTON_RST_PIN,
nrf52840::uicr::Regulator0Output::DEFAULT,
)
.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_PIN]),
Some(&gpio_port[LED2_PIN]),
Some(&gpio_port[LED3_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 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 rng = components::rng::RngComponent::new(board_kernel, &nrf52840::trng::TRNG).finalize(());
nrf52840::spi::SPIM0.configure(
nrf52840::pinmux::Pinmux::new(SPI_MOSI as u32),
nrf52840::pinmux::Pinmux::new(SPI_MISO as u32),
nrf52840::pinmux::Pinmux::new(SPI_CLK as u32),
);
// 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
));
nrf52_components::NrfClockComponent::new().finalize(());
let platform = Platform {
button,
pconsole,
console,
led,
gpio,
rng,
alarm,
analog_comparator,
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,
&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,
);
}