9 #if UAVCAN_STM32_TIMER_NUMBER 17 # if UAVCAN_STM32_NUTTX 18 # define TIMX UAVCAN_STM32_GLUE3(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER, _BASE) 19 # define TMR_REG(o) (TIMX + (o)) 20 # define TIMX_INPUT_CLOCK UAVCAN_STM32_GLUE3(STM32_APB1_TIM, UAVCAN_STM32_TIMER_NUMBER, _CLKIN) 22 # define TIMX_IRQn UAVCAN_STM32_GLUE2(STM32_IRQ_TIM, UAVCAN_STM32_TIMER_NUMBER) 25 # if UAVCAN_STM32_TIMER_NUMBER >= 2 && UAVCAN_STM32_TIMER_NUMBER <= 7 26 # define TIMX_RCC_ENR RCC->APB1ENR 27 # define TIMX_RCC_RSTR RCC->APB1RSTR 28 # define TIMX_RCC_ENR_MASK UAVCAN_STM32_GLUE3(RCC_APB1ENR_TIM, UAVCAN_STM32_TIMER_NUMBER, EN) 29 # define TIMX_RCC_RSTR_MASK UAVCAN_STM32_GLUE3(RCC_APB1RSTR_TIM, UAVCAN_STM32_TIMER_NUMBER, RST) 31 # error "This UAVCAN_STM32_TIMER_NUMBER is not supported yet" 46 # ifdef UAVCAN_STM32_TIMX_INPUT_CLOCK 47 # undef TIMX_INPUT_CLOCK 48 # define TIMX_INPUT_CLOCK UAVCAN_STM32_TIMX_INPUT_CLOCK 60 const uavcan::uint32_t USecPerOverflow = 65536;
64 bool initialized =
false;
67 bool utc_locked =
false;
68 uavcan::uint32_t utc_jump_cnt = 0;
69 UtcSyncParams utc_sync_params;
70 float utc_prev_adj = 0;
71 float utc_rel_rate_ppm = 0;
72 float utc_rel_rate_error_integral = 0;
73 uavcan::int32_t utc_accumulated_correction_nsec = 0;
74 uavcan::int32_t utc_correction_nsec_per_overflow = 0;
75 uavcan::MonotonicTime prev_utc_adj_at;
77 uavcan::uint64_t time_mono = 0;
78 uavcan::uint64_t time_utc = 0;
85 CriticalSectionLocker
lock;
94 # if UAVCAN_STM32_NUTTX 97 irq_attach(TIMX_IRQn, &TIMX_IRQHandler, NULL);
100 modifyreg32(STM32_RCC_APB1ENR, 0, TIMX_RCC_ENR_MASK);
101 modifyreg32(STM32_RCC_APB1RSTR, 0, TIMX_RCC_RSTR_MASK);
102 modifyreg32(STM32_RCC_APB1RSTR, TIMX_RCC_RSTR_MASK, 0);
106 putreg32(0xFFFF, TMR_REG(STM32_BTIM_ARR_OFFSET));
107 putreg16(((TIMX_INPUT_CLOCK / 1000000) - 1), TMR_REG(STM32_BTIM_PSC_OFFSET));
108 putreg16(BTIM_CR1_URS, TMR_REG(STM32_BTIM_CR1_OFFSET));
109 putreg16(0, TMR_REG(STM32_BTIM_SR_OFFSET));
110 putreg16(BTIM_EGR_UG, TMR_REG(STM32_BTIM_EGR_OFFSET));
111 putreg16(BTIM_DIER_UIE, TMR_REG(STM32_BTIM_DIER_OFFSET));
112 putreg16(BTIM_CR1_CEN, TMR_REG(STM32_BTIM_CR1_OFFSET));
118 up_enable_irq(TIMX_IRQn);
123 void setUtc(uavcan::UtcTime time)
125 MutexLocker mlocker(mutex);
126 UAVCAN_ASSERT(initialized);
129 CriticalSectionLocker locker;
130 time_utc = time.toUSec();
137 utc_rel_rate_ppm = 0;
140 static uavcan::uint64_t sampleUtcFromCriticalSection()
142 # if UAVCAN_STM32_NUTTX 144 UAVCAN_ASSERT(initialized);
145 UAVCAN_ASSERT(getreg16(TMR_REG(STM32_BTIM_DIER_OFFSET)) & BTIM_DIER_UIE);
147 volatile uavcan::uint64_t time = time_utc;
148 volatile uavcan::uint32_t cnt = getreg16(TMR_REG(STM32_BTIM_CNT_OFFSET));
150 if (getreg16(TMR_REG(STM32_BTIM_SR_OFFSET)) & BTIM_SR_UIF) {
151 cnt = getreg16(TMR_REG(STM32_BTIM_CNT_OFFSET));
152 const uavcan::int32_t add = uavcan::int32_t(USecPerOverflow) +
153 (utc_accumulated_correction_nsec + utc_correction_nsec_per_overflow) / 1000;
154 time = uavcan::uint64_t(uavcan::int64_t(time) + add);
163 return utc_set ? sampleUtcFromCriticalSection() : 0;
168 uavcan::uint64_t usec = 0;
171 CriticalSectionLocker locker;
173 volatile uavcan::uint64_t time = time_mono;
175 # if UAVCAN_STM32_NUTTX 177 volatile uavcan::uint32_t cnt = getreg16(TMR_REG(STM32_BTIM_CNT_OFFSET));
179 if (getreg16(TMR_REG(STM32_BTIM_SR_OFFSET)) & BTIM_SR_UIF) {
180 cnt = getreg16(TMR_REG(STM32_BTIM_CNT_OFFSET));
182 time += USecPerOverflow;
188 static uavcan::uint64_t prev_usec = 0;
189 UAVCAN_ASSERT(prev_usec <= usec);
195 return uavcan::MonotonicTime::fromUSec(usec);
201 uavcan::uint64_t usec = 0;
203 CriticalSectionLocker locker;
204 usec = sampleUtcFromCriticalSection();
206 return uavcan::UtcTime::fromUSec(usec);
209 return uavcan::UtcTime();
212 static float lowpass(
float xold,
float xnew,
float corner,
float dt)
214 const float tau = 1.F / corner;
215 return (dt * xnew + tau * xold) / (dt + tau);
218 static void updateRatePID(uavcan::UtcDuration adjustment)
221 const float dt = float((ts - prev_utc_adj_at).toUSec()) / 1e6F;
222 prev_utc_adj_at = ts;
223 const float adj_usec = float(adjustment.toUSec());
229 const float target_rel_rate_ppm = adj_usec * utc_sync_params.offset_p;
235 const float new_rel_rate_ppm = (utc_prev_adj - adj_usec) / dt;
236 utc_prev_adj = adj_usec;
237 utc_rel_rate_ppm = lowpass(utc_rel_rate_ppm, new_rel_rate_ppm, utc_sync_params.rate_error_corner_freq, dt);
239 const float rel_rate_error = target_rel_rate_ppm - utc_rel_rate_ppm;
242 utc_rel_rate_error_integral = 0;
245 utc_rel_rate_error_integral += rel_rate_error * dt * utc_sync_params.rate_i;
246 utc_rel_rate_error_integral =
247 uavcan::max(utc_rel_rate_error_integral, -utc_sync_params.max_rate_correction_ppm);
248 utc_rel_rate_error_integral =
249 uavcan::min(utc_rel_rate_error_integral, utc_sync_params.max_rate_correction_ppm);
255 float total_rate_correction_ppm = rel_rate_error + utc_rel_rate_error_integral;
256 total_rate_correction_ppm =
uavcan::max(total_rate_correction_ppm, -utc_sync_params.max_rate_correction_ppm);
257 total_rate_correction_ppm =
uavcan::min(total_rate_correction_ppm, utc_sync_params.max_rate_correction_ppm);
259 utc_correction_nsec_per_overflow = uavcan::int32_t((USecPerOverflow * 1000) * (total_rate_correction_ppm / 1e6F));
266 void adjustUtc(uavcan::UtcDuration adjustment)
268 MutexLocker mlocker(mutex);
269 UAVCAN_ASSERT(initialized);
271 if (adjustment.getAbs() > utc_sync_params.min_jump || !utc_set) {
272 const uavcan::int64_t adj_usec = adjustment.toUSec();
275 CriticalSectionLocker locker;
277 if ((adj_usec < 0) && uavcan::uint64_t(-adj_usec) > time_utc) {
281 time_utc = uavcan::uint64_t(uavcan::int64_t(time_utc) + adj_usec);
289 utc_rel_rate_ppm = 0;
292 updateRatePID(adjustment);
296 (
std::abs(utc_rel_rate_ppm) < utc_sync_params.lock_thres_rate_ppm) &&
297 (
std::abs(utc_prev_adj) < float(utc_sync_params.lock_thres_offset.toUSec()));
304 MutexLocker mlocker(mutex);
305 const float rate_correction_mult = float(utc_correction_nsec_per_overflow) / float(USecPerOverflow * 1000);
306 return 1e6F * rate_correction_mult;
311 MutexLocker mlocker(mutex);
317 MutexLocker mlocker(mutex);
323 MutexLocker mlocker(mutex);
324 return utc_sync_params;
329 MutexLocker mlocker(mutex);
331 utc_sync_params = params;
338 static union SystemClockStorage {
339 uavcan::uint8_t buffer[
sizeof(SystemClock)];
340 long long _aligner_1;
341 long double _aligner_2;
344 SystemClock *
const ptr =
reinterpret_cast<SystemClock *
>(storage.buffer);
346 if (!clock::initialized) {
347 MutexLocker mlocker(clock::mutex);
349 new (ptr)SystemClock();
365 UAVCAN_STM32_IRQ_PROLOGUE();
367 # if UAVCAN_STM32_NUTTX 368 putreg16(0, TMR_REG(STM32_BTIM_SR_OFFSET));
372 UAVCAN_ASSERT(initialized);
374 time_mono += USecPerOverflow;
377 time_utc += USecPerOverflow;
378 utc_accumulated_correction_nsec += utc_correction_nsec_per_overflow;
380 if (
std::abs(utc_accumulated_correction_nsec) >= 1000) {
381 time_utc = uavcan::uint64_t(uavcan::int64_t(time_utc) + utc_accumulated_correction_nsec / 1000);
382 utc_accumulated_correction_nsec %= 1000;
386 if (utc_correction_nsec_per_overflow > 0) {
387 utc_correction_nsec_per_overflow--;
389 }
else if (utc_correction_nsec_per_overflow < 0) {
390 utc_correction_nsec_per_overflow++;
397 UAVCAN_STM32_IRQ_EPILOGUE();
float getUtcRateCorrectionPPM()
Clock rate error.
uavcan::uint32_t getUtcJumpCount()
Number of non-gradual adjustments performed so far.
static SystemClock & instance()
Calls clock::init() as needed.
uavcan::uint64_t getUtcUSecFromCanInterrupt()
void adjustUtc(uavcan::UtcDuration adjustment)
Performs UTC phase and frequency adjustment.
UAVCAN_STM32_IRQ_HANDLER(CAN1_TX_IRQHandler)
UtcSyncParams getUtcSyncParams()
UTC sync params get/set.
uavcan::UtcTime getUtc()
Returns UTC time if it has been set, otherwise returns zero time.
constexpr _Tp min(_Tp a, _Tp b)
constexpr _Tp max(_Tp a, _Tp b)
void init()
Starts the clock.
bool isUtcLocked()
Whether UTC is synchronized and locked.
uavcan::MonotonicTime getMonotonic()
Returns current monotonic time since the moment when clock::init() was called.
void setUtcSyncParams(const UtcSyncParams ¶ms)
Dual< Scalar, N > abs(const Dual< Scalar, N > &a)
void setUtc(uavcan::UtcTime time)
Sets the driver's notion of the system UTC.