I have a question about the I2C commands used. The datasheet is rather confusing, and the example isn’t very helpful imo. Can someone please explain to me how the I2C commands work? What does “10 minutes” mean in the datasheet?
Have a look at the [sample code n the SparkFun site to see how to communicate with the chip. I don’t have the datasheet in front of me, but I suspect “10 minutes” refers to the 10’s portion of the minutes (i.e. 10, 20, 30, etc.).](http://www.sparkfun.com/datasheets/Components/rtc-demo.zip)
robodude666:
I said I already looked at the example and I didn’t understand it…
Sorry. You said that the datasheet is rather confusing, and the example isn’t very helpful. I took that to mean the information in the datasheet and not SparkFun’s demo code. But now we’re on the same page.
This means that SF is using a software method if I2C rather than hardware I2C?
Yes. Most SPI and I2C examples that I’ve seen tend to use software bit-banging over the hardware alternatives. You gain the ability to assign your own I/O pins but lose the performance of the hardware implementation.
I don’t remember the link, but its not hard to find though if you search for DS1307 RTC. Heres the header file that Paymaan on the forums sent me a while back. It requires a little tabbing, but otherwise works great.
#ifndef _PJI2CRTC_
#define _PJI2CRTC_
/* I2C and RTC functions based on limpol's I2C routines */
/* Copyright (c)2006 Paymaan Jafari Taayemeh */
/* All rights reserved worldwide */
/* Admin [at ] paymaan [DoT ] com */
/* currently tested with DS1307 RTC */
/* define CLOCK (cpu clock) and BITRATE (i2cbus rate, e.g 100000 for 100khz bus) */
/* then allocate unsigned char dataPacket_byte[64]; to store DS1307 registers */
/* and use writertc() to write [16] to [22] to DS1307, or readrtc() to read to [0] to [6] */
//#include "pjdelays.h"
void enablei2c ( void ) {
TRISCbits.TRISC4 = 1; // data
TRISCbits.TRISC3 = 1; // clock
SSPSTAT = 0x0;
SSPADD = ((CLOCK/BITRATE)/4)-1; // = 49 for 100kHz @ 20MHz and 0x7f is the lowest possible.
SSPCON1 = 0x28;
SSPCON2 = 0x0;
}
void disablei2c ( void ) {
SSPCON1bits.SSPEN = 0;
}
void IdleI2C ( void ){
while (( SSPCON2 & 0x1F ) | (SSPSTATbits.R_W)) continue;
}
void StartI2C ( void ) {
SSPCON2bits.SEN = 1;
while (SSPCON2bits.SEN);
}
unsigned char WriteI2C ( unsigned char data_out ) {
SSPBUF = data_out;
if (SSPCON1bits.WCOL) return -1;
while (SSPSTATbits.BF);
return 0;
}
void StopI2C ( void ) {
SSPCON2bits.PEN = 1;
while (SSPCON2bits.PEN);
}
void NotAckI2C ( void ) {
SSPCON2bits.ACKDT = 1;
SSPCON2bits.ACKEN = 1;
}
#define ACKTEST !SSPCON2bits.ACKSTAT
#define control 0xd0
signed char write_rtc ( unsigned char address, unsigned char data ) {
IdleI2C();
StartI2C();
if (PIR2bits.BCLIF) { StopI2C(); return -1; }
if (WriteI2C(control & 0xFE)) { StopI2C(); return -3; }
IdleI2C();
if (ACKTEST) {
if (WriteI2C(address)) { StopI2C(); return -3; }
IdleI2C();
if (ACKTEST) {
if (WriteI2C(data)) { StopI2C(); return -3; }
IdleI2C();
if (ACKTEST) {
StopI2C();
if (PIR2bits.BCLIF) return -1;
return 0;
}
}
}
StopI2C();
return -2;
}
signed char write_rtc_address ( unsigned char address ) {
IdleI2C();
StartI2C();
if (PIR2bits.BCLIF) { StopI2C(); return -1; }
if (WriteI2C(control & 0xFE)) { StopI2C(); return -3; }
IdleI2C();
if (ACKTEST) {
if (WriteI2C(address)) { StopI2C(); return -3; }
IdleI2C();
if (ACKTEST) {
StopI2C();
if (PIR2bits.BCLIF) return -1;
return 0;
}
}
StopI2C();
return -2;
}
signed char _read_rtc ( unsigned char address ) {
if (write_rtc_address(address)) return -4;
IdleI2C();
StartI2C();
if (PIR2bits.BCLIF) { StopI2C(); return -1; }
if (WriteI2C(control | 1)) { StopI2C(); return -3; }
IdleI2C();
if (ACKTEST) {
SSPCON2bits.RCEN = 1;
while (SSPCON2bits.RCEN);
NotAckI2C();
while (SSPCON2bits.ACKEN);
StopI2C();
if (PIR2bits.BCLIF) { return -1; }
return 0;
}
StopI2C();
return -2;
}
unsigned char read_rtc ( unsigned char address ) {
_read_rtc(address);
return SSPBUF;
}
void writertc ( void ) {
enablei2c();
write_rtc(0,dataPacket_byte[16] & 0xfe); // place your data pointers here
write_rtc(1,dataPacket_byte[17]);
write_rtc(2,dataPacket_byte[18]);
write_rtc(3,dataPacket_byte[19]);
write_rtc(4,dataPacket_byte[20]);
write_rtc(5,dataPacket_byte[21]);
write_rtc(6,dataPacket_byte[22]);
write_rtc(7,0);
disablei2c();
}
void readrtc ( void ) {
enablei2c();
dataPacket_byte[0] = read_rtc(0) & 0b01111111; // place your data pointers here
dataPacket_byte[1] = read_rtc(1) & 0b01111111;
dataPacket_byte[2] = read_rtc(2) & 0b00111111;
dataPacket_byte[3] = read_rtc(3) & 0b00000111;
dataPacket_byte[4] = read_rtc(4) & 0b00111111;
dataPacket_byte[5] = read_rtc(5) & 0b00011111;
dataPacket_byte[6] = read_rtc(6);
disablei2c();
}
#endif
I no longer have my working code because I lost the MPLAB project on a hard drive that left me ='[. Its pretty simple to understand though I think. If you are a little confused about it, feel free to ask and I’ll get an example of how its used, or you can search for paymaan on the MicroChip forums and look for his threads
But you basically define CLOCK as your CPU’s clock, and the BITRATE, then enablei2c. Then simply read/write rtc and read/write to dataPacket_byte which needs to be declared.
That code probably would be confusing, except that I’ve already written all the same routines myself (albeit far less elegantly). This is a great sanity check, though. It shows that I’m on the right track. Thanks so much for posting that!