Blame | Last modification | View Log | Download
/*--------------------------------------------------------------------------*/
/* RTC controls */
#include <avr/io.h>
#include <string.h>
#include "rtc.h"
#define SCL_LOW() DDRE |= 0x04 /* SCL = LOW */
#define SCL_HIGH() DDRE &= 0xFB /* SCL = High-Z */
#define SCL_VAL ((PINE & 0x04) ? 1 : 0) /* SCL input level */
#define SDA_LOW() DDRE |= 0x08 /* SDA = LOW */
#define SDA_HIGH() DDRE &= 0xF7 /* SDA = High-Z */
#define SDA_VAL ((PINE & 0x08) ? 1 : 0) /* SDA input level */
static
void iic_delay (void)
{
int n;
BYTE d;
for (n = 4; n; n--) d = PINE;
}
/* Generate start condition on the IIC bus */
static
void iic_start (void)
{
SDA_HIGH();
iic_delay();
SCL_HIGH();
iic_delay();
SDA_LOW();
iic_delay();
SCL_LOW();
iic_delay();
}
/* Generate stop condition on the IIC bus */
static
void iic_stop (void)
{
SDA_LOW();
iic_delay();
SCL_HIGH();
iic_delay();
SDA_HIGH();
iic_delay();
}
/* Send a byte to the IIC bus */
static
BOOL iic_send (BYTE dat)
{
BYTE b = 0x80;
BOOL ack;
do {
if (dat & b) { /* SDA = Z/L */
SDA_HIGH();
} else {
SDA_LOW();
}
iic_delay();
SCL_HIGH();
iic_delay();
SCL_LOW();
iic_delay();
} while (b >>= 1);
SDA_HIGH();
iic_delay();
SCL_HIGH();
ack = SDA_VAL ? FALSE : TRUE; /* Sample ACK */
iic_delay();
SCL_LOW();
iic_delay();
return ack;
}
/* Receive a byte from the IIC bus */
static
BYTE iic_rcvr (BOOL ack)
{
UINT d = 1;
do {
d <<= 1;
SCL_HIGH();
if (SDA_VAL) d++;
iic_delay();
SCL_LOW();
iic_delay();
} while (d < 0x100);
if (ack) { /* SDA = ACK */
SDA_LOW();
} else {
SDA_HIGH();
}
iic_delay();
SCL_HIGH();
iic_delay();
SCL_LOW();
SDA_HIGH();
iic_delay();
return (BYTE)d;
}
BOOL rtc_read (
UINT adr, /* Read start address */
UINT cnt, /* Read byte count */
void* buff /* Read data buffer */
)
{
BYTE *rbuff = buff;
int n;
if (!cnt) return FALSE;
n = 10;
do { /* Select DS1338 (0xD0) */
iic_start();
} while (!iic_send(0xD0) && --n);
if (!n) return FALSE;
if (iic_send((BYTE)adr)) { /* Set start address */
iic_start(); /* Reselect DS1338 in read mode (0xD1) */
if (iic_send(0xD1)) {
do { /* Receive data */
cnt--;
*rbuff++ = iic_rcvr(cnt ? TRUE : FALSE);
} while (cnt);
}
}
iic_stop(); /* Deselect device */
return cnt ? FALSE : TRUE;
}
BOOL rtc_write (
UINT adr, /* Write start address */
UINT cnt, /* Write byte count */
const void* buff /* Data to be written */
)
{
const BYTE *wbuff = buff;
int n;
if (!cnt) return FALSE;
n = 10;
do { /* Select DS1338 (0xD0) */
iic_start();
} while (!iic_send(0xD0) && --n);
if (!n) return FALSE;
if (iic_send((BYTE)adr)) { /* Set start address */
do { /* Send data */
if (!iic_send(*wbuff++)) break;
} while (--cnt);
}
iic_stop(); /* Deselect device */
return cnt ? FALSE : TRUE;
}
BOOL rtc_gettime (RTC *rtc)
{
BYTE buf[8];
if (!rtc_read(0, 7, buf)) return FALSE;
rtc->sec = (buf[0] & 0x0F) + ((buf[0] >> 4) & 7) * 10;
rtc->min = (buf[1] & 0x0F) + (buf[1] >> 4) * 10;
rtc->hour = (buf[2] & 0x0F) + ((buf[2] >> 4) & 3) * 10;
rtc->mday = (buf[4] & 0x0F) + ((buf[4] >> 4) & 3) * 10;
rtc->month = (buf[5] & 0x0F) + ((buf[5] >> 4) & 1) * 10;
rtc->year = 2000 + (buf[6] & 0x0F) + (buf[6] >> 4) * 10;
return TRUE;
}
BOOL rtc_settime (const RTC *rtc)
{
BYTE buf[8];
buf[0] = rtc->sec / 10 * 16 + rtc->sec % 10;
buf[1] = rtc->min / 10 * 16 + rtc->min % 10;
buf[2] = rtc->hour / 10 * 16 + rtc->hour % 10;
buf[3] = 0;
buf[4] = rtc->mday / 10 * 16 + rtc->mday % 10;
buf[5] = rtc->month / 10 * 16 + rtc->month % 10;
buf[6] = (rtc->year - 2000) / 10 * 16 + (rtc->year - 2000) % 10;
rtc_write(0, 7, buf);
return TRUE;
}
BOOL rtc_init (void)
{
BYTE buf[8]; /* RTC R/W buffer */
UINT n;
/* Read RTC registers */
if (!rtc_read(0, 8, buf)) return FALSE; /* IIC error */
if (buf[7] & 0x20) { /* When RTC data has been broken, set default time */
/* Reset time to Jan 1, '08 */
memset(buf, 0, 8);
buf[4] = 1; buf[5] = 1; buf[6] = 8;
rtc_write(0, 8, buf);
/* Clear data memory */
memset(buf, 0, 8);
for (n = 8; n < 64; n += 8)
rtc_write(n, 8, buf);
return FALSE;
}
return TRUE;
}