📄 ds12887.c
字号:
/* ds12887Rtc.c - DS12887 Rea-Time Clock chip driver */
/*
DESCRIPTION
This module is to be used by including it from <target>/sysLib.c file,
it adds two functions to handle to RTC chip for the BSP.
This driver is written for the Dallas Semiconductor 12887,
but should work well with any PC motherboard, with a compatible chip.
The date and time format here is compatible with ANSI time,
and one should define INCLUDE_RTC in <target>config.h
to enable these functions.
Although it is much easier to use this chip in binary mode,
this driver uses it in BCD mode, so that the time and date
settings are compatible with the BIOS and MS-DOS.
*/
/* includes */
#include "vxWorks.h"
#include "time.h"
#include "intLib.h"
#include "sp.h"
/* macro to check that <v> is between <l> and <h> inclusive range */
#define CHECK_RANGE(v,l,h) (((v)>=(l))&&((v)<=(h)))
/* Macros to convert 2-digit BCD into binary and vice versa */
#define BIN2BCD(b) (((b)%10) | (((b)/10)<<4))
#define BCD2BIN(b) (((b)&0xf) + ((b)>>4)*10)
/* RTC register access, macros should be defined for a particular BSP */
#if CPU_FAMILY==I80X86
#define RTC_REG_SET(reg,val) \
(sysOutByte(RTC_INDEX,(reg)),sysOutByte(RTC_DATA,(val)))
#define RTC_REG_GET(reg) (sysOutByte(RTC_INDEX,(reg)),sysInByte(RTC_DATA))
#else
#ifndef RTC_JMP
#define RTC_JMP 1
#endif
#ifndef RTC_BASE
#define RTC_BASE 0xFFE00000
#endif
#define RTC_REG(o) ((volatile u_char *)(RTC_BASE + (o)*RTC_JMP))
#define RTC_REG_SET(reg,val) (*RTC_REG(reg) = (val))
#define RTC_REG_GET(reg) (*RTC_REG(reg))
#endif
/******************************************************************************
*
* sysRtcGet - get the current date abd time from a Real Time Clock chip
*
* The values are returned in a ANSI time structure.
* During initialization phase, the POSIX clock of the system is
* set according to the Real Time Clock time and date, thus
* it is recommended to use the POSIX functions and avoid calling
* this function from the application software,
* to acheive similar results but with greater portability.
*
* NOTE: Interrupts are locked during reading of the values from the chip.
*
* RETURNS: OK or ERROR
*
* SEE ALSO
* clockLib(), ansiTime
*
*/
STATUS sysRtcGet
(
struct tm *tm
)
{
FAST int ipl ;
FAST int count = 50;
ipl = intLock();
/* wait until registers update is done, then we got 244 us
* to read the regs without loosing sanity
*/
while((count--) && (RTC_REG_GET(0x0a) & 0x80));
tm->tm_hour = RTC_REG_GET( 0x04); /* get BCD regs as is */
tm->tm_min = RTC_REG_GET( 0x02); /* while ints are off, */
tm->tm_sec = RTC_REG_GET( 0x00); /* and decode later */
tm->tm_mon = RTC_REG_GET( 0x08);
tm->tm_mday = RTC_REG_GET( 0x07);
tm->tm_year = RTC_REG_GET( 0x09);
tm->tm_wday = RTC_REG_GET( 0x06);
intUnlock(ipl);
/* corrections - all registers are BCD, we need them in binary */
tm->tm_hour = BCD2BIN( tm->tm_hour );
tm->tm_min = BCD2BIN( tm->tm_min );
tm->tm_sec = BCD2BIN( tm->tm_sec );
tm->tm_mon = BCD2BIN( tm->tm_mon );
tm->tm_mday = BCD2BIN( tm->tm_mday );
tm->tm_year = BCD2BIN( tm->tm_year );
tm->tm_wday = BCD2BIN( tm->tm_wday );
/* corrections - some fields range is defined differently */
/* tm->tm_mon -- ;*/ /* chip does 1-12, POSIX needs 0-11 */
/* tm->tm_wday -- ;*/ /* chip does 1-7, POSIX needs 0-6 */
/* corrections - handle year after y2k */
if( tm->tm_year < 80 )
tm->tm_year += 100 ;
/* These fields are unknown, filled with 0 */
tm->tm_yday = 0; /* days since January 1 - [0, 365] */
tm->tm_isdst= 0; /* Daylight Saving Time flag */
return OK ;
}
/******************************************************************************
*
* sysRtcSet - Set the time and date into the RTC chip
*
* NOTE
* Setting the time is done with interrupts locked, but it is expected
* to be called rarely.
*
* RETURNS: OK or ERROR if values are out of range.
*/
STATUS sysRtcSet
(
const struct tm *timedate
)
{
struct tm t1 = * timedate ;
FAST struct tm *tm = &t1 ; /* make a local copy of the argument */
FAST int count = 50;
FAST int ipl;
/* Check value ranges */
if( !CHECK_RANGE( tm->tm_sec, 0, 59)) return ERROR ;
if( !CHECK_RANGE( tm->tm_min, 0, 59)) return ERROR ;
if( !CHECK_RANGE( tm->tm_hour, 0, 23)) return ERROR ;
if( !CHECK_RANGE( tm->tm_mday, 1, 31)) return ERROR ;
if( !CHECK_RANGE( tm->tm_mon , 1, 12)) return ERROR ;
if( !CHECK_RANGE( tm->tm_wday , 1, 7)) return ERROR ;
/* correction - for y2k */
if( tm->tm_year > 99 )
tm->tm_year -= 100 ;
if( !CHECK_RANGE( tm->tm_year, 0, 99)) return ERROR ;
/* corrections - convert to BSD and add offset where needed. */
tm->tm_hour = BIN2BCD( tm->tm_hour );
tm->tm_min = BIN2BCD( tm->tm_min );
tm->tm_sec = BIN2BCD( tm->tm_sec );
tm->tm_mon = BIN2BCD( tm->tm_mon );
tm->tm_mday = BIN2BCD( tm->tm_mday );
tm->tm_year = BIN2BCD( tm->tm_year );
tm->tm_wday = BIN2BCD( tm->tm_wday );
ipl = intLock();
/* wait until registers update is done, then we got 244 us
* to read the regs without loosing sanity
*/
while((count--) && (RTC_REG_GET(0x0a) & 0x80));
RTC_REG_SET( 0x04, tm->tm_hour );
RTC_REG_SET( 0x02, tm->tm_min );
RTC_REG_SET( 0x00, tm->tm_sec );
RTC_REG_SET( 0x08, tm->tm_mon );
RTC_REG_SET( 0x07, tm->tm_mday);
RTC_REG_SET( 0x09, tm->tm_year);
RTC_REG_SET( 0x06, tm->tm_wday);
intUnlock(ipl);
return OK ;
}
/******************************************************************************
*
* sysRtcInit - initialize the RTC chip
*
* This function should called from sysHwInit2(). With this particular
* device, there is nothing we need to do here.
*
*/
STATUS sysRtcInit ( void)
{
/* turn the oscilator on, just in case */
RTC_REG_SET( 0x0a, 0x2F ); /* periodic interrupt rate is set to 500ms */
RTC_REG_SET( 0x0b, 0x0A ); /* set 24-hr & BCD modes, periodic interrupt disable */
return OK ;
}
/******************************************************************************
*
* sysRtcShutdown - put the RTC chip in to sleep mode
*
* The sleep mode is designed to save on battery life during inactive
* storage of the equipment. During this time the date & time do not
* progress.
*
*/
void sysRtcShutdown(void)
{
RTC_REG_SET( 0x0a, 0x00 );
}
/******************************************************************************
*
* ds12887int - interrupt level processing
*
* This routine handles interrupts from the RTC
*
* RETURNS: N/A
*/
void ds12887int
(
)
{
UCHAR irq;
UCHAR led;
irq = RTC_REG_GET(0x0c);
if((irq & 0x40) != 0)
{
led = *(UCHAR *)0xFFE60003;
*(UCHAR *)0xFFE60003 = ((~led) & 0xC0) | (led & 0x3F);/* light led */
}
}
/******************************************************************************
*
* sysDS12887lHwInit2 - connect BSP RTC device interrupts
*
* This routine connects the BSP RTC device interrupts. It is called from
* sysHwInit2().
*
* RETURNS: N/A
*
* SEE ALSO: sysHwInit2()
*/
void sysDS12887HwInit2 (void)
{
(void) intConnect (INUM_TO_IVEC (RTC_INT_LVL),
ds12887int, 0);
intEnable (RTC_INT_LVL);
}
/* End Of File */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -