/**
* @file rtc.c
*
* @date 05.07.2012
* @author Pascal Gollor
* web http://www.pgollor.de
*
* @copyright Dieses Werk ist unter einer Creative Commons Lizenz vom Typ
* Namensnennung - Nicht-kommerziell - Weitergabe unter gleichen Bedingungen 3.0 Deutschland zugänglich.
* Um eine Kopie dieser Lizenz einzusehen, konsultieren Sie
* http://creativecommons.org/licenses/by-nc-sa/3.0/de/ oder wenden Sie sich
* brieflich an Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
*
* -- englisch version --
* @n This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Germany License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
*
*/
#include "rtc.h"
#include "i2cmaster.h"
/**
* @brief system time
*/
time rtc_time;
/**
* @brief system date
*/
date rtc_date;
/**
* @brief init flag
*/
uint8_t init_rtc = 0;
/**
* decimal to binary
* @param val : decimal
* @return binary
*/
uint8_t DecToBcd(uint8_t val)
{
return (val/10*16) + (val%10);
}
/**
* binary to decimal
* @param val : binary
* @return decimal
*/
uint8_t BcdToDec(uint8_t val)
{
return (val/16*10) + (val%16);
}
/**
* @brief enable RTC device
* @param e: enable
*
* e = 1: enable
* e = 0: disable
*/
void rtc_enable(uint8_t e)
{
uint8_t second = rtc_read_ram(0x00) & 0b01111111;
second = BcdToDec(second);
if (e == 1)
{
second = DecToBcd(second) & 0b01111111;
rtc_write_ram(0x00, second);
}
else if (e == 0)
{
second = DecToBcd(second) | 0b10000000;
rtc_write_ram(0x00, second);
}
}
/**
* @brief write to RTC RAM
* @param addr : address
* @param val : value to write
*/
void rtc_write_ram(uint8_t addr, uint8_t val)
{
if (init_rtc == 0)
return;
i2c_start_wait(I2C_RTC+I2C_WRITE);
i2c_write(addr);
i2c_write(val);
i2c_stop();
}
/**
* @brief read from RTC RAM
* @param addr : address
* @return value from address
*/
uint8_t rtc_read_ram(uint8_t addr)
{
char val = 0x00;
if (init_rtc == 0)
return 0;
i2c_start_wait(I2C_RTC+I2C_WRITE);
i2c_write(addr);
i2c_rep_start(I2C_RTC+I2C_READ);
val = i2c_readNak();
i2c_stop();
return val;
}
/**
* @brief set time and date for RTC
* @param year
* @param month
* @param day
* @param hour
* @param minute
* @param second
*/
void rtc_setup(uint8_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t minute, uint8_t second)
{
second = DecToBcd(second) | 0b10000000;
i2c_start_wait(I2C_RTC+I2C_WRITE);
i2c_write(0x00);
i2c_write(second);
i2c_write(DecToBcd(minute));
i2c_write(DecToBcd(hour));
i2c_write(DecToBcd(1));
i2c_write(DecToBcd(day));
i2c_write(DecToBcd(month));
i2c_write(DecToBcd(year));
i2c_write(0b00010000); // clock out = 1Hz
i2c_stop();
rtc_enable(1);
rtc_read();
}
/**
* @brief set date to RTC
* @param datum: date
*/
void rtc_set_date(date* datum)
{
// stop rtc
rtc_enable(0);
i2c_start_wait(I2C_RTC+I2C_WRITE);
i2c_write(0x04);
i2c_write(DecToBcd(datum->day));
i2c_write(DecToBcd(datum->month));
i2c_write(DecToBcd(datum->year));
i2c_write(0b00010000);
i2c_stop();
// start rtc
rtc_enable(1);
rtc_read();
}
/**
* @brief set time to RTC
* @param zeit: time
*/
void rtc_set_time(time* zeit)
{
uint8_t second = DecToBcd(zeit->second) | 0b10000000;
i2c_start_wait(I2C_RTC+I2C_WRITE);
i2c_write(0x00);
i2c_write(second);
i2c_write(DecToBcd(zeit->minute));
i2c_write(DecToBcd(zeit->hour));
i2c_stop();
// start rtc
rtc_enable(1);
rtc_read();
}
/**
* initialize the RTC device on startup
* @retval 0: accessible
* @retval 1: failed to access device
*/
uint8_t rtc_init(void)
{
init_rtc = 0;
rtc_time.hour = 0;
rtc_time.minute = 0;
rtc_time.second = 0;
rtc_date.day = 0;
rtc_date.month = 0;
rtc_date.weekday = 0;
rtc_date.year = 0;
#ifdef DEBUG
uart_puts_P("init rtc.. ");
#endif
for (int i = 0; i < 100; i++)
{
if (i2c_start(I2C_RTC+I2C_READ) != 0)
{
i2c_stop();
}
else
{
init_rtc = 1;
break;
}
}
if (init_rtc == 0)
{
#ifdef DEBUG
uart_puts_P("fail" CR);
#endif
return 0;
}
i2c_stop();
rtc_write_ram(0x07, 0b00010000);
rtc_enable(1);
rtc_read();
init_rtc = 1;
#ifdef DEBUG
uart_puts_P("okay" CR);
#endif
return 1;
}
/**
* @brief read date and time from RTC Device
*
* save date and time in global vars
*/
void rtc_read(void)
{
if (init_rtc == 0)
return;
i2c_start_wait(I2C_RTC+I2C_WRITE);
i2c_write(0x00);
i2c_rep_start(I2C_RTC+I2C_READ);
rtc_time.second = i2c_readAck() & 0b01111111;
rtc_time.second = BcdToDec(rtc_time.second);
rtc_time.minute = BcdToDec(i2c_readAck());
rtc_time.hour = i2c_readAck() & 0b00111111;
rtc_time.hour = BcdToDec(rtc_time.hour);
rtc_date.weekday = BcdToDec(i2c_readAck());
rtc_date.day = BcdToDec(i2c_readAck());
rtc_date.month = BcdToDec(i2c_readAck());
rtc_date.year = BcdToDec(i2c_readNak());
i2c_stop();
}
/**
* @brief add one second
*/
void rtc_inc(void)
{
rtc_time.second++;
if (rtc_time.second >= 60)
{
rtc_time.second = 0;
rtc_time.minute++;
if (rtc_time.minute >= 60)
{
rtc_time.minute = 0;
rtc_time.hour++;
if (rtc_time.hour >= 24)
{
rtc_time.hour = 0;
rtc_date.day++;
// wenn keine rtc verfuegbar werden Monate und Jahre nicht hochgezaehlt
}
}
}
}
/**
* @brief get second from global var
* @return second
*/
uint8_t rtc_getSecond(void)
{
return rtc_time.second;
}
/**
* @brief get minute from global var
* @return minute
*/
uint8_t rtc_getMinute(void)
{
return rtc_time.minute;
}
/**
* @brief get hour from global var
* @return hour
*/
uint8_t rtc_getHour(void)
{
return rtc_time.hour;
}
/**
* @brief get day from global var
* @return day
*/
uint8_t rtc_getDay(void)
{
return rtc_date.day;
}
/**
* @brief get month from global var
* @return month
*/
uint8_t rtc_getMonth(void)
{
return rtc_date.month;
}
/**
* @brief get year from global var
* @return year
*/
uint8_t rtc_getYear(void)
{
return rtc_date.year;
}
/**
* @brief get copy of global time struct
* @return time
*/
time rtc_getTime(void)
{
return rtc_time;
}
/**
* @brief get global time struct pointer
* @return time
*/
time* rtc_getTimeP(void)
{
return &rtc_time;
}
/**
* @brief get copy of global date struct
* @return date
*/
date rtc_getDate(void)
{
return rtc_date;
}
/**
* @brief get global date struct pointer
* @return date
*/
date* rtc_getDateP(void)
{
return &rtc_date;
}