Skip to content

Commit e058327

Browse files
committed
nrfx: drivers: grtc: Add function dedicated for nrf_grtc_timer
Add functions that improves performance of nrf_grtc_timer: - Channel allocation with callback. Previously callback is written on every CC val setting which is redundant - Function for setting CCADD register - Function for setting CC register Signed-off-by: Krzysztof Chruściński <[email protected]>
1 parent 45758e2 commit e058327

File tree

2 files changed

+154
-10
lines changed

2 files changed

+154
-10
lines changed

nrfx/drivers/include/nrfx_grtc.h

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,19 @@ nrfx_err_t nrfx_grtc_sleep_configuration_get(nrfx_grtc_sleep_config_t * p_sleep_
169169
*/
170170
nrfx_err_t nrfx_grtc_channel_alloc(uint8_t * p_channel);
171171

172+
/**
173+
* @brief Function for setting a callback to a channel.
174+
*
175+
* Function enabled the interrupt for that channel.
176+
*
177+
* @param[in] channel Pointer to the capture/compare channel.
178+
* @param[in] handler User handler called when channel expires.
179+
* @param[in] p_context Context passed to the callback.
180+
*/
181+
void nrfx_grtc_channel_callback_set(uint8_t channel,
182+
nrfx_grtc_cc_handler_t handler,
183+
void * p_context);
184+
172185
/**
173186
* @brief Function for freeing the GRTC capture/compare channel.
174187
*
@@ -296,7 +309,6 @@ void nrfx_grtc_syscountervalid_int_disable(void);
296309
*/
297310

298311
nrfx_err_t nrfx_grtc_syscounter_start(bool busy_wait, uint8_t * p_main_cc_channel);
299-
300312
/**
301313
* @brief Function for performing an action for the GRTC.
302314
*
@@ -359,6 +371,22 @@ nrfx_err_t nrfx_grtc_syscounter_cc_absolute_set(nrfx_grtc_channel_t * p_chan_dat
359371
uint64_t val,
360372
bool enable_irq);
361373

374+
/**
375+
* @brief Function for setting the absolute compare value for the SYSCOUNTER.
376+
*
377+
* Function must be called with interrupts locked. If %p safe_setting is true then
378+
* it means that previous CC for that channel did not yet expired and it
379+
* was set to a value earlier than %p val so there is a chance that it will
380+
* expire during setting the new value. In that case compare event may be misinterpreted.
381+
* Slower but safe procedure is used in that case. If %p safe_setting is false then
382+
* function just sets new CC value.
383+
*
384+
* @param[in] channel Channel.
385+
* @param[in] val Absolute value to be set in the compare register.
386+
* @param[in] safe_setting Use safe procedure if true or just set CC to a new value if false.
387+
*/
388+
void nrfx_grtc_syscounter_cc_abs_set(uint8_t channel, uint64_t val, bool safe_setting);
389+
362390
/**
363391
* @brief Function for setting the relative compare value for the SYSCOUNTER.
364392
*
@@ -379,6 +407,22 @@ nrfx_err_t nrfx_grtc_syscounter_cc_relative_set(nrfx_grtc_channel_t *
379407
bool enable_irq,
380408
nrfx_grtc_cc_relative_reference_t reference);
381409

410+
/**
411+
* @brief Function for setting the relative compare value for the SYSCOUNTER.
412+
*
413+
* Function just sets CCADD value and does not attempt to enable or disable the interrupt.
414+
* It assumes that expected channel configuration is done prior to that call.
415+
* Function assumes that previously used CC value has already expired so new value
416+
* can be safely set without a risk of spurious CC expiration.
417+
*
418+
* @param[in] channel Channel.
419+
* @param[in] val Relative value to be set in the CCADD register.
420+
* @param[in] reference Reference. Current counter value or current CC value.
421+
*/
422+
void nrfx_grtc_syscounter_cc_rel_set(uint8_t channel,
423+
uint32_t val,
424+
nrfx_grtc_cc_relative_reference_t reference);
425+
382426
/**
383427
* @brief Function for disabling the SYSCOUNTER compare interrupt.
384428
*
@@ -539,6 +583,15 @@ NRFX_STATIC_INLINE bool nrfx_grtc_sys_counter_cc_enable_check(uint8_t channel);
539583
*/
540584
NRFX_STATIC_INLINE bool nrfx_grtc_syscounter_compare_event_check(uint8_t channel);
541585

586+
/**
587+
* @brief Function for retrieving CC value.
588+
*
589+
* @param[in] channel Compare channel.
590+
*
591+
* @return Value read from CC register.
592+
*/
593+
NRFX_STATIC_INLINE uint64_t nrfx_grtc_sys_counter_cc_get(uint8_t channel);
594+
542595
#if NRF_GRTC_HAS_RTCOUNTER || defined(__NRFX_DOXYGEN__)
543596
/**
544597
* @brief Function for reading the GRTC RTCOUNTER value.
@@ -590,6 +643,11 @@ NRFX_STATIC_INLINE bool nrfx_grtc_syscounter_compare_event_check(uint8_t channel
590643
return nrfy_grtc_sys_counter_compare_event_check(NRF_GRTC, channel);
591644
}
592645

646+
NRFX_STATIC_INLINE uint64_t nrfx_grtc_sys_counter_cc_get(uint8_t channel)
647+
{
648+
return nrfy_grtc_sys_counter_cc_get(NRF_GRTC, channel);
649+
}
650+
593651
#if NRF_GRTC_HAS_RTCOUNTER
594652
NRFX_STATIC_INLINE uint64_t nrfx_grtc_rtcounter_get(void)
595653
{

nrfx/drivers/src/nrfx_grtc.c

Lines changed: 95 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ typedef struct
102102
nrfx_atomic_t available_channels; /**< Bitmask of available channels. */
103103
uint32_t used_channels; /**< Bitmask of channels used by the driver. */
104104
nrfx_grtc_channel_t channel_data[NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS + 1]; /**< Channel specific data. */
105+
uint8_t ch_to_data[GRTC_NCC_SIZE]; /**< Mapping of channel indext to channel_data index. */
106+
uint64_t cc_value[NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS]; /**< Last CC value. */
107+
nrfx_atomic_t read_cc_mask; /**< Indicating if CC value must be passed to the handler. */
105108
#if NRF_GRTC_HAS_RTCOUNTER
106109
nrfx_grtc_rtcomparesync_handler_t rtcomparesync_handler; /**< User handler corresponding to rtcomparesync event.*/
107110
void * rtcomparesync_context; /**< User context for rtcomparesync event handler. */
@@ -306,6 +309,18 @@ nrfx_err_t nrfx_grtc_syscounter_get(uint64_t * p_counter)
306309
return err_code;
307310
}
308311

312+
void nrfx_grtc_channel_callback_set(uint8_t channel,
313+
nrfx_grtc_cc_handler_t handler,
314+
void * p_context)
315+
{
316+
uint8_t ch_data_idx = get_ch_data_index_for_channel(channel);
317+
318+
m_cb.channel_data[ch_data_idx].handler = handler;
319+
m_cb.channel_data[ch_data_idx].p_context = p_context;
320+
m_cb.channel_data[ch_data_idx].channel = channel;
321+
nrfy_grtc_int_enable(NRF_GRTC, GRTC_CHANNEL_TO_BITMASK(channel));
322+
}
323+
309324
nrfx_err_t nrfx_grtc_channel_alloc(uint8_t * p_channel)
310325
{
311326
NRFX_ASSERT(p_channel);
@@ -394,7 +409,10 @@ nrfx_err_t nrfx_grtc_init(uint8_t interrupt_priority)
394409

395410
for (uint8_t i = 0; i < NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS; i++)
396411
{
397-
m_cb.channel_data[i].channel = get_channel_for_ch_data_idx(i);
412+
uint8_t ch = get_channel_for_ch_data_idx(i);
413+
414+
m_cb.channel_data[i].channel = ch;
415+
m_cb.ch_to_data[ch] = i;
398416
}
399417

400418
nrfy_grtc_int_init(NRF_GRTC, GRTC_ALL_INT_MASK, interrupt_priority, false);
@@ -732,6 +750,29 @@ nrfx_err_t nrfx_grtc_syscounter_cc_disable(uint8_t channel)
732750
return err_code;
733751
}
734752

753+
void nrfx_grtc_syscounter_cc_abs_set(uint8_t channel, uint64_t val, bool safe_setting)
754+
{
755+
m_cb.cc_value[m_cb.ch_to_data[channel]] = val;
756+
if (safe_setting)
757+
{
758+
nrfy_grtc_sys_counter_cc_set(NRF_GRTC, channel, val);
759+
if (nrfy_grtc_sys_counter_compare_event_check(NRF_GRTC, channel))
760+
{
761+
uint64_t now;
762+
763+
nrfx_grtc_syscounter_get(&now);
764+
if (val > now)
765+
{
766+
nrfy_grtc_sys_counter_compare_event_clear(NRF_GRTC, channel);
767+
}
768+
}
769+
}
770+
else
771+
{
772+
nrfy_grtc_sys_counter_cc_set(NRF_GRTC, channel, val);
773+
}
774+
}
775+
735776
nrfx_err_t nrfx_grtc_syscounter_cc_absolute_set(nrfx_grtc_channel_t * p_chan_data,
736777
uint64_t val,
737778
bool enable_irq)
@@ -755,6 +796,7 @@ nrfx_err_t nrfx_grtc_syscounter_cc_absolute_set(nrfx_grtc_channel_t * p_chan_dat
755796

756797
if (enable_irq)
757798
{
799+
NRFX_ATOMIC_FETCH_OR(&m_cb.read_cc_mask, NRFX_BIT(p_chan_data->channel));
758800
nrfy_grtc_int_enable(NRF_GRTC, GRTC_CHANNEL_TO_BITMASK(p_chan_data->channel));
759801
}
760802

@@ -764,6 +806,17 @@ nrfx_err_t nrfx_grtc_syscounter_cc_absolute_set(nrfx_grtc_channel_t * p_chan_dat
764806
return err_code;
765807
}
766808

809+
void nrfx_grtc_syscounter_cc_rel_set(uint8_t channel,
810+
uint32_t val,
811+
nrfx_grtc_cc_relative_reference_t reference)
812+
{
813+
m_cb.cc_value[m_cb.ch_to_data[channel]] += val;
814+
nrfy_grtc_sys_counter_cc_add_set(NRF_GRTC,
815+
channel,
816+
val,
817+
(nrf_grtc_cc_add_reference_t)reference);
818+
}
819+
767820
nrfx_err_t nrfx_grtc_syscounter_cc_relative_set(nrfx_grtc_channel_t * p_chan_data,
768821
uint32_t val,
769822
bool enable_irq,
@@ -793,6 +846,7 @@ nrfx_err_t nrfx_grtc_syscounter_cc_relative_set(nrfx_grtc_channel_t *
793846

794847
if (enable_irq)
795848
{
849+
NRFX_ATOMIC_FETCH_OR(&m_cb.read_cc_mask, NRFX_BIT(p_chan_data->channel));
796850
nrfy_grtc_int_enable(NRF_GRTC, GRTC_CHANNEL_TO_BITMASK(p_chan_data->channel));
797851
}
798852

@@ -905,30 +959,61 @@ static void grtc_irq_handler(void)
905959
uint32_t intpend = nrf_grtc_int_pending_get(NRF_GRTC);
906960

907961
while (intpend) {
908-
uint32_t idx = 31 - NRFX_CLZ(intpend);
962+
uint8_t idx = (uint8_t)(31 - NRFX_CLZ(intpend));
909963

910964
intpend &= ~NRFX_BIT(idx);
911-
nrf_grtc_event_clear(NRF_GRTC, NRFY_INT_BITPOS_TO_EVENT(idx));
912965

913-
if (!NRFX_IS_ENABLED(GRTC_EXT) || idx < 16)
966+
if (!NRFX_IS_ENABLED(GRTC_EXT) || idx < GRTC_NCC_SIZE)
914967
{
915-
for (uint32_t i = 0; i < NRFX_GRTC_CONFIG_NUM_OF_CC_CHANNELS; i++)
968+
uint32_t i = m_cb.ch_to_data[idx];
969+
970+
NRFX_ASSERT(m_cb.channel_data[i].channel == idx);
971+
972+
if (m_cb.channel_data[i].handler)
916973
{
917-
if ((m_cb.channel_data[i].channel == idx) && m_cb.channel_data[i].handler)
974+
uint64_t cc_value;
975+
976+
if (NRFX_ATOMIC_FETCH_AND(&m_cb.read_cc_mask, ~NRFX_BIT(idx)) & NRFX_BIT(idx))
918977
{
919-
m_cb.channel_data[i].handler(idx, m_cb.channel_data[i].p_context);
920-
break;
978+
/* Read CC value only if channel was set using legacy functions. It is done
979+
* for API backward compatibility. Reading 64 bit value from GRTC is costly
980+
* and it is avoided if possible.
981+
*/
982+
cc_value = nrfy_grtc_sys_counter_cc_get(NRF_GRTC, idx);
921983
}
984+
else
985+
{
986+
/* If CC was set using optimized API then CC is stored in RAM (much faster
987+
* access).
988+
*/
989+
cc_value = m_cb.cc_value[i];
990+
}
991+
992+
/* Check event again (initially checked via INTPEND). It is possible that
993+
* CC is reconfigured from higher priority context. In that case event
994+
* might be cleared.
995+
*/
996+
if (!nrf_grtc_event_check(NRF_GRTC, NRFY_INT_BITPOS_TO_EVENT(idx)))
997+
{
998+
break;
999+
}
1000+
1001+
nrf_grtc_event_clear(NRF_GRTC, NRFY_INT_BITPOS_TO_EVENT(idx));
1002+
1003+
m_cb.channel_data[i].handler(idx, cc_value, m_cb.channel_data[i].p_context);
1004+
break;
9221005
}
1006+
9231007
/* Return early as this is the most likely scenario (single CC expiring). */
924-
if (intpend == 0)
1008+
if (NRFX_IS_ENABLED(GRTC_EXT) && (intpend == 0))
9251009
{
9261010
break;
9271011
}
9281012
}
9291013
#if NRF_GRTC_HAS_RTCOUNTER
9301014
if (idx == NRFY_EVENT_TO_INT_BITPOS(NRF_GRTC_EVENT_RTCOMPARE))
9311015
{
1016+
nrf_grtc_event_clear(NRF_GRTC, NRFY_INT_BITPOS_TO_EVENT(idx));
9321017
nrfx_grtc_channel_t const * p_channel =
9331018
&m_cb.channel_data[GRTC_RTCOUNTER_CC_HANDLER_IDX];
9341019
if (p_channel->handler)
@@ -946,6 +1031,7 @@ static void grtc_irq_handler(void)
9461031
* and set when returning from this state. It can't be cleared inside the ISR
9471032
* procedure because we rely on it during SYSCOUNTER value reading procedure. */
9481033
NRFX_LOG_INFO("Event: NRF_GRTC_EVENT_SYSCOUNTERVALID.");
1034+
nrf_grtc_event_clear(NRF_GRTC, NRFY_INT_BITPOS_TO_EVENT(idx));
9491035
if (m_cb.syscountervalid_handler)
9501036
{
9511037
m_cb.syscountervalid_handler(m_cb.syscountervalid_context);

0 commit comments

Comments
 (0)