uc_kinetis_clock.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014, 2018 Pavel Kirienko <pavel.kirienko@gmail.com>
3  * Kinetis Port Author David Sidrane <david_s5@nscdg.com>
4  */
5 
8 #include "internal.hpp"
9 
10 #if UAVCAN_KINETIS_TIMER_NUMBER
11 # include <cassert>
12 # include <cmath>
13 
14 /*
15  * Timer instance
16  * todo:Consider using Lifetime Timer support
17  */
18 # define TIMX_IRQHandler UAVCAN_KINETIS_GLUE3(PIT, UAVCAN_KINETIS_TIMER_NUMBER, _IRQHandler)
19 # define TIMX (KINETIS_PIT_BASE + (UAVCAN_KINETIS_TIMER_NUMBER << 4))
20 # define TMR_REG(o) (TIMX + (o))
21 # define TIMX_INPUT_CLOCK BOARD_BUS_FREQ
22 # define TIMX_INTERRUPT_FREQ 16
23 # define TIMX_IRQn UAVCAN_KINETIS_GLUE2(KINETIS_IRQ_PITCH, UAVCAN_KINETIS_TIMER_NUMBER)
24 
25 # if UAVCAN_KINETIS_TIMER_NUMBER >= 0 && UAVCAN_KINETIS_TIMER_NUMBER <= 3
26 # define KINETIS_PIT_LDVAL_OFFSET KINETIS_PIT_LDVAL0_OFFSET
27 # define KINETIS_PIT_CVAL_OFFSET KINETIS_PIT_CVAL0_OFFSET
28 # define KINETIS_PIT_TCTRL_OFFSET KINETIS_PIT_TCTRL0_OFFSET
29 # define KINETIS_PIT_TFLG_OFFSET KINETIS_PIT_TFLG0_OFFSET
30 # else
31 # error "This UAVCAN_KINETIS_TIMER_NUMBER is not supported yet"
32 # endif
33 
34 extern "C" UAVCAN_KINETIS_IRQ_HANDLER(TIMX_IRQHandler);
35 
36 namespace uavcan_kinetis
37 {
38 namespace clock
39 {
40 namespace
41 {
42 
43 const uavcan::uint32_t CountsPerPeriod = (TIMX_INPUT_CLOCK / TIMX_INTERRUPT_FREQ);
44 const uavcan::uint32_t CountsPerUs = (TIMX_INPUT_CLOCK / 1000000);
45 const uavcan::uint32_t USecPerOverflow = (1000000 / TIMX_INTERRUPT_FREQ);
46 
47 Mutex mutex;
48 
49 bool initialized = false;
50 
51 bool utc_set = false;
52 bool utc_locked = false;
53 uavcan::uint32_t utc_jump_cnt = 0;
54 UtcSyncParams utc_sync_params;
55 float utc_prev_adj = 0;
56 float utc_rel_rate_ppm = 0;
57 float utc_rel_rate_error_integral = 0;
58 uavcan::int32_t utc_accumulated_correction_nsec = 0;
59 uavcan::int32_t utc_correction_nsec_per_overflow = 0;
60 uavcan::MonotonicTime prev_utc_adj_at;
61 
62 uavcan::uint64_t time_mono = 0;
63 uavcan::uint64_t time_utc = 0;
64 
65 }
66 
67 void init()
68 {
69  CriticalSectionLocker lock;
70  if (initialized)
71  {
72  return;
73  }
74  initialized = true;
75 
76  // Attach IRQ
77  irq_attach(TIMX_IRQn, &TIMX_IRQHandler, NULL);
78 
79  // Power-on Clock
80  modifyreg32(KINETIS_SIM_SCGC6, 0, SIM_SCGC6_PIT);
81 
82  // Enable module
83  putreg32(0, KINETIS_PIT_MCR);
84 
85  // Start the timer
86 
87  putreg32(CountsPerPeriod - 1, TMR_REG(KINETIS_PIT_LDVAL_OFFSET));
88  putreg32(PIT_TCTRL_TEN | PIT_TCTRL_TIE, TMR_REG(KINETIS_PIT_TCTRL_OFFSET)); // Start
89 
90  // Prioritize and Enable IRQ
91 
92 #if 0
93  // This has to be off or uses the default priority
94  // Without the ability to point the vector
95  // Directly to this ISR this will reenter the
96  // exception_common and cause the interrupt
97  // Stack pointer to be reset
98  up_prioritize_irq(TIMX_IRQn, NVIC_SYSH_HIGH_PRIORITY);
99 #endif
100  up_enable_irq(TIMX_IRQn);
101 }
102 
103 void setUtc(uavcan::UtcTime time)
104 {
105  MutexLocker mlocker(mutex);
106  UAVCAN_ASSERT(initialized);
107 
108  {
109  CriticalSectionLocker locker;
110  time_utc = time.toUSec();
111  }
112 
113  utc_set = true;
114  utc_locked = false;
115  utc_jump_cnt++;
116  utc_prev_adj = 0;
117  utc_rel_rate_ppm = 0;
118 }
119 
120 static uavcan::uint64_t sampleUtcFromCriticalSection()
121 {
122  UAVCAN_ASSERT(initialized);
123  UAVCAN_ASSERT(getreg32(TMR_REG(KINETIS_PIT_TCTRL_OFFSET)) & PIT_TCTRL_TIE);
124 
125  volatile uavcan::uint64_t time = time_utc;
126  volatile uavcan::uint32_t cnt = CountsPerPeriod - getreg32(TMR_REG(KINETIS_PIT_CVAL_OFFSET));
127 
128  if (getreg32(TMR_REG(KINETIS_PIT_TFLG_OFFSET)) & PIT_TFLG_TIF)
129  {
130  cnt = CountsPerPeriod - getreg32(TMR_REG(KINETIS_PIT_CVAL_OFFSET));
131  const uavcan::int32_t add = uavcan::int32_t(USecPerOverflow) +
132  (utc_accumulated_correction_nsec + utc_correction_nsec_per_overflow) / 1000;
133  time = uavcan::uint64_t(uavcan::int64_t(time) + add);
134  }
135  return time + (cnt / CountsPerUs);
136 }
137 
139 {
140  return utc_set ? sampleUtcFromCriticalSection() : 0;
141 }
142 
144 {
145  uavcan::uint64_t usec = 0;
146  // Scope Critical section
147  {
148  CriticalSectionLocker locker;
149 
150  volatile uavcan::uint64_t time = time_mono;
151  volatile uavcan::uint32_t cnt = CountsPerPeriod - getreg32(TMR_REG(KINETIS_PIT_CVAL_OFFSET));
152 
153  if (getreg32(TMR_REG(KINETIS_PIT_TFLG_OFFSET)) & PIT_TFLG_TIF)
154  {
155  cnt = CountsPerPeriod - getreg32(TMR_REG(KINETIS_PIT_CVAL_OFFSET));
156  time += USecPerOverflow;
157  }
158  usec = time + (cnt / CountsPerUs);
159 
160  } // End Scope Critical section
161 
162  return uavcan::MonotonicTime::fromUSec(usec);
163 }
164 
165 
167 {
168  if (utc_set)
169  {
170  uavcan::uint64_t usec = 0;
171  {
172  CriticalSectionLocker locker;
173  usec = sampleUtcFromCriticalSection();
174  }
175  return uavcan::UtcTime::fromUSec(usec);
176  }
177  return uavcan::UtcTime();
178 }
179 
180 static float lowpass(float xold, float xnew, float corner, float dt)
181 {
182  const float tau = 1.F / corner;
183  return (dt * xnew + tau * xold) / (dt + tau);
184 }
185 
186 static void updateRatePID(uavcan::UtcDuration adjustment)
187 {
188  const uavcan::MonotonicTime ts = getMonotonic();
189  const float dt = float((ts - prev_utc_adj_at).toUSec()) / 1e6F;
190  prev_utc_adj_at = ts;
191  const float adj_usec = float(adjustment.toUSec());
192 
193  /*
194  * Target relative rate in PPM
195  * Positive to go faster
196  */
197  const float target_rel_rate_ppm = adj_usec * utc_sync_params.offset_p;
198 
199  /*
200  * Current relative rate in PPM
201  * Positive if the local clock is faster
202  */
203  const float new_rel_rate_ppm = (utc_prev_adj - adj_usec) / dt; // rate error in [usec/sec], which is PPM
204  utc_prev_adj = adj_usec;
205  utc_rel_rate_ppm = lowpass(utc_rel_rate_ppm, new_rel_rate_ppm, utc_sync_params.rate_error_corner_freq, dt);
206 
207  const float rel_rate_error = target_rel_rate_ppm - utc_rel_rate_ppm;
208 
209  if (dt > 10)
210  {
211  utc_rel_rate_error_integral = 0;
212  }
213  else
214  {
215  utc_rel_rate_error_integral += rel_rate_error * dt * utc_sync_params.rate_i;
216  utc_rel_rate_error_integral =
217  uavcan::max(utc_rel_rate_error_integral, -utc_sync_params.max_rate_correction_ppm);
218  utc_rel_rate_error_integral =
219  uavcan::min(utc_rel_rate_error_integral, utc_sync_params.max_rate_correction_ppm);
220  }
221 
222  /*
223  * Rate controller
224  */
225  float total_rate_correction_ppm = rel_rate_error + utc_rel_rate_error_integral;
226  total_rate_correction_ppm = uavcan::max(total_rate_correction_ppm, -utc_sync_params.max_rate_correction_ppm);
227  total_rate_correction_ppm = uavcan::min(total_rate_correction_ppm, utc_sync_params.max_rate_correction_ppm);
228 
229  utc_correction_nsec_per_overflow = uavcan::int32_t((USecPerOverflow * 1000) * (total_rate_correction_ppm / 1e6F));
230 
231 // syslog("$ adj=%f rel_rate=%f rel_rate_eint=%f tgt_rel_rate=%f ppm=%f\n",
232 // adj_usec, utc_rel_rate_ppm, utc_rel_rate_error_integral, target_rel_rate_ppm,
233 // total_rate_correction_ppm);
234 }
235 
236 void adjustUtc(uavcan::UtcDuration adjustment)
237 {
238  MutexLocker mlocker(mutex);
239  UAVCAN_ASSERT(initialized);
240 
241  if (adjustment.getAbs() > utc_sync_params.min_jump || !utc_set)
242  {
243  const uavcan::int64_t adj_usec = adjustment.toUSec();
244 
245  {
246  CriticalSectionLocker locker;
247  if ((adj_usec < 0) && uavcan::uint64_t(-adj_usec) > time_utc)
248  {
249  time_utc = 1;
250  }
251  else
252  {
253  time_utc = uavcan::uint64_t(uavcan::int64_t(time_utc) + adj_usec);
254  }
255  }
256 
257  utc_set = true;
258  utc_locked = false;
259  utc_jump_cnt++;
260  utc_prev_adj = 0;
261  utc_rel_rate_ppm = 0;
262  }
263  else
264  {
265  updateRatePID(adjustment);
266 
267  if (!utc_locked)
268  {
269  utc_locked =
270  (std::abs(utc_rel_rate_ppm) < utc_sync_params.lock_thres_rate_ppm) &&
271  (std::abs(utc_prev_adj) < float(utc_sync_params.lock_thres_offset.toUSec()));
272  }
273  }
274 }
275 
277 {
278  MutexLocker mlocker(mutex);
279  const float rate_correction_mult = float(utc_correction_nsec_per_overflow) / float(USecPerOverflow * 1000);
280  return 1e6F * rate_correction_mult;
281 }
282 
284 {
285  MutexLocker mlocker(mutex);
286  return utc_jump_cnt;
287 }
288 
289 bool isUtcLocked()
290 {
291  MutexLocker mlocker(mutex);
292  return utc_locked;
293 }
294 
295 UtcSyncParams getUtcSyncParams()
296 {
297  MutexLocker mlocker(mutex);
298  return utc_sync_params;
299 }
300 
301 void setUtcSyncParams(const UtcSyncParams& params)
302 {
303  MutexLocker mlocker(mutex);
304  // Add some sanity check
305  utc_sync_params = params;
306 }
307 
308 } // namespace clock
309 
310 SystemClock& SystemClock::instance()
311 {
312  static union SystemClockStorage
313  {
314  uavcan::uint8_t buffer[sizeof(SystemClock)];
315  long long _aligner_1;
316  long double _aligner_2;
317  } storage;
318 
319  SystemClock* const ptr = reinterpret_cast<SystemClock*>(storage.buffer);
320 
321  if (!clock::initialized)
322  {
323  MutexLocker mlocker(clock::mutex);
324  clock::init();
325  new (ptr)SystemClock();
326  }
327  return *ptr;
328 }
329 
330 } // namespace uavcan_kinetis
331 
332 
337 extern "C"
338 UAVCAN_KINETIS_IRQ_HANDLER(TIMX_IRQHandler)
339 {
340  putreg32(PIT_TFLG_TIF, TMR_REG(KINETIS_PIT_TFLG_OFFSET));
341 
342  using namespace uavcan_kinetis::clock;
343  UAVCAN_ASSERT(initialized);
344 
345  time_mono += USecPerOverflow;
346 
347  if (utc_set)
348  {
349  time_utc += USecPerOverflow;
350  utc_accumulated_correction_nsec += utc_correction_nsec_per_overflow;
351  if (std::abs(utc_accumulated_correction_nsec) >= 1000)
352  {
353  time_utc = uavcan::uint64_t(uavcan::int64_t(time_utc) + utc_accumulated_correction_nsec / 1000);
354  utc_accumulated_correction_nsec %= 1000;
355  }
356 
357  // Correction decay - 1 nsec per 65536 usec
358  if (utc_correction_nsec_per_overflow > 0)
359  {
360  utc_correction_nsec_per_overflow--;
361  }
362  else if (utc_correction_nsec_per_overflow < 0)
363  {
364  utc_correction_nsec_per_overflow++;
365  }
366  else
367  {
368  ; // Zero
369  }
370  }
371  return 0;
372 }
373 
374 #endif
uavcan_kinetis::SystemClock::SystemClock
SystemClock()
Definition: platform_specific_components/kinetis/libuavcan/driver/include/uavcan_kinetis/clock.hpp:109
internal.hpp
uavcan_kinetis::clock::isUtcLocked
bool isUtcLocked()
uavcan::uint64_t
std::uint64_t uint64_t
Definition: std.hpp:27
uavcan::uint32_t
std::uint32_t uint32_t
Definition: std.hpp:26
uavcan::UtcTime
Implicitly convertible to/from uavcan.Timestamp.
Definition: time.hpp:191
uavcan::UtcDuration
Definition: time.hpp:189
uavcan::DurationBase::getAbs
D getAbs() const
Definition: time.hpp:46
uavcan::int64_t
std::int64_t int64_t
Definition: std.hpp:32
uavcan_kinetis::clock::setUtcSyncParams
void setUtcSyncParams(const UtcSyncParams &params)
uavcan_kinetis::SystemClock::instance
static SystemClock & instance()
uavcan_kinetis
Definition: platform_specific_components/kinetis/libuavcan/driver/include/uavcan_kinetis/can.hpp:13
uavcan::int32_t
std::int32_t int32_t
Definition: std.hpp:31
uavcan::TimeBase< MonotonicTime, MonotonicDuration >::fromUSec
static MonotonicTime fromUSec(uint64_t us)
Definition: time.hpp:112
uavcan_kinetis::clock::getUtcSyncParams
UtcSyncParams getUtcSyncParams()
uavcan::uint8_t
std::uint8_t uint8_t
Definition: std.hpp:24
uavcan::max
const UAVCAN_EXPORT T & max(const T &a, const T &b)
Definition: templates.hpp:291
uavcan_kinetis::clock::setUtc
void setUtc(uavcan::UtcTime time)
UAVCAN_KINETIS_IRQ_HANDLER
#define UAVCAN_KINETIS_IRQ_HANDLER(id)
Definition: kinetis/libuavcan/driver/src/internal.hpp:35
uavcan::min
const UAVCAN_EXPORT T & min(const T &a, const T &b)
Definition: templates.hpp:281
uavcan_kinetis::clock::getUtc
uavcan::UtcTime getUtc()
Definition: clock.cpp:97
uavcan_kinetis::clock::adjustUtc
void adjustUtc(uavcan::UtcDuration adjustment)
Definition: clock.cpp:117
uavcan_kinetis::clock::getMonotonic
uavcan::MonotonicTime getMonotonic()
Definition: clock.cpp:83
uavcan_kinetis::clock
Definition: platform_specific_components/kinetis/libuavcan/driver/include/uavcan_kinetis/clock.hpp:14
uavcan_kinetis::clock::getUtcUSecFromCanInterrupt
uavcan::uint64_t getUtcUSecFromCanInterrupt()
Definition: clock.cpp:78
NULL
#define NULL
Nullzeiger.
Definition: utils.h:64
thread.hpp
uavcan_kinetis::clock::init
void init()
Definition: clock.cpp:43
uavcan_kinetis::clock::getUtcRateCorrectionPPM
float getUtcRateCorrectionPPM()
uavcan::MonotonicTime
Definition: time.hpp:184
uavcan_kinetis::clock::getUtcJumpCount
uavcan::uint32_t getUtcJumpCount()
clock.hpp
uavcan::TimeBase::toUSec
uint64_t toUSec() const
Definition: time.hpp:120
uavcan::DurationBase::toUSec
int64_t toUSec() const
Definition: time.hpp:43
UAVCAN_ASSERT
#define UAVCAN_ASSERT(x)
Definition: libuavcan/libuavcan/include/uavcan/build_config.hpp:184


uavcan_communicator
Author(s):
autogenerated on Fri Dec 13 2024 03:10:03