123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- /*
- * The MIT License (MIT)
- *
- * Copyright (c) 2014 Pavel Kirienko
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
- * the Software, and to permit persons to whom the Software is furnished to do so,
- * subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- /*
- * This file is free software: you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * Modified for Ardupilot by Siddharth Bharat Purohit
- */
- #include "AP_HAL_ChibiOS.h"
- #if HAL_WITH_UAVCAN
- #include "CANClock.h"
- #include "CANThread.h"
- #include "CANInternal.h"
- #ifndef UAVCAN_STM32_TIMER_NUMBER
- #define UAVCAN_STM32_TIMER_NUMBER 0
- #endif
- #if UAVCAN_STM32_TIMER_NUMBER
- #include <cassert>
- #include <cmath>
- /*
- * Timer instance
- */
- # if (CH_KERNEL_MAJOR == 2)
- # define TIMX UAVCAN_STM32_GLUE2(TIM, UAVCAN_STM32_TIMER_NUMBER)
- # define TIMX_IRQn UAVCAN_STM32_GLUE3(TIM, UAVCAN_STM32_TIMER_NUMBER, _IRQn)
- # define TIMX_INPUT_CLOCK STM32_TIMCLK1
- # endif
- # if (CH_KERNEL_MAJOR == 3 || CH_KERNEL_MAJOR == 4)
- # define TIMX UAVCAN_STM32_GLUE2(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER)
- # define TIMX_IRQn UAVCAN_STM32_GLUE3(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER, _NUMBER)
- # define TIMX_IRQHandler UAVCAN_STM32_GLUE3(STM32_TIM, UAVCAN_STM32_TIMER_NUMBER, _HANDLER)
- # define TIMX_INPUT_CLOCK STM32_TIMCLK1
- # else
- # define TIMX_IRQHandler UAVCAN_STM32_GLUE3(TIM, UAVCAN_STM32_TIMER_NUMBER, _IRQHandler)
- # endif
- # if UAVCAN_STM32_TIMER_NUMBER >= 2 && UAVCAN_STM32_TIMER_NUMBER <= 7
- # define TIMX_RCC_ENR RCC->APB1ENR
- # define TIMX_RCC_RSTR RCC->APB1RSTR
- # define TIMX_RCC_ENR_MASK UAVCAN_STM32_GLUE3(RCC_APB1ENR_TIM, UAVCAN_STM32_TIMER_NUMBER, EN)
- # define TIMX_RCC_RSTR_MASK UAVCAN_STM32_GLUE3(RCC_APB1RSTR_TIM, UAVCAN_STM32_TIMER_NUMBER, RST)
- # else
- # error "This UAVCAN_STM32_TIMER_NUMBER is not supported yet"
- # endif
- # if (TIMX_INPUT_CLOCK % 1000000) != 0
- # error "No way, timer clock must be divisible to 1e6. FIXME!"
- # endif
- extern "C" UAVCAN_STM32_IRQ_HANDLER(TIMX_IRQHandler);
- namespace ChibiOS_CAN {
- namespace clock {
- namespace {
- const uavcan::uint32_t USecPerOverflow = 65536;
- Mutex mutex;
- bool initialized = false;
- bool utc_set = false;
- bool utc_locked = false;
- uavcan::uint32_t utc_jump_cnt = 0;
- UtcSyncParams utc_sync_params;
- float utc_prev_adj = 0;
- float utc_rel_rate_ppm = 0;
- float utc_rel_rate_error_integral = 0;
- uavcan::int32_t utc_accumulated_correction_nsec = 0;
- uavcan::int32_t utc_correction_nsec_per_overflow = 0;
- uavcan::MonotonicTime prev_utc_adj_at;
- uavcan::uint64_t time_mono = 0;
- uavcan::uint64_t time_utc = 0;
- }
- void init()
- {
- CriticalSectionLocker lock;
- if (initialized) {
- return;
- }
- initialized = true;
- // Power-on and reset
- TIMX_RCC_ENR |= TIMX_RCC_ENR_MASK;
- TIMX_RCC_RSTR |= TIMX_RCC_RSTR_MASK;
- TIMX_RCC_RSTR &= ~TIMX_RCC_RSTR_MASK;
- // Enable IRQ
- nvicEnableVector(TIMX_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
- # if (TIMX_INPUT_CLOCK % 1000000) != 0
- # error "No way, timer clock must be divisible to 1e6. FIXME!"
- # endif
- // Start the timer
- TIMX->ARR = 0xFFFF;
- TIMX->PSC = (TIMX_INPUT_CLOCK / 1000000) - 1; // 1 tick == 1 microsecond
- TIMX->CR1 = TIM_CR1_URS;
- TIMX->SR = 0;
- TIMX->EGR = TIM_EGR_UG; // Reload immediately
- TIMX->DIER = TIM_DIER_UIE;
- TIMX->CR1 = TIM_CR1_CEN; // Start
- }
- void setUtc(uavcan::UtcTime time)
- {
- MutexLocker mlocker(mutex);
- UAVCAN_ASSERT(initialized);
- {
- CriticalSectionLocker locker;
- time_utc = time.toUSec();
- }
- utc_set = true;
- utc_locked = false;
- utc_jump_cnt++;
- utc_prev_adj = 0;
- utc_rel_rate_ppm = 0;
- }
- static uavcan::uint64_t sampleUtcFromCriticalSection()
- {
- UAVCAN_ASSERT(initialized);
- UAVCAN_ASSERT(TIMX->DIER & TIM_DIER_UIE);
- volatile uavcan::uint64_t time = time_utc;
- volatile uavcan::uint32_t cnt = TIMX->CNT;
- if (TIMX->SR & TIM_SR_UIF) {
- cnt = TIMX->CNT;
- const uavcan::int32_t add = uavcan::int32_t(USecPerOverflow) +
- (utc_accumulated_correction_nsec + utc_correction_nsec_per_overflow) / 1000;
- time = uavcan::uint64_t(uavcan::int64_t(time) + add);
- }
- return time + cnt;
- }
- uavcan::uint64_t getUtcUSecFromCanInterrupt()
- {
- return utc_set ? sampleUtcFromCriticalSection() : 0;
- }
- uavcan::MonotonicTime getMonotonic()
- {
- uavcan::uint64_t usec = 0;
- // Scope Critical section
- {
- CriticalSectionLocker locker;
- volatile uavcan::uint64_t time = time_mono;
- volatile uavcan::uint32_t cnt = TIMX->CNT;
- if (TIMX->SR & TIM_SR_UIF) {
- cnt = TIMX->CNT;
- time += USecPerOverflow;
- }
- usec = time + cnt;
- # ifndef NDEBUG
- static uavcan::uint64_t prev_usec = 0; // Self-test
- UAVCAN_ASSERT(prev_usec <= usec);
- (void)prev_usec;
- prev_usec = usec;
- # endif
- } // End Scope Critical section
- return uavcan::MonotonicTime::fromUSec(usec);
- }
- uavcan::UtcTime getUtc()
- {
- if (utc_set) {
- uavcan::uint64_t usec = 0;
- {
- CriticalSectionLocker locker;
- usec = sampleUtcFromCriticalSection();
- }
- return uavcan::UtcTime::fromUSec(usec);
- }
- return uavcan::UtcTime();
- }
- static float lowpass(float xold, float xnew, float corner, float dt)
- {
- const float tau = 1.F / corner;
- return (dt * xnew + tau * xold) / (dt + tau);
- }
- static void updateRatePID(uavcan::UtcDuration adjustment)
- {
- const uavcan::MonotonicTime ts = getMonotonic();
- const float dt = float((ts - prev_utc_adj_at).toUSec()) / 1e6F;
- prev_utc_adj_at = ts;
- const float adj_usec = float(adjustment.toUSec());
- /*
- * Target relative rate in PPM
- * Positive to go faster
- */
- const float target_rel_rate_ppm = adj_usec * utc_sync_params.offset_p;
- /*
- * Current relative rate in PPM
- * Positive if the local clock is faster
- */
- const float new_rel_rate_ppm = (utc_prev_adj - adj_usec) / dt; // rate error in [usec/sec], which is PPM
- utc_prev_adj = adj_usec;
- utc_rel_rate_ppm = lowpass(utc_rel_rate_ppm, new_rel_rate_ppm, utc_sync_params.rate_error_corner_freq, dt);
- const float rel_rate_error = target_rel_rate_ppm - utc_rel_rate_ppm;
- if (dt > 10) {
- utc_rel_rate_error_integral = 0;
- }
- else {
- utc_rel_rate_error_integral += rel_rate_error * dt * utc_sync_params.rate_i;
- utc_rel_rate_error_integral =
- uavcan::max(utc_rel_rate_error_integral, -utc_sync_params.max_rate_correction_ppm);
- utc_rel_rate_error_integral =
- uavcan::min(utc_rel_rate_error_integral, utc_sync_params.max_rate_correction_ppm);
- }
- /*
- * Rate controller
- */
- float total_rate_correction_ppm = rel_rate_error + utc_rel_rate_error_integral;
- total_rate_correction_ppm = uavcan::max(total_rate_correction_ppm, -utc_sync_params.max_rate_correction_ppm);
- total_rate_correction_ppm = uavcan::min(total_rate_correction_ppm, utc_sync_params.max_rate_correction_ppm);
- utc_correction_nsec_per_overflow = uavcan::int32_t((USecPerOverflow * 1000) * (total_rate_correction_ppm / 1e6F));
- // syslog("$ adj=%f rel_rate=%f rel_rate_eint=%f tgt_rel_rate=%f ppm=%f\n",
- // adj_usec, utc_rel_rate_ppm, utc_rel_rate_error_integral, target_rel_rate_ppm,
- // total_rate_correction_ppm);
- }
- void adjustUtc(uavcan::UtcDuration adjustment)
- {
- MutexLocker mlocker(mutex);
- UAVCAN_ASSERT(initialized);
- if (adjustment.getAbs() > utc_sync_params.min_jump || !utc_set) {
- const uavcan::int64_t adj_usec = adjustment.toUSec();
- {
- CriticalSectionLocker locker;
- if ((adj_usec < 0) && uavcan::uint64_t(-adj_usec) > time_utc) {
- time_utc = 1;
- }
- else {
- time_utc = uavcan::uint64_t(uavcan::int64_t(time_utc) + adj_usec);
- }
- }
- utc_set = true;
- utc_locked = false;
- utc_jump_cnt++;
- utc_prev_adj = 0;
- utc_rel_rate_ppm = 0;
- }
- else {
- updateRatePID(adjustment);
- if (!utc_locked) {
- utc_locked =
- (std::abs(utc_rel_rate_ppm) < utc_sync_params.lock_thres_rate_ppm) &&
- (std::abs(utc_prev_adj) < utc_sync_params.lock_thres_offset.toUSec());
- }
- }
- }
- float getUtcRateCorrectionPPM()
- {
- MutexLocker mlocker(mutex);
- const float rate_correction_mult = float(utc_correction_nsec_per_overflow) / float(USecPerOverflow * 1000);
- return 1e6F * rate_correction_mult;
- }
- uavcan::uint32_t getUtcJumpCount()
- {
- MutexLocker mlocker(mutex);
- return utc_jump_cnt;
- }
- bool isUtcLocked()
- {
- MutexLocker mlocker(mutex);
- return utc_locked;
- }
- UtcSyncParams getUtcSyncParams()
- {
- MutexLocker mlocker(mutex);
- return utc_sync_params;
- }
- void setUtcSyncParams(const UtcSyncParams& params)
- {
- MutexLocker mlocker(mutex);
- // Add some sanity check
- utc_sync_params = params;
- }
- } // namespace clock
- SystemClock& SystemClock::get_singleton()
- {
- static union SystemClockStorage {
- uavcan::uint8_t buffer[sizeof(SystemClock)];
- long long _aligner_1;
- long double _aligner_2;
- } storage;
- SystemClock* const ptr = reinterpret_cast<SystemClock*>(storage.buffer);
- if (!clock::initialized) {
- MutexLocker mlocker(clock::mutex);
- clock::init();
- new (ptr)SystemClock();
- }
- return *ptr;
- }
- } // namespace uavcan_stm32
- /**
- * Timer interrupt handler
- */
- extern "C"
- UAVCAN_STM32_IRQ_HANDLER(TIMX_IRQHandler)
- {
- UAVCAN_STM32_IRQ_PROLOGUE();
- TIMX->SR = 0;
- using namespace uavcan_stm32::clock;
- UAVCAN_ASSERT(initialized);
- time_mono += USecPerOverflow;
- if (utc_set) {
- time_utc += USecPerOverflow;
- utc_accumulated_correction_nsec += utc_correction_nsec_per_overflow;
- if (std::abs(utc_accumulated_correction_nsec) >= 1000) {
- time_utc = uavcan::uint64_t(uavcan::int64_t(time_utc) + utc_accumulated_correction_nsec / 1000);
- utc_accumulated_correction_nsec %= 1000;
- }
- // Correction decay - 1 nsec per 65536 usec
- if (utc_correction_nsec_per_overflow > 0) {
- utc_correction_nsec_per_overflow--;
- }
- else if (utc_correction_nsec_per_overflow < 0) {
- utc_correction_nsec_per_overflow++;
- }
- else {
- ; // Zero
- }
- }
- UAVCAN_STM32_IRQ_EPILOGUE();
- }
- #endif
- #endif //HAL_WITH_UAVCAN
|