diff --git a/tests/drivers/clock_control/nrf_clock_calibration/CMakeLists.txt b/tests/drivers/clock_control/nrf_clock_calibration/CMakeLists.txt new file mode 100644 index 00000000000..7ac5982e37d --- /dev/null +++ b/tests/drivers/clock_control/nrf_clock_calibration/CMakeLists.txt @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.13.1) + +include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE) +project(NONE) + +FILE(GLOB app_sources src/*.c) +target_sources(app PRIVATE ${app_sources}) diff --git a/tests/drivers/clock_control/nrf_clock_calibration/prj.conf b/tests/drivers/clock_control/nrf_clock_calibration/prj.conf new file mode 100644 index 00000000000..45e9febc1d2 --- /dev/null +++ b/tests/drivers/clock_control/nrf_clock_calibration/prj.conf @@ -0,0 +1,6 @@ +CONFIG_ZTEST=y +CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y +CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_MAX_SKIP=0 +CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_PERIOD=1 +CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_DEBUG=y + diff --git a/tests/drivers/clock_control/nrf_clock_calibration/src/test_nrf_clock_calibration.c b/tests/drivers/clock_control/nrf_clock_calibration/src/test_nrf_clock_calibration.c new file mode 100644 index 00000000000..934c77826e4 --- /dev/null +++ b/tests/drivers/clock_control/nrf_clock_calibration/src/test_nrf_clock_calibration.c @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2019, Nordic Semiconductor ASA + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include +#include +#include +LOG_MODULE_REGISTER(test); + +#ifndef CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC +#error "LFCLK must use RC source" +#endif + +#if CONFIG_CLOCK_CONTROL_NRF_CALIBRATION_PERIOD != 1 +#error "Expected 250ms calibration period" +#endif + +static void turn_off_clock(struct device *dev) +{ + int err; + + do { + err = clock_control_off(dev, 0); + } while (err == 0); +} + +static void lfclk_started_cb(struct device *dev, void *user_data) +{ + *(bool *)user_data = true; +} + +/* Test checks if calibration clock is running and generates interrupt as + * expected and starts calibration. Validates that HF clock is turned on + * for calibration and turned off once calibration is done. + */ +static void test_clock_calibration(void) +{ + struct device *hfclk_dev = + device_get_binding(DT_INST_0_NORDIC_NRF_CLOCK_LABEL "_16M"); + struct device *lfclk_dev = + device_get_binding(DT_INST_0_NORDIC_NRF_CLOCK_LABEL "_32K"); + volatile bool started = false; + struct clock_control_async_data lfclk_data = { + .cb = lfclk_started_cb, + .user_data = (void *)&started + }; + int key; + u32_t cnt = 0; + u32_t max_cnt = 1000; + + turn_off_clock(hfclk_dev); + turn_off_clock(lfclk_dev); + + /* In case calibration needs to be completed. */ + k_busy_wait(100000); + + clock_control_async_on(lfclk_dev, NULL, &lfclk_data); + + while (started == false) { + } + + k_busy_wait(35000); + + key = irq_lock(); + while (nrf_clock_event_check(NRF_CLOCK_EVENT_CTTO) == 0) { + k_busy_wait(1000); + cnt++; + if (cnt == max_cnt) { + irq_unlock(key); + clock_control_off(lfclk_dev, NULL); + zassert_true(false, ""); + } + } + + zassert_within(cnt, 250, 10, "Expected 250ms period"); + + irq_unlock(key); + + while (clock_control_get_status(hfclk_dev, NULL) + != CLOCK_CONTROL_STATUS_ON) { + } + + key = irq_lock(); + cnt = 0; + while (nrf_clock_event_check(NRF_CLOCK_EVENT_DONE) == 0) { + k_busy_wait(1000); + cnt++; + if (cnt == max_cnt) { + irq_unlock(key); + clock_control_off(lfclk_dev, NULL); + zassert_true(false, ""); + } + } + + irq_unlock(key); + + zassert_equal(clock_control_get_status(hfclk_dev, NULL), + CLOCK_CONTROL_STATUS_OFF, + "Expected hfclk off after calibration."); + + key = irq_lock(); + cnt = 0; + + while (nrf_clock_event_check(NRF_CLOCK_EVENT_CTTO) == 0) { + k_busy_wait(1000); + cnt++; + if (cnt == max_cnt) { + irq_unlock(key); + clock_control_off(lfclk_dev, NULL); + zassert_true(false, ""); + } + } + + zassert_within(cnt, 250, 10, "Expected 250ms period (got %d)", cnt); + + irq_unlock(key); + + clock_control_off(lfclk_dev, NULL); +} + +/* Test checks that when calibration is active then LF clock is not stopped. + * Stopping is deferred until calibration is done. Test validates that after + * completing calibration LF clock is shut down. + */ +static void test_stopping_when_calibration(void) +{ + struct device *hfclk_dev = + device_get_binding(DT_INST_0_NORDIC_NRF_CLOCK_LABEL "_16M"); + struct device *lfclk_dev = + device_get_binding(DT_INST_0_NORDIC_NRF_CLOCK_LABEL "_32K"); + volatile bool started = false; + struct clock_control_async_data lfclk_data = { + .cb = lfclk_started_cb, + .user_data = (void *)&started + }; + int key; + u32_t cnt = 0; + u32_t max_cnt = 1000; + + turn_off_clock(hfclk_dev); + turn_off_clock(lfclk_dev); + + /* In case calibration needs to be completed. */ + k_busy_wait(100000); + + clock_control_async_on(lfclk_dev, NULL, &lfclk_data); + + while (started == false) { + } + + /* when lfclk is started first calibration is performed. Wait until it + * is done. + */ + k_busy_wait(35000); + + key = irq_lock(); + while (nrf_clock_event_check(NRF_CLOCK_EVENT_CTTO) == 0) { + k_busy_wait(1000); + cnt++; + if (cnt == max_cnt) { + irq_unlock(key); + clock_control_off(lfclk_dev, NULL); + zassert_true(false, ""); + } + } + + zassert_within(cnt, 250, 10, "Expected 250ms period"); + + irq_unlock(key); + + while (clock_control_get_status(hfclk_dev, NULL) + != CLOCK_CONTROL_STATUS_ON) { + } + + /* calibration started */ + key = irq_lock(); + clock_control_off(lfclk_dev, NULL); + + zassert_true(nrf_clock_lf_is_running(), "Expected LF still on"); + + while (nrf_clock_event_check(NRF_CLOCK_EVENT_DONE) == 0) { + k_busy_wait(1000); + cnt++; + if (cnt == max_cnt) { + irq_unlock(key); + clock_control_off(lfclk_dev, NULL); + zassert_true(false, ""); + } + } + + irq_unlock(key); + + /* wait some time after which clock should be off. */ + k_busy_wait(300); + + zassert_false(nrf_clock_lf_is_running(), "Expected LF off"); + + clock_control_off(lfclk_dev, NULL); +} + +static u32_t pend_on_next_calibration(void) +{ + u32_t stamp = k_uptime_get_32(); + int cnt = z_nrf_clock_calibration_count(); + + while (cnt == z_nrf_clock_calibration_count()) { + if ((k_uptime_get_32() - stamp) > 300) { + zassert_true(false, "Expected calibration"); + return UINT32_MAX; + } + } + + return k_uptime_get_32() - stamp; +} + +static void test_clock_calibration_force(void) +{ + struct device *hfclk_dev = + device_get_binding(DT_INST_0_NORDIC_NRF_CLOCK_LABEL "_16M"); + struct device *lfclk_dev = + device_get_binding(DT_INST_0_NORDIC_NRF_CLOCK_LABEL "_32K"); + volatile bool started = false; + struct clock_control_async_data lfclk_data = { + .cb = lfclk_started_cb, + .user_data = (void *)&started + }; + u32_t cnt = 0; + u32_t period; + + turn_off_clock(hfclk_dev); + turn_off_clock(lfclk_dev); + + /* In case calibration needs to be completed. */ + k_busy_wait(100000); + + clock_control_async_on(lfclk_dev, NULL, &lfclk_data); + + while (started == false) { + } + + cnt = z_nrf_clock_calibration_count(); + + pend_on_next_calibration(); + + zassert_equal(cnt + 1, z_nrf_clock_calibration_count(), + "Unexpected number of calibrations %d (expected: %d)", + z_nrf_clock_calibration_count(), cnt + 1); + + /* Next calibration should happen in 250ms, after forcing it should be + * done sooner. + */ + z_nrf_clock_calibration_force_start(); + period = pend_on_next_calibration(); + zassert_equal(cnt + 2, z_nrf_clock_calibration_count(), + "Unexpected number of calibrations"); + zassert_true(period < 100, "Unexpected calibration period."); + + k_busy_wait(80000); + + /* Next calibration should happen as scheduled. */ + period = pend_on_next_calibration(); + zassert_equal(cnt + 3, z_nrf_clock_calibration_count(), + "Unexpected number of calibrations"); + zassert_true(period < 200, + "Unexpected calibration period %d ms.", period); + +} + +void test_main(void) +{ + ztest_test_suite(test_nrf_clock_calibration, + ztest_unit_test(test_clock_calibration), + ztest_unit_test(test_stopping_when_calibration), + ztest_unit_test(test_clock_calibration_force) + ); + ztest_run_test_suite(test_nrf_clock_calibration); +} diff --git a/tests/drivers/clock_control/nrf_clock_calibration/testcase.yaml b/tests/drivers/clock_control/nrf_clock_calibration/testcase.yaml new file mode 100644 index 00000000000..1e289f23130 --- /dev/null +++ b/tests/drivers/clock_control/nrf_clock_calibration/testcase.yaml @@ -0,0 +1,5 @@ +tests: + peripheral.nrf5_clock_calibration: + tags: drivers + platform_whitelist: nrf51_pca10028 nrf52_pca10040 nrf52840_pca10056 +