TWI interface problem between atmega8 and ds1307

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have DS1307 for real time/calender (RTC) , and need to communicate with this IC thought atmega8 controller .

I read the section of TWI interface in atmega8 datasheet and understand all the instructions to use I2C protocol .

I found a library for GCC-avr :
http://homepage.hispeed.ch/peter...

It has all the function I need and implement the I2C interface operations .

I tried to edit the twimaster.c ... I just wrote additional functions for debugging use and I wrote the main function :


/*
until this point twimaster.c except the init_fail() and write_fail() functions which just do some light effects depend on statues .
*/

void main(){

DDRD |= 0xFF;
DDRC |=0x0F;
DDRB |=0x7F;

unsigned int addr ;
addr=0+I2C_WRITE;

while(i2c_start(addr)) init_fail() ;// if i2c_start(addr)=1 that means starting is failed .

int m=0x40;// the value of Minuit I want to write to DS1307 
while(i2c_write(m)) write_fail() ;// if i2c_write(m)=1 that means writing is failed .
while(1)
{
	while(i2c_rep_start(addr+I2C_READ)) init_fail();

	unsigned char data = i2c_readNak();

  		if(data==0x40) {// show me somthing on sevent segment
                PORTC=(1<<PINC3)|(1<<PINC2);
		PORTB=(1<<PINB5)|(1<<PINB4)|(1<<PINB3)|(1<<PINB2)|(1<<PINB0);
		PORTD=(1<<PIND6)|(1<<PIND3)|(1<<PIND7);
		}
			else{
                              //failed ? show me another  thing on seven segment
                               PORTC=0xDF;}
	}}


I attached the schematic .

If I have any problem in the schematic you can edit online :
http://upverter.com/yahya%20tawi...

For pull-up resistors I tried to use both 5k2 and 10K .

Any help :) ?

p.s : maybe my code is messy because I still starter in programming micro-controller using raw C , I'm arduino user :)

Attachment(s): 

Last Edited: Sun. Apr 7, 2013 - 02:53 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First off. Never edit libary code like twimaster.c

Your pull-ups of 5k1 should be fine.

You don't appear to use the correct DS1307 Slave address (0xD0)

Simply use the return values from i2c_start() and i2c_write(). You will see your problems immediately !!

Incidentally, I have never seen 20pF called 0.02nF
Perfectly valid. Just unusual.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Firstly, welcome to AVRFreaks.

A few comments/observations.

1. You have not connected the GND pin of the DS1307.

2. The reset pin on the mega8 is floating. Connect a 10K resistor to it and connect the other end of the resistor to the Vcc line.

3. You do not have a backup battery connected to the DS1307. Therefore when you turn off your Vcc supply, the current date and time will be lost ... and next time you will have to set them correctly again.

Cheers,

Ross

Ross McKenzie ValuSoft Melbourne Australia

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thank you very much MR.david.prentice and MR.valusoft for help .

MR.valusoft : I've forget the ground connection of DS1307 just in the schematic not in the breadboard. and I tied a 10K resistor to rst but It didn't work .

MR.david.prentice : that is true address is incorrect .

I tried to edit the code , the address and I put 10K pull resistor for rst pin , It didn't work .

If there aren't more advices I will try again and again , and I hope it works :) .

there is a little question why when I remove the I2C pull-up resistors the all of PORTD goes high although the my code doesn't say that ?!!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Should I mention yet again power supply bypass caps on all chips?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In the DS1307 datasheet say :

Quote:
The slave address byte is the first byte received
after the master generates the START condition. The slave address byte contains the 7-bit DS1307
address, which is 1101000, followed by the direction bit (R/W), which for a write is 0. After receiving and
decoding the slave address byte, the DS1307 outputs an acknowledge on SDA. After the DS1307
acknowledges the slave address + write bit, the master transmits a word address to the DS1307. This
sets the register pointer on the DS1307

which of the following is correct :

unsigned int addr ;
addr=0xD0+I2C_WRITE;

while(i2c_start(addr)) init_fail() ;// if i2c_start(addr)=1 that means starting is failed .

while(i2c_rep_start(0xD0)) init_fail() ; // seconds register

or :

unsigned int addr ;
addr=0xD0+I2C_WRITE;

while(i2c_start(addr)) init_fail() ;// if i2c_start(addr)=1 that means starting is failed .

while(i2c_rep_start(0x00)) init_fail() ; // seconds register

If not of the before is correct , How I implement what is said in the Quoted paragraph .

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
    ret1 = i2c_start(0xD0 + I2C_WRITE);
    if (ret1 != 0) failure....

    i2c_write(0);     //set register pointer to seconds #0

    ret2 = i2c_rep_start(0xD0 + I2C_READ);
    if (ret2 != 0) failure...

    seconds = i2c_read_ACK();
    minutes = i2c_read_ACK();
    hours = i2c_read_NAK();      // use NAK on last byte

    i2c_stop();

Note that if ret1 fails, you might just as well give up. It means the DS1307 is running off the backup battery and the I2C is disabled.

If ret1 succeeds, so will ret2 and any i2c_write() or i2c_read().
OTOH, if you pull chips while the application is running, it is worth testing these values.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thank you very much ME.David .

I edited the main function to the following :

while(1) // I put all of code in while to make sure if it works good 
{
	int ret1,ret2,ret3;
	ret1 = i2c_start(0xD0 + I2C_WRITE);
	if (ret1 != 0) init_fail();

	i2c_write(0x01);     //set register pointer to minuits #0


	int m=0x40;// the value of Minuit I want to write to DS1307
	ret3=i2c_write(m);
	if(ret3 != 0) write_fail() ;// if i2c_write(m)=1 that means writing is failed .

   ret2 = i2c_rep_start(0xD0 + I2C_READ);
       if (ret2 != 0) init_fail();

   int data = i2c_readNak();

   i2c_stop();

        if(data==m) { PORTB=0;_delay_ms(5000);
      }
         else{ PORTB=1;_delay_ms(1000);

   }
}
}

I thought that 3 volt battery doesn't matter(Vbat) , but when I but the battery with the new main , initialization is done but I don't know why data is not equal to m which is 40 ... I noticed that because of light on PORTB0 .

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Have you examined ret1, ret2, ret3, ... ?

You appear to be setting the minutes register to 0x40 ok.
Of course it is possible that the minute has updated to 0x41 but unlikely.

To be safe, write 0 to the seconds register first.

Otherwise, it looks as if you are approaching the problem sensibly. i.e. using return values.

If you don't have an RS232 or LCD to print the values to, you can write 0 to register #0 and then 0x10 to register #7. This will give you a running clock that does a square wave @ 1Hz on the SQWV/OUT pin (#7 on DIP-8 package)

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Exactly . I think I must use a connection with computer to send data value through serial connection (like ft232rl ) . this will make me Sure were the problem is .

or I will use your solution through SQWV/OUT .