Skip to content

Commit

Permalink
drivers: clock_control: Use k_cycle_get_32() for start/sop timestamping
Browse files Browse the repository at this point in the history
When shell command is enabled, start/stop is timestamped to provide
status. Previously, k_uptime_get() was used which locks interrupts and
takes more cycles. It was leading to bluetooth failures because
clock is controlled in critical path and any delays are unaccepted.

Converted to use k_cycle_get_32() which has lockless implementation
but is limited to 32 bits which means that status will be invalid
if clock state change occurs too far in the past (~36 hours). Note was
added to status command help message.

Signed-off-by: Krzysztof Chruscinski <[email protected]>
  • Loading branch information
nordic-krch committed Apr 19, 2021
1 parent 911616e commit 0e522cc
Showing 1 changed file with 30 additions and 17 deletions.
47 changes: 30 additions & 17 deletions drivers/clock_control/clock_control_nrf.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ struct nrf_clock_control_config {
};

static atomic_t hfclk_users;
static uint64_t hf_start_tstamp;
static uint64_t hf_stop_tstamp;
static bool hf_started;
static uint32_t hf_start_tstamp;
static uint32_t hf_stop_tstamp;

static struct nrf_clock_control_sub_data *get_sub_data(const struct device *dev,
enum clock_control_nrf_type type)
Expand Down Expand Up @@ -221,17 +222,18 @@ static void lfclk_stop(void)

static void hfclk_start(void)
{
nrfx_clock_hfclk_start();

if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) {
hf_start_tstamp = k_uptime_get();
hf_start_tstamp = k_cycle_get_32();
hf_started = true;
}

nrfx_clock_hfclk_start();
}

static void hfclk_stop(void)
{
if (IS_ENABLED(CONFIG_CLOCK_CONTROL_NRF_SHELL)) {
hf_stop_tstamp = k_uptime_get();
hf_stop_tstamp = k_cycle_get_32();
}

nrfx_clock_hfclk_stop();
Expand Down Expand Up @@ -718,24 +720,32 @@ static int cmd_status(const struct shell *shell, size_t argc, char **argv)
struct onoff_manager *lf_mgr =
get_onoff_manager(CLOCK_DEVICE,
CLOCK_CONTROL_NRF_TYPE_LFCLK);
uint32_t abs_start, abs_stop;
uint32_t diff_start, diff_stop;
int key = irq_lock();
uint64_t now = k_uptime_get();
uint32_t now = k_cycle_get_32();
uint64_t now_ms = k_uptime_get();

(void)nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, (void *)&hfclk_src);
hf_status = (hfclk_src == NRF_CLOCK_HFCLK_HIGH_ACCURACY);

abs_start = hf_start_tstamp;
abs_stop = hf_stop_tstamp;
irq_unlock(key);

diff_start = k_cyc_to_ms_floor32(now - hf_start_tstamp);
diff_stop = k_cyc_to_ms_floor32(now - hf_stop_tstamp);

shell_print(shell, "HF clock:");
shell_print(shell, "\t- %srunning (users: %u)",
hf_status ? "" : "not ", hf_mgr->refs);
shell_print(shell, "\t- last start: %u ms (%u ms ago)",
(uint32_t)abs_start, (uint32_t)(now - abs_start));
shell_print(shell, "\t- last stop: %u ms (%u ms ago)",
(uint32_t)abs_stop, (uint32_t)(now - abs_stop));

if (hf_started) {
shell_print(shell, "\t- %srunning (users: %u)",
hf_status ? "" : "not ", hf_mgr->refs);
shell_print(shell, "\t- last start: %u ms (%u ms ago)",
(uint32_t)now_ms - diff_start, diff_start);
shell_print(shell, "\t- last stop: %u ms (%u ms ago)",
(uint32_t)now_ms - diff_stop, diff_stop);
} else {
shell_print(shell, "\t - never started");
}

shell_print(shell, "LF clock:");
shell_print(shell, "\t- %srunning (users: %u)",
lf_status ? "" : "not ", lf_mgr->refs);
Expand All @@ -744,7 +754,10 @@ static int cmd_status(const struct shell *shell, size_t argc, char **argv)
}

SHELL_STATIC_SUBCMD_SET_CREATE(subcmds,
SHELL_CMD_ARG(status, NULL, "Status", cmd_status, 1, 0),
SHELL_CMD_ARG(status, NULL, "Print clock control status. Note that "
"timing report may be invalid if high frequency clock state "
"changes are too far in the past (e.g. exceeds 36h when RTC "
"is used as system clock", cmd_status, 1, 0),
SHELL_SUBCMD_SET_END
);

Expand Down

0 comments on commit 0e522cc

Please sign in to comment.