Newer
Older
rtc / rtc.c
/**
 *   @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;
}