static unsigned int const halNbDaysSince[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, };
static bool halDateLeap(uint32_t y) //return true if y is leap year
{
if (y%400==0) return true;
if (y%100==0) return false;
return ((y&3)==0);
}
static int32_t halDateDayIndexFromDateinternal(uint32_t d, uint32_t m, uint32_t y, bool leap)
{
y=y-1582;
uint32_t r= y*365;
r+=(y+2)/4; // every 4th year is leap
r-=(y+82)/100; // but every 100 is not
r+=(y+382)/400; // but every 400 is!
r+= halNbDaysSince[m-1]; // add months
if (leap && (m<=2)) r--; // adjust for leaps
r+= d-1; // add current day, 0 based, not 1...
if (r<273+14) return -1; // if before 15 october 1582, not a good date
return r;
}
static bool halDateFromDayIndex2(uint32_t a, uint32_t *Y, uint32_t *M, uint32_t *D)
{
uint32_t y, m;
if (a<273+14) return false; // begining of time
if (a>3074610) return false; // end of time 31 dec 9999
y= 1582;
if (a>=365) { y++; a-= 365; }
if (a>=365) { y++; a-= 365; } // up to 84, leap
if (a>=1461) { y+= 4; a-=1461; }
if (a>=1461) { y+= 4; a-=1461; }
if (a>=1461) { y+= 4; a-=1461; }
if (a>=1461) { y+= 4; a-=1461; } // up to 1600, leap...
while (a>=146097) { y+= 400; a-=146097; } // number of days in 400 years, leap years included
if (a>=36525) { y+= 100; a-=36525; } // number of days in 100 years with first year leap...
if (a>=36524) { y+= 100; a-=36524; } // number of days in 100 years
if (a>=36524) { y+= 100; a-=36524; } // number of days in 100 years
while (a>=(1461-(halDateLeap(y)?0:1))) { a-=(1461-(halDateLeap(y)?0:1)); y+= 4; } // number of days in 4 years.. handle case where first year is not leap!
while (a>=(365+(halDateLeap(y)?1:0))) { a-= (365+(halDateLeap(y)?1:0)); y++; }
m=11;
while ((uint32_t)a<(halNbDaysSince[m]+((m>=2)&&(halDateLeap(y)?1:0)))) m--;
a= a - halNbDaysSince[m] - ((m>=2)&&(halDateLeap(y)?1:0));
a++; // days are 1 based, not 0...
m++; // same for months
if (Y!=NULL) *Y= y; if (M!=NULL) *M= m; if (D!=NULL) *D= a;
return true;
}
static uint32_t volatile * const SNVS= (uint32_t volatile *)0x400D4000;
static uint32_t volatile * const HPCOMR= SNVS+(0x4/4);
static uint32_t volatile * const HPCR= SNVS+(0x8/4);
static uint32_t volatile * const HPSRTCMR= SNVS+(0x24/4);
static uint32_t volatile * const HPSRTCLR= SNVS+(0x28/4);
static uint64_t RTC_GetNow()
{
// get timer. since it is spread on 2 registers. one 32 bit one and one 15 bit ones, need to do 2 reads and make sure that they match
uint64_t t1= (((uint64_t)*HPSRTCMR)<<32) + *HPSRTCLR; // Get "now"
while (true) { uint64_t t2= (((uint64_t)*HPSRTCMR)<<32) + *HPSRTCLR; if (t1==t2) return t1; t1= t2; }
}
void getDateTime(uint32_t *year, uint32_t *month, uint32_t *day, uint32_t *hour, uint32_t *min, uint32_t *sec, uint32_t *ms)
{
uint64_t t1= RTC_GetNow();
// 15 bit per seconds... use lower 15 bits for ms if needed
if (ms!=NULL) *ms= (((uint32_t)t1 & 0x7fff) * 1000) >> 15; // get the number of ms if needed
uint32_t tquot= (uint32_t)(t1>>15)/60; if (sec!=NULL) *sec= (uint32_t)(t1>>15)-tquot*60; // div mod nb seconds by 60 to separate seconds from the rest
uint32_t tquot2= tquot/60; if (min!=NULL) *min= tquot-tquot2*60; // div mod rest by 60 to get minutes and the rest
tquot= tquot2/24; if (hour!=NULL) *hour= tquot2-tquot*24; // div mod rest by 24 to get hours and days since jan 1 2000
// 152671 days from jan 1 1582 to jan 1 2000 (uncorrected for calendar change), which is what is used by DateFromDayIndex2 in napier
halDateFromDayIndex2(152671+tquot, year, month, day);
}
void setDateTime(int32_t year, int32_t month, int32_t day, int32_t hour, int32_t min, int32_t sec)
{
uint32_t y2, m2, d2, h2, M2, s2;
getDateTime(&y2, &m2, &d2, &h2, &M2, &s2, NULL);
if (year==-1) year= y2; if (month==-1) month= m2; if (day==-1) day= d2; if (hour==-1) hour= h2; if (min==-1) min= M2; if (sec==-1) sec= s2;
uint64_t res= (halDateDayIndexFromDateinternal(day, month, year, halDateLeap(year))-152671)*24*60*60;
res+= 60*60*hour + 60*min + sec;
res<<=15;
*HPCR&= ~1; while ((*HPCR&1)!=0); // stop RTC
*HPSRTCLR= (uint32_t)res; *HPSRTCMR= (uint32_t)(res>>32); // program registers
*HPCR|= 1; while ((*HPCR&1)==0); // re-enable RTC
}
void RTC_boot()
{
CCM->CCGR5 |= CCM_CCGR5_CG14(3); //SNVS_HP_CLK_ENABLE
CCM->CCGR5 |= CCM_CCGR5_CG15(3); //SNVS_LP_CLK_ENABLE
*HPCOMR = (1U<<31); // enable all can read registers
// SNVS->HPCR= SNVS_HPCR_BTN_CONFIG(3) | SNVS_HPCR_BTN_MASK_MASK; // ON button active on falling edge and ON button irq enabled
// while ((SNVS->HPCR&SNVS_HPCR_BTN_MASK_MASK)==0); // wait until validated
//SNVS->LPCR= (2<<20) | (3<<16) | (1<<5) | 1; // Set ON_TIME delay, BTN debounce, dumb_pmic, clock enabled
*HPCR|= 1;
while ((*HPCR&1)==0); // make sure clock is on!
}