Subversion Repositories svnkaklik

Rev

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;
}