tests: drivers: clock_control: Add test for nRF clock calibration
Added test for LF clock calibration when RC source is used. Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
parent
488d74f125
commit
42a1e19a7d
4 changed files with 300 additions and 0 deletions
|
@ -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})
|
|
@ -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
|
||||||
|
|
|
@ -0,0 +1,280 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Nordic Semiconductor ASA
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <ztest.h>
|
||||||
|
#include <clock_control.h>
|
||||||
|
#include <drivers/clock_control/nrf_clock_control.h>
|
||||||
|
#include <hal/nrf_clock.h>
|
||||||
|
#include <logging/log.h>
|
||||||
|
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);
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
tests:
|
||||||
|
peripheral.nrf5_clock_calibration:
|
||||||
|
tags: drivers
|
||||||
|
platform_whitelist: nrf51_pca10028 nrf52_pca10040 nrf52840_pca10056
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue