Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

DS1307 Accessing Halted

Status
Not open for further replies.

Suraj143

Active Member
My DS1307 is not giving any results.I use PIC16F886 with MSSP Module.I use 4.7K pullups.

I need to read Minutes & Hours.

Code:
;=============================================================
;Read Time & split into segment digits
;=============================================================
Read_Time	movlw	01h
		movwf	E2_Add_Low		; point to buffer Minutes
		call	I2C_Byte_Read
		andlw	b'01111111'		; ignore 7th bit CH
		call	BCD_To_Bin
		movf	Bin_Number,W
		movwf	Minutes
		;
		incf	E2_Add_Low,F		; point to buffer Hours
		call	I2C_Byte_Read
		andlw	b'00111111'
		call	BCD_To_Bin
		movf	Bin_Number,W
		movwf	Hours
		;
		call	Split_Minutes
		call	Split_Hours
		return

I2C_Byte_Read	call	I2C_Start
		movlw	b'11010000'
		call	I2C_Write
		movf	E2_Add_Low,W
		call	I2C_Write
		call	I2C_Restart
		movlw	b'11010001'		; Slave Address - Read
		call	I2C_Write
		call	I2C_Read
		movf	SSPBUF,W
		call	NACK_Slave
		call	I2C_Stop
		return
 
Looks like you may not be waiting for the I2C bus to be idle each time before sending more commands (impossible to tell without seeing the rest of your code). The DS1307 (and other I2C chips) need time to do their thing. If you just blast away it won't work. Go get and read Microchip's **broken link removed**. It explains it all well, with example code segments.

Here's my working i2c_read() function, with built-in ack send. I also have a i2c_read_nack() function that sends a nack after the last read. Though you use asm, you should hopefully be able to see what I'm doing and in what order. If not, ask questions:
Code:
unsigned char i2c_read(void){
    unsigned char dat;
    busywait();
    sspcon2.RCEN = 1;       //receive enable
    while(sspcon2.RCEN);
    dat = sspbuf;
    sspcon2.ACKDT = 0;      //send ack
    sspcon2.ACKEN = 1;
    while(sspcon2.ACKEN);
    return(dat);
}
Busywait() is taken directly from AN735 (I wrote the same thing in C - they call it "Generic Idle Check"). It may not be necessary in this function, but it's there just in case.

while(sspcon2.RCEN); waits for RCEN to go low, indicating that the receive is complete and the bus is idle.

Similarly, while(sspcon2.ACKEN); waits for ACKEN to go low, indicating that the ACK has been sent and the bus is idle.
 
Last edited:
Hi Futz here is my I2C routines it worked well with 24C eeproms but not with DS1307 :(

Code:
I2C_Start	bcf	PIR1,SSPIF		; Clear Interrupt flag bit
		bsf	STATUS,RP0
		bsf	SSPCON2,SEN		; Start Condition Enable
		bcf	STATUS,RP0
		goto	I2C_Wait_SSPIF
			
I2C_Stop	bcf	PIR1,SSPIF		; Clear Interrupt flag bit
		bsf	STATUS,RP0
		bsf	SSPCON2,PEN		; Stop Condition Enable
		bcf	STATUS,RP0	
		goto	I2C_Wait_SSPIF
			
			
ACK_Slave	bcf	PIR1,SSPIF		; Clear Interrupt flag bit
		bsf	STATUS,RP0
		bcf	SSPCON2,ACKDT		; Master Acknowledge the Slave
		bsf	SSPCON2,ACKSTAT
		bcf	STATUS,RP0
		goto	I2C_Wait_SSPIF

NACK_Slave	bcf	PIR1,SSPIF		; Clear Interrupt flag bit
		bsf	STATUS,RP0
		bsf	SSPCON2,ACKSTAT
		bsf	SSPCON2,ACKDT		; Master Not Acknowledge the Slave
		bcf	STATUS,RP0
		return
			
I2C_Restart	bcf	PIR1,SSPIF		; Clear Interrupt flag bit
		bsf	STATUS,RP0
		bsf	SSPCON2,RSEN		; Enable Repeated Start Condition
		bcf	STATUS,RP0
I2C_Wait_SSPIF	btfss	PIR1,SSPIF
		goto	$-1
		return
 
Last edited:
When you send the slave address the DS1307 should acknowledge, otherwise it is still busy. If it doesn't ACK then you have to send a restart and the address again until it does.

Mike.
 
Hi Mike that means my problem occurs in I2C_Write routine?

Code:
I2C_Write	bsf	STATUS,RP0
		bcf	SSPCON2,RCEN		; Disable Recieve Mode
		bcf	STATUS,RP0	
		bcf	PIR1,SSPIF		; Clear Interrupt flag bit
		movwf	SSPBUF
		call	I2C_Wait_SSPIF
		bsf	STATUS,RP0
		btfsc	SSPCON2,ACKSTAT		; Wait until Slave device
		goto	$-1			; Acknowledge
		bcf	STATUS,RP0
		return
 
Another problem you may have is that the bus can stall especially if you interupt it during a transfer. This often happens during development due to compiling etc. To fix it I do the following before I initialize the bus,

Code:
I2cInit		bsf	STATUS,RP0	;bank 1
		bsf	TRISC,3		;set to input
		bsf	TRISC,4
		bcf	STATUS,RP0	;bank 0
ClockLoop	btfsc	PORTC,4		;if data high 
		goto	BusFixed	;all is well
		bcf	PORTC,3		;else
		bsf	STATUS,RP0	;send a clock puse
		bcf	TRISC,3
		goto	$+1
		bsf	TRISC,3
		bcf	STATUS,RP0
		goto	ClockLoop

BusFixed

The other way to clear it is to power down the circuit.

Edit, just checked the DS1307 datasheet and it doesn't mention any busy times so my first suggestion is probably wrong.

Mike.
 
Last edited:
Hello guys now it worked nicely.The problem was there were no any battery backup provided & never grounded that pin.

I have a question.

Data sheet says the initial power on state all registers is not defined.Therefore it is important to enable the CH bit = 0 during initial configuration.

The problem is when I clear (0) this 7th CH bit when initial power up state the seconds will be reset.So every time after a power back it will change the seconds.This is a big error.
 
Last edited:
The other problem is how to use this buffer registers!!

00h-07h = RTC registers.

But there are 56 some other registers. 08h-3fh how these are mapped! data sheet never explained.
 
The battery will keep the clock running and the CH bit clear. The RAM is mapped after the 8 timekeeping registers.

Edit, if you read the CH bit and only clear it if it is set then that will solve the seconds problem.

Mike.
 
Last edited:
The battery will keep the clock running and the CH bit clear.

Edit, if you read the CH bit and only clear it if it is set then that will solve the seconds problem.

I understood this very well I'll do like you said.That's a good method thanks mike.

The RAM is mapped after the 8 timekeeping registers.

Have a doubt here.That means if I read 08h location that means I'm reading seconds register?
If I read 09h then am I reading Minutes like wise.............?

But it will end 0fh.What data will hold this area? 10h-3fh?
 
See page 8 of the attached document for the memory map.

Mike.
 

Attachments

  • DS1307.pdf
    695.4 KB · Views: 299
If you send 0xd0, 0x08, 0x23, stop then it will write 0x23 to location 8 (first RAM location). To read it send 0xd1, 0x08, stop, 0xd0, readbyte, stop.

Mike.
 
Last edited:
Hi mike thanks for your help.

In my application I always reading I2C, Ex: 10 times per second etc……..so I need a smooth working code.

I have spotted some points please help me to solve this.

* In master receive mode I never use SSPCON2,ACKEN bit.
You can see in my ACK_Slave & NACK_Slave subroutines I have never used that bit, do I need to use that bit?

* In my I2C_Wait_SSPIF subroutine I’m waiting inside an inner loop, this is not a good idea. Because if not any reply from slave side this code will hang inside this loop.

*Also I never check whether the bus is idle or not. Do I need this as well?

Code:
ACK_Slave	bcf	PIR1,SSPIF		; Clear Interrupt flag bit
		bsf	STATUS,RP0
		bcf	SSPCON2,ACKDT		; Master Acknowledge the Slave
		bsf	SSPCON2,ACKSTAT
		bcf	STATUS,RP0
		goto	I2C_Wait_SSPIF

NACK_Slave	bcf	PIR1,SSPIF		; Clear Interrupt flag bit
		bsf	STATUS,RP0
		bsf	SSPCON2,ACKSTAT
		bsf	SSPCON2,ACKDT		; Master Not Acknowledge the Slave
		bcf	STATUS,RP0
		return
I2C_Wait_SSPIF	btfss	PIR1,SSPIF
		goto	$-1
		return
 
Last edited:
Status
Not open for further replies.

Latest threads

Back
Top