dpechman
Joined: 04 Dec 2007 Posts: 43
|
Driver RTC MCP79411 |
Posted: Thu Jul 02, 2015 8:11 am |
|
|
Code: |
////////////////////////////////////////////////////////////////////////////////
/// MCP79411.h
/// Driver for Real Time Clock
///
/// Daniel Pechmann
///
/// Data: 22/05/2012 First Release
///
/// rtc_init() - Enable oscillator without clearing the seconds register -
/// used when PIC loses power and rtc run from 3V BAT
/// - Disable squarewave output
///
/// rtc_set_date_time(day,mth,year,dow,hour,min,sec) Set the date/time
///
/// rtc_get_date(day,mth,year,dow) Get the date
///
/// rtc_get_time(hr,min,sec) Get the time
///
/// rtc_get_mac(BYTE &mc5, ..., BYTE &mc0) Get MAC Address
///
/// rtc_get_powerdown(BYTE &min, ..., BYTE &mth) Get timestamp of powerdown
///
/// rtc_get_powerup(BYTE &min, ..., BYTE &mth) Get timestamp of powerup
///
/// rtc_set_alarm0(BYTE sec, ..., BYTE mth) Adjust Alarm0
///
/// rtc_set_alarm1(BYTE sec, ..., BYTE mth) Adjust Alarm1
///
/// void rtc_write_byte(...) Write byte anywhere in rtc
///
/// void rtc_read_byte(...) Read byte anywhere in rtc
///
////////////////////////////////////////////////////////////////////////////////
#define RTC_SDA PIN_C4
#define RTC_SCL PIN_C3
#define ADDR_EEPROM_WRITE 0xae // DEVICE ADDR for EEPROM (writes)
#define ADDR_EEPROM_READ 0xaf // DEVICE ADDR for EEPROM (reads)
#define ADDR_RTCC_WRITE 0xde // DEVICE ADDR for RTCC MCHP (writes)
#define ADDR_RTCC_READ 0xdf
#define ADDR_UNIQUE_ID 0xf2
#define SRAM_PTR 0x20 // pointer of the SRAM area (RTCC)
#define ADDR_EEPROM_SR 0xff // STATUS REGISTER in the EEPROM
#define ADDR_SEC 0x00 // address of SECONDS register
#define ADDR_MIN 0x01 // address of MINUTES register
#define ADDR_HOUR 0x02 // address of HOURS register
#define ADDR_DAY 0x03 // address of DAY OF WEEK register
#define ADDR_STAT 0x03 // address of STATUS register
#define ADDR_DATE 0x04 // address of DATE register
#define ADDR_MNTH 0x05 // address of MONTH register
#define ADDR_YEAR 0x06 // address of YEAR register
#define ADDR_CTRL 0x07 // address of CONTROL register
#define ADDR_CAL 0x08 // address of CALIB register
#define ADDR_ULID 0x09 // address of UNLOCK ID register
#define ADDR_ALM0SEC 0x0a // address of ALARMO SEC register
#define ADDR_ALM0MIN 0x0b // address of ALARMO MIN register
#define ADDR_ALM0HR 0x0c // address of ALARMO HOUR register
#define ADDR_ALM0CTL 0x0d // address of ALARM0 CONTR register
#define ADDR_ALM0DAT 0x0e // address of ALARMO DATE register
#define ADDR_ALM0MTH 0x0f // address of ALARMO MONTH register
#define ADDR_ALM1SEC 0x11 // address of ALARM1 SEC register
#define ADDR_ALM1MIN 0x12 // address of ALARM1 MIN register
#define ADDR_ALM1HR 0x13 // address of ALARM1 HOUR register
#define ADDR_ALM1CTL 0x14 // address of ALARM1 CONTR register
#define ADDR_ALM1DAT 0x15 // address of ALARM1 DATE register
#define ADDR_ALM1MTH 0x16 // address of ALARM1 MONTH register
#define ADDR_SAVtoBAT_MIN 0x18 // address of T_SAVER MIN(VDD->BAT)
#define ADDR_SAVtoBAT_HR 0x19 // address of T_SAVER HR (VDD->BAT)
#define ADDR_SAVtoBAT_DAT 0x1a // address of T_SAVER DAT(VDD->BAT)
#define ADDR_SAVtoBAT_MTH 0x1b // address of T_SAVER MTH(VDD->BAT)
#define ADDR_SAVtoVDD_MIN 0x1c // address of T_SAVER MIN(BAT->VDD)
#define ADDR_SAVtoVDD_HR 0x1d // address of T_SAVER HR (BAT->VDD)
#define ADDR_SAVtoVDD_DAT 0x1e // address of T_SAVER DAT(BAT->VDD)
#define ADDR_SAVtoVDD_MTH 0x1f // address of T_SAVER MTH(BAT->VDD)
#define START_32KHZ 0x80 // start crystal: ST = b7 (ADDR_SEC)
#define LP 0x20 // mask for the leap year bit(MONTH REG)
#define HOUR_12 0x40 // 12 hours format (ADDR_HOUR)
#define PM 0x20 // post-meridian bit (ADDR_HOUR)
#define OUT_PIN 0x80 // = b7 (ADDR_CTRL)
#define SQWE 0x40 // SQWE = b6 (ADDR_CTRL)
#define ALM_NO 0x00 // no alarm activated (ADDR_CTRL)
#define ALM_0 0x10 // ALARM0 is activated (ADDR_CTRL)
#define ALM_1 0x20 // ALARM1 is activated (ADDR_CTRL)
#define ALM_01 0x30 // both alarms are activated (ADDR_CTRL)
#define MFP_01H 0x00 // MFP = SQVAW(01 HERZ) (ADDR_CTRL)
#define MFP_04K 0x01 // MFP = SQVAW(04 KHZ) (ADDR_CTRL)
#define MFP_08K 0x02 // MFP = SQVAW(08 KHZ) (ADDR_CTRL)
#define MFP_32K 0x03 // MFP = SQVAW(32 KHZ) (ADDR_CTRL)
#define MFP_64H 0x04 // MFP = SQVAW(64 HERZ) (ADDR_CTRL)
#define ALMx_POL 0x80 // polarity of MFP on alarm (ADDR_ALMxCTL)
#define ALMxC_SEC 0x00 // ALARM compare on SEC (ADDR_ALMxCTL)
#define ALMxC_MIN 0x10 // ALARM compare on MIN (ADDR_ALMxCTL)
#define ALMxC_HR 0x20 // ALARM compare on HOUR (ADDR_ALMxCTL)
#define ALMxC_DAY 0x30 // ALARM compare on DAY (ADDR_ALMxCTL)
#define ALMxC_DAT 0x40 // ALARM compare on DATE (ADDR_ALMxCTL)
#define ALMxC_ALL 0x70 // ALARM compare on all param(ADDR_ALMxCTL)
#define ALMx_IF 0x08 // MASK of the ALARM_IF (ADDR_ALMxCTL)
#define OSCON 0x20 // state of the oscillator(running or not)
#define VBATEN 0x08 // enable battery for back-up
#use i2c(master, sda=RTC_SDA, scl=RTC_SCL, FORCE_SW, FAST)
//Prototypes
BYTE bin2bcd(BYTE binary_value);
BYTE bcd2bin(BYTE bcd_value);
// Init Real Time Clock
void rtc_Init(void)
{
BYTE seconds = 0;
i2c_start();
i2c_write(ADDR_RTCC_WRITE); // WR to RTC
i2c_write(ADDR_SEC); // REG 0
i2c_start();
i2c_write(ADDR_RTCC_READ); // RD from RTC
seconds = bcd2bin(i2c_read(0)); // Read current "seconds" in rtc
i2c_stop();
//seconds &= 0x7F;
seconds |= 0x80; //set to 1 bit 7 of seconds(ST) enabling oscillator
delay_us(3);
i2c_start();
i2c_write(ADDR_RTCC_WRITE); // WR to RTC
i2c_write(ADDR_SEC); // REG 0
i2c_write(bin2bcd(seconds) | 0x80); // Start oscillator with current "seconds value
i2c_start();
i2c_write(ADDR_RTCC_WRITE); // WR to RTC
i2c_write(0x07); // Control Register
i2c_write(0x80); // Disable squarewave output pin
i2c_stop();
}
//function to set datetime
void rtc_set_date_time(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min, BYTE sec)
{
i2c_start();
i2c_write(ADDR_RTCC_WRITE); // I2C write address
i2c_write(ADDR_SEC); // Point to start writing at REG 0 - Seconds
i2c_write(bin2bcd(sec) | 0x80 ); // ST ON
i2c_write(bin2bcd(min));
i2c_write(bin2bcd(hr));
i2c_write(bin2bcd(dow) | 0x08 ); // VBATEN ON
i2c_write(bin2bcd(day));
i2c_write(bin2bcd(mth));
i2c_write(bin2bcd(year));
i2c_write(0x80); // REG 7 - Disable squarewave output pin
//i2c_write(0x10); // REG 4 - turn on with 1Hz the square pin
i2c_stop();
}
void rtc_get_date(BYTE &day, BYTE &mth, BYTE &year, BYTE &dow)
{
i2c_start();
i2c_write(ADDR_RTCC_WRITE);
i2c_write(0x03); // Start at REG 3 - Day of week
i2c_start();
i2c_write(ADDR_RTCC_READ);
dow = bcd2bin(i2c_read() & 0x07); // REG 3
day = bcd2bin(i2c_read() & 0x3f); // REG 4
mth = bcd2bin(i2c_read() & 0x1f); // REG 5
year = bcd2bin(i2c_read(0)); // REG 6
i2c_stop();
}
void rtc_get_time(BYTE &hr, BYTE &min, BYTE &sec)
{
i2c_start();
i2c_write(ADDR_RTCC_WRITE);
i2c_write(0x00); // Start at REG 0 - Seconds
i2c_start();
i2c_write(ADDR_RTCC_READ);
sec = bcd2bin(i2c_read() & 0x7f); //0x7f b01111111
min = bcd2bin(i2c_read() & 0x7f); //0x7f
hr = bcd2bin(i2c_read(0) & 0x3f); //0x3f b00111111
i2c_stop();
}
void rtc_get_mac(BYTE &mc5, BYTE &mc4, BYTE &mc3, BYTE &mc2, BYTE &mc1, BYTE &mc0)
{
i2c_start();
i2c_write(ADDR_EEPROM_WRITE); //0x57
i2c_write(ADDR_UNIQUE_ID); // Start point ADDR_UNIQUE_ID
i2c_start();
i2c_write(ADDR_EEPROM_READ);
mc5 = bcd2bin(i2c_read());
mc4 = bcd2bin(i2c_read());
mc3 = bcd2bin(i2c_read());
mc2 = bcd2bin(i2c_read());
mc1 = bcd2bin(i2c_read());
mc0 = bcd2bin(i2c_read(0));
i2c_stop();
}
void rtc_get_powerdown(BYTE &min, BYTE &hr, BYTE &dow, BYTE &date, BYTE &mth)
{
BYTE tmp;
i2c_start();
i2c_write(ADDR_RTCC_WRITE);
i2c_write(ADDR_SAVtoBAT_MIN); // Start point ADDR_SAVtoBAT_MIN
i2c_start();
i2c_write(ADDR_RTCC_READ);
min = bcd2bin(i2c_read());
hr = bcd2bin(i2c_read());
date = bcd2bin(i2c_read()& 0x3F);
tmp = i2c_read(0);
i2c_stop();
mth = bcd2bin(tmp & 0x0F);
dow = bcd2bin(tmp & 0xE0);
}
void rtc_get_powerup(BYTE &min, BYTE &hr, BYTE &dow, BYTE &date, BYTE &mth)
{
BYTE tmp;
i2c_start();
i2c_write(ADDR_RTCC_WRITE);
i2c_write(ADDR_SAVtoVDD_MIN); // Start point ADDR_SAVtoVDD_MIN
i2c_start();
i2c_write(ADDR_RTCC_READ);
min = bcd2bin(i2c_read());
hr = bcd2bin(i2c_read());
date = bcd2bin(i2c_read()& 0x3F);
tmp = i2c_read(0);
i2c_stop();
mth = bcd2bin(tmp & 0x0F);
dow = bcd2bin(tmp & 0xE0);
}
void rtc_set_alarm0(BYTE sec, BYTE min, BYTE hr, BYTE dow, BYTE day, BYTE mth)
{
i2c_start();
i2c_write(ADDR_RTCC_WRITE);
i2c_write(ADDR_ALM0SEC); // Start point ADDR_ALM0SEC
i2c_start();
i2c_write(ADDR_RTCC_WRITE);
i2c_write(bin2bcd(sec));
i2c_write(bin2bcd(min));
i2c_write(bin2bcd(hr));
i2c_write(bin2bcd(dow));
i2c_write(bin2bcd(day));
i2c_write(bin2bcd(mth));
i2c_stop();
}
void rtc_set_alarm1(BYTE sec, BYTE min, BYTE hr, BYTE dow, BYTE day, BYTE mth)
{
i2c_start();
i2c_write(ADDR_RTCC_WRITE);
i2c_write(ADDR_ALM1SEC); // Start point ADDR_ALM1SEC
i2c_start();
i2c_write(ADDR_RTCC_WRITE);
i2c_write(bin2bcd(sec));
i2c_write(bin2bcd(min));
i2c_write(bin2bcd(hr));
i2c_write(bin2bcd(dow));
i2c_write(bin2bcd(day));
i2c_write(bin2bcd(mth));
i2c_stop();
}
void rtc_clear_stamp()
{
BYTE regtmp = 0;
i2c_start();
i2c_write(ADDR_RTCC_WRITE); // WR to RTC
i2c_write(ADDR_DAY); // REG 0
i2c_start();
i2c_write(ADDR_RTCC_READ); // RD from RTC
regtmp = bcd2bin(i2c_read(0)); // le para regtmp o valor do registrador 0x03 no rtc
i2c_stop();
regtmp |= 0x10; //set to 1 4th bit of register 0x03 cleaning timestamps
delay_us(3);
i2c_start();
i2c_write(ADDR_RTCC_WRITE); // WR to RTC
i2c_write(ADDR_DAY); // REG 0
i2c_start();
i2c_write(ADDR_RTCC_WRITE); // WR to RTC
i2c_write(regtmp); // read value + bit 4 set
i2c_stop();
}
BYTE rtc_read_byte(BYTE address)
{
BYTE tmp;
i2c_start();
i2c_write(ADDR_EEPROM_WRITE);
i2c_write(address); // Start point to specific address
i2c_start();
i2c_write(ADDR_EEPROM_READ);
tmp = bcd2bin(i2c_read(0));
i2c_stop();
return tmp;
}
void rtc_write_byte(BYTE address, BYTE value)
{
i2c_start();
i2c_write(ADDR_EEPROM_WRITE);
i2c_write(address); // Start point to specific address
i2c_start();
i2c_write(ADDR_EEPROM_WRITE);
i2c_write(value);
i2c_stop();
}
BYTE bin2bcd(BYTE binary_value)
{
BYTE temp;
BYTE retval;
temp = binary_value;
retval = 0;
if(temp >= 10)
{
temp -= 10;
retval += 0x10;
}
else
{
retval += temp;
break;
}
return(retval);
}
BYTE bcd2bin(BYTE bcd_value)
{
BYTE temp;
temp = bcd_value;
temp >>= 1;
temp &= 0x78;
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
|
|
|