47
47
#include "softdevice_handler.h"
48
48
#endif
49
49
50
+
50
51
//------------------------------------------------------------------------------
51
52
// Common stuff used also by lp_ticker and rtc_api (see "common_rtc.h").
52
53
//
53
54
#include "app_util_platform.h"
54
55
55
56
bool m_common_rtc_enabled = false;
56
57
uint32_t volatile m_common_rtc_overflows = 0 ;
58
+ bool volatile lp_ticker_interrupt_fire = false;
57
59
58
60
__STATIC_INLINE void rtc_ovf_event_check (void )
59
61
{
60
62
if (nrf_rtc_event_pending (COMMON_RTC_INSTANCE , NRF_RTC_EVENT_OVERFLOW )) {
61
63
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. */
63
66
64
67
++ m_common_rtc_overflows ;
65
68
}
@@ -74,14 +77,19 @@ void COMMON_RTC_IRQ_HANDLER(void)
74
77
rtc_ovf_event_check ();
75
78
76
79
#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
+ }
78
86
79
87
lp_ticker_irq_handler ();
80
88
}
81
89
#endif
82
90
}
83
91
84
- // Function for fix errata 20: RTC Register values are invalid
92
+ /* Function for fix errata 20: RTC Register values are invalid. */
85
93
__STATIC_INLINE void errata_20 (void )
86
94
{
87
95
#if defined(NRF52_ERRATA_20 )
@@ -103,20 +111,28 @@ void RTC1_IRQHandler(void);
103
111
void common_rtc_init (void )
104
112
{
105
113
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
106
118
return ;
107
119
}
108
120
109
121
errata_20 ();
110
122
123
+ nrf_rtc_task_trigger (COMMON_RTC_INSTANCE , NRF_RTC_TASK_STOP );
124
+
111
125
NVIC_SetVector (RTC1_IRQn , (uint32_t )RTC1_IRQHandler );
112
126
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
+ */
117
132
118
133
nrf_rtc_prescaler_set (COMMON_RTC_INSTANCE , 0 );
119
134
135
+ /* Clear all RTC events. */
120
136
#if defined(TARGET_MCU_NRF51822 )
121
137
nrf_rtc_event_clear (COMMON_RTC_INSTANCE , OS_TICK_EVENT );
122
138
#endif
@@ -125,27 +141,29 @@ void common_rtc_init(void)
125
141
#endif
126
142
nrf_rtc_event_clear (COMMON_RTC_INSTANCE , NRF_RTC_EVENT_OVERFLOW );
127
143
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
+ */
136
148
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
142
150
#if defined(TARGET_MCU_NRF51822 )
143
- OS_TICK_INT_MASK |
151
+ | OS_TICK_INT_MASK
144
152
#endif
145
153
#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 );
147
166
#endif
148
- );
149
167
150
168
nrf_drv_common_irq_enable (nrf_drv_get_IRQn (COMMON_RTC_INSTANCE ),
151
169
#ifdef NRF51
@@ -160,93 +178,38 @@ void common_rtc_init(void)
160
178
m_common_rtc_enabled = true;
161
179
}
162
180
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 )
174
183
{
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. */
193
186
194
- return ticks ;
195
- }
187
+ core_util_critical_section_enter ();
196
188
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 );
203
194
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 ;
224
198
}
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 );
229
199
200
+ nrf_rtc_cc_set (COMMON_RTC_INSTANCE , cc_channel , RTC_WRAP (ticks_count ));
230
201
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 );
240
205
}
241
206
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
-
245
207
core_util_critical_section_exit ();
246
208
}
247
209
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
+ */
250
213
#if defined(TARGET_MCU_NRF51822 )
251
214
252
215
#include "mbed_toolchain.h"
0 commit comments