jecottrell
Joined: 16 Jan 2005 Posts: 559 Location: Tucson, AZ
|
DS1337 RTC Driver |
Posted: Mon Oct 02, 2006 8:57 am |
|
|
Here is a driver for the Maxim DS1337 I2C RTC. This is PCM Programmer's PCF8583 driver code from post:
http://www.ccsinfo.com/forum/viewtopic.php?t=27988
That has been modified for the DS1337. The basic functionality has been tested but I can't guarantee that it's 100% error free. I will edit the post with any bug corrections.
The DS1337 is good solution for a simple and small RTC that has alarms, although it may be hard to find.
Version1 10/02/06
Code: |
// DS1337.H
/* ---------------------------------------------
Use the following lines or declare in application.
#ifndef DS1337_SDA
#define DS1337_SDA PIN_C4
#define DS1337_SCL PIN_C3
#endif
#use i2c(master, sda=DS1337_SDA, scl=DS1337_SCL)
*/
// i2c addresses
#define DS1337_I2C_WRITE_ADDR 0xD0
#define DS1337_I2C_READ_ADDR 0xD1
// DS1337 register addresses
#define DS1337_SECONDS_REG 0x00
#define DS1337_MINUTES_REG 0x01
#define DS1337_HOURS_REG 0x02
#define DS1337_DAY_OF_WEEK_REG 0x03
#define DS1337_DATE_REG 0x04
#define DS1337_MONTH_REG 0x05
#define DS1337_YEAR_REG 0x06
//DS1337 Unique Registers
#define DS1337_ALM1_SECONDS_REG 0x07
#define DS1337_ALM1_MINUTES_REG 0x08
#define DS1337_ALM1_HOURS_REG 0x09
#define DS1337_ALM1_DAYDATE_REG 0x0A
#define DS1337_ALM2_MINUTES_REG 0x0B
#define DS1337_ALM2_HOURS_REG 0x0C
#define DS1337_ALM2_DAYDATE_REG 0x0D
#define DS1337_CONTROL_REG 0x0E
#define DS1337_STATUS_REG 0x0F
//Enable Oscillator, Disable SQWV, Disable Ints
#define DS1337_CTRL_REG_INIT_VAL 0x04
//Clear OSF (Oscillator Stop Flag), A2F (Alarm 2 Flag), and A1F (Alarm 1 Flag)
#define DS1337_CLEAR_STATUS_VAL 0x00
char const weekday_names[7][4] = { {"Sun"},
{"Mon"},
{"Tue"},
{"Wed"},
{"Thu"},
{"Fri"},
{"Sat"} };
// This structure defines the user's date and time data.
// The values are stored as unsigned integers. The user
// should declare a structure of this type in the application
// program. Then the address of the structure should be
// passed to the DS1337 read/write functions in this
// driver, whenever you want to talk to the chip.
typedef struct {
int8 seconds; // 0 to 59
int8 minutes; // 0 to 59
int8 hours; // 0 to 23 (24-hour time)
int8 day; // 0 = Sunday, 1 = Monday, etc.
int8 date; // 1 to 31
int8 month; // 1 to 12
int8 year; // 00 to 99
} date_time_t;
//----------------------------------------------
void DS1337_write_byte(int8 address, int8 data) {
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(DS1337_I2C_WRITE_ADDR);
i2c_write(address);
i2c_write(data);
i2c_stop();
enable_interrupts(GLOBAL);
}
//----------------------------------------------
int8 DS1337_read_byte(int8 address) {
int8 retval;
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(DS1337_I2C_WRITE_ADDR);
i2c_write(address);
i2c_start();
i2c_write(DS1337_I2C_READ_ADDR);
retval = i2c_read(0);
i2c_stop();
enable_interrupts(GLOBAL);
return(retval);
}
//----------------------------------------------
// This function converts an 8 bit binary value
// to an 8 bit BCD value.
// The input range must be from 0 to 99.
int8 bin2bcd(int8 value) {
char retval;
retval = 0;
while(1)
{
// Get the tens digit by doing multiple subtraction
// of 10 from the binary value.
if(value >= 10)
{
value -= 10;
retval += 0x10;
}
else // Get the ones digit by adding the remainder.
{
retval += value;
break;
}
}
return(retval);
}
//----------------------------------------------
// This function converts an 8 bit BCD value to
// an 8 bit binary value.
// The input range must be from 00 to 99.
char bcd2bin(char bcd_value) {
char temp;
temp = bcd_value;
// Shifting the upper digit right by 1 is
// the same as multiplying it by 8.
temp >>= 1;
// Isolate the bits for the upper digit.
temp &= 0x78;
// Now return: (Tens * 8) + (Tens * 2) + Ones
return(temp + (temp >> 2) + (bcd_value & 0x0f));
}
//----------------------------------------------
void DS1337_set_datetime(date_time_t *dt) {
int8 bcd_sec;
int8 bcd_min;
int8 bcd_hrs;
int8 bcd_day;
int8 bcd_date;
int8 bcd_mon;
int8 bcd_year;
// Convert the input date/time into BCD values
// that are formatted for the DS1337 registers.
bcd_sec = bin2bcd(dt->seconds);
bcd_min = bin2bcd(dt->minutes);
bcd_hrs = bin2bcd(dt->hours); //default to 24 hour mode
bcd_day = bin2bcd(dt->day);
bcd_date = bin2bcd(dt->date);
bcd_mon = bin2bcd(dt->month); //ignore century bit
bcd_year = bin2bcd(dt->year);
// Write to the date and time registers. Disable interrupts
// so they can't disrupt the i2c operations.
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(DS1337_I2C_WRITE_ADDR);
i2c_write(DS1337_SECONDS_REG); // Start at seconds register
i2c_write(bcd_sec);
i2c_write(bcd_min);
i2c_write(bcd_hrs);
i2c_write(bcd_day);
i2c_write(bcd_date);
i2c_write(bcd_mon);
i2c_write(bcd_year);
i2c_stop();
enable_interrupts(GLOBAL);
}
//----------------------------------------------
// Read the Date and Time from the hardware registers
// in the DS1337.
void DS1337_read_datetime(date_time_t *dt) {
int8 bcd_sec;
int8 bcd_min;
int8 bcd_hrs;
int8 bcd_day;
int8 bcd_date;
int8 bcd_mon;
int8 bcd_year;
// Disable interrupts so the i2c process is not disrupted.
disable_interrupts(GLOBAL);
// Read the date/time registers from the DS1337.
i2c_start();
i2c_write(DS1337_I2C_WRITE_ADDR);
i2c_write(DS1337_SECONDS_REG); // Start at seconds register
i2c_start();
i2c_write(DS1337_I2C_READ_ADDR);
bcd_sec = i2c_read();
bcd_min = i2c_read();
bcd_hrs = i2c_read();
bcd_day = i2c_read();
bcd_date = i2c_read();
bcd_mon = i2c_read();
bcd_year = i2c_read(0);
i2c_stop();
enable_interrupts(GLOBAL);
// Convert the date/time values from BCD to
// unsigned 8-bit integers. Unpack bits in
// DS1337 registers where required.
dt->seconds = bcd2bin(bcd_sec & 0x7F);
dt->minutes = bcd2bin(bcd_min & 0x7F);
dt->hours = bcd2bin(bcd_hrs & 0x3F);
dt->day = bcd2bin(bcd_day & 0x07);
dt->date = bcd2bin(bcd_date & 0x3F);
dt->month = bcd2bin(bcd_mon & 0x1F);
dt->year = bcd2bin(bcd_year);
}
//----------------------------------------------
//If there has been an oscillator failure since last
//init, then init DS1337. A default time and date is set as well.
void DS1337_init(void) {
int8 temp = 0;
//Read the status register to see if the oscillator has failed.
temp = DS1337_read_byte(DS1337_STATUS_REG);
//Unpack OSF bit
temp = temp >> 7;
//If oscillator has failed then init DS1337
if(temp) {
disable_interrupts(GLOBAL);
i2c_start();
i2c_write(DS1337_I2C_WRITE_ADDR);
i2c_write(DS1337_SECONDS_REG);
i2c_write(0x00); //seconds
i2c_write(0x00); //minutes
i2c_write(0x40); //hours & 12/24 hour mode
i2c_write(0x00); //day
i2c_write(0x01); //date
i2c_write(0x01); //month
i2c_write(0x06); //year
i2c_write(0x00); //alm1 seconds
i2c_write(0x00); //alm1 minutes
i2c_write(0x00); //alm1 hours
i2c_write(0x00); //alm1 day/date
i2c_write(0x00); //alm2 minutes
i2c_write(0x00); //alm2 hours
i2c_write(0x00); //alm2 day/date
i2c_write(DS1337_CTRL_REG_INIT_VAL); //Turn off the squarewave output pin.
i2c_write(DS1337_CLEAR_STATUS_VAL); //Clear the status registers
i2c_stop();
enable_interrupts(GLOBAL);
}
}
|
|
|