Sean wrote:
>Hello everyone,
>
>I've got a bit of a strange problem with the RTC in my setup. I have a
>dedicated lithium battery going to the Vbat pin to power the RTC, and it
>usually works fine, however periodically the clock changes to an invalid
>value and stops running. Usually this value is something like "Year:129
>Month:00 Day:16 Hour:02 Min:09 Sec:08", and unless I reset the RTC to a
>valid value it stops running. This will usually happen after several hours
>of Vcc absent (i.e. device powered off) or after a day or two running
>constantly. Nothing else is disrupted. I have a 3.6V lithium running
>through a diode which drops the voltage at the pin down to 3.165V when Vcc
>present and to 3.232V when Vcc absent (implying that more current is drawn
>when the micro is powered on??)
>
>
>
Diode switching is needed to maintain the Vbat when Vdd (3.3v main) is
absent and to switch over to the battery when Vdd disappears. It sounds
like you have that working? It will take two diodes (1N4148A) and a
resistor (560ohm) to do this properly. Cathodes of both diodes go to
Vbat line, anode of one diode goes to Vdd, anode of other diode is
series with 560ohm to positive terminal of Lithium cell.
This is half the solution, the hardware half. I found that my clock
would also "explode" on occasion and seemingly at random. The solution
I took was a bit more aggressive in the software. Study my clock
routines, especially awakenClock() and sleepClock(). Essentially, when
the clock registers are not needed, they are "disconnected".
=============== begin RTCfuncs.c ===================
/*************************************************************
* RealTime awareness functions. Provide for elapsed time
* intervals as well as reading data & time from RTC.
*
* (C) 2005 - Tom Walsh <tom@...>
* May be used for hobby or commercial purposes as long as
* this notice remains intact.
*************************************************************/
#include <LPC21xx.h>
#include <lpcRTC.h>
#include <time.h>
#include <sys/times.h>
#include <sysdefs.h>
#include <system.h>
#define CCR_CLKEN BIT(0)
#define CCR_CTCRST BIT(1)
#define CCR_CTTEST0 BIT(2)
#define CCR_CTTEST1 BIT(3)
#define CCR_CLKSRC BIT(4)
#define T0_MS_DIV (PCLK / 10000)
long systemTickCounter;
static inline void sleepClock(void)
{// place RTC on 32kHz xtal and disconnect power.
RTCCCR = (CCR_CLKEN | CCR_CLKSRC);
// power off the clock registers.
PCONP &= ~PCRTC;
}
static inline void awakenClock(void)
{// prepare clock for interactive use.
RTCCCR = (CCR_CLKEN | CCR_CLKSRC);
// power up the clock registers.
PCONP |= PCRTC;
}
static void startMsTimer (void)
{// tick timer, 1ms heartbeat for the system.
// connect VIC to Timer0
Timer0VectAddr = (uint32_t)timer0ISR; // address of the ISR
Timer0VectCntl = VIC_ENABLE | VIC_TIMER0;
VICIntSelect &= ~VIC_BIT(VIC_TIMER0); // Timer0 selected as IRQ
VICIntEnable = VIC_BIT(VIC_TIMER0); // Timer0 interrupt enabled
T0TCR = TCR_RESET; // reset & disable timer 0
T0PC = 0;
T0PR = T0_MS_DIV;
T0CCR = 0; // timer mode.
T0EMR = 0; // no external match.
T0MR0 = 9;
T0MCR = 3; // reset and interrupt on terminal count.
T0TCR = TCR_ENABLE;
// init the system ticks.
systemTickCounter = 0;
}
void setElapsed (int HowLong, struct TIMER * timer, timertype_t TimerType)
{ /* set for a TimeElapsed event. */
timer->HowLong = HowLong;
timer->Type = TimerType;
if (timer->Type == TimerInMilli) timer->SetTime = times (0);
else timer->SetTime = time (0);
}
bool timeElapsed (struct TIMER * timer)
{ /* return True if preset interval has expired. */
time_t TestTimerNow, TestTimeStart;
if (timer->Type == TimerInMilli) TestTimerNow = times (0);
else TestTimerNow = time (0);
TestTimeStart = timer->SetTime;
if (((TestTimeStart>TestTimerNow) ? (TestTimerNow +
(~TestTimeStart)) : (TestTimerNow - TestTimeStart)) > timer->HowLong) {
return True;
}
return False;
}
void initRTC(void)
{// start clock so that the sytsem may use it.
#ifdef HAS_CLOCK
bool nonsense = False;
rtcCTIME0_t ctime0;
rtcCTIME1_t ctime1;
rtcCTIME2_t ctime2;
struct tm newTime;
time_t resetTime;
awakenClock();
// see if clock contains nonsense values.
// grab time as consolidated to avoid misses.
ctime0 = RTCCTIME0; ctime1 = RTCCTIME1; ctime2 = RTCCTIME2;
// leisurely tear the packed time apart into individual time.
if ((ctime0.seconds < 0) || (ctime0.seconds > 59)) nonsense = True;
if ((ctime0.minutes < 0) || (ctime0.minutes > 59)) nonsense = True;
if ((ctime0.hours < 0) || (ctime0.hours > 23)) nonsense = True;
if ((ctime1.dayOfMonth < 1) || (ctime1.dayOfMonth > 31)) nonsense =
True;
if ((ctime1.month < 1) || (ctime1.month > 12)) nonsense = True;
if ((ctime1.year < 1980) || (ctime1.year > 2050)) nonsense = True;
if ((ctime0.dayOfWeek < 0) || (ctime0.dayOfWeek > 6)) nonsense = True;
if ((ctime2.dayOfYear < 0) || (ctime2.dayOfYear > 366)) nonsense = True;
sleepClock ();
if (nonsense) {
// set the clock to Jan 1, 2006 00:00:00
resetTime = 1136073600l;
localtime_r (&resetTime, &newTime);
newTime.tm_year += 1900;
newTime.tm_mon += 1;
newTime.tm_yday += 1;
writeRTC (&newTime);
}
#endif
// start realtime heartbeat (1ms period).
startMsTimer();
}
/**************************************************
*
* readRTC & writeRTC are supporting functions
* for the newlib stubs.
*
**************************************************/
void readRTC (struct tm *theTime)
{// read clock registers and return tm structure.
#ifdef HAS_CLOCK
rtcCTIME0_t ctime0;
rtcCTIME1_t ctime1;
rtcCTIME2_t ctime2;
awakenClock();
// grab time as consolidated to avoid misses.
ctime0 = RTCCTIME0; ctime1 = RTCCTIME1; ctime2 = RTCCTIME2;
// leisurely tear the packed time apart into individual time.
theTime->tm_sec = ctime0.seconds;
theTime->tm_min = ctime0.minutes;
theTime->tm_hour = ctime0.hours;
theTime->tm_mday = ctime1.dayOfMonth;
theTime->tm_mon = ctime1.month;
theTime->tm_year = ctime1.year;
theTime->tm_wday = ctime0.dayOfWeek;
theTime->tm_yday = ctime2.dayOfYear;
theTime->tm_isdst = False;
sleepClock ();
#endif
}
void writeRTC (struct tm *newTime)
{// set clock to new values.
#ifdef HAS_CLOCK
awakenClock();
// grab time as consolidated to avoid misses.
RTCTCR->seconds = newTime->tm_sec;
RTCTCR->minutes = newTime->tm_min;
RTCTCR->hours = newTime->tm_hour;
RTCTCR->dayOfMonth = newTime->tm_mday;
RTCTCR->month = newTime->tm_mon;
RTCTCR->year = newTime->tm_year;
RTCTCR->dayOfWeek = newTime->tm_wday;
RTCTCR->dayOfYear = newTime->tm_yday;
sleepClock ();
#endif
}
================== snip ========================
The above functions are designed to work with the newlib gettimeofday(),
settimeofday(), localtime(), etc..
My clock has been running for several months without failure. It has
lost about 5 minutes, so I need to tweak the crystal capacitance...
What also may be of note is how I setup my power control during system
initialization:
PCONP = ((PCTIM0 | PCTIM1 | PCUART0 | PCUART1 | PCRTC |
PCSPI1 | PCAD0) & ~PCONP_MASK);
Hope this helps,
TomW
--
Tom Walsh - WN3L - Embedded Systems Consultant
http://openhardware.net, http://cyberiansoftware.com
"Windows? No thanks, I have work to do..."
----------------------------------------------------Message
Re: [lpc2000] RTC problem in LPC2148
2006-01-31 by Tom Walsh
Attachments
- No local attachments were found for this message.