Hi, I've been encountering a couple problems with my Dallas DS1307 real time clock. I'm wondering if anyone out there has encountered these problems = or knows ways to fix them. I've implemented using interrupts on a PIC16F877 using the MSSP module. I've taken the code off of Microchip's AN735 and modified it for my = needs. Problems. 1. It doesn't store the DS1307 registers (secs, mins, hours, etc) into = the right registers on the PIC. For example, it seems to put the DS1307 = secs into the PIC's secs and mins, and then stores the DS307 mins into the = PIC's hours and days, etc. (This is my major concern) 2. When using a work around for problem 1...the DS1307 appears to need = a delay of ~2-10secs before it starts incrementing the time. (This only appeared recently which doesn't make me worry but leaves me feeling unsettled. ) WorkArounds.. 1. The first workaround I came up with was instead of relying on the = MSSP interrupts I used a timer1 and waited 0xFFFF * Tosc between each stage = of ServiceI2C. This worked fine but didn't seem very appropriate 2. The second workaround which I'm using right now is waiting 0x0C00 between each subsequent call to stage 7. (reading the DS1307 registers) Thanks in advance.. Adam. - The Student The Code... 1. ServiceI2c 2. Variable Declaration 3. interrupt handler 4. I2cInit ;************************************************************************= *************** ; ServiceI2c ;************************************************************************= **************** ServiceI2c movlw high I2CJump ; fetch upper byte of jump table address movwf PCLATH ; load into upper PC latch movlw CmdSizeMask banksel i2cState ; select GPR bank andwf i2cState,w ; retrieve current I2C state addlw low (I2CJump + 1) ; calc state machine jump addr into W btfsc STATUS,C ; skip if carry occured incf PCLATH,f ; otherwise add carry I2CJump movwf PCL ; index into state machine jump table ; jump to processing for = each state =3D i2cState value for each state goto WrtStart ; write start sequence =3D 0 goto SendWrtAddr ; write address, R/W=3D1 =3D 1 goto WrtAckTest ; test ack,write data =3D 2 goto WrtStop ; do stop if done =3D 3 goto ReadStart ; write start sequence =3D 4 goto SendReadAddr ; write address, R/W=3D0 =3D 5 goto ReadAckTest ; test acknowledge after address =3D 6 goto ReadData ; read more data =3D 7 goto ReadStop ; generate stop sequence =3D 8 I2CJumpEnd Fill (return), (I2CJump-I2CJumpEnd) + CmdSizeMask ;---------------------------------------------------------------------- ; ********************* Write data to Slave ********************* ;---------------------------------------------------------------------- ; Generate I2C bus start condition [ I2C STATE -> 0 ] WrtStart banksel i2cState incf i2cState,f ; update I2C state = variable banksel SSPCON2 ; select SFR bank bsf SSPCON2,SEN ; initiate I2C bus start condition return ; ; Generate I2C address write (R/W=3D0) [ I2C STATE -> 1 ] SendWrtAddr banksel ClockAddress ; select GPR bank movlw 0x01 ; pre-set datacount to 1 btfsc ClockFlags, WriteEn ; check if WriteBitEnabled movlw 0x09 ; yes, so set datacount = to 9 movwf WClockDataCount ; set datacount movlw WClockStart ; movwf WClockPointer ; Reset Write Pointers incf i2cState,f ; update I2C state = variable bcf STATUS,C ; ensure carry bit is clear rlf ClockAddress,w ; compose 7-bit address movwf SSPBUF ; initiate I2C bus write = condition return=20 ; Test acknowledge after address and data write [ I2C STATE -> 2 ] WrtAckTest banksel SSPCON2 ; select SFR bank btfss SSPCON2,ACKSTAT ; test for acknowledge from slave goto WrtData ; go to write data = module ; banksel eflag_event ; select GPR bank ; bsf eflag_event,ack_error ; set acknowledge = error clrf i2cState ; reset I2C state = variable banksel SSPCON2 ; select SFR bank bsf SSPCON2,PEN ; initiate I2C bus stop = condition return=20 ; Generate I2C write data condition WrtData banksel WClockDataCount movf WClockDataCount,w ; move DataCount to W = register sublw 0x09 ; check if = DataCount =3D 9 btfsc STATUS, Z=20 bsf ClockFlags, WriteProg ; DataCount =3D 9, so set = bit (Write in Progress) movf WClockPointer, w ; retrieve ptr address movwf FSR ; update FSR movf INDF,w ; retrieve byte = into w decfsz WClockDataCount,f ; test if all done with writes goto send_byte ; not end of string incf i2cState,f ; Done with = writes, so update I2C state variable btfss ClockFlags, WriteProg ; check if write was in progress goto send_byte bcf ClockFlags, WriteEn ; Done with write.. no need = for flags bcf ClockFlags, WriteProg movlw 0x08 ; need to reset the = DS1307 internal pointer to 0x00 movwf i2cState ; so set i2cState =3D 8, = therefore stops and then restarts. send_ byte banksel SSPBUF ; select SFR bank movwf SSPBUF ; initiate I2C bus write = condition incf WClockPointer,f ; increment pointer return ; ; Generate I2C bus stop condition [ I2C STATE -> 3 ] WrtStop banksel SSPCON2 ; select SFR bank btfss SSPCON2,ACKSTAT ; test for acknowledge from slave goto no_error ; bypass setting error = flag ; banksel eflag_event ; select GPR bank ; bsf eflag_event,ack_error ; set acknowledge error clrf i2cState ; reset I2C state = variable goto stop no_error banksel i2cState ; select GPR bank incf i2cState,f ; update I2C state = variable for read stop banksel SSPCON2 ; select SFR bank bsf SSPCON2,PEN ; initiate I2C bus stop = condition return=20 ;---------------------------------------------------------------------- ; ********************* Read data from Slave ********************* ;---------------------------------------------------------------------- ; Generate I2C start condition [ I2C STATE -> 4 ] ReadStart banksel i2cState incf i2cState,f ; update I2C state = variable banksel SSPCON2 ; select SFR bank bsf SSPCON2,SEN ; initiate I2C bus start condition return ; Generate I2C address write (R/W=3D1) [ I2C STATE -> 5 ] SendReadAddr banksel RClockDataCount ; select GPR bank movlw 0x08 ; movwf RClockDataCount ; set RClockDataCount =3D 8 movlw RClockSecs ; reinitialize RClock Pointer movwf RClockPointer ; to RClockSecs incf i2cState,f ; update I2C state variable bsf STATUS,C ; ensure cary bit is clear rlf ClockAddress,w ; compose 7 bit address movwf SSPBUF ; initiate I2C bus write condition return ; Test acknowledge after address write [ I2C STATE -> 6 ] ReadAckTest banksel SSPCON2 ; select SFR bank btfss SSPCON2,ACKSTAT ; test for not acknowledge from slave goto StartReadData ; good ack, go issue bus read ; banksel eflag_event ; ack error, so select GPR = bank ; bsf eflag_event,ack_error ; set ack error flag clrf i2cState ; reset I2C state = variable banksel SSPCON2 ; select SFR bank bsf SSPCON2,PEN ; initiate I2C bus stop condition return StartReadData bsf SSPCON2,RCEN ; generate receive condition banksel i2cState ; select GPR bank incf i2cState,f ; update I2C state variable return ; Read slave I2C [ I2C STATE -> 7 ] ; ; This is state that causes major problems.... seems to go too fast ; have tried checking BF flag in SSPSTAT but seems to hang on the last = read.. ??? ReadData banksel RClockPointer movf RClockPointer, w ; retrieve ptr address movwf FSR ; update FSR movf SSPBUF,w ; save off byte into W decfsz RClockDataCount,f ; test if all done with reads goto SendReadAck ; not end of string so send ACK ; Send Not Acknowledge SendReadNack movwf INDF ; save off null character incf i2cState,f ; update I2C state = variable banksel SSPCON2 ; select SFR bank bsf SSPCON2,ACKDT ; acknowledge bit state to send (not = ack) bsf SSPCON2,ACKEN ; initiate acknowledge sequence return ; Send Acknowledge SendReadAck movwf INDF ; no, save off byte incf RClockPointer,f ; update receive pointer banksel SSPCON2 ; select SFR bank bcf SSPCON2,ACKDT ; acknowledge bit state to send bsf SSPCON2,ACKEN ; initiate acknowledge sequence btfsc SSPCON2,ACKEN ; ack cycle complete? goto $-1 ; no, so loop again bsf SSPCON2,RCEN ; generate receive condition return ; ; Generate I2C stop condition [ I2C STATE -> 8 ] ReadStop banksel SSPCON2 ; select SFR bank bcf PIE1,SSPIE ; disable SSP = interrupt bsf SSPCON2,PEN ; initiate I2C bus = stop condition banksel i2cState ; select GPR = bank clrf i2cState ; reset = I2C state variable bsf StatusFlags, RWComplete ; set read/write done flag return ;************************************************************************= ******* ; Variable Declaration ;******************************************************************** ; Clock Info ; ------------ClockFlags SetHour12_24 equ 7 Hour12_24 equ 6 Am_Pm equ 5 cf4 equ 4 cf3 equ 3 cf2 equ 2 WriteProg equ 1 ; 1 =3D Write WClock in progress = 0 =3D nothing interesting WriteEn equ 0 ; 1 =3D Write WClock Data struc = to RTC 0 =3D only write 0x00 address cblock 0x20 ClockAddress ; b'1101000' WClockWrite ; 0/1 -- 1 =3D update data in RTC, = 0 =3D don't WClockDataCount ; 1 - 9 WClockPointer =20 WClockStart ; start address =3D 0x00 WClockSecs ; 00 - 59 WClockMins ; 00 - 59 WClockHours ; bit 6 =3D 12/24, 1 - 12, 00 - 23 WClockDay ; 1 - 7 WClockDate ; 1 - 31 WClockMonth ; 01 - 12 WClockYear ; 00 - 99 WClockControl ; Control RClockDataCount RClockPointer ; 1 - 7=20 RClockSecs ; 00 - 59 RClockMins ; 00 - 59 RClockHours ; bit 6 =3D 12/24, 1 - 12, 00 - 23 RClockDay ; 1 - 7 RClockDate ; 1 - 31 RClockMonth ; 01 - 12 RClockYear ; 00 - 99 RClockControl ; Control i2cState endc ;************************************************************* ; interrupt handler ;*********************************************************** . . . . TestI2cEvent banksel PIE1 =20 btfss PIE1, SSPIE ; test the i2c interrupt goto TestTimer1Overflow ; no, so skip banksel PIR1 ;=20 btfss PIR1, SSPIF ; test the i2c flag goto TestTimer1Overflow ; no, so skip =20 bcf PIR1, SSPIF ; clear flag movf i2cState,w ; Check to see if in = state 7 then add an additional delay sublw 0x07 ; ontop of the = Hardware interrupt. btfss STATUS, Z goto DoI2cEvent =20 bcf PIR1, TMR1IF ; ensure flag is reset bcf T1CON,TMR1ON ; turn off Timer1 module movlw 0x00 movwf TMR1L movlw 0xC0 movwf TMR1H bsf T1CON, TMR1ON =20 bsf STATUS, RP0 ; bank 1 bsf PIE1, TMR1IE ; disable timer1 = interrupt bcf PIE1, SSPIE ; enable SSP hardware = interrupts goto ExitIsr DoI2cEvent call ServiceI2c ; not in state 7 TestTimer1Overflow banksel PIE1 ; select SFR bank btfss PIE1, TMR1IE ; test if interrup is = enabled goto TestADConversion ; no, so skip bcf STATUS, RP0 ; select SFR bank btfss PIR1, TMR1IF ; test the Timer Overflow = Flag goto TestADConversion ; no, so skip banksel PIR1 ; bank 0 bcf PIR1, TMR1IF ; ensure flag is reset bcf PIR1, SSPIF bcf T1CON,TMR1ON ; turn off Timer1 module bsf STATUS, RP0 ; bank 1 bcf PIE1, TMR1IE ; disable timer1 = interrupt bsf PIE1, SSPIE ; enable SSP hardware = interrupts call ServiceI2c ; call proper = subroutine ;********************************************************* ; I2C init routine ;********************************************************* I2cInit =20 movlw b'00111000' ; configure W register with I2C = Master mode banksel SSPCON ; select proper SFR movwf SSPCON ; Load into appropriate register bcf PIR1, SSPIF ; clear SSP flag =20 movlw 0x09 ; configure W register for a bit = rate 100Khz banksel SSPADD ; need to select proper SFR movwf SSPADD ; baudrate =3D 100 Khz @ 4 Mhz movlw 0x80 ; configure W register for slew = rate disabled (100Khz) movwf SSPSTAT ; no need to select SFR already done = above [banksel SSPADD] ; bsf PIE1, SSPIE ; turn on SSP interrupts - no need = to do it here... its done when first called via Timer1 ; This is initalization for the RTC internal registers ; This should only be done once... in reality ; Because the backup battery should keep the power. banksel WClockSecs movlw 0x00 movwf WClockSecs movlw 0x26 movwf WClockMins movlw 0x71 movwf WClockHours movlw 0x03 movwf WClockDay movlw 0x29 movwf WClockDate movlw 0x01 movwf WClockMonth movlw 0x02 movwf WClockYear movlw 0x00 movwf WClockControl =20 bsf ClockFlags, WriteEn ; allow writing to the = RTC =20 return -- http://www.piclist.com hint: The PICList is archived three different ways. See http://www.piclist.com/#archives for details.