diff --git a/CODEOWNERS b/CODEOWNERS index b78bbe47c985..32a9f0d37788 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -79,6 +79,7 @@ /boards/arm/nrf*/ @carlescufi @lemrey @ioannisg /boards/arm/nucleo*/ @erwango /boards/arm/nucleo_f401re/ @rsalveti @idlethread +/boards/arm/qemu_cortex_m*/ @ioannisg /boards/arm/sam4s_xplained/ @fallrisk /boards/arm/v2m_beetle/ @fvincenzo /boards/arm/olimexino_stm32/ @ydamigos diff --git a/boards/arm/qemu_cortex_m0/CMakeLists.txt b/boards/arm/qemu_cortex_m0/CMakeLists.txt new file mode 100644 index 000000000000..d5670359eda1 --- /dev/null +++ b/boards/arm/qemu_cortex_m0/CMakeLists.txt @@ -0,0 +1,7 @@ +# +# Copyright (c) 2019, Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 +# + +zephyr_sources_if_kconfig( nrf_timer_timer.c) diff --git a/boards/arm/qemu_cortex_m0/Kconfig.board b/boards/arm/qemu_cortex_m0/Kconfig.board new file mode 100644 index 000000000000..7c4f9646d143 --- /dev/null +++ b/boards/arm/qemu_cortex_m0/Kconfig.board @@ -0,0 +1,10 @@ +# Kconfig - QEMU Cortex-M0 board configuration +# +# Copyright (c) 2019 Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 + +config BOARD_QEMU_CORTEX_M0 + bool "Cortex-M0 Emulation (QEMU)" + depends on SOC_NRF51822_QFAA + select QEMU_TARGET diff --git a/boards/arm/qemu_cortex_m0/Kconfig.defconfig b/boards/arm/qemu_cortex_m0/Kconfig.defconfig new file mode 100644 index 000000000000..b742112fae34 --- /dev/null +++ b/boards/arm/qemu_cortex_m0/Kconfig.defconfig @@ -0,0 +1,42 @@ +# Kconfig - QEMU Cortex-M0 board configuration +# +# Copyright (c) 2019 Nordic Semiconductor ASA. +# +# SPDX-License-Identifier: Apache-2.0 + +if BOARD_QEMU_CORTEX_M0 + +config BOARD + default "qemu_cortex_m0" + +if SYS_CLOCK_EXISTS + +config NRF_TIMER_TIMER + bool "nRF Timer Counter (NRF_TIMER0) Timer" + depends on CLOCK_CONTROL + depends on SOC_COMPATIBLE_NRF + select TICKLESS_CAPABLE + default y + help + This module implements a kernel device driver for the nRF Timer + Counter NRF_TIMER0 and provides the standard "system clock driver" + interfaces. + +config NRF_RTC_TIMER + default n + +endif # SYS_CLOCK_EXISTS + +config SYS_CLOCK_HW_CYCLES_PER_SEC + int + default 1000000 + +config SYS_CLOCK_TICKS_PER_SEC + int + default 100 + +config ENTROPY_NRF_FORCE_ALT + bool + default y + +endif # BOARD_QEMU_CORTEX_M0 diff --git a/boards/arm/qemu_cortex_m0/board.cmake b/boards/arm/qemu_cortex_m0/board.cmake new file mode 100644 index 000000000000..5591c1405646 --- /dev/null +++ b/boards/arm/qemu_cortex_m0/board.cmake @@ -0,0 +1,16 @@ +# +# Copyright (c) 2019, Nordic Semiconductor ASA +# +# SPDX-License-Identifier: Apache-2.0 + +set(EMU_PLATFORM qemu) + +set(QEMU_CPU_TYPE_${ARCH} cortex-m0) +set(QEMU_FLAGS_${ARCH} + -cpu ${QEMU_CPU_TYPE_${ARCH}} + -machine microbit + -nographic + -vga none + ) + +board_set_debugger_ifnset(qemu) diff --git a/boards/arm/qemu_cortex_m0/doc/index.rst b/boards/arm/qemu_cortex_m0/doc/index.rst new file mode 100644 index 000000000000..8e7497b2ec83 --- /dev/null +++ b/boards/arm/qemu_cortex_m0/doc/index.rst @@ -0,0 +1,118 @@ +.. _qemu_cortex_m0: + +ARM Cortex-M0 Emulation (QEMU) +############################## + +Overview +******** + +This board configuration will use QEMU to emulate the +BBC Microbit (Nordic nRF51822) platform. + +.. figure:: qemu_cortex_m0.png + :width: 600px + :align: center + :alt: Qemu + + Qemu (Credit: qemu.org) + +This configuration provides support for an ARM Cortex-M0 CPU and these devices: + +* Nested Vectored Interrupt Controller +* TIMER (nRF TIMER System Clock) + +.. note:: + This board configuration makes no claims about its suitability for use + with an actual nRF51 Microbit hardware system, or any other hardware system. + +Hardware +******** +Supported Features +================== + +The following hardware features are supported: + ++--------------+------------+----------------------+ +| Interface | Controller | Driver/Component | ++==============+============+======================+ +| NVIC | on-chip | nested vectored | +| | | interrupt controller | ++--------------+------------+----------------------+ +| nRF | on-chip | serial port | +| UART | | | ++--------------+------------+----------------------+ +| nRF TIMER | on-chip | system clock | ++--------------+------------+----------------------+ + +The kernel currently does not support other hardware features on this platform. + +Devices +======== +System Clock +------------ + +This board configuration uses a system clock frequency of 1 MHz. + +Serial Port +----------- + +This board configuration uses a single serial communication channel with the +CPU's UART0. + +Known Problems or Limitations +============================== + +The following platform features are unsupported: + +* Writing to the hardware's flash memory + + +Programming and Debugging +************************* + +Use this configuration to run basic Zephyr applications and kernel tests in the QEMU +emulated environment, for example, with the :ref:`synchronization_sample`: + +.. zephyr-app-commands:: + :zephyr-app: samples/synchronization + :host-os: unix + :board: qemu_cortex_m0 + :goals: run + +This will build an image with the synchronization sample app, boot it using +QEMU, and display the following console output: + +.. code-block:: console + + ***** BOOTING ZEPHYR OS v1.8.99 - BUILD: Jun 27 2017 13:09:26 ***** + threadA: Hello World from arm! + threadB: Hello World from arm! + threadA: Hello World from arm! + threadB: Hello World from arm! + threadA: Hello World from arm! + threadB: Hello World from arm! + threadA: Hello World from arm! + threadB: Hello World from arm! + threadA: Hello World from arm! + threadB: Hello World from arm! + +Exit QEMU by pressing :kbd:`CTRL+A` :kbd:`x`. + +Debugging +========= + +Refer to the detailed overview about :ref:`application_debugging`. + +Networking +========== + +References +********** + +1. The Definitive Guide to the ARM Cortex-M0, Second Edition by Joseph Yiu (ISBN + 978-0-12-803278-7) +2. ARMv6-M Architecture Technical Reference Manual (ARM DDI 0419D 0403D ID051917) +3. Procedure Call Standard for the ARM Architecture (ARM IHI 0042E, current + through ABI release 2.09, 2012/11/30) +4. Cortex-M0 Revision r2p1 Technical Reference Manual (ARM DDI 0432C ID113009) +5. Cortex-M0 Devices Generic User Guide (ARM DUI 0497A ID112109) diff --git a/boards/arm/qemu_cortex_m0/doc/qemu_cortex_m0.png b/boards/arm/qemu_cortex_m0/doc/qemu_cortex_m0.png new file mode 100644 index 000000000000..70ec0f85273a Binary files /dev/null and b/boards/arm/qemu_cortex_m0/doc/qemu_cortex_m0.png differ diff --git a/boards/arm/qemu_cortex_m0/nrf_timer_timer.c b/boards/arm/qemu_cortex_m0/nrf_timer_timer.c new file mode 100644 index 000000000000..7715bd821fa2 --- /dev/null +++ b/boards/arm/qemu_cortex_m0/nrf_timer_timer.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2016-2019 Nordic Semiconductor ASA + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include + +#define TIMER NRF_TIMER0 + +#define COUNTER_MAX 0xffffffff +#define CYC_PER_TICK (sys_clock_hw_cycles_per_sec() \ + / CONFIG_SYS_CLOCK_TICKS_PER_SEC) +#define MAX_TICKS ((COUNTER_MAX - CYC_PER_TICK) / CYC_PER_TICK) + +static struct k_spinlock lock; + +static u32_t last_count; + +static u32_t counter_sub(u32_t a, u32_t b) +{ + return (a - b) & COUNTER_MAX; +} + +static void set_comparator(u32_t cyc) +{ + nrf_timer_cc_write(TIMER, 0, cyc & COUNTER_MAX); +} + +static u32_t counter(void) +{ + nrf_timer_task_trigger(TIMER, nrf_timer_capture_task_get(1)); + + return nrf_timer_cc_read(TIMER, 1); +} + +void timer0_nrf_isr(void *arg) +{ + ARG_UNUSED(arg); + TIMER->EVENTS_COMPARE[0] = 0; + + k_spinlock_key_t key = k_spin_lock(&lock); + u32_t t = counter(); + u32_t dticks = counter_sub(t, last_count) / CYC_PER_TICK; + + last_count += dticks * CYC_PER_TICK; + + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + u32_t next = last_count + CYC_PER_TICK; + + /* As below: we're guaranteed to get an interrupt as + * long as it's set two or more cycles in the future + */ + if (counter_sub(next, t) < 3) { + next += CYC_PER_TICK; + } + set_comparator(next); + } + + k_spin_unlock(&lock, key); + z_clock_announce(IS_ENABLED(CONFIG_TICKLESS_KERNEL) ? dticks : 1); +} + +int z_clock_driver_init(struct device *device) +{ + struct device *clock; + + ARG_UNUSED(device); + + clock = device_get_binding(DT_INST_0_NORDIC_NRF_CLOCK_LABEL "_16M"); + if (!clock) { + return -1; + } + + /* turn on clock in blocking mode. */ + clock_control_on(clock, (void *)1); + + nrf_timer_frequency_set(TIMER, NRF_TIMER_FREQ_1MHz); + nrf_timer_bit_width_set(TIMER, NRF_TIMER_BIT_WIDTH_32); + nrf_timer_cc_write(TIMER, 0, CYC_PER_TICK); + nrf_timer_int_enable(TIMER, TIMER_INTENSET_COMPARE0_Msk); + + /* Clear the event flag and possible pending interrupt */ + nrf_timer_event_clear(TIMER, NRF_TIMER_EVENT_COMPARE0); + NVIC_ClearPendingIRQ(TIMER0_IRQn); + + IRQ_CONNECT(TIMER0_IRQn, 1, timer0_nrf_isr, 0, 0); + irq_enable(TIMER0_IRQn); + + nrf_timer_task_trigger(TIMER, NRF_TIMER_TASK_CLEAR); + nrf_timer_task_trigger(TIMER, NRF_TIMER_TASK_START); + + if (!IS_ENABLED(TICKLESS_KERNEL)) { + set_comparator(counter() + CYC_PER_TICK); + } + + return 0; +} + +void z_clock_set_timeout(s32_t ticks, bool idle) +{ + ARG_UNUSED(idle); + +#ifdef CONFIG_TICKLESS_KERNEL + ticks = (ticks == K_FOREVER) ? MAX_TICKS : ticks; + ticks = MAX(MIN(ticks - 1, (s32_t)MAX_TICKS), 0); + + k_spinlock_key_t key = k_spin_lock(&lock); + u32_t cyc, dt, t = counter(); + bool zli_fixup = IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS); + + /* Round up to next tick boundary */ + cyc = ticks * CYC_PER_TICK + 1 + counter_sub(t, last_count); + cyc += (CYC_PER_TICK - 1); + cyc = (cyc / CYC_PER_TICK) * CYC_PER_TICK; + cyc += last_count; + + if (counter_sub(cyc, t) > 2) { + set_comparator(cyc); + } else { + set_comparator(cyc); + dt = counter_sub(cyc, counter()); + if (dt == 0 || dt > 0x7fffff) { + /* Missed it! */ + NVIC_SetPendingIRQ(TIMER0_IRQn); + if (IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)) { + zli_fixup = false; + } + } else if (dt == 1) { + /* Too soon, interrupt won't arrive. */ + set_comparator(cyc + 2); + } + /* Otherwise it was two cycles out, we're fine */ + } + +#ifdef CONFIG_ZERO_LATENCY_IRQS + /* Failsafe. ZLIs can preempt us even though interrupts are + * masked, blowing up the sensitive timing above. If the + * feature is enabled and we haven't recorded the presence of + * a pending interrupt then we need a final check (in a loop! + * because this too can be interrupted) to confirm that the + * comparator is still in the future. Don't bother being + * fancy with cycle counting here, just set an interrupt + * "soon" that we know will get the timer back to a known + * state. This handles (via some hairy modular expressions) + * the wraparound cases where we are preempted for as much as + * half the counter space. + */ + if (zli_fixup && counter_sub(cyc, counter()) <= 0x7fffff) { + while (counter_sub(cyc, counter() + 2) > 0x7fffff) { + cyc = counter() + 3; + set_comparator(cyc); + } + } +#endif + + k_spin_unlock(&lock, key); +#endif /* CONFIG_TICKLESS_KERNEL */ +} + +u32_t z_clock_elapsed(void) +{ + if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) { + return 0; + } + + k_spinlock_key_t key = k_spin_lock(&lock); + u32_t ret = counter_sub(counter(), last_count) / CYC_PER_TICK; + + k_spin_unlock(&lock, key); + return ret; +} + +u32_t z_timer_cycle_get_32(void) +{ + k_spinlock_key_t key = k_spin_lock(&lock); + u32_t ret = counter_sub(counter(), last_count) + last_count; + + k_spin_unlock(&lock, key); + return ret; +} diff --git a/boards/arm/qemu_cortex_m0/qemu_cortex_m0.dts b/boards/arm/qemu_cortex_m0/qemu_cortex_m0.dts new file mode 100644 index 000000000000..4823fc750113 --- /dev/null +++ b/boards/arm/qemu_cortex_m0/qemu_cortex_m0.dts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2019 Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ + +/dts-v1/; + +#include + +/ { + model = "QEMU Cortex-M0"; + compatible = "nordic,nrf51822-qfaa", "nordic,nrf51822"; + + chosen { + zephyr,console = &uart0; + zephyr,shell-uart = &uart0; + zephyr,bt-mon-uart = &uart0; + zephyr,bt-c2h-uart = &uart0; + zephyr,sram = &sram0; + zephyr,flash = &flash0; + zephyr,code-partition = &slot0_partition; + }; +}; + +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + +&uart0 { + status = "okay"; + current-speed = <115200>; + tx-pin = <24>; + rx-pin = <25>; +}; + +&flash0 { + /* + * For more information, see: + * http://docs.zephyrproject.org/latest/guides/dts/index.html#flash-partitions + */ + partitions { + compatible = "fixed-partitions"; + #address-cells = <1>; + #size-cells = <1>; + + boot_partition: partition@0 { + label = "mcuboot"; + reg = <0x00000000 0x8000>; + }; + slot0_partition: partition@8000 { + label = "image-0"; + reg = <0x00008000 0x1a000>; + }; + slot1_partition: partition@22000 { + label = "image-1"; + reg = <0x00022000 0x1a000>; + }; + scratch_partition: partition@3c000 { + label = "image-scratch"; + reg = <0x0003c000 0x2000>; + }; + storage_partition: partition@3e000 { + label = "storage"; + reg = <0x0003e000 0x00002000>; + }; + }; +}; diff --git a/boards/arm/qemu_cortex_m0/qemu_cortex_m0.yaml b/boards/arm/qemu_cortex_m0/qemu_cortex_m0.yaml new file mode 100644 index 000000000000..a0605830d5ee --- /dev/null +++ b/boards/arm/qemu_cortex_m0/qemu_cortex_m0.yaml @@ -0,0 +1,16 @@ +identifier: qemu_cortex_m0 +name: QEMU Emulation for Cortex-M0 +type: qemu +simulation: qemu +arch: arm +toolchain: + - zephyr + - gnuarmemb + - xtools +ram: 16 +flash: 256 +testing: + default: true + ignore_tags: + - net + - bluetooth diff --git a/boards/arm/qemu_cortex_m0/qemu_cortex_m0_defconfig b/boards/arm/qemu_cortex_m0/qemu_cortex_m0_defconfig new file mode 100644 index 000000000000..b648d6f7196c --- /dev/null +++ b/boards/arm/qemu_cortex_m0/qemu_cortex_m0_defconfig @@ -0,0 +1,25 @@ +# SPDX-License-Identifier: Apache-2.0 + +CONFIG_ARM=y +CONFIG_SOC_FAMILY_NRF=y +CONFIG_SOC_SERIES_NRF51X=y +CONFIG_SOC_NRF51822_QFAA=y +CONFIG_BOARD_QEMU_CORTEX_M0=y + +# enable GPIO +CONFIG_GPIO=y + +# clock control +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_250PPM=y + +# enable uart driver +CONFIG_SERIAL=y +CONFIG_UART_0_NRF_UART=y + +# enable console +CONFIG_CONSOLE=y +CONFIG_UART_CONSOLE=y + +# logging +CONFIG_LOG_BUFFER_SIZE=128 diff --git a/drivers/timer/nrf_rtc_timer.c b/drivers/timer/nrf_rtc_timer.c index fe8c34a5198f..53f72121a623 100644 --- a/drivers/timer/nrf_rtc_timer.c +++ b/drivers/timer/nrf_rtc_timer.c @@ -41,7 +41,7 @@ static u32_t counter(void) /* Note: this function has public linkage, and MUST have this * particular name. The platform architecture itself doesn't care, - * but there is a test (tests/kernel/arm_irq_vector_table) that needs + * but there is a test (tests/arch/arm_irq_vector_table) that needs * to find it to it can set it in a custom vector table. Should * probably better abstract that at some point (e.g. query and reset * it by pointer at runtime, maybe?) so we don't have this leaky diff --git a/tests/kernel/interrupt/src/nested_irq.c b/tests/kernel/interrupt/src/nested_irq.c index 3ef6e997ac8c..c8aa5bf13066 100644 --- a/tests/kernel/interrupt/src/nested_irq.c +++ b/tests/kernel/interrupt/src/nested_irq.c @@ -74,7 +74,19 @@ void isr0(void *param) { ARG_UNUSED(param); printk("%s running !!\n", __func__); +#if defined(CONFIG_BOARD_QEMU_CORTEX_M0) + /* QEMU Cortex-M0 timer emulation appears to not capturing the + * current time accurately, resulting in erroneous busy wait + * implementation. + * + * Work-around: + * Increase busy-loop duration to ensure the timer interrupt will fire + * during the busy loop waiting. + */ + k_busy_wait(MS_TO_US(1000)); +#else k_busy_wait(MS_TO_US(10)); +#endif printk("%s execution completed !!\n", __func__); zassert_equal(new_val, old_val, "Nested interrupt is not working\n"); } diff --git a/tests/kernel/tickless/tickless_concept/testcase.yaml b/tests/kernel/tickless/tickless_concept/testcase.yaml index bb9f43ccc9ff..9ca709d032d9 100644 --- a/tests/kernel/tickless/tickless_concept/testcase.yaml +++ b/tests/kernel/tickless/tickless_concept/testcase.yaml @@ -3,5 +3,7 @@ tests: arch_exclude: riscv32 nios2 # FIXME: This test fails sporadically on all QEMU platforms, but fails # consistently when coverage is enabled. Disable until 14173 is fixed. - platform_exclude: qemu_x86_coverage + # This test fails on qemu_cortex_m0 consistently. Disable until the + # root cause is identified. + platform_exclude: qemu_x86_coverage qemu_cortex_m0 tags: kernel diff --git a/tests/kernel/timer/timer_api/testcase.yaml b/tests/kernel/timer/timer_api/testcase.yaml index 27edf175cd0b..2e728fa22fdd 100644 --- a/tests/kernel/timer/timer_api/testcase.yaml +++ b/tests/kernel/timer/timer_api/testcase.yaml @@ -1,7 +1,7 @@ tests: kernel.timer: tags: kernel userspace - platform_exclude: qemu_x86_coverage + platform_exclude: qemu_x86_coverage qemu_cortex_m0 kernel.timer.tickless: build_only: true extra_args: CONF_FILE="prj_tickless.conf"