View previous topic :: View next topic |
Author |
Message |
Andrew
Joined: 12 Aug 2004 Posts: 7
|
DS1307 to PIC18F452 |
Posted: Thu Aug 12, 2004 2:08 pm |
|
|
Hello
I'm going to be using a real-time clock in a project and the DS1307 RTC looked to be the best one. I can't seem to read from or write to it very reliably though.
My test program is set up to read address 0x00 (the seconds register) from the DS1307 once each second. However, the value is usually read incorrectly or not read at all. For example, I read the values (one per second) 29 30 31 18 FF 00 over a six second period. The 29 30 31 values show that the DS1307 is accurately keeping the time but the 18 FF 00 indicate trouble. Another test program indicated that the DS1307 wasn't always acknowledging the write/read commands.
I've searched this forum (and other places) for example code and stuff but haven't found anything to help.
I'm using 4.7k pull-up resistors on the I2C bus, I have an I2C EEPROM chip (24LC256) on the same bus (the results seem to be the same whether the EEPROM is in its socket or not though), I have a 3.3V regulator attached to the Vbat pin on the DS1307 to simulate a battery, and I'm using a PIC18F452 running at 20MHz as the I2C master.
Here's the test program I'm using:
Code: |
// main.h
#include <18F452.h>
#device adc=8
#use delay(clock=20000000,RESTART_WDT)
#fuses HS, BROWNOUT, BORV20, PUT, STVREN
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,restart_wdt)
#use i2c(Master,Fast,sda=PIN_C4,scl=PIN_C3,restart_wdt,force_hw)
#USE DYNAMIC_MEMORY
|
Code: |
// main.c
#include "main.h"
#ZERO_RAM
unsigned int read_rtc(unsigned int adr);
unsigned int read_eeprom(unsigned int adr);
void main()
{
disable_interrupts(global);
output_float(PIN_C3);
output_float(PIN_C4);
i2c_start();
i2c_write(0xd0);
i2c_write(0x00);
i2c_write(0x00);
i2c_stop();
printf("\fStarting...\r\n");
while(1)
{
printf("%x %x\r\n", read_rtc(0), read_eeprom(0));
delay_ms(1000);
}
}
unsigned int read_rtc(unsigned int adr)
{
unsigned int data;
i2c_start();
i2c_write(0xd0);
i2c_write(adr);
i2c_start();
i2c_write(0xd1);
data = i2c_read(0);
i2c_stop();
return data;
}
unsigned int read_eeprom(unsigned int adr)
{
unsigned int data;
i2c_start();
i2c_write(0xa0);
i2c_write(adr);
i2c_start();
i2c_write(0xa1);
data = i2c_read(0);
i2c_stop();
return data;
}
|
Also, if I use 'Slow' in the '#use i2c' instead of 'Fast', I only read FF. If I remove the 'force_hw', I read mostly jibberish or FF.
Is there something I'm overlooking? Something I'm doing incorrectly? Any suggestions (or solutions) would be greatly appreciated.
Thanks in advance,
Andrew |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Aug 12, 2004 2:23 pm |
|
|
Does the EEPROM always give you the correct value?
You should probably specify the NOLVP flag in the fuses if you are not using the low voltage programming. It is bound to byte you in the butt if you don't. |
|
|
Andrew
Joined: 12 Aug 2004 Posts: 7
|
|
Posted: Thu Aug 12, 2004 2:43 pm |
|
|
I've decided to keep the EEPROM out of its socket for now and focus solely on getting the RTC to interface correctly. The EEPROM did, however, function as expected (with or without the DS1307 on the bus).
I also added the NOLVP flag as you suggested even though I disable low-voltage programming via the PIC programmer (EPIC from microEngineering Labs, Inc.) |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Aug 12, 2004 2:48 pm |
|
|
What voltage are you running the DS1307 at? |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Aug 12, 2004 2:55 pm |
|
|
Quote: | Also, if I use 'Slow' in the '#use i2c' instead of 'Fast', I only read FF |
The ds1307 is a Standard (slow) speed device. It only runs at 100 KHz,
max. You can't use "Fast" speed with it. See page 3 of the data sheet.
http://pdfserv.maxim-ic.com/en/ds/DS1307.pdf |
|
|
Andrew
Joined: 12 Aug 2004 Posts: 7
|
|
Posted: Thu Aug 12, 2004 3:05 pm |
|
|
Mark:
The DS1307 (along with everything else) is being run at 5V.
Following your post, I grounded the Vbat pin just to be sure the DS1307 wasn't switching over to battery power and disallowing access. Unfortunately this didn't affect the problem and the results were still the same (eg. 01 27 01 04 05 06 07 FF)
PCM Programmer:
Quote: | Also, if I use 'Slow' in the '#use i2c' instead of 'Fast', I only read FF. |
I've kept using 'Fast' because it seems to be the only way to get any sort of valid response from the DS1307. I've also tried running the 18F452 at 4MHz to slow the bus speed down and used both 'Fast' and 'Slow', but the results were the same (ie. 'Fast' lead to some valid data, 'Slow' lead to all FF's)
Am I using the 'Slow' option incorrectly? It seems like using 'Slow' should make a positive difference but that's not the case, which only confuses me more.
Last edited by Andrew on Thu Aug 12, 2004 3:10 pm; edited 1 time in total |
|
|
LomasS Guest
|
|
Posted: Thu Aug 12, 2004 3:10 pm |
|
|
I have a DS1307 but I am using 18F252 so similar to your setup, my clock is at 3.6864MHz though.
I tried your code after changing the #include to <18F252.h> and the
#use delay(clock=3686400,RESTART_WDT).
With these changes & no EEPROM, your code works OK with seconds changing by 1 without a hiccough.
Hope this helps.
Steve. |
|
|
Andrew
Joined: 12 Aug 2004 Posts: 7
|
|
Posted: Thu Aug 12, 2004 3:29 pm |
|
|
Alright thinking along the lines of the write command not being acknowledged, I modified the read_rtc() to wait for an ack...
Code: |
unsigned int read_rtc(unsigned int adr)
{
unsigned int data;
short ackbit;
do
{
i2c_start();
ackbit = i2c_write(0xd0);
} while(ackbit);
i2c_write(adr);
i2c_start();
i2c_write(0xd1);
data = i2c_read(0);
i2c_stop();
return data;
}
|
That seems to fix the problem, both at 20MHz and 4MHz. I'd used something similar to that 'wait-for-ack' code before, but that seemed to hang the 18F452 sometimes and using a timeout variable was as non-productive as before.
However, I still use 'Fast' in the #use i2c directive, 'Slow' continues to cause only FF to be read. Am I missing something? Using 'Slow' seems like it should be the correct one (especially at 20MHz), but it's not. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Aug 12, 2004 3:33 pm |
|
|
I see another problem. Your EEPROM code is incorrect.
It looks like you're writing your routines as if an "int" is 16-bits.
The problem with this is, in CCS an int is 8-bits. Also, the
CCS i2c routines expect 8-bit parameters. You're using them
as if they accept 16-bit values.
So your code is not sending the proper number of bytes to
the EEPROM. I don't know what problems this will cause, but
it might screw up the i2c bus. See the CCS driver file, 24256.C,
for sample routines. The file can be found in this folder:
c:\Program Files\Picc\Drivers |
|
|
Andrew
Joined: 12 Aug 2004 Posts: 7
|
|
Posted: Thu Aug 12, 2004 4:40 pm |
|
|
I never really used the EEPROM part of the code to do serious reading/writing, I just wrote a value to address 0x0000, verified that it read back correctly several times, and shifted my focus to the DS1307. I'll be sure to correct the code and addressing and stuff when I actually use it, thanks for bringing that to my attention. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Aug 12, 2004 4:45 pm |
|
|
In a test program, all possible sources of error should be removed.
Routines that are known to be incorrect should not be included in
the program. Also, interface speeds that are known to be out of
spec should not be used. If you want to do such things, you are
on your own. |
|
|
Mark
Joined: 07 Sep 2003 Posts: 2838 Location: Atlanta, GA
|
|
Posted: Thu Aug 12, 2004 6:07 pm |
|
|
You should always do the ack check or else your data might not be valid.
I have a function like this
Code: |
/* *************************************************************************
DESCRIPTION: This function checks to see if an i2c device will ACK
RETURN: TRUE if device ACKed otherwise FALSE
ALGORITHM: none
NOTES: none
*************************************************************************** */
static BOOLEAN I2C_Device_Ready(
UINT8 id) /* Address of I2C device */
{
do
{
/* Important to clear these bits before we attempt to write */
PIR2bits.BCLIF = 0;
SSPCON1bits.WCOL = 0;
I2C_IDLE(); /* ensure module is idle */
I2C_START();
} while (PIR2bits.BCLIF);
I2C_WRITE(id);
if (!SSPCON2bits.ACKSTAT) /* test for ACK condition, if received */
return (TRUE);
return (FALSE);
} |
Note that the I2C_????() functions are my own and not CCS's |
|
|
John Morley
Joined: 09 Aug 2004 Posts: 97
|
|
Posted: Thu Aug 12, 2004 9:00 pm |
|
|
Hi,
Here is a link to a project that uses the DS1307 RTC with CCS C. The URL for the project (a talking clock) is:
http://www.rentron.com/CCS_C/SERLED_C.htm _________________ John Morley |
|
|
Andrew
Joined: 12 Aug 2004 Posts: 7
|
|
Posted: Fri Aug 13, 2004 2:38 pm |
|
|
Alright so I got a simple interface to the DS1307 working. It reads the time from the DS1307 and relays it out the serial port to display the time in hyperterminal.
However, it seems like the initialization code (simply write_rtc(0x00, 0x00); write_rtc(0x07, 0x10); ) hangs and it can require several watchdog-timeout restarts before the initialization goes through and the program gets to the main loop. My guess is it's stalling in the do...while(ackbit) loop.
Code: |
void main()
{
unsigned int v;
unsigned char c;
printf("\r\n\nInit...\r\n");
disable_interrupts(global);
output_float(PIN_C3);
output_float(PIN_C4);
write_rtc(0x00, 0x00);
write_rtc(0x07, 0x10);
printf("Starting...\r\n");
while(1)
{
printf("%x:%02x:%02x\r\n", read_rtc(2), read_rtc(1), read_rtc(0));
delay_ms(1000);
}
} |
Code: |
void write_rtc(unsigned int address, unsigned int data)
{
short ackbit;
do
{
i2c_start();
ackbit = i2c_write(0xd0);
} while(ackbit);
i2c_write(address);
i2c_write(data);
i2c_stop();
return;
} |
Any ideas why sometimes it stalls and others it doesn't? Once it's initialized it runs and runs just fine until I stop it.
Here's one example...
Code: |
Init...
Init...
Starting...
02:53:00
02:53:01
02:53:02
02:53:03
02:53:04
|
Suggestions, comments, everything is appreciated.
Andrew |
|
|
Gabriel Caffese
Joined: 09 Oct 2003 Posts: 39 Location: LA PLATA, ARGENTINA
|
|
Posted: Fri Aug 13, 2004 4:04 pm |
|
|
Andrew,
Canīt you use Timer1, for using the micro as a RTC, too ?
A few months ago, I was involved in a project where costs should be cut off. One thing Iīve done, was replacing DS1307, and doing same thing with the same micro.
Itīs a very, very simple task, wich takes nearly nothing of your micro processing time.
Gabriel.- |
|
|
|