I2C / TWI Newbie Question - DS1307

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

Hello All,

I have started learning i2c/twi protocol and picked up a DS1307 RTC to experiment.

I am not confident that what I am doing is correct, I mainly looked at tutorials/code from internet + atmrga8 datasheet.

What I am doing is to initialize twi on atmega8 + write control register of ds1307 to enable 1Hz clock @ out pin. i then have connected an led on out pin pf ds1307 to see it flashing @ 1hz.

my code is:

void TWIInit(void)
{
	//SET SCL = 100KHZ
	//SET PRESCALER = 16
	TWSR = ((1<<TWPS1) | (0<<TWPS0));
	//WRITE 2 TO TWBR
	TWBR = 0x02;
	//ENABLE TWI
	TWCR = (1<<TWEN);
}

void TWIStart(void)
{
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
}

void TWIStop(void)
{
	TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}

void TWIWrite(uint8_t data)
{
	TWDR = data;
	TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
}

uint8_t TWIReadACK(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);
    while ((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}

uint8_t TWIReadNACK(void)
{
    TWCR = (1<<TWINT)|(1<<TWEN);
    while ((TWCR & (1<<TWINT)) == 0);
    return TWDR;
}

uint8_t TWIGetStatus(void)
{
    uint8_t status;
    //GET UPPER 5 BITS FOR THE STATUS
    status = TWSR & 0xF8;
    return status;
}

uint8_t set1307OutSecondClock(void)
{
	TWIStart();
	if(TWIGetStatus() != 0x08){return TWI_ERROR;}
	//SELECT DS1307 DEVICE + WRITE OPERATION
	TWIWrite((DS1307_DEV_ID<<1) | 0);
	if(TWIGetStatus() != 0x18){return TWI_ERROR;}
	//SELECT DS1307 CONTROL REGISTER TO WRITE
	TWIWrite(0x07);
	if(TWIGetStatus() != 0x28){return TWI_ERROR;}
	//SET 1 SEC CLOCK IN 1307 CONTROL REGISTER
	TWIWrite(0x10);
	if(TWIGetStatus() != 0x28){return TWI_ERROR;}
	
	//SELECT SECONDS REGISTER
	TWIWrite(0x00);
	if(TWIGetStatus() != 0x28){return TWI_ERROR;}
	//WRITE SECONDS VALUE = 0, CH = 0 = ENABLE
	TWIWrite(0x00);
	if(TWIGetStatus() != 0x28){return TWI_ERROR;}
	TWIStop();

	return TWI_SUCCESS;
}

I then invoke the above code from main using

//ENABLE TWI
	TWIInit();
	//SET DS1307 OUT 1 SECOND CLOCK
	if(set1307OutSecondClock() == TWI_SUCCESS){PORTC |= _BV(TEST_LED_PIN);}

The result is that the "test LED" lights up but the led connected to the out pin of ds1307 does not.

I have several questions

1. is the code correct ?

2. when i do a multiple byte transfer (for example writing data to multiple slave registers) do i need to send i2c stop and start again after each write ?

3. in ds1307 "Max Active Supply Current = 1.5ma". Is that the maximum current the device can sink/source?

thank you for the help !

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

Be aware the SQW/OUT pin is open collector - not a traditional "output" pin.

You need Vcc --> LED --> LED resistor --> SQW/OUT

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

MartinM57 wrote:
Be aware the SQW/OUT pin is open collector - not a traditional "output" pin.

You need Vcc --> LED --> LED resistor --> SQW/OUT

Hi Martin,

Where did find that info from ? Since the datasheet i have does not mention it

ankit

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

Nevermidn ..just checked again .. it is clearly mentioned in the datasheet !

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

After rewiring the led, it now stays constantly lit ..so my i2c initialization is not working properly

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

I typed ds1307 into the field the search button gave me, and got 426 threads with that part number in it. I betcha you can find something that makes sense in there, and something that doesnt. Ignore that one.

Imagecraft compiler user

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

First off, it is always easier using respected libraries.

Then you may write some 'helper functions' e.g. write or read a specific register. (or block of registers)

Design these helpers with your convenience in mind.

Now all you need to do is put it all together. e.g.

writeDS1307reg_val(0, 0);          // clear CH
writeDS1307reg_val(7, 0b00010000); // set SQW @ 1Hz 

Note that you need your LED to be wired 'active-low'

After you have got your LED flashing, you probably want to set/display the time. So you need to convert between BCD and binary.

When you come down to think about it, any DS1307 program is going to be pretty simple. But your first design choices are down to choosing the 'convenient' functions.

Don't be proud. Look at everyone else's solutions. Some are elegant. Some are a nightmare. Pick and choose what appeals to you.

David.

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

I did not read the datasheet but usually it is only possible to send



but not possible to send like you are sending


But you have the datasheet, read how your chip works.

Edit: Oh you did ask if this was it.

1) Yes there is a problem, because
2) Yes you need to enclose a register write with start and stop sequence (as you can only write many contiguous registers by sending address of first register to write and then multiple bytes). See the suggestion to build a subroutine to write one register and use it to write all registers in the order you like.
3) No that is the supply current the chip uses by itself. The pins are all either inputs or open collector outputs, no pin can source any current, and the only specification there is that if you sink 5mA the voltage is guaranteed to be below 0.4V, it does not say what is the maximum it can sink. In other words, keep sinking below 5mA per pin, at least standard I2C bus requires to be compatible with weaker 3mA sinking. I bet 4k7 pull-up resistors are enough.