Руслан Урядинский / libuavcan

Dependents:   UAVCAN UAVCAN_Subscriber

Committer:
RuslanUrya
Date:
Sat Apr 14 10:25:32 2018 +0000
Revision:
0:dfe6edabb8ec
Initial commit

Who changed what in which revision?

UserRevisionLine numberNew contents of line
RuslanUrya 0:dfe6edabb8ec 1 /*
RuslanUrya 0:dfe6edabb8ec 2 * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
RuslanUrya 0:dfe6edabb8ec 3 */
RuslanUrya 0:dfe6edabb8ec 4
RuslanUrya 0:dfe6edabb8ec 5 #include <uavcan_lpc11c24/clock.hpp>
RuslanUrya 0:dfe6edabb8ec 6 #include <uavcan/util/templates.hpp>
RuslanUrya 0:dfe6edabb8ec 7 #include <chip.h>
RuslanUrya 0:dfe6edabb8ec 8 #include "internal.hpp"
RuslanUrya 0:dfe6edabb8ec 9
RuslanUrya 0:dfe6edabb8ec 10 namespace uavcan_lpc11c24
RuslanUrya 0:dfe6edabb8ec 11 {
RuslanUrya 0:dfe6edabb8ec 12 namespace clock
RuslanUrya 0:dfe6edabb8ec 13 {
RuslanUrya 0:dfe6edabb8ec 14 namespace
RuslanUrya 0:dfe6edabb8ec 15 {
RuslanUrya 0:dfe6edabb8ec 16
RuslanUrya 0:dfe6edabb8ec 17 bool initialized = false;
RuslanUrya 0:dfe6edabb8ec 18 bool utc_set = false;
RuslanUrya 0:dfe6edabb8ec 19
RuslanUrya 0:dfe6edabb8ec 20 std::int32_t utc_correction_usec_per_overflow_x16 = 0;
RuslanUrya 0:dfe6edabb8ec 21 std::int64_t prev_adjustment = 0;
RuslanUrya 0:dfe6edabb8ec 22
RuslanUrya 0:dfe6edabb8ec 23 std::uint64_t time_mono = 0;
RuslanUrya 0:dfe6edabb8ec 24 std::uint64_t time_utc = 0;
RuslanUrya 0:dfe6edabb8ec 25
RuslanUrya 0:dfe6edabb8ec 26 /**
RuslanUrya 0:dfe6edabb8ec 27 * If this value is too large for the given core clock, reload value will be out of the 24-bit integer range.
RuslanUrya 0:dfe6edabb8ec 28 * This will be detected at run time during timer initialization - refer to SysTick_Config().
RuslanUrya 0:dfe6edabb8ec 29 */
RuslanUrya 0:dfe6edabb8ec 30 constexpr std::uint32_t USecPerOverflow = 65536 * 2;
RuslanUrya 0:dfe6edabb8ec 31 constexpr std::int32_t MaxUtcSpeedCorrectionX16 = 100 * 16;
RuslanUrya 0:dfe6edabb8ec 32
RuslanUrya 0:dfe6edabb8ec 33 }
RuslanUrya 0:dfe6edabb8ec 34
RuslanUrya 0:dfe6edabb8ec 35 #if __GNUC__
RuslanUrya 0:dfe6edabb8ec 36 __attribute__((noreturn))
RuslanUrya 0:dfe6edabb8ec 37 #endif
RuslanUrya 0:dfe6edabb8ec 38 static void fail()
RuslanUrya 0:dfe6edabb8ec 39 {
RuslanUrya 0:dfe6edabb8ec 40 while (true) { }
RuslanUrya 0:dfe6edabb8ec 41 }
RuslanUrya 0:dfe6edabb8ec 42
RuslanUrya 0:dfe6edabb8ec 43 void init()
RuslanUrya 0:dfe6edabb8ec 44 {
RuslanUrya 0:dfe6edabb8ec 45 CriticalSectionLocker lock;
RuslanUrya 0:dfe6edabb8ec 46 if (!initialized)
RuslanUrya 0:dfe6edabb8ec 47 {
RuslanUrya 0:dfe6edabb8ec 48 initialized = true;
RuslanUrya 0:dfe6edabb8ec 49
RuslanUrya 0:dfe6edabb8ec 50 if ((SystemCoreClock % 1000000) != 0) // Core clock frequency validation
RuslanUrya 0:dfe6edabb8ec 51 {
RuslanUrya 0:dfe6edabb8ec 52 fail();
RuslanUrya 0:dfe6edabb8ec 53 }
RuslanUrya 0:dfe6edabb8ec 54
RuslanUrya 0:dfe6edabb8ec 55 if (SysTick_Config((SystemCoreClock / 1000000) * USecPerOverflow) != 0)
RuslanUrya 0:dfe6edabb8ec 56 {
RuslanUrya 0:dfe6edabb8ec 57 fail();
RuslanUrya 0:dfe6edabb8ec 58 }
RuslanUrya 0:dfe6edabb8ec 59 }
RuslanUrya 0:dfe6edabb8ec 60 }
RuslanUrya 0:dfe6edabb8ec 61
RuslanUrya 0:dfe6edabb8ec 62 static std::uint64_t sampleFromCriticalSection(const volatile std::uint64_t* const value)
RuslanUrya 0:dfe6edabb8ec 63 {
RuslanUrya 0:dfe6edabb8ec 64 const std::uint32_t reload = SysTick->LOAD + 1; // SysTick counts downwards, hence the value subtracted from reload
RuslanUrya 0:dfe6edabb8ec 65
RuslanUrya 0:dfe6edabb8ec 66 volatile std::uint64_t time = *value;
RuslanUrya 0:dfe6edabb8ec 67 volatile std::uint32_t cycles = reload - SysTick->VAL;
RuslanUrya 0:dfe6edabb8ec 68
RuslanUrya 0:dfe6edabb8ec 69 if ((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) == SCB_ICSR_PENDSTSET_Msk)
RuslanUrya 0:dfe6edabb8ec 70 {
RuslanUrya 0:dfe6edabb8ec 71 cycles = reload - SysTick->VAL;
RuslanUrya 0:dfe6edabb8ec 72 time += USecPerOverflow;
RuslanUrya 0:dfe6edabb8ec 73 }
RuslanUrya 0:dfe6edabb8ec 74 const std::uint32_t cycles_per_usec = SystemCoreClock / 1000000;
RuslanUrya 0:dfe6edabb8ec 75 return time + (cycles / cycles_per_usec);
RuslanUrya 0:dfe6edabb8ec 76 }
RuslanUrya 0:dfe6edabb8ec 77
RuslanUrya 0:dfe6edabb8ec 78 std::uint64_t getUtcUSecFromCanInterrupt()
RuslanUrya 0:dfe6edabb8ec 79 {
RuslanUrya 0:dfe6edabb8ec 80 return utc_set ? sampleFromCriticalSection(&time_utc) : 0;
RuslanUrya 0:dfe6edabb8ec 81 }
RuslanUrya 0:dfe6edabb8ec 82
RuslanUrya 0:dfe6edabb8ec 83 uavcan::MonotonicTime getMonotonic()
RuslanUrya 0:dfe6edabb8ec 84 {
RuslanUrya 0:dfe6edabb8ec 85 if (!initialized)
RuslanUrya 0:dfe6edabb8ec 86 {
RuslanUrya 0:dfe6edabb8ec 87 fail();
RuslanUrya 0:dfe6edabb8ec 88 }
RuslanUrya 0:dfe6edabb8ec 89 std::uint64_t usec = 0;
RuslanUrya 0:dfe6edabb8ec 90 {
RuslanUrya 0:dfe6edabb8ec 91 CriticalSectionLocker locker;
RuslanUrya 0:dfe6edabb8ec 92 usec = sampleFromCriticalSection(&time_mono);
RuslanUrya 0:dfe6edabb8ec 93 }
RuslanUrya 0:dfe6edabb8ec 94 return uavcan::MonotonicTime::fromUSec(usec);
RuslanUrya 0:dfe6edabb8ec 95 }
RuslanUrya 0:dfe6edabb8ec 96
RuslanUrya 0:dfe6edabb8ec 97 uavcan::UtcTime getUtc()
RuslanUrya 0:dfe6edabb8ec 98 {
RuslanUrya 0:dfe6edabb8ec 99 if (!initialized)
RuslanUrya 0:dfe6edabb8ec 100 {
RuslanUrya 0:dfe6edabb8ec 101 fail();
RuslanUrya 0:dfe6edabb8ec 102 }
RuslanUrya 0:dfe6edabb8ec 103 std::uint64_t usec = 0;
RuslanUrya 0:dfe6edabb8ec 104 if (utc_set)
RuslanUrya 0:dfe6edabb8ec 105 {
RuslanUrya 0:dfe6edabb8ec 106 CriticalSectionLocker locker;
RuslanUrya 0:dfe6edabb8ec 107 usec = sampleFromCriticalSection(&time_utc);
RuslanUrya 0:dfe6edabb8ec 108 }
RuslanUrya 0:dfe6edabb8ec 109 return uavcan::UtcTime::fromUSec(usec);
RuslanUrya 0:dfe6edabb8ec 110 }
RuslanUrya 0:dfe6edabb8ec 111
RuslanUrya 0:dfe6edabb8ec 112 uavcan::UtcDuration getPrevUtcAdjustment()
RuslanUrya 0:dfe6edabb8ec 113 {
RuslanUrya 0:dfe6edabb8ec 114 return uavcan::UtcDuration::fromUSec(prev_adjustment);
RuslanUrya 0:dfe6edabb8ec 115 }
RuslanUrya 0:dfe6edabb8ec 116
RuslanUrya 0:dfe6edabb8ec 117 void adjustUtc(uavcan::UtcDuration adjustment)
RuslanUrya 0:dfe6edabb8ec 118 {
RuslanUrya 0:dfe6edabb8ec 119 const std::int64_t adj_delta = adjustment.toUSec() - prev_adjustment; // This is the P term
RuslanUrya 0:dfe6edabb8ec 120 prev_adjustment = adjustment.toUSec();
RuslanUrya 0:dfe6edabb8ec 121
RuslanUrya 0:dfe6edabb8ec 122 utc_correction_usec_per_overflow_x16 += adjustment.isPositive() ? 1 : -1; // I
RuslanUrya 0:dfe6edabb8ec 123 utc_correction_usec_per_overflow_x16 += (adj_delta > 0) ? 1 : -1; // P
RuslanUrya 0:dfe6edabb8ec 124
RuslanUrya 0:dfe6edabb8ec 125 utc_correction_usec_per_overflow_x16 =
RuslanUrya 0:dfe6edabb8ec 126 uavcan::max(utc_correction_usec_per_overflow_x16, -MaxUtcSpeedCorrectionX16);
RuslanUrya 0:dfe6edabb8ec 127 utc_correction_usec_per_overflow_x16 =
RuslanUrya 0:dfe6edabb8ec 128 uavcan::min(utc_correction_usec_per_overflow_x16, MaxUtcSpeedCorrectionX16);
RuslanUrya 0:dfe6edabb8ec 129
RuslanUrya 0:dfe6edabb8ec 130 if (adjustment.getAbs().toMSec() > 9 || !utc_set)
RuslanUrya 0:dfe6edabb8ec 131 {
RuslanUrya 0:dfe6edabb8ec 132 const std::int64_t adj_usec = adjustment.toUSec();
RuslanUrya 0:dfe6edabb8ec 133 {
RuslanUrya 0:dfe6edabb8ec 134 CriticalSectionLocker locker;
RuslanUrya 0:dfe6edabb8ec 135 if ((adj_usec < 0) && std::uint64_t(-adj_usec) > time_utc)
RuslanUrya 0:dfe6edabb8ec 136 {
RuslanUrya 0:dfe6edabb8ec 137 time_utc = 1;
RuslanUrya 0:dfe6edabb8ec 138 }
RuslanUrya 0:dfe6edabb8ec 139 else
RuslanUrya 0:dfe6edabb8ec 140 {
RuslanUrya 0:dfe6edabb8ec 141 time_utc = std::uint64_t(std::int64_t(time_utc) + adj_usec);
RuslanUrya 0:dfe6edabb8ec 142 }
RuslanUrya 0:dfe6edabb8ec 143 }
RuslanUrya 0:dfe6edabb8ec 144 if (!utc_set)
RuslanUrya 0:dfe6edabb8ec 145 {
RuslanUrya 0:dfe6edabb8ec 146 utc_set = true;
RuslanUrya 0:dfe6edabb8ec 147 utc_correction_usec_per_overflow_x16 = 0;
RuslanUrya 0:dfe6edabb8ec 148 }
RuslanUrya 0:dfe6edabb8ec 149 }
RuslanUrya 0:dfe6edabb8ec 150 }
RuslanUrya 0:dfe6edabb8ec 151
RuslanUrya 0:dfe6edabb8ec 152 } // namespace clock
RuslanUrya 0:dfe6edabb8ec 153
RuslanUrya 0:dfe6edabb8ec 154 SystemClock SystemClock::self;
RuslanUrya 0:dfe6edabb8ec 155
RuslanUrya 0:dfe6edabb8ec 156 SystemClock& SystemClock::instance()
RuslanUrya 0:dfe6edabb8ec 157 {
RuslanUrya 0:dfe6edabb8ec 158 clock::init();
RuslanUrya 0:dfe6edabb8ec 159 return self;
RuslanUrya 0:dfe6edabb8ec 160 }
RuslanUrya 0:dfe6edabb8ec 161
RuslanUrya 0:dfe6edabb8ec 162 }
RuslanUrya 0:dfe6edabb8ec 163
RuslanUrya 0:dfe6edabb8ec 164 /*
RuslanUrya 0:dfe6edabb8ec 165 * Timer interrupt handler
RuslanUrya 0:dfe6edabb8ec 166 */
RuslanUrya 0:dfe6edabb8ec 167 extern "C"
RuslanUrya 0:dfe6edabb8ec 168 {
RuslanUrya 0:dfe6edabb8ec 169
RuslanUrya 0:dfe6edabb8ec 170 void SysTick_Handler();
RuslanUrya 0:dfe6edabb8ec 171
RuslanUrya 0:dfe6edabb8ec 172 void SysTick_Handler()
RuslanUrya 0:dfe6edabb8ec 173 {
RuslanUrya 0:dfe6edabb8ec 174 using namespace uavcan_lpc11c24::clock;
RuslanUrya 0:dfe6edabb8ec 175 if (initialized)
RuslanUrya 0:dfe6edabb8ec 176 {
RuslanUrya 0:dfe6edabb8ec 177 time_mono += USecPerOverflow;
RuslanUrya 0:dfe6edabb8ec 178 if (utc_set)
RuslanUrya 0:dfe6edabb8ec 179 {
RuslanUrya 0:dfe6edabb8ec 180 // Values below 16 are ignored
RuslanUrya 0:dfe6edabb8ec 181 time_utc += std::uint64_t(std::int32_t(USecPerOverflow) + (utc_correction_usec_per_overflow_x16 / 16));
RuslanUrya 0:dfe6edabb8ec 182 }
RuslanUrya 0:dfe6edabb8ec 183 }
RuslanUrya 0:dfe6edabb8ec 184 else
RuslanUrya 0:dfe6edabb8ec 185 {
RuslanUrya 0:dfe6edabb8ec 186 fail();
RuslanUrya 0:dfe6edabb8ec 187 }
RuslanUrya 0:dfe6edabb8ec 188 }
RuslanUrya 0:dfe6edabb8ec 189
RuslanUrya 0:dfe6edabb8ec 190 }