Skip to content

Commit 5c62186

Browse files
mprse0xc0170
authored andcommitted
Update lp ticker to be consistent with the new standards.
Provide the following modifications for lp ticker driver: - According to NRF51_DK reference manual rtc interrupt cannot be controlled by rtc event. In the previous implementation interrupts were enabled permanently and specific interrupt was enabled/disabled by enabling/disabling the specific event. If event is enabled, then event signal is provided to Programmable Peripheral Interconnect (PPI). If interrupt is enabled, then interrupt signal is provided to Nested Vector Interrupt Controller (NVIC). Disable all events permanently. Enable lp ticker overflow interrupt permanently(needed for RTC), disable lp ticker capture/compare interrupt on init (lp_ticker_init) , enable lp ticker interrupt when lp ticker interrupt is set (lp_ticker_set_interrupt), disable lp ticker interrupt on disable request(lp_ticker_disable_interrupt). - Provide lp ticker data for higher level (freq: 32kHz / len: 24 bits), - Add the following features to init routine: disable lp ticker interrupt. - Make ticker driver to operate on ticks instead of us. - Simplify lp ticker read and set interrupt routines (upper layers handle conversion to us and interrupt scheduling).
1 parent 4f086f1 commit 5c62186

File tree

3 files changed

+80
-107
lines changed

3 files changed

+80
-107
lines changed

targets/TARGET_NORDIC/TARGET_NRF5/common_rtc.c

Lines changed: 61 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,22 @@
4747
#include "softdevice_handler.h"
4848
#endif
4949

50+
5051
//------------------------------------------------------------------------------
5152
// Common stuff used also by lp_ticker and rtc_api (see "common_rtc.h").
5253
//
5354
#include "app_util_platform.h"
5455

5556
bool m_common_rtc_enabled = false;
5657
uint32_t volatile m_common_rtc_overflows = 0;
58+
bool volatile lp_ticker_interrupt_fire = false;
5759

5860
__STATIC_INLINE void rtc_ovf_event_check(void)
5961
{
6062
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW)) {
6163
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
62-
// Don't disable this event. It shall occur periodically.
64+
/* Don't disable this event. It shall occur periodically.
65+
* It is needed for RTC. */
6366

6467
++m_common_rtc_overflows;
6568
}
@@ -74,14 +77,19 @@ void COMMON_RTC_IRQ_HANDLER(void)
7477
rtc_ovf_event_check();
7578

7679
#if DEVICE_LOWPOWERTIMER
77-
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, LP_TICKER_EVENT)) {
80+
if (nrf_rtc_event_pending(COMMON_RTC_INSTANCE, LP_TICKER_EVENT) ||
81+
lp_ticker_interrupt_fire) {
82+
83+
if (lp_ticker_interrupt_fire) {
84+
lp_ticker_interrupt_fire = false;
85+
}
7886

7987
lp_ticker_irq_handler();
8088
}
8189
#endif
8290
}
8391

84-
// Function for fix errata 20: RTC Register values are invalid
92+
/* Function for fix errata 20: RTC Register values are invalid. */
8593
__STATIC_INLINE void errata_20(void)
8694
{
8795
#if defined(NRF52_ERRATA_20)
@@ -103,20 +111,28 @@ void RTC1_IRQHandler(void);
103111
void common_rtc_init(void)
104112
{
105113
if (m_common_rtc_enabled) {
114+
#if DEVICE_LOWPOWERTIMER
115+
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, LP_TICKER_EVENT);
116+
nrf_rtc_int_disable(COMMON_RTC_INSTANCE, LP_TICKER_INT_MASK);
117+
#endif
106118
return;
107119
}
108120

109121
errata_20();
110122

123+
nrf_rtc_task_trigger(COMMON_RTC_INSTANCE, NRF_RTC_TASK_STOP);
124+
111125
NVIC_SetVector(RTC1_IRQn, (uint32_t)RTC1_IRQHandler);
112126

113-
// RTC is driven by the low frequency (32.768 kHz) clock, a proper request
114-
// must be made to have it running.
115-
// Currently this clock is started in 'SystemInit' (see "system_nrf51.c"
116-
// or "system_nrf52.c", respectively).
127+
/* RTC is driven by the low frequency (32.768 kHz) clock, a proper request
128+
* must be made to have it running.
129+
* Currently this clock is started in 'SystemInit' (see "system_nrf51.c"
130+
* or "system_nrf52.c", respectively).
131+
*/
117132

118133
nrf_rtc_prescaler_set(COMMON_RTC_INSTANCE, 0);
119134

135+
/* Clear all RTC events. */
120136
#if defined(TARGET_MCU_NRF51822)
121137
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, OS_TICK_EVENT);
122138
#endif
@@ -125,27 +141,29 @@ void common_rtc_init(void)
125141
#endif
126142
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
127143

128-
// Interrupts on all related events are enabled permanently. Particular
129-
// events will be enabled or disabled as needed (such approach is more
130-
// energy efficient).
131-
nrf_rtc_int_enable(COMMON_RTC_INSTANCE,
132-
#if DEVICE_LOWPOWERTIMER
133-
LP_TICKER_INT_MASK |
134-
#endif
135-
NRF_RTC_INT_OVERFLOW_MASK);
144+
/* Disable all RTC events (According to NRF_51 Reference Manual
145+
* RTC events can not be used to control RTC interrupts).
146+
* IRQ signal to NVIC is provided if interrupt is enabled.
147+
*/
136148

137-
// This event is enabled permanently, since overflow indications are needed
138-
// continuously.
139-
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK);
140-
// All other relevant events are initially disabled.
141-
nrf_rtc_event_disable(COMMON_RTC_INSTANCE, 0 |
149+
nrf_rtc_event_disable(COMMON_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK
142150
#if defined(TARGET_MCU_NRF51822)
143-
OS_TICK_INT_MASK |
151+
| OS_TICK_INT_MASK
144152
#endif
145153
#if DEVICE_LOWPOWERTIMER
146-
LP_TICKER_INT_MASK
154+
| LP_TICKER_INT_MASK
155+
#endif
156+
);
157+
158+
/* This interrupt is enabled permanently, since overflow indications are needed
159+
* continuously.
160+
*/
161+
nrf_rtc_int_enable(COMMON_RTC_INSTANCE, NRF_RTC_INT_OVERFLOW_MASK);
162+
163+
/* Disable LP ticker interrupt for now. */
164+
#if DEVICE_LOWPOWERTIMER
165+
nrf_rtc_int_disable(COMMON_RTC_INSTANCE, LP_TICKER_INT_MASK);
147166
#endif
148-
);
149167

150168
nrf_drv_common_irq_enable(nrf_drv_get_IRQn(COMMON_RTC_INSTANCE),
151169
#ifdef NRF51
@@ -160,93 +178,38 @@ void common_rtc_init(void)
160178
m_common_rtc_enabled = true;
161179
}
162180

163-
__STATIC_INLINE void rtc_ovf_event_safe_check(void)
164-
{
165-
core_util_critical_section_enter();
166-
167-
rtc_ovf_event_check();
168-
169-
core_util_critical_section_exit();
170-
}
171-
172-
173-
uint32_t common_rtc_32bit_ticks_get(void)
181+
void common_rtc_set_interrupt(uint32_t ticks_count, uint32_t cc_channel,
182+
uint32_t int_mask)
174183
{
175-
uint32_t ticks;
176-
uint32_t prev_overflows;
177-
178-
do {
179-
prev_overflows = m_common_rtc_overflows;
180-
181-
ticks = nrf_rtc_counter_get(COMMON_RTC_INSTANCE);
182-
// The counter used for time measurements is less than 32 bit wide,
183-
// so its value is complemented with the number of registered overflows
184-
// of the counter.
185-
ticks += (m_common_rtc_overflows << RTC_COUNTER_BITS);
186-
187-
// Check in case that OVF occurred during execution of a RTC handler (apply if call was from RTC handler)
188-
// m_common_rtc_overflows might been updated in this call.
189-
rtc_ovf_event_safe_check();
190-
191-
// If call was made from a low priority level m_common_rtc_overflows might have been updated in RTC handler.
192-
} while (m_common_rtc_overflows != prev_overflows);
184+
/* Set ticks value when interrupt should be fired.
185+
* Interrupt scheduling is performed in upper layers. */
193186

194-
return ticks;
195-
}
187+
core_util_critical_section_enter();
196188

197-
uint64_t common_rtc_64bit_us_get(void)
198-
{
199-
uint32_t ticks = common_rtc_32bit_ticks_get();
200-
// [ticks -> microseconds]
201-
return ROUNDED_DIV(((uint64_t)ticks) * 1000000, RTC_INPUT_FREQ);
202-
}
189+
/* COMPARE occurs when a CC register is N and the COUNTER value transitions from N-1 to N.
190+
* If the COUNTER is N, writing N+2 to a CC register is guaranteed to trigger a
191+
* COMPARE event at N+2.
192+
*/
193+
const uint32_t now = nrf_rtc_counter_get(COMMON_RTC_INSTANCE);
203194

204-
void common_rtc_set_interrupt(uint32_t us_timestamp, uint32_t cc_channel,
205-
uint32_t int_mask)
206-
{
207-
// The internal counter is clocked with a frequency that cannot be easily
208-
// multiplied to 1 MHz, therefore besides the translation of values
209-
// (microsecond <-> ticks) a special care of overflows handling must be
210-
// taken. Here the 32-bit timestamp value is complemented with information
211-
// about current the system up time of (ticks + number of overflows of tick
212-
// counter on upper bits, converted to microseconds), and such 64-bit value
213-
// is then translated to counter ticks. Finally, the lower 24 bits of thus
214-
// calculated value is written to the counter compare register to prepare
215-
// the interrupt generation.
216-
uint64_t current_time64 = common_rtc_64bit_us_get();
217-
// [add upper 32 bits from the current time to the timestamp value]
218-
uint64_t timestamp64 = us_timestamp +
219-
(current_time64 & ~(uint64_t)0xFFFFFFFF);
220-
// [if the original timestamp value happens to be after the 32 bit counter
221-
// of microsends overflows, correct the upper 32 bits accordingly]
222-
if (us_timestamp < (uint32_t)(current_time64 & 0xFFFFFFFF)) {
223-
timestamp64 += ((uint64_t)1 << 32);
195+
if (now == ticks_count ||
196+
RTC_WRAP(now + 1) == ticks_count) {
197+
ticks_count += 2;
224198
}
225-
// [microseconds -> ticks, always round the result up to avoid too early
226-
// interrupt generation]
227-
uint32_t compare_value =
228-
(uint32_t)CEIL_DIV((timestamp64) * RTC_INPUT_FREQ, 1000000);
229199

200+
nrf_rtc_cc_set(COMMON_RTC_INSTANCE, cc_channel, RTC_WRAP(ticks_count));
230201

231-
core_util_critical_section_enter();
232-
// The COMPARE event occurs when the value in compare register is N and
233-
// the counter value changes from N-1 to N. Therefore, the minimal safe
234-
// difference between the compare value to be set and the current counter
235-
// value is 2 ticks. This guarantees that the compare trigger is properly
236-
// setup before the compare condition occurs.
237-
uint32_t closest_safe_compare = common_rtc_32bit_ticks_get() + 2;
238-
if ((int)(compare_value - closest_safe_compare) <= 0) {
239-
compare_value = closest_safe_compare;
202+
if (!nrf_rtc_int_is_enabled(COMMON_RTC_INSTANCE, int_mask)) {
203+
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, LP_TICKER_EVENT);
204+
nrf_rtc_int_enable(COMMON_RTC_INSTANCE, int_mask);
240205
}
241206

242-
nrf_rtc_cc_set(COMMON_RTC_INSTANCE, cc_channel, RTC_WRAP(compare_value));
243-
nrf_rtc_event_enable(COMMON_RTC_INSTANCE, int_mask);
244-
245207
core_util_critical_section_exit();
246208
}
247209

248-
// Since there is no SysTick on NRF51, the RTC1 channel 1 is used as an
249-
// alternative source of RTOS ticks.
210+
/* Since there is no SysTick on NRF51, the RTC1 channel 0 is used as an
211+
* alternative source of RTOS ticks.
212+
*/
250213
#if defined(TARGET_MCU_NRF51822)
251214

252215
#include "mbed_toolchain.h"

targets/TARGET_NORDIC/TARGET_NRF5/common_rtc.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "nrf_rtc.h"
2121

2222
#define RTC_COUNTER_BITS 24u
23+
#define RTC_FREQ 32768u
2324

2425
// Instance 0 is reserved for SoftDevice.
2526
// Instance 1 is used as a common one for lp_ticker and (in case
@@ -29,9 +30,6 @@
2930
#define OS_TICK_CC_CHANNEL 0
3031
#define LP_TICKER_CC_CHANNEL 1
3132

32-
#define US_TICKER_SW_IRQ_MASK 0x1
33-
#define LP_TICKER_SW_IRQ_MASK 0x2
34-
3533
#define COMMON_RTC_EVENT_COMPARE(channel) \
3634
CONCAT_2(NRF_RTC_EVENT_COMPARE_, channel)
3735
#define COMMON_RTC_INT_COMPARE_MASK(channel) \
@@ -44,7 +42,7 @@
4442

4543
extern bool m_common_rtc_enabled;
4644
extern uint32_t volatile m_common_rtc_overflows;
47-
extern uint8_t volatile m_common_sw_irq_flag;
45+
extern bool volatile lp_ticker_interrupt_fire;
4846

4947
void common_rtc_init(void);
5048
uint32_t common_rtc_32bit_ticks_get(void);

targets/TARGET_NORDIC/TARGET_NRF5/lp_ticker.c

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,20 @@
1414
* limitations under the License.
1515
*/
1616
#include "lp_ticker_api.h"
17+
#include "common_rtc.h"
18+
#include "platform/mbed_critical.h"
1719

1820
#if DEVICE_LPTICKER
1921

20-
#include "common_rtc.h"
21-
#include "mbed_critical.h"
22+
/* LP ticker is driven by 32kHz clock and counter length is 24 bits. */
23+
const ticker_info_t* lp_ticker_get_info()
24+
{
25+
static const ticker_info_t info = {
26+
RTC_FREQ,
27+
RTC_COUNTER_BITS
28+
};
29+
return &info;
30+
}
2231

2332
void lp_ticker_init(void)
2433
{
@@ -33,7 +42,7 @@ void lp_ticker_free(void)
3342

3443
uint32_t lp_ticker_read()
3544
{
36-
return (uint32_t)common_rtc_64bit_us_get();
45+
return nrf_rtc_counter_get(COMMON_RTC_INSTANCE);
3746
}
3847

3948
void lp_ticker_set_interrupt(timestamp_t timestamp)
@@ -45,14 +54,17 @@ void lp_ticker_set_interrupt(timestamp_t timestamp)
4554
void lp_ticker_fire_interrupt(void)
4655
{
4756
core_util_critical_section_enter();
48-
m_common_sw_irq_flag |= LP_TICKER_SW_IRQ_MASK;
57+
58+
lp_ticker_interrupt_fire = true;
59+
4960
NVIC_SetPendingIRQ(RTC1_IRQn);
61+
5062
core_util_critical_section_exit();
5163
}
5264

5365
void lp_ticker_disable_interrupt(void)
5466
{
55-
nrf_rtc_event_disable(COMMON_RTC_INSTANCE, LP_TICKER_INT_MASK);
67+
nrf_rtc_int_disable(COMMON_RTC_INSTANCE, LP_TICKER_INT_MASK);
5668
}
5769

5870
void lp_ticker_clear_interrupt(void)

0 commit comments

Comments
 (0)