Skip to content

Commit

Permalink
drivers: counter: add support for top value configuration on native_p…
Browse files Browse the repository at this point in the history
…osix

The counter_native_posix driver currently does not support top value
configuration, i.e. `ctr_set_top_value` returns `-ENOTSUP`. This commit
adds support for top value configuration, and with the counter API now
fully implemented, adds `counter` to `supported` peripherals for
native_posix target.

Signed-off-by: Jason Wright <[email protected]>
  • Loading branch information
jpwright committed Oct 13, 2023
1 parent 5cf5282 commit 4a9c003
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 25 deletions.
13 changes: 13 additions & 0 deletions boards/posix/native_posix/hw_counter.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ void hw_counter_stop(void)
hwm_find_next_timer();
}

bool hw_counter_is_started(void)
{
return counter_running;
}

/**
* Returns the current counter value.
*/
Expand All @@ -90,6 +95,14 @@ uint64_t hw_counter_get_value(void)
return counter_value;
}

/**
* Resets the counter value.
*/
void hw_counter_reset(void)
{
counter_value = 0;
}

/**
* Configures the counter to generate an interrupt
* when its count value reaches target.
Expand Down
2 changes: 2 additions & 0 deletions boards/posix/native_posix/hw_counter.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@ void hw_counter_set_period(uint64_t period);
void hw_counter_set_target(uint64_t counter_target);
void hw_counter_start(void);
void hw_counter_stop(void);
bool hw_counter_is_started(void);
uint64_t hw_counter_get_value(void);
void hw_counter_reset(void);

#ifdef __cplusplus
}
Expand Down
1 change: 1 addition & 0 deletions boards/posix/native_posix/native_posix.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ supported:
- spi
- gpio
- rtc
- counter
testing:
default: true
vendor: zephyr
94 changes: 69 additions & 25 deletions drivers/counter/counter_native_posix.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,51 @@
#include <soc.h>
#include <hw_counter.h>
#include <limits.h>
#include <stdio.h>

#define DRIVER_CONFIG_INFO_FLAGS (COUNTER_CONFIG_INFO_COUNT_UP)
#define DRIVER_CONFIG_INFO_CHANNELS 1
#define COUNTER_NATIVE_POSIX_IRQ_FLAGS (0)
#define DRIVER_CONFIG_INFO_FLAGS (COUNTER_CONFIG_INFO_COUNT_UP)
#define DRIVER_CONFIG_INFO_CHANNELS 1
#define COUNTER_NATIVE_POSIX_IRQ_FLAGS (0)
#define COUNTER_NATIVE_POSIX_IRQ_PRIORITY (2)

#define COUNTER_PERIOD (USEC_PER_SEC / CONFIG_COUNTER_NATIVE_POSIX_FREQUENCY)
#define TOP_VALUE (UINT_MAX)
#define TOP_VALUE (UINT_MAX)

static struct counter_alarm_cfg pending_alarm;
static bool is_alarm_pending;
static uint32_t alarm_start;
static struct counter_top_cfg top;
static bool is_top_set;
static const struct device *device;

static void counter_isr(const void *arg)
{
ARG_UNUSED(arg);
uint32_t current_value = hw_counter_get_value();

if (is_alarm_pending) {
if (is_alarm_pending && (current_value == pending_alarm.ticks)) {
is_alarm_pending = false;
pending_alarm.callback(device, 0, current_value,
pending_alarm.user_data);
if (pending_alarm.callback) {
pending_alarm.callback(device, 0, current_value, pending_alarm.user_data);
}
}

if (is_top_set) {
if (top.callback) {
top.callback(device, top.user_data);
}
hw_counter_set_target(current_value + top.ticks);
}
}

static int ctr_init(const struct device *dev)
{
device = dev;
is_alarm_pending = false;
is_top_set = false;

IRQ_CONNECT(COUNTER_EVENT_IRQ, COUNTER_NATIVE_POSIX_IRQ_PRIORITY,
counter_isr, NULL, COUNTER_NATIVE_POSIX_IRQ_FLAGS);
IRQ_CONNECT(COUNTER_EVENT_IRQ, COUNTER_NATIVE_POSIX_IRQ_PRIORITY, counter_isr, NULL,
COUNTER_NATIVE_POSIX_IRQ_FLAGS);
hw_counter_set_period(COUNTER_PERIOD);
hw_counter_set_target(TOP_VALUE);

Expand Down Expand Up @@ -80,18 +93,41 @@ static uint32_t ctr_get_pending_int(const struct device *dev)
return 0;
}

static int ctr_set_top_value(const struct device *dev,
const struct counter_top_cfg *cfg)
static int ctr_set_top_value(const struct device *dev, const struct counter_top_cfg *cfg)
{
ARG_UNUSED(dev);
ARG_UNUSED(cfg);

posix_print_warning("%s not supported\n", __func__);
return -ENOTSUP;
if (is_alarm_pending) {
posix_print_warning("can't set top value while alarm is active\n");
return -EBUSY;
}

if (cfg->flags & COUNTER_TOP_CFG_DONT_RESET) {
if (hw_counter_get_value() > cfg->ticks) {
if (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) {
hw_counter_reset();
}
return -ETIME;
}
} else {
hw_counter_reset();
}

top = *cfg;
is_top_set = true;

hw_counter_set_target(cfg->ticks);
irq_enable(COUNTER_EVENT_IRQ);

return 0;
}

static uint32_t ctr_get_top_value(const struct device *dev)
{
if (is_top_set) {
return top.ticks;
}

return TOP_VALUE;
}

Expand All @@ -105,12 +141,18 @@ static int ctr_set_alarm(const struct device *dev, uint8_t chan_id,
return -ENOTSUP;
}

if (is_top_set && alarm_cfg->ticks > top.ticks) {
posix_print_warning("alarm ticks %u exceed top ticks %u\n", alarm_cfg->ticks,
top.ticks);
return -EINVAL;
}

pending_alarm = *alarm_cfg;
is_alarm_pending = true;

if (!(alarm_cfg->flags & COUNTER_ALARM_CFG_ABSOLUTE)) {
pending_alarm.ticks =
hw_counter_get_value() + pending_alarm.ticks;
alarm_start = hw_counter_get_value();
pending_alarm.ticks = alarm_start + pending_alarm.ticks;
}

hw_counter_set_target(pending_alarm.ticks);
Expand All @@ -128,6 +170,11 @@ static int ctr_cancel_alarm(const struct device *dev, uint8_t chan_id)
return -ENOTSUP;
}

if (!hw_counter_is_started()) {
posix_print_warning("counter not started\n");
return -ENOTSUP;
}

is_alarm_pending = false;

return 0;
Expand All @@ -144,13 +191,10 @@ static const struct counter_driver_api ctr_api = {
.get_top_value = ctr_get_top_value,
};

static const struct counter_config_info ctr_config = {
.max_top_value = UINT_MAX,
.freq = CONFIG_COUNTER_NATIVE_POSIX_FREQUENCY,
.channels = DRIVER_CONFIG_INFO_CHANNELS,
.flags = DRIVER_CONFIG_INFO_FLAGS
};
static const struct counter_config_info ctr_config = {.max_top_value = UINT_MAX,
.freq = CONFIG_COUNTER_NATIVE_POSIX_FREQUENCY,
.channels = DRIVER_CONFIG_INFO_CHANNELS,
.flags = DRIVER_CONFIG_INFO_FLAGS};

DEVICE_DT_INST_DEFINE(0, ctr_init,
NULL, NULL, &ctr_config, PRE_KERNEL_1,
CONFIG_COUNTER_INIT_PRIORITY, &ctr_api);
DEVICE_DT_INST_DEFINE(0, ctr_init, NULL, NULL, &ctr_config, PRE_KERNEL_1,
CONFIG_COUNTER_INIT_PRIORITY, &ctr_api);

0 comments on commit 4a9c003

Please sign in to comment.