[alarm-API] Update usec-alarm API to use single 32-bit microsecond (#1949)

* Update the usec-alarm API to use single 32-bit microsecond
* Update nRf52840's alarm implementation to support the new usec-alarm API
* So both milliseconds timer and microsecond timer will maintain 32-bit time
This commit is contained in:
Shu Chen
2017-07-06 01:07:19 +08:00
committed by Jonathan Hui
parent f17b98d84a
commit fd6a52dba9
5 changed files with 78 additions and 116 deletions
+67 -77
View File
@@ -70,9 +70,8 @@ typedef enum
typedef struct
{
volatile bool mFireAlarm; ///< Information for processing function, that alarm should fire.
otPlatUsecAlarmTime mT0; ///< Alarm start time, for tracking overflows.
otPlatUsecAlarmTime mTargetTime; ///< Alarm fire time.
volatile bool mFireAlarm; ///< Information for processing function, that alarm should fire.
uint32_t mTargetTime; ///< Alarm fire time (in millisecond for MsTimer, in microsecond for UsTimer)
} AlarmData;
typedef struct
@@ -83,8 +82,8 @@ typedef struct
nrf_rtc_int_t mCompareInt;
} AlarmChannelData;
static volatile otPlatUsecAlarmTime sTimeOffset = { 0 }; ///< Time offset to keep track of current time.
static AlarmData sTimerData[kNumTimers]; ///< Data of the timers.
static volatile uint32_t sTimeOffset = 0; ///< Time offset to keep track of current time (in millisecond).
static AlarmData sTimerData[kNumTimers]; ///< Data of the timers.
static const AlarmChannelData sChannelData[kNumTimers] =
{
[kMsTimer] = {
@@ -106,38 +105,32 @@ static void *sUsecContext = NULL; ///< The context information
static void HandleOverflow(void);
static inline uint32_t TimeToTicks(otPlatUsecAlarmTime aTime)
static inline uint32_t TimeToTicks(uint32_t aTime, AlarmIndex aIndex)
{
uint64_t microseconds = US_PER_MS * (uint64_t)aTime.mMs + (uint64_t)aTime.mUs;
return (uint32_t)CEIL_DIV((microseconds * RTC_FREQUENCY), US_PER_S) & RTC_CC_COMPARE_Msk;
}
uint32_t ticks;
static inline otPlatUsecAlarmTime TicksToTime(uint32_t aTicks)
{
uint64_t microseconds = CEIL_DIV((US_PER_S * (uint64_t)aTicks), RTC_FREQUENCY);
return (otPlatUsecAlarmTime) {microseconds / US_PER_MS, microseconds % US_PER_MS};
}
static inline otPlatUsecAlarmTime TimeAdd(otPlatUsecAlarmTime aTime1, otPlatUsecAlarmTime aTime2)
{
otPlatUsecAlarmTime result = { aTime1.mMs + aTime2.mMs, aTime1.mUs + aTime2.mUs };
assert(result.mUs < 2 * US_PER_MS);
if (result.mUs >= US_PER_MS)
if (aIndex == kMsTimer)
{
result.mMs++;
result.mUs -= US_PER_MS;
ticks = (uint32_t)CEIL_DIV((aTime * US_PER_MS * RTC_FREQUENCY), US_PER_S) & RTC_CC_COMPARE_Msk;
}
else
{
ticks = (uint32_t)CEIL_DIV((aTime * RTC_FREQUENCY), US_PER_S) & RTC_CC_COMPARE_Msk;
}
return result;
return ticks;
}
static inline otPlatUsecAlarmTime AlarmGetCurrentTime(void)
static inline uint64_t TicksToTime(uint32_t aTicks)
{
return CEIL_DIV((US_PER_S * (uint64_t)aTicks), RTC_FREQUENCY);
}
static inline uint64_t AlarmGetCurrentTime()
{
uint32_t rtcValue1;
uint32_t rtcValue2;
otPlatUsecAlarmTime offset;
uint32_t offset;
rtcValue1 = nrf_rtc_counter_get(RTC_INSTANCE);
@@ -172,46 +165,53 @@ static inline otPlatUsecAlarmTime AlarmGetCurrentTime(void)
offset = sTimeOffset;
}
return TimeAdd(offset, TicksToTime(rtcValue2));
return US_PER_MS * (uint64_t)offset + TicksToTime(rtcValue2);
}
static inline otPlatUsecAlarmTime AlarmGetCurrentTimeRtcProtected(void)
static inline uint32_t AlarmGetCurrentTimeRtcProtected(AlarmIndex aIndex)
{
return TimeAdd(AlarmGetCurrentTime(), (otPlatUsecAlarmTime) {0, 2 * US_PER_TICK});
}
uint64_t usecTime = AlarmGetCurrentTime() + 2 * US_PER_TICK;
uint32_t currentTime;
static inline bool TimeIsLower(otPlatUsecAlarmTime aTime1, otPlatUsecAlarmTime aTime2)
{
return ((aTime1.mMs < aTime2.mMs) ||
((aTime1.mMs == aTime2.mMs) && (aTime1.mUs < aTime2.mUs)));
}
static inline bool AlarmShallStrike(otPlatUsecAlarmTime aNow, AlarmIndex aIndex)
{
if (TimeIsLower(sTimerData[aIndex].mTargetTime, sTimerData[aIndex].mT0))
if (aIndex == kMsTimer)
{
// Handle situation when timespan included timer overflow.
if (TimeIsLower(aNow, sTimerData[aIndex].mT0) && !TimeIsLower(aNow, sTimerData[aIndex].mTargetTime))
{
return true;
}
currentTime = (uint32_t)(usecTime / US_PER_MS);
}
else
{
if (TimeIsLower(aNow, sTimerData[aIndex].mT0) || !TimeIsLower(aNow, sTimerData[aIndex].mTargetTime))
{
return true;
}
currentTime = (uint32_t)usecTime;
}
return false;
return currentTime;
}
static inline bool AlarmShallStrike(uint32_t aNow, AlarmIndex aIndex)
{
uint32_t diff = aNow - sTimerData[aIndex].mTargetTime;
// Three cases:
// 1) aNow is before mTargetTime => Difference is negative (last bit of difference is set) => Returning false.
// 2) aNow is same as mTargetTime => Difference is zero (last bit of difference is clear) => Returning true.
// 3) aNow is after mTargetTime => Difference is positive (last bit of difference is clear) => Returning true.
return !((diff & (1UL << 31)) != 0);
}
static void HandleCompareMatch(AlarmIndex aIndex, bool aSkipCheck)
{
nrf_rtc_event_clear(RTC_INSTANCE, sChannelData[aIndex].mCompareEvent);
otPlatUsecAlarmTime now = AlarmGetCurrentTime();
uint64_t usecTime = AlarmGetCurrentTime();
uint32_t now;
if (aIndex == kMsTimer)
{
now = (uint32_t)(usecTime / US_PER_MS);
}
else
{
now = (uint32_t)usecTime;
}
// In case the target time was larger than single overflow,
// we should only strike the timer on final compare event.
@@ -229,25 +229,24 @@ static void HandleOverflow(void)
nrf_rtc_event_clear(RTC_INSTANCE, NRF_RTC_EVENT_OVERFLOW);
// Increment counter on overflow.
sTimeOffset = TimeAdd(sTimeOffset, (otPlatUsecAlarmTime) {MS_PER_OVERFLOW, 0});
sTimeOffset = sTimeOffset + MS_PER_OVERFLOW;
}
static void AlarmStartAt(const otPlatUsecAlarmTime *aT0, const otPlatUsecAlarmTime *aTargetTime, AlarmIndex aIndex)
static void AlarmStartAt(uint32_t aTargetTime, AlarmIndex aIndex)
{
uint32_t targetCounter;
otPlatUsecAlarmTime now;
uint32_t now;
nrf_rtc_int_disable(RTC_INSTANCE, sChannelData[aIndex].mCompareInt);
nrf_rtc_event_enable(RTC_INSTANCE, sChannelData[aIndex].mCompareEventMask);
sTimerData[aIndex].mT0 = *aT0;
sTimerData[aIndex].mTargetTime = *aTargetTime;
sTimerData[aIndex].mTargetTime = aTargetTime;
targetCounter = TimeToTicks(sTimerData[aIndex].mTargetTime);
targetCounter = TimeToTicks(sTimerData[aIndex].mTargetTime, aIndex);
nrf_rtc_cc_set(RTC_INSTANCE, sChannelData[aIndex].mChannelNumber, targetCounter);
now = AlarmGetCurrentTimeRtcProtected();
now = AlarmGetCurrentTimeRtcProtected(aIndex);
if (AlarmShallStrike(now, aIndex))
{
@@ -270,8 +269,7 @@ static void AlarmStop(AlarmIndex aIndex)
void nrf5AlarmInit(void)
{
sTimeOffset.mMs = 0;
sTimeOffset.mUs = 0;
sTimeOffset = 0;
memset(sTimerData, 0, sizeof(sTimerData));
// Setup low frequency clock.
@@ -351,18 +349,15 @@ void nrf5AlarmProcess(otInstance *aInstance)
uint32_t otPlatAlarmGetNow(void)
{
otPlatUsecAlarmTime now = AlarmGetCurrentTime();
return now.mMs;
return (uint32_t)(AlarmGetCurrentTime() / US_PER_MS);
}
void otPlatAlarmStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
{
(void)aInstance;
otPlatUsecAlarmTime T0 = (otPlatUsecAlarmTime) {aT0, 0};
otPlatUsecAlarmTime TargetTime = (otPlatUsecAlarmTime) {aT0 + aDt, 0};
uint32_t targetTime = aT0 + aDt;
AlarmStartAt(&T0, &TargetTime, kMsTimer);
AlarmStartAt(targetTime, kMsTimer);
}
void otPlatAlarmStop(otInstance *aInstance)
@@ -372,23 +367,18 @@ void otPlatAlarmStop(otInstance *aInstance)
AlarmStop(kMsTimer);
}
void otPlatUsecAlarmGetNow(otPlatUsecAlarmTime *aNow)
uint32_t otPlatUsecAlarmGetNow(void)
{
otPlatUsecAlarmTime now = AlarmGetCurrentTime();
memcpy(aNow, &now, sizeof(*aNow));
return (uint32_t)AlarmGetCurrentTime();
}
void otPlatUsecAlarmStartAt(otInstance *aInstance,
const otPlatUsecAlarmTime *aT0,
const otPlatUsecAlarmTime *aDt,
otPlatUsecAlarmHandler aHandler,
void *aContext)
void otPlatUsecAlarmStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt,
otPlatUsecAlarmHandler aHandler, void *aContext)
{
(void)aInstance;
otPlatUsecAlarmTime TargetTime = TimeAdd(*aT0, *aDt);
uint32_t targetTime = aT0 + aDt;
AlarmStartAt(aT0, &TargetTime, kUsTimer);
AlarmStartAt(targetTime, kUsTimer);
sUsecHandler = aHandler;
sUsecContext = aContext;
+1 -1
View File
@@ -29,7 +29,7 @@
/**
* @file
* @brief
* This file includes the platform abstraction for the alarm service.
* This file includes the platform abstraction for the millisecond alarm service.
*/
#ifndef ALARM_H_
+6 -19
View File
@@ -50,16 +50,6 @@ extern "C" {
*
*/
/**
* This structure represents time in microseconds.
*
*/
typedef struct
{
uint32_t mMs; ///< Time in milliseconds.
uint16_t mUs; ///< Time fraction in microseconds.
} otPlatUsecAlarmTime;
/**
* This defines the callback for indicating when the alarm has expired.
*
@@ -69,20 +59,17 @@ typedef struct
typedef void (*otPlatUsecAlarmHandler)(void *aContext);
/**
* Set the alarm to fire at @p aDt milliseconds and microseconds after @p aT0.
* Set the alarm to fire at @p aDt microseconds after @p aT0.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aT0 The reference time.
* @param[in] aDt The time delay in milliseconds and microseconds from @p aT0.
* @param[in] aDt The time delay in microseconds from @p aT0.
* @param[in] aHandler A pointer to a function that is called when the timer expires.
* @param[in] aContext A pointer to arbitrary context information.
*
*/
void otPlatUsecAlarmStartAt(otInstance *aInstance,
const otPlatUsecAlarmTime *aT0,
const otPlatUsecAlarmTime *aDt,
otPlatUsecAlarmHandler aHandler,
void *aContext);
void otPlatUsecAlarmStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt,
otPlatUsecAlarmHandler aHandler, void *aContext);
/**
* Stop the alarm.
@@ -95,10 +82,10 @@ void otPlatUsecAlarmStop(otInstance *aInstance);
/**
* Get the current time.
*
* @param[out] aNow The current time in milliseconds and microseconds.
* @param[out] aNow The current time in microseconds.
*
*/
void otPlatUsecAlarmGetNow(otPlatUsecAlarmTime *aNow);
uint32_t otPlatUsecAlarmGetNow(void);
/**
* @}
+3 -11
View File
@@ -562,22 +562,14 @@ void LinkRaw::StartCsmaBackoff(void)
backoff = (otPlatRandomGet() % (1UL << backoffExponent));
backoff *= (static_cast<uint32_t>(Mac::kUnitBackoffPeriod) * OT_RADIO_SYMBOL_TIME);
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER
otPlatUsecAlarmTime now;
otPlatUsecAlarmTime delay;
otPlatUsecAlarmGetNow(&now);
delay.mMs = backoff / 1000UL;
delay.mUs = backoff - (delay.mMs * 1000UL);
otLogDebgPlat(aInstance, "LinkRaw Starting RetransmitTimeout Timer (%d ms)", backoff);
mTimerReason = kTimerReasonRetransmitTimeout;
otPlatUsecAlarmStartAt(&mInstance, &now, &delay, &HandleTimer, this);
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER
otPlatUsecAlarmStartAt(&mInstance, otPlatUsecAlarmGetNow(), backoff, &HandleTimer, this);
#else // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER
mTimerReason = kTimerReasonRetransmitTimeout;
mTimer.Start(backoff / 1000UL);
#endif // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER
}
#endif // OPENTHREAD_CONFIG_ENABLE_SOFTWARE_RETRANSMIT
+1 -8
View File
@@ -99,14 +99,7 @@ void Mac::StartCsmaBackoff(void)
backoff *= (static_cast<uint32_t>(kUnitBackoffPeriod) * OT_RADIO_SYMBOL_TIME);
#if OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER
otPlatUsecAlarmTime now;
otPlatUsecAlarmTime delay;
otPlatUsecAlarmGetNow(&now);
delay.mMs = backoff / 1000UL;
delay.mUs = backoff - (delay.mMs * 1000UL);
otPlatUsecAlarmStartAt(GetInstance(), &now, &delay, &Mac::HandleBeginTransmit, this);
otPlatUsecAlarmStartAt(GetInstance(), otPlatUsecAlarmGetNow(), backoff, &Mac::HandleBeginTransmit, this);
#else // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER
mBackoffTimer.Start(backoff / 1000UL);
#endif // OPENTHREAD_CONFIG_ENABLE_PLATFORM_USEC_BACKOFF_TIMER