static void event_handler(nrfx_rtc_int_type_t int_type, void *p_context) { struct device *dev = p_context; struct counter_nrfx_data *data = get_dev_data(dev); if (int_type == COUNTER_TOP_INT) { /* Manually reset counter if top value is different than max. */ if ((data->top != COUNTER_MAX_TOP_VALUE) #if CONFIG_COUNTER_RTC_WITH_PPI_WRAP && !get_nrfx_config(dev)->use_ppi #endif ) { nrfx_rtc_counter_clear(&get_nrfx_config(dev)->rtc); } nrfx_rtc_cc_set(&get_nrfx_config(dev)->rtc, TOP_CH, data->top, true); if (data->top_cb) { data->top_cb(dev, data->top_user_data); } } else if (int_type > COUNTER_TOP_INT) { alarm_event_handler(dev, CC_TO_ID(int_type)); } }
static int counter_nrfx_set_top_value(struct device *dev, u32_t ticks, counter_top_callback_t callback, void *user_data) { const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev); const nrfx_rtc_t *rtc = &nrfx_config->rtc; struct counter_nrfx_data *dev_data = get_dev_data(dev); for (int i = 0; i < counter_get_num_of_channels(dev); i++) { /* Overflow can be changed only when all alarms are * disables. */ if (nrfx_config->ch_data[i].callback) { return -EBUSY; } } nrfx_rtc_cc_disable(rtc, TOP_CH); nrfx_rtc_counter_clear(rtc); dev_data->top_cb = callback; dev_data->top_user_data = user_data; dev_data->top = ticks; nrfx_rtc_cc_set(rtc, TOP_CH, ticks, callback ? true : false); return 0; }
static int init_rtc(struct device *dev, const nrfx_rtc_config_t *config, nrfx_rtc_handler_t handler) { struct device *clock; const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev); const nrfx_rtc_t *rtc = &nrfx_config->rtc; clock = device_get_binding(DT_NORDIC_NRF_CLOCK_0_LABEL "_32K"); if (!clock) { return -ENODEV; } clock_control_on(clock, (void *)CLOCK_CONTROL_NRF_K32SRC); nrfx_err_t result = nrfx_rtc_init(rtc, config, handler); if (result != NRFX_SUCCESS) { LOG_INST_ERR(nrfx_config->log, "Failed to initialize device."); return -EBUSY; } get_dev_data(dev)->top = COUNTER_MAX_TOP_VALUE; LOG_INST_DBG(nrfx_config->log, "Initialized"); return 0; }
static int counter_nrfx_set_top_value(struct device *dev, u32_t ticks, counter_top_callback_t callback, void *user_data) { const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev); const nrfx_timer_t *timer = &nrfx_config->timer; struct counter_nrfx_data *data = get_dev_data(dev); for (int i = 0; i < counter_get_num_of_channels(dev); i++) { /* Overflow can be changed only when all alarms are * disables. */ if (nrfx_config->ch_data[i].callback) { return -EBUSY; } } nrfx_timer_compare_int_disable(timer, TOP_CH); nrfx_timer_clear(timer); data->top_cb = callback; data->top_user_data = user_data; nrfx_timer_extended_compare(timer, TOP_CH, ticks, COUNTER_OVERFLOW_SHORT, callback ? true : false); return 0; }
static void _disable(struct device *dev, u8_t id) { const struct counter_nrfx_config *config = get_nrfx_config(dev); nrfx_timer_compare_int_disable(&config->timer, ID_TO_CC(id)); config->ch_data[id].callback = NULL; }
static void disable(struct device *dev, u8_t id) { const struct counter_nrfx_config *config = get_nrfx_config(dev); nrfx_rtc_cc_disable(&config->rtc, ID_TO_CC(id)); config->ch_data[id].callback = NULL; }
static void alarm_event_handler(struct device *dev, u32_t id) { const struct counter_nrfx_config *config = get_nrfx_config(dev); counter_alarm_callback_t clbk = config->ch_data[id].callback; u32_t cc_val; if (!clbk) { return; } cc_val = nrfx_timer_capture_get(&config->timer, ID_TO_CC(id)); _disable(dev, id); clbk(dev, id, cc_val, config->ch_data[id].user_data); }
static int init_timer(struct device *dev, const nrfx_timer_config_t *config) { const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev); const nrfx_timer_t *timer = &nrfx_config->timer; nrfx_err_t result = nrfx_timer_init(timer, config, event_handler); if (result != NRFX_SUCCESS) { LOG_INST_ERR(nrfx_config->log, "Failed to initialize device."); return -EBUSY; } nrfx_timer_compare(timer, TOP_CH, UINT32_MAX, false); LOG_INST_DBG(nrfx_config->log, "Initialized"); return 0; }
static int ppi_setup(struct device *dev) { #if CONFIG_COUNTER_RTC_WITH_PPI_WRAP const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev); struct counter_nrfx_data *data = get_dev_data(dev); const nrfx_rtc_t *rtc = &nrfx_config->rtc; nrfx_err_t result; if (!nrfx_config->use_ppi) { return 0; } #ifdef DPPI_PRESENT result = nrfx_dppi_channel_alloc(&data->ppi_ch); if (result != NRFX_SUCCESS) { LOG_INST_ERR(nrfx_config->log, "Failed to allocate PPI channel."); return -ENODEV; } nrf_rtc_subscribe_set(rtc->p_reg, NRF_RTC_TASK_CLEAR, data->ppi_ch); nrf_rtc_publish_set(rtc->p_reg, NRF_RTC_EVENT_COMPARE_0, data->ppi_ch); (void)nrfx_dppi_channel_enable(data->ppi_ch); #else /* DPPI_PRESENT */ u32_t evt; u32_t task; evt = nrfx_rtc_event_address_get(rtc, NRF_RTC_EVENT_COMPARE_0); task = nrfx_rtc_task_address_get(rtc, NRF_RTC_TASK_CLEAR); result = nrfx_ppi_channel_alloc(&data->ppi_ch); if (result != NRFX_SUCCESS) { LOG_INST_ERR(nrfx_config->log, "Failed to allocate PPI channel."); return -ENODEV; } (void)nrfx_ppi_channel_assign(data->ppi_ch, evt, task); (void)nrfx_ppi_channel_enable(data->ppi_ch); #endif #endif /* CONFIG_COUNTER_RTC_WITH_PPI_WRAP */ return 0; }
static int counter_nrfx_set_alarm(struct device *dev, u8_t chan_id, const struct counter_alarm_cfg *alarm_cfg) { const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev); const nrfx_rtc_t *rtc = &nrfx_config->rtc; u32_t cc_val; if (alarm_cfg->ticks > get_dev_data(dev)->top) { return -EINVAL; } if (nrfx_config->ch_data[chan_id].callback) { return -EBUSY; } if (alarm_cfg->absolute) { cc_val = alarm_cfg->ticks; } else { /* As RTC is 24 bit there is no risk of overflow. */ cc_val = alarm_cfg->ticks + nrfx_rtc_counter_get(rtc); cc_val -= (cc_val > get_dev_data(dev)->top) ? get_dev_data(dev)->top : 0; } nrfx_config->ch_data[chan_id].callback = alarm_cfg->callback; nrfx_config->ch_data[chan_id].user_data = alarm_cfg->user_data; if ((cc_val == 0) && (get_dev_data(dev)->top != counter_get_max_top_value(dev))) { /* From Product Specification: If a CC register value is 0 when * a CLEAR task is set, this will not trigger a COMPARE event. */ LOG_INST_INF(nrfx_config->log, "Attempt to set CC to 0, delayed to 1."); cc_val++; } nrfx_rtc_cc_set(rtc, ID_TO_CC(chan_id), cc_val, true); return 0; }
static int counter_nrfx_set_alarm(struct device *dev, u8_t chan_id, const struct counter_alarm_cfg *alarm_cfg) { const struct counter_nrfx_config *nrfx_config = get_nrfx_config(dev); const nrfx_timer_t *timer = &nrfx_config->timer; u32_t cc_val; if (alarm_cfg->ticks > nrfx_timer_capture_get(timer, TOP_CH)) { return -EINVAL; } if (nrfx_config->ch_data[chan_id].callback) { return -EBUSY; } cc_val = alarm_cfg->ticks + (alarm_cfg->absolute ? 0 : nrfx_timer_capture(timer, COUNTER_READ_CC)); nrfx_config->ch_data[chan_id].callback = alarm_cfg->callback; nrfx_config->ch_data[chan_id].user_data = alarm_cfg->user_data; nrfx_timer_compare(timer, ID_TO_CC(chan_id), cc_val, true); return 0; }
static int counter_nrfx_start(struct device *dev) { nrfx_timer_enable(&get_nrfx_config(dev)->timer); return 0; }
static u32_t counter_nrfx_read(struct device *dev) { return nrfx_rtc_counter_get(&get_nrfx_config(dev)->rtc); }
static int counter_nrfx_stop(struct device *dev) { nrfx_rtc_disable(&get_nrfx_config(dev)->rtc); return 0; }
static u32_t counter_nrfx_get_top_value(struct device *dev) { return nrfx_timer_capture_get(&get_nrfx_config(dev)->timer, TOP_CH); }
static u32_t counter_nrfx_get_max_relative_alarm(struct device *dev) { return nrfx_timer_capture_get(&get_nrfx_config(dev)->timer, TOP_CH); }
static u32_t counter_nrfx_read(struct device *dev) { return nrfx_timer_capture(&get_nrfx_config(dev)->timer, COUNTER_READ_CC); }