mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-23 23:23:34 +08:00
LPC11C24 clock driver. Not well tested yet, but generally seems to be OK
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
*/
|
||||
|
||||
#include <uavcan_lpc11c24/can.hpp>
|
||||
#include <uavcan_lpc11c24/clock.hpp>
|
||||
#include <chip.h>
|
||||
#include "internal.hpp"
|
||||
|
||||
@@ -264,8 +265,8 @@ uavcan::int16_t CanDriver::send(const uavcan::CanFrame& frame, uavcan::Monotonic
|
||||
uavcan::int16_t CanDriver::receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic,
|
||||
uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags)
|
||||
{
|
||||
out_ts_monotonic = uavcan::MonotonicTime(); // TODO: read monotonic
|
||||
out_flags = 0; // We don't support any flags
|
||||
out_ts_monotonic = uavcan_lpc11c24::clock::getMonotonic();
|
||||
out_flags = 0; // We don't support any IO flags
|
||||
|
||||
CriticalSectionLocker locker;
|
||||
if (rx_queue.getLength() == 0)
|
||||
@@ -368,9 +369,9 @@ void canErrorCallback(uint32_t error_info)
|
||||
}
|
||||
}
|
||||
|
||||
void CAN_IRQHandler(void)
|
||||
void CAN_IRQHandler()
|
||||
{
|
||||
uavcan_lpc11c24::last_irq_utc_timestamp = 0; // TODO: Read UTC timestamp
|
||||
uavcan_lpc11c24::last_irq_utc_timestamp = uavcan_lpc11c24::clock::getUtcUSecFromCanInterrupt();
|
||||
LPC_CCAN_API->isr();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
|
||||
*/
|
||||
|
||||
#include <uavcan_lpc11c24/clock.hpp>
|
||||
#include <chip.h>
|
||||
#include "internal.hpp"
|
||||
|
||||
namespace uavcan_lpc11c24
|
||||
{
|
||||
namespace clock
|
||||
{
|
||||
namespace
|
||||
{
|
||||
|
||||
bool initialized = false;
|
||||
bool utc_set = false;
|
||||
|
||||
int32_t utc_correction_usec_per_overflow_x16 = 0;
|
||||
int64_t prev_adjustment = 0;
|
||||
|
||||
uint64_t time_mono = 0;
|
||||
uint64_t time_utc = 0;
|
||||
|
||||
/**
|
||||
* If this value is too large for the given core clock, reload value will be out of the 24-bit integer range.
|
||||
* This will be detected at run time during timer initialization - refer to SysTick_Config().
|
||||
*/
|
||||
const uint32_t USecPerOverflow = 65536 * 2;
|
||||
const int32_t MaxUtcSpeedCorrectionX16 = 100 * 16;
|
||||
|
||||
}
|
||||
|
||||
__attribute((noreturn))
|
||||
void fail()
|
||||
{
|
||||
while (true) { }
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
CriticalSectionLocker lock;
|
||||
if (!initialized)
|
||||
{
|
||||
initialized = true;
|
||||
|
||||
if ((SystemCoreClock % 1000000) != 0) // Core clock frequency validation
|
||||
{
|
||||
fail();
|
||||
}
|
||||
|
||||
if (SysTick_Config((SystemCoreClock / 1000000) * USecPerOverflow) != 0)
|
||||
{
|
||||
fail();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Optimizer breaks this function.
|
||||
__attribute__((optimize("0")))
|
||||
static uint64_t sampleFromCriticalSection(const volatile uint64_t* const value)
|
||||
{
|
||||
const uint32_t reload = SysTick->LOAD; // SysTick counts downwards, hence the value subtracted from reload
|
||||
volatile uint64_t time = *value;
|
||||
volatile uint32_t cycles = reload - SysTick->VAL;
|
||||
|
||||
if (NVIC_GetPendingIRQ(SysTick_IRQn))
|
||||
{
|
||||
/*
|
||||
* The timer has overflowed either before or after CNT sample was obtained.
|
||||
* We need to sample it once more to be sure that the obtained
|
||||
* counter value has wrapped over zero.
|
||||
*/
|
||||
cycles = reload - SysTick->VAL;
|
||||
/*
|
||||
* The timer interrupt was set, but not handled yet.
|
||||
* Thus we need to adjust the tick counter manually.
|
||||
*/
|
||||
time += USecPerOverflow;
|
||||
}
|
||||
/*
|
||||
* Raw counter value must be converted from core cycles to microseconds
|
||||
*/
|
||||
return time + (cycles / (SystemCoreClock / 1000000));
|
||||
}
|
||||
|
||||
uint64_t getUtcUSecFromCanInterrupt()
|
||||
{
|
||||
return utc_set ? sampleFromCriticalSection(&time_utc) : 0;
|
||||
}
|
||||
|
||||
uavcan::MonotonicTime getMonotonic()
|
||||
{
|
||||
uint64_t usec = 0;
|
||||
{
|
||||
CriticalSectionLocker locker;
|
||||
usec = sampleFromCriticalSection(&time_mono);
|
||||
}
|
||||
return uavcan::MonotonicTime::fromUSec(usec);
|
||||
}
|
||||
|
||||
uavcan::UtcTime getUtc()
|
||||
{
|
||||
if (utc_set)
|
||||
{
|
||||
uint64_t usec = 0;
|
||||
{
|
||||
CriticalSectionLocker locker;
|
||||
usec = sampleFromCriticalSection(&time_utc);
|
||||
}
|
||||
return uavcan::UtcTime::fromUSec(usec);
|
||||
}
|
||||
return uavcan::UtcTime();
|
||||
}
|
||||
|
||||
uavcan::UtcDuration getPrevUtcAdjustment()
|
||||
{
|
||||
return uavcan::UtcDuration::fromUSec(prev_adjustment);
|
||||
}
|
||||
|
||||
void adjustUtc(uavcan::UtcDuration adjustment)
|
||||
{
|
||||
const int64_t adj_delta = adjustment.toUSec() - prev_adjustment; // This is the P term
|
||||
prev_adjustment = adjustment.toUSec();
|
||||
|
||||
utc_correction_usec_per_overflow_x16 += adjustment.isPositive() ? 1 : -1; // I
|
||||
utc_correction_usec_per_overflow_x16 += (adj_delta > 0) ? 1 : -1; // P
|
||||
|
||||
utc_correction_usec_per_overflow_x16 = std::max(utc_correction_usec_per_overflow_x16, -MaxUtcSpeedCorrectionX16);
|
||||
utc_correction_usec_per_overflow_x16 = std::min(utc_correction_usec_per_overflow_x16, MaxUtcSpeedCorrectionX16);
|
||||
|
||||
if (adjustment.getAbs().toMSec() > 2 || !utc_set)
|
||||
{
|
||||
const int64_t adj_usec = adjustment.toUSec();
|
||||
{
|
||||
CriticalSectionLocker locker;
|
||||
if ((adj_usec < 0) && uint64_t(-adj_usec) > time_utc)
|
||||
{
|
||||
time_utc = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
time_utc += adj_usec;
|
||||
}
|
||||
}
|
||||
if (!utc_set)
|
||||
{
|
||||
utc_set = true;
|
||||
utc_correction_usec_per_overflow_x16 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace clock
|
||||
|
||||
SystemClock SystemClock::self;
|
||||
|
||||
SystemClock& SystemClock::instance()
|
||||
{
|
||||
clock::init();
|
||||
return self;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Timer interrupt handler
|
||||
*/
|
||||
extern "C"
|
||||
{
|
||||
|
||||
__attribute__((optimize("0")))
|
||||
void SysTick_Handler()
|
||||
{
|
||||
using namespace uavcan_lpc11c24::clock;
|
||||
if (initialized)
|
||||
{
|
||||
time_mono += USecPerOverflow;
|
||||
if (utc_set)
|
||||
{
|
||||
// Values below 16 are ignored
|
||||
time_utc += USecPerOverflow + (utc_correction_usec_per_overflow_x16 / 16);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fail();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chip.h>
|
||||
|
||||
namespace uavcan_lpc11c24
|
||||
{
|
||||
|
||||
@@ -23,4 +25,14 @@ struct CriticalSectionLocker
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Internal for the driver
|
||||
*/
|
||||
namespace clock
|
||||
{
|
||||
|
||||
uint64_t getUtcUSecFromCanInterrupt();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user