Andrew Boyson / clock

Dependents:   oldheating gps motorhome heating

tick.c

Committer:
andrewboyson
Date:
2018-01-22
Revision:
24:6c9833e2a049
Parent:
23:07b19cd5f6d0
Child:
25:81014a201736

File content as of revision 24:6c9833e2a049:

#include <stdint.h>
#include <stdbool.h>

#include "peripherals.h"
#include "rtc.h"
#include "time.h"
#include "tick.h"
#include "timer.h"
#include "led.h"
#include "log.h"

#define ONE_BILLION 1000000000

static volatile int64_t nsTickCount;
static volatile int64_t nsSlewCount;
static bool nsCountIsSet = false;
bool  TickIsSet() { return nsCountIsSet; }

static volatile int32_t slew = 0; //ns     - up to +/- 2.147s of slew
int32_t TickGetSlew() { return slew; }
void    TickSetSlew(int32_t value) { slew = value; }

static volatile int32_t ppb  = 0;
int32_t TickGetPpb () { return ppb;  }
void    TickSetPpb (int32_t value) { ppb  = value; LPC_RTC->GPREG0 = ppb; }
void    TickAddPpb (int32_t value) { ppb += value; LPC_RTC->GPREG0 = ppb; }

bool TickTicked = false;

/*
+---------+---------------+
| Seconds |   Base count  |
+---------+---------------+
|    0    |             0 |
|    1    |    96,000,000 |
|   ...   |       ...     |
|   44    | 4,224,000,000 |
|   44.74 |          2^32 |
|   45    |    25,032,704 |
|   ...   |       ...     |
+---------+---------------+
*/
static uint32_t secondsBaseCount = 0;

int64_t TickTime = 0; //30th bit is one second

void TickSet(int64_t extClock)
{
    uint32_t       tc = TimerNowCount();
    uint32_t  seconds =       tc / TICK_COUNT_PER_SECOND; //0 to 44
    uint32_t     base =  seconds * TICK_COUNT_PER_SECOND; //0 to 2^32
    uint32_t fraction =       tc % TICK_COUNT_PER_SECOND; //0 to 96,000,000
    uint32_t fractionNs = fraction / 96 * 1000;           //0 to 1,000,000,000 which fits into 32 bits
     int64_t       ns = extClock - fractionNs;
     
    __disable_irq();
             nsTickCount = ns;
             nsSlewCount = 0;
        secondsBaseCount = base;
    __enable_irq();
    
    nsCountIsSet = true;
}
void TickMain()
{
    uint32_t sinceSecondsBaseCount = TimerSinceCount(secondsBaseCount);
    
    //Update the times whenever there has been a system second
    if (sinceSecondsBaseCount > TICK_COUNT_PER_SECOND)
    { 
        __disable_irq();
        secondsBaseCount += TICK_COUNT_PER_SECOND;
             nsTickCount += ONE_BILLION + ppb;
             nsSlewCount += slew;
                    slew  = 0;
        __enable_irq();
        sinceSecondsBaseCount -= TICK_COUNT_PER_SECOND;
    }
    
    //Update TickTime
    int64_t   fraction = sinceSecondsBaseCount;
              fraction <<= 32;
              fraction /= TICK_COUNT_PER_SECOND;
    
    int64_t nsBase     = nsTickCount + nsSlewCount;
    int64_t nsPerTick  = ONE_BILLION + ppb + slew;
    int64_t nsFraction = (nsPerTick * fraction) >> 32;
    TickTime = nsBase + nsFraction;
    
    //Update the ticked flag
    static bool lastTick = false;
    bool thisTick = TickTime & (1ULL << 30);
    TickTicked = thisTick && !lastTick;
    lastTick = TickTicked;

}
static volatile  int64_t nsTickSnapshot;
static volatile  int64_t nsSlewSnapshot;
static volatile uint32_t  timerSnapshot;

void TickSaveSnapshot()
{
     timerSnapshot = TimerSinceCount(secondsBaseCount);
    nsTickSnapshot = nsTickCount;
    nsSlewSnapshot = nsSlewCount;
}
static void makeTimesFromCounts(uint32_t timerCount, int64_t tickNs, int64_t slewNs, int64_t* pNsInt, int64_t* pNsAbs)
{
    int64_t   fraction = timerCount;
              fraction <<= 32;
              fraction /= TICK_COUNT_PER_SECOND;

    int64_t nsFraction;
    
    int64_t nsBase     = tickNs;
    int64_t nsPerTick  = ONE_BILLION + ppb;
    nsFraction = (nsPerTick * fraction) >> 32;
    *pNsInt = nsBase + nsFraction;

    nsBase    += slewNs;
    nsPerTick += slew;
    nsFraction = (nsPerTick * fraction) >> 32;
    *pNsAbs = nsBase + nsFraction;
}
void TickGetTimesFromSnapshot(int64_t* pNsInt, int64_t* pNsAbs)
{
    makeTimesFromCounts(timerSnapshot, nsTickSnapshot, nsSlewSnapshot, pNsInt, pNsAbs);
}
void TickGetTimes(int64_t* pNsInt, int64_t* pNsAbs)
{   
    makeTimesFromCounts(TimerSinceCount(secondsBaseCount), nsTickCount, nsSlewCount, pNsInt, pNsAbs);
}
void TickInit(void)
{
    nsTickCount = 0;
    nsSlewCount = 0;
    
    ppb  = LPC_RTC->GPREG0; //This is saved each time Tickppb is updated
    slew = 0;
    nsCountIsSet = false;
}