Bit banging i2c on 08M

matherp

Senior Member
I want to use a 08M to do some very simple i2C communications. I found the attached code from Hippy which appears to do the job but can't get it to work. I'm trying to use it to read and write the memory on a DS1307 ($08-$37) so the only changes I've made are to set the correct slave address and limit the read/write address range. The DS1307 is mounted on a AXE091. I've proved the chip works fine using hi2c routines from a 28x2 on the same board. SCL is connected to pin 4 and SDA pin 1 as per the symbols in the routine and of course the axe091 has the pullups built in.

The problem is that the I2cStrobeScl routine never returns from the loop in which it waits for SCL to go high.

Any help would be gratefully received (particulalry Hippy!)

Thanks

Peter

Code:
#picaxe 08m
; *****************************************************************************
; *                                                                           *
; *     I2C Master Test Program for the PICAXE-08M              MAST08-1.BAS  *
; *                                            ^^^                            *
; *****************************************************************************
; *                                                                           *
; *     This is an version of MAST18-1.BAS specifically designed to run on    *
; *     the PICAXE-08M using its bi-directional port abilities.               *
; *                                                                           *
; *     The program will write to a series of adderesses and then read the    *
; *     values back.ad the address back ( the value should be what was sent   *
; *                                                                           *
; *     The I2C code has been altered to only send a byte address, and the    *
; *     device address of the PICAXE-18X I2C Slave is $B0.                    *
; *                                                                           *
; *****************************************************************************

;                              --.---.-- +V
;                               .|. .|.
;                               | | | | 2 x 4K7
;        PICAXE-08M             |_| |_|             PICAXE-18X
;        I2C MASTER              |   |              I2C SLAVE
;       .----------.             |   |             . - - - - -.
;       |       X1 |-------------^---|-------------: O1       :
;       |          |                 |             :          :
;       |       X4 |-----------------^-------------: O4       :
;       `----------'                               `- - - - - '

; *****************************************************************************
; *                                                                           *
; *     Define the I2C device being used                                      *
; *                                                                           *
; *****************************************************************************

        Symbol  I2C_ADDRESS     = %11010000     ; $D0 for DS1307

; *****************************************************************************
; *                                                                           *
; *     Variables                                                             *
; *                                                                           *
; *****************************************************************************

        Symbol  tstAdr          = b0
        Symbol  tstVal          = b1

        Symbol  i2cAdr          = w1    ' b3:b2
        Symbol  i2cAdrLsb       = b2
        Symbol  i2cAdrMsb       = b3

        Symbol  i2cVal          = b4

        Symbol  i2cDataByte     = b5
        Symbol  i2cAckBit       = b6
        Symbol  i2cBitCount     = b7

; *****************************************************************************
; *                                                                           *
; *     Bit-Banged I/O definitions                                            *
; *                                                                           *
; *****************************************************************************

        Symbol  SDA             = 1
        Symbol  SCL             = 4

        Symbol  SDA_PIN         = pin1
        Symbol  SCL_PIN         = pin4

; *****************************************************************************
; *                                                                           *
; *     Main Program Code                                                     *
; *                                                                           *
; *****************************************************************************

        ; Initialise the I2C comms

        Gosub InitI2cDevice

        ; Test I2C

        Do

          For i2cAdr = $08 To $3F
            Toggle 0
            i2cVal = i2cAdr ^ $80
            Gosub WriteI2cData
            Pause 1000
          Next

          For i2cAdr = $08 To $3F
            Toggle 0
            Gosub ReadI2cData
            Pause 1000
          Next

        Loop

; *****************************************************************************
; *                                                                           *
; *     High-Level I2C Interface Routines                                     *
; *                                                                           *
; *****************************************************************************

WriteI2cData:

        Gosub I2cSendHeader

        i2cDataByte = i2cVal
        Gosub I2cSendByte

        Gosub InitI2cDevice

        Pause 20                        ; 20mS to allow write

        Return

ReadI2cData:

        Gosub I2cSendHeader

        Gosub I2cStart

        i2cDataByte = I2C_ADDRESS | $01
        Gosub I2cSendByte

        Input SDA                       ; SDA = 1 / Tri-State SDA
        For i2cBitCount = 0 To 7
          Gosub I2cStrobeScl
          i2cVal= i2cVal * 2 | i2cAckBit
        Next

InitI2cDevice:

        Low SCL                         ; SCL = 0
        Low SDA                         ; SDA = 0
        Input SCL                       ; SCL = 1
        Input SDA                       ; SDA = 1
        Return

; *****************************************************************************
; *                                                                           *
; *     Low-Level I2C Interface                                               *
; *                                                                           *
; *****************************************************************************

I2cSendHeader:

        Gosub I2cStart

        i2cDataByte = I2C_ADDRESS & $FE
        Gosub I2cSendByte

        i2cDataByte = i2cAdrLsb

I2cSendByte:

        For i2cBitCount = 0 TO 7
          If i2cDataByte < $80 Then
            Low SDA                     ; SDA = 0
          Else
            Input SDA                   ; SDA = 1
          End If
          Gosub I2cStrobeScl
          i2cDataByte = i2cDataByte * 2
        Next
        Input SDA                       ; SDA = 1 / Tri-State SDA
        Gosub I2cStrobeScl
; ---   if i2cAckBit = 1 Then
; ---     SerTxd( "ACK FAILED",CR,LF )
; ---   end if
        Return

I2cStart:

        Input SDA                       ; SDA = 1
        Input SCL                       ; SCL = 1
        Low SDA                         ; SDA = 0
        Low SCL                         ; SCL = 0
        Return

I2cStrobeScl:

        Input SCL                       ; SCL = 1
        Do
        Loop Until SCL_PIN = 1
        i2cAckBit = SDA_PIN
        Low SCL                         ; SCL = 0
        Return

; *****************************************************************************
; *                                                                           *
; *     End of program                                                        *
; *                                                                           *
; *****************************************************************************
 

matherp

Senior Member
OK solved

I win moron of the week award.

When the code says pin 1 it means I/O pin 1 (i.e. pin 6) not physical pin 1, same for pin 4

Hippy - thanks for the code snippet - now I just need to mod it to read and write multiple bytes in one go

Best regards

Peter
 

Technical

Technical Support
Staff member
Study

I2cSendHeader:

And you will see it is already sending two bytes back to back - (slave then data)
once with Gosub I2cSendByte and then by 'falling into' I2cSendByte again.

You can expand this to three or more bytes by just adding more
Gosub I2cSendByte
 

matherp

Senior Member
Yes got that bit. Then to read two bytes I need to send an ACK after the first byte read to get the next byte.
Code:
Low SDA                         
Gosub I2cStrobeScl
input SDA
seems to work

Thanks

Peter
 
Last edited:

Technical

Technical Support
Staff member
Yes, just us an 'ack' (low SDA) when you want another byte and a 'nack' (input SDA) to finish.
 

newplumber

Senior Member
Hi
I was playing around with the code and for me it seems very complicated ...out of my league

If I use this code I seem to get no response from the sertxd so something is out of whack
Code:
#picaxe 20X2
'#NO_DATA
#terminal 9600
; *****************************************************************************
; *                                                                           *
; *     I2C Master Test Program for the PICAXE-08M              MAST08-1.BAS  *
; *                                            ^^^                            *
; *****************************************************************************

        Symbol  I2C_ADDRESS     = %11010000     ; $D0 for DS1307

; *****************************************************************************
; *                                                                           *
; *     Variables                                                             *
; *                                                                           *
; *****************************************************************************
        Symbol  tstAdr          = b0
        Symbol  tstVal          = b1
        Symbol  i2cAdr          = w1    ' b3:b2
        Symbol  i2cAdrLsb       = b2
        Symbol  i2cAdrMsb       = b3
        Symbol  i2cVal          = b4
        Symbol  i2cDataByte     = b5
        Symbol  i2cAckBit       = b6
        Symbol  i2cBitCount     = b7
; *****************************************************************************
; *                                                                           *
; *     Bit-Banged I/O definitions                                            *
; *                                                                           *
; *****************************************************************************
pause 1000
        Symbol  SDA             = B.1
        Symbol  SCL             = B.0

        Symbol  SDA_PIN         = pinB.1 
        Symbol  SCL_PIN         = pinB.0
; *****************************************************************************
; *                                                                           *
; *     Main Program Code                                                     *
; *                                                                           *
; *****************************************************************************

        ; Initialise the I2C comms
        Gosub InitI2cDevice

; Test I2C

       Do
          For i2cAdr = $08 To $3F
            Toggle 0
            i2cVal = i2cAdr ^ $80
            Gosub WriteI2cData
            Pause 1000
          Next

          For i2cAdr = $08 To $3F
            Toggle 0
            Gosub ReadI2cData
            Pause 2000
		sertxd ("____START_____",cr,lf)	  ' added code to see what values show  	
		sertxd ("tstAdr = ",#tstAdr,cr,lf)
		sertxd ("tstVal = ",#tstVal,cr,lf)		
		sertxd ("i2cAdr  = ",#i2cAdr ,cr,lf)		
		sertxd ("i2cAdrLsb = ",#i2cAdrLsb,cr,lf)		
		sertxd ("i2cAdrMsb = ",#i2cAdrMsb,cr,lf)	
		sertxd ("i2cVal = ",#i2cVal,cr,lf)		
		sertxd ("i2cDataByte = ",#i2cDataByte,cr,lf)		
		sertxd ("i2cAckBit = ",#i2cAckBit,cr,lf)		
		sertxd ("i2cBitCount = ",#i2cBitCount,cr,lf)		
		sertxd ("____END_____",cr,lf)
           Next
         Loop
  return
  
  


; *****************************************************************************
; *                                                                           *
; *     High-Level I2C Interface Routines                                     *
; *                                                                           *
; *****************************************************************************

WriteI2cData:

        Gosub I2cSendHeader

        i2cDataByte = i2cVal
        Gosub I2cSendByte

        Gosub InitI2cDevice

        Pause 20                        ; 20mS to allow write

        Return

ReadI2cData:

        Gosub I2cSendHeader

        Gosub I2cStart

        i2cDataByte = I2C_ADDRESS | $01
        Gosub I2cSendByte

        Input SDA                       ; SDA = 1 / Tri-State SDA
        For i2cBitCount = 0 To 7
          Gosub I2cStrobeScl
          i2cVal= i2cVal * 2 | i2cAckBit
        Next

InitI2cDevice:

        Low SCL                         ; SCL = 0
        Low SDA                         ; SDA = 0
        Input SCL                       ; SCL = 1
        Input SDA                       ; SDA = 1
        Return

; *****************************************************************************
; *                                                                           *
; *     Low-Level I2C Interface                                               *
; *                                                                           *
; *****************************************************************************

I2cSendHeader:

        Gosub I2cStart

        i2cDataByte = I2C_ADDRESS & $FE
        Gosub I2cSendByte

        i2cDataByte = i2cAdrLsb

I2cSendByte:

        For i2cBitCount = 0 TO 7
          If i2cDataByte < $80 Then
            Low SDA                     ; SDA = 0
          Else
            Input SDA                   ; SDA = 1
          End If
          Gosub I2cStrobeScl
          i2cDataByte = i2cDataByte * 2
        Next
        Input SDA                       ; SDA = 1 / Tri-State SDA
        Gosub I2cStrobeScl
; ---   if i2cAckBit = 1 Then
; ---     SerTxd( "ACK FAILED",CR,LF )
; ---   end if
        Return

I2cStart:
        Input SDA                       ; SDA = 1
        Input SCL                       ; SCL = 1
        Low SDA                         ; SDA = 0
        Low SCL                         ; SCL = 0
        Return

I2cStrobeScl:

        Input SCL                       ; SCL = 1
        Do
        Loop Until SCL_PIN = 1
        i2cAckBit = SDA_PIN
        Low SCL                         ; SCL = 0
        Return

; *****************************************************************************
; *                                                                           *
; *     End of program                                                        *
; *                                                                           *
; *****************************************************************************
Its like the program just ends before sertxding and I don't see where that's at

EDIT: I do finally get it to show setxd but the values seem in the fog
 

newplumber

Senior Member
Hi
I finally won at the code thanks to hippys example
the part that i missed ...big mistake was
matherp said:
I'm trying to use it to read and write the memory on a DS1307 ($08-$37)
so I had to change the address to $00-$06 instead of ($08-$37)
but here is the working code if a person is just going to read the time from a DS3231 RTC
Code:
#picaxe 20X2
'#NO_DATA
#terminal 38400
setfreq m32
; *****************************************************************************
; *                                                                           *
; *     I2C Master Test Program for the PICAXE-08M              MAST08-1.BAS  *
; *                                            ^^^                            *
; *****************************************************************************

        Symbol  I2C_ADDRESS     = %11010000     ; $D0 for DS1307

; *****************************************************************************
; *                                                                           *
; *     Variables                                                             *
; *                                                                           *
; *****************************************************************************
        Symbol  tstAdr          = b0
        Symbol  tstVal          = b1
        Symbol  i2cAdr          = w1    ' b3:b2
        Symbol  i2cAdrLsb       = b2
        Symbol  i2cAdrMsb       = b3
        Symbol  i2cVal          = b4
        Symbol  i2cDataByte     = b5
        Symbol  i2cAckBit       = b6
        Symbol  i2cBitCount     = b7
        Symbol  Index	        = b8
	  SYMBOL  hours           = b9
        SYMBOL  mins            = b10
        SYMBOL  secs            = b11  
        SYMBOL  day             = b12     ' not used 
        SYMBOL  date            = b13  
        SYMBOL  month           = b14   
        SYMBOL  year            = b15  
	  
	  
	  
#Define BcdToDec(bcd) bcd / $10 * 250 + bcd	  
	  
; *****************************************************************************
; *     Bit-Banged I/O definitions                                            *
; *****************************************************************************

        Symbol  SDA             = B.1
        Symbol  SCL             = B.0

        Symbol  SDA_PIN         = pinB.1 
        Symbol  SCL_PIN         = pinB.0
; *****************************************************************************
; *                                                                           *
; *     Main Program Code                                                     *
; *                                                                           *
; *****************************************************************************

        ; Initialise the I2C comms
        Gosub InitI2cDevice

; Test I2C

       Do	 
           i2cAdr = $00 
  		'Toggle 0
            Gosub ReadI2cData         
		  secs = i2cVal
		
           i2cAdr = $01 
  		'Toggle 0
            Gosub ReadI2cData         
		  mins = i2cVal		
		
           i2cAdr = $02 
  		'Toggle 0
            Gosub ReadI2cData         
		  hours = i2cVal
           
           i2cAdr = $03 
  		'Toggle 0
            Gosub ReadI2cData         
		  day = i2cVal

            i2cAdr = $04 
  		'Toggle 0
            Gosub ReadI2cData         
		  date = i2cVal  
   
           i2cAdr = $05 
  		'Toggle 0
            Gosub ReadI2cData         
		  month = i2cVal   
   
            i2cAdr = $06 
  		'Toggle 0
            Gosub ReadI2cData         
		  year = i2cVal  
		  
  secs  = BcdToDec( secs  )		  
  mins  = BcdToDec( mins  )
  hours = BcdToDec( hours )
  date  = BcdToDec( date  )
  month = BcdToDec( month )
  year  = BcdToDec( year  ) 	 		

 sertxd ("----Start----",cr,lf)	
 sertxd ("secs = ",#secs,cr,lf)
 sertxd ("mins = ",#mins,cr,lf) 
 sertxd ("hours = ",#hours,cr,lf) 
 sertxd ("day = ",#day,cr,lf) 
 sertxd ("date = ",#date,cr,lf) 
 sertxd ("month = ",#month,cr,lf) 
 sertxd ("year = ",#year,cr,lf)
 sertxd ("----End----",cr,lf)
pause 2000
           
         Loop
  return

ReadI2cData:
        Gosub I2cSendHeader
        Gosub I2cStart
        i2cDataByte = I2C_ADDRESS | $01
        Gosub I2cSendByte
        Input SDA                       ; SDA = 1 / Tri-State SDA
        For i2cBitCount = 0 To 7
          Gosub I2cStrobeScl		    
          i2cVal= i2cVal * 2 | i2cAckBit
        Next
InitI2cDevice:
        Low SCL                         ; SCL = 0
        Low SDA                         ; SDA = 0
        Input SCL                       ; SCL = 1
        Input SDA                       ; SDA = 1
        Return

; *****************************************************************************
; *     Low-Level I2C Interface                                               *
; *****************************************************************************

I2cSendHeader:
        Gosub I2cStart
        i2cDataByte = I2C_ADDRESS & $FE
        Gosub I2cSendByte
        i2cDataByte = i2cAdrLsb
I2cSendByte:
        For i2cBitCount = 0 TO 7
          If i2cDataByte < $80 Then
            Low SDA                     ; SDA = 0
          Else
            Input SDA                   ; SDA = 1
          End If
          Gosub I2cStrobeScl
          i2cDataByte = i2cDataByte * 2
        Next
        Input SDA                       ; SDA = 1 / Tri-State SDA
        Gosub I2cStrobeScl
        Return

I2cStart:
        Input SDA                       ; SDA = 1
        Input SCL                       ; SCL = 1
        Low SDA                         ; SDA = 0
        Low SCL                         ; SCL = 0
        Return

I2cStrobeScl:
        Input SCL                       ; SCL = 1
        Do
        Loop Until SCL_PIN = 1
        i2cAckBit = SDA_PIN
        Low SCL                         ; SCL = 0
        Return
 

hippy

Technical Support
Staff member
It is better to modify the code so it reads the complete RTC data in one read packet. If reading a byte at a time there is a chance that, after one value is read, it increments, rolls over and increments the next value up before that is read.

For example; at "00:59" you read the minutes (59), there's a clock tick and at "01:00" you read the hour (01), which gives an apparent time of "01:59" which is not correct.

An alternative is to re-read the least significant data and check it is the same as originally read; if not there has been a tick behind the scene and a re-read of all the data should resolve that.
 

newplumber

Senior Member
hippy said:
It is better to modify the code so it reads the complete RTC data in one read packet.
thanks hippy, I understand what you simply explained , but I guess I need alot more time to see how that can be done
and its a good point. I'll keep trying different ways
 

newplumber

Senior Member
This is the only way I could think of reading in one packet
Code:
Main:
 gosub Read_Time
  secs  = BcdToDec( secs  )		  
  mins  = BcdToDec( mins  )
  hours = BcdToDec( hours )
  date  = BcdToDec( date  )
  month = BcdToDec( month )
  year  = BcdToDec( year  ) 	 		
 sertxd ("----Start----",cr,lf)	
 sertxd ("b9=secs = ",#secs,cr,lf)
 sertxd ("b10=mins = ",#mins,cr,lf) 
 sertxd ("b11=hours = ",#hours,cr,lf) 
 sertxd ("b12=day = ",#day,cr,lf) 
 sertxd ("b13=date = ",#date,cr,lf) 
 sertxd ("b14=month = ",#month,cr,lf) 
 sertxd ("b15=year = ",#year,cr,lf)
 sertxd ("----End----",cr,lf)
  pause 10000
Goto Main 

		  
Read_Time: Bptr = 9 
For i2cAdr = $00 to $06
        Gosub I2cSendHeader
        Gosub I2cStart
        i2cDataByte = I2C_ADDRESS | $01
        Gosub I2cSendByte
        Input SDA                       ; SDA = 1 / Tri-State SDA
        For i2cBitCount = 0 To 7
          Gosub I2cStrobeScl		    
          i2cVal= i2cVal * 2 | i2cAckBit
        Next
  @bptrinc = i2cVal
InitI2cDevice:
        Low SCL                         ; SCL = 0
        Low SDA                         ; SDA = 0
        Input SCL                       ; SCL = 1
        Input SDA                       ; SDA = 1
Next   
        Return
Theres probably a better way ..but its all I can think of right now
 

hippy

Technical Support
Staff member
That is still reading each byte at a time. You need to perform a single multi-byte read rather than multiple single byte reads.

There may be an example of bit-banged multi-byte read on the forum or you will have to look at the I2C specification and follow the sequence of start and stop bits, sending and reading bytes. The existing code can be used as a basis but needs to be changed.
 

newplumber

Senior Member
hippy said:
You need to perform a single multi-byte read rather than multiple single byte reads
Now that is going over my head...although I will try but I am getting confused (sadly don't take much)
Code:
        For i2cBitCount = 0 To 7
          Gosub I2cStrobeScl		    
          i2cVal= i2cVal * 2 | i2cAckBit
        Next
because each byte needs to have 0 to 7 in order to read during a specific time
I am learning tho ....well.....tiny bit
 

AllyCat

Senior Member
Hi,

I think the aim is to send only one start sequence (and Slave address) and then read all 7 bytes quickly in sequence. That probably needs the For i2cAdr = $00 to $06 to be moved to immediately before the For i2cBitCount = 0 To 7 (but you may need to initaialise.i2cAdr in the original position for the unshown subroutine to work correctly). The corresponding next then needs to be located at least after the @bptrinc = i2cVal , but I'm not sure how much further down.... The program appears to "fall into" the InitI2cDevice: routine , which is a "trick" I often use myself,, but I do usually include a comment that it's supposed to happen. ;)

However, I think we can assume that the fall through is intended to happen because the code is very similar to that suggested by Technical in post #2 of this thread. As you may see from that thread, my preference was to use the hardware I2C and find an "alternative" solution to a pin conflict, so I've never actually tried that code.

Cheers, Alan.
 

newplumber

Senior Member
Thanks Allycat
I am breaking down the code bit by bit so I can try to understand correctly ...
Allycat said:
That probably needs the For i2cAdr = $00 to $06 to be moved to immediately before the For i2cBitCount = 0 To 7 (but you may need to initaialise.i2cAdr in the original position for the unshown subroutine to work correctly). The corresponding next then needs to be located at least after the @bptrinc = i2cVal
I will do some tests on how that might be done
 

newplumber

Senior Member
While I am doing my slow homework and studying the DS3231 datasheet I found here

https://www.openimpulse.com/blog/wp-content/uploads/wpsc/downloadables/DS3231-I2C-Real-Time-Clock-Datasheet.pdf
I thought this might be interesting ..if I am reading it right ...on page 11 it states
Figure 1 shows the address map for the DS3231 timekeeping
registers. During a multibyte access, when the
address pointer reaches the end of the register space
(12h), it wraps around to location 00h. On an I2C
START or address pointer incrementing to location 00h,
the current time is transferred to a second set of registers.
The time information is read from these secondary
registers, while the clock may continue to run. This
eliminates the need to reread the registers in case the
main registers update during a read.
Of course I still have to get the code to read a single multi-byte read...but thought maybe
its impossible to get a misreading when the DS3231 updates ...its just my thought
or do I have the page upside down :)


UPDATE:
I made the code line by line (with no gosubs) to make it easier to follow
and 8hrs later I'm still missing something...I know it can be done ...but I have to understand a whole lot more
btw
Code:
        For i2cBitCount = 0 TO 7
          If i2cDataByte < $80 Then
            Low SDA                     ; SDA = 0
          Else
            Input SDA                   ; SDA = 1
          End If
          Gosub I2cStrobeScl
          i2cDataByte = i2cDataByte * 2
        Next
is pure genius
 
Last edited:

newplumber

Senior Member
Hi
on page 15 on the DS3231 data sheet (post #16)
in the bottom right hand corner
it states
Acknowledge: Each receiving device, when
addressed, is obliged to generate an acknowledge
after the reception of each byte. The master device
must generate an extra clock pulse, which is associated
with this acknowledge bit.
but the code is working as
Acknowledging each BIT this is where i am frooze up
because if I use
Code:
[color=Black]I2C_Send_Byte:      
   [/color][color=Blue]For [/color][color=Purple]i2cBitCount [/color][color=DarkCyan]= [/color][color=Navy]0 [/color][color=Blue]TO [/color][color=Navy]7
       [/color][color=Blue]If [/color][color=Purple]i2cDataByte [/color][color=DarkCyan]< [/color][color=Navy]$80 [/color][color=Blue]Then
        Low SDA                     [/color][color=Green]; SDA = 0
       [/color][color=Blue]Else
        Input SDA                   [/color][color=Green]; SDA = 1
      [/color][color=Blue]End If
            Input SCL                       [/color][color=Green]; SCL = 1
             [/color][color=Blue]Do
             Loop Until [/color][color=Purple]SCL_PIN [/color][color=DarkCyan]= [/color][color=Navy]1
        [/color][color=Purple]i2cAckBit [/color][color=DarkCyan]= [/color][color=Purple]SDA_PIN
            [/color][color=Blue]Low SCL                         [/color][color=Green]; SCL = 0            
     [/color][color=Purple]i2cDataByte [/color][color=DarkCyan]= [/color][color=Purple]i2cDataByte [/color][color=DarkCyan]* [/color][color=Navy]2             
   [/color][color=Blue]Next     
    Input SDA       
Return[/color]
it seems to me its acknowledging each bit
 

hippy

Technical Support
Staff member
if I use ...
That's sending each of the 8 data bits but it's not reading the ACK after those 8 bits. At the end you need to make SDA an input so it floats high, then clock out an SCL pulse.

The full sequence to read the data should be similar to this, untested -

Code:
                        Gosub SendStartBit
i2cDataByte = $D0 | 0 : Gosub SendByteAndReadAck                      ; Write to device $D0
i2cDataByte = $00     : Gosub SendByteAndReadAck                      ; Set address to $00
                        Gosub SendStopBit

                        Gosub SendStartBit
i2cDataByte = $D0 | 1 : Gosub SendByteAndReadAck                      ; Read from device $D0
                        Gosub ReadByteAndSendAck : secs = i2cDataByte ; Read location $00
                          :                                                            :
                        Gosub ReadByteAndSendAck : year = i2cDataByte ; Read location $06
                        Gosub SendStopBit
Code:
SendByteAndReadAck:      
  For i2cBitCount = 0 TO 7
    If i2cDataByte < $80 Then
      Low SDA                                ; SDA = 0
    Else
      Input SDA                              ; SDA = 1
    End If
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    Low SCL                                  ; SCL = 0            
    i2cDataByte = i2cDataByte * 2             
  Next     
  Input SDA
  Input SCL                                  ; SCL = 1
  Do : Loop Until SCL_PIN = 1
  i2cAckBit = SDA_PIN
  Low SCL                                    ; SCL = 0            
  Return
Code:
ReadByteAndSendAck:
  Input SDA      
  For i2cBitCount = 0 TO 7
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    i2cDataByte = i2cDataByte * 2 | SDA_PIN            
    Low SCL                                  ; SCL = 0            
  Next     
  Input SCL                                  ; SCL = 1
  Do : Loop Until SCL_PIN = 1
  Low SCL                                    ; SCL = 0            
  Return
 
Last edited:

newplumber

Senior Member
That's sending each of the 8 data bits but it's not reading the ACK after those 8 bits. At the end you need to make SDA an input so it floats high, then clock out an SCL pulse.
Thanks Hippy ...I will look into that example ....you might of saved me 2 weeks
I see/read how the sequence is to send/receive to the DS3231 but how to send bytes from M(master) to S (slave) is confusing for me
so in a example your do/loop until

Code:
SendByteAndReadAck:      
  For i2cBitCount = 0 TO 7
    If i2cDataByte < $80 Then
      Low SDA                                ; SDA = 0
    Else
      Input SDA                              ; SDA = 1
    End If
    Input SCL                                ; SCL = 1
[SIZE=4]    Do : Loop Until SCL_PIN = 1[/SIZE]
For me it means its (do/loop) waiting for the DS3231 to send SCL high and that means its ready for the next bit?
but it is not the end of the "byte" "acknowledge bit" as shown in the data sheet? ...hopefully I make sense
 

newplumber

Senior Member
Its a sweet example Hippy ...but for some reason its stuck on reading seconds only like showing
"terminal"
start sertxd
b9=secs = 23
b10=mins = 165
b11=hours = 165
b12=day = 255
b13=date = 165
b14=month = 165
b15=year = 165
end sertxd

start sertxd
b9=secs = 26
b10=mins = 165
b11=hours = 165
b12=day = 255
b13=date = 165
b14=month = 165
b15=year = 165
end sertxd
Code:
Main:				
				
				    Gosub I2C_Start
i2cDataByte = I2C_ADR | 0 : Gosub SendByteAndReadAck                      ; Write to device $D0
i2cDataByte = $00         : Gosub SendByteAndReadAck                      ; Set address to $00
                            Gosub I2C_Stop

                            Gosub I2C_Start
i2cDataByte = I2C_ADR | 1 : Gosub SendByteAndReadAck                      ; Read from device $D0
                            Gosub ReadByteAndSendAck : secs   = i2cDataByte ; Read location $00
                            Gosub ReadByteAndSendAck : mins   = i2cDataByte ; Read location $01
				    Gosub ReadByteAndSendAck : hours  = i2cDataByte ; Read location $02
				    Gosub ReadByteAndSendAck : day    = i2cDataByte ; Read location $03
				    Gosub ReadByteAndSendAck : date   = i2cDataByte ; Read location $04
				    Gosub ReadByteAndSendAck : month  = i2cDataByte ; Read location $05
				    Gosub ReadByteAndSendAck : year   = i2cDataByte ; Read location $06				    
                            Gosub I2C_Stop				
			          gosub Sertxd_Time                       'sertxd out all 6 bytes of data recieved by ds3231
Goto Main
Its been this kind of problem 36 hrs ago ...and my simple brain can only read it with resending the data address
which in turn is not a single multi-byte read ...maybe i am missing the Ack after the
Gosub ReadByteAndSendAck : secs = i2cDataByte ; Read location $00
Code:
Main:				
				
				    Gosub I2C_Start
i2cDataByte = I2C_ADR | 0 : Gosub SendByteAndReadAck                      ; Write to device $D0


i2cDataByte = $00         : Gosub SendByteAndReadAck                      ; Set address to $00
                            Gosub I2C_Stop

                            Gosub I2C_Start
i2cDataByte = I2C_ADR | 1 : Gosub SendByteAndReadAck                      ; Read from device $D0
                            Gosub ReadByteAndSendAck : secs   = i2cDataByte ; Read location $00
i2cDataByte = $00         : Gosub SendByteAndReadAck                      ; Set address to $00
                            Gosub I2C_Stop

                            Gosub I2C_Start
i2cDataByte = I2C_ADR | 1 : Gosub SendByteAndReadAck                      ; Read from device $D0
                            Gosub ReadByteAndSendAck : mins  = i2cDataByte ; Read location $00
       				    
                            Gosub I2C_Stop				
			          gosub Sertxd_Time                       'sertxd out all 6 bytes of data recieved by ds3231
Goto Main
But always I am having fun learning how the bits are biting
 

newplumber

Senior Member
Another mystery to my puzzle is if I use this code
Code:
Main:				
Bptr = 9				
				    Gosub I2C_Start
i2cDataByte = I2C_ADR | 0 : Gosub SendByteAndReadAck                      ; Write to device $D0

for b1 = 0 to 6
[COLOR="#FF0000"]i2cDataByte = $00[/COLOR]         : Gosub SendByteAndReadAck                      ; Set address to $00
                            Gosub I2C_Stop
                            Gosub I2C_Start
i2cDataByte = I2C_ADR | 1 : Gosub SendByteAndReadAck                      ; Read from device $D0
                            Gosub ReadByteAndSendAck : @bptrinc = i2cDataByte ; Read location $00
next b1				    
                            Gosub I2C_Stop				
			          gosub Sertxd_Time                       'sertxd out all 6 bytes of data recieved by ds3231
Goto Main
it shows the date,time perfectly
so it is running thru $00 to $06 with out changing the
"i2cDataByte = $00"
 

hippy

Technical Support
Staff member
Post #21 works because the chip supports address auto-incrementing. But, with additional stops then starts you are back to reading multiple single bytes not one multiple byte read.
 

hippy

Technical Support
Staff member
For me it means its (do/loop) waiting for the DS3231 to send SCL high and that means its ready for the next bit?
but it is not the end of the "byte" "acknowledge bit" as shown in the data sheet? ...hopefully I make sense
That is to allow the I2C device to do clock-stretching. The device may hold SCL low until it is ready even if the master has let SCL go high. It waits until the device tells the master it can proceed.
 

newplumber

Senior Member
Post #21 works because the chip supports address auto-incrementing. But, with additional stops then starts you are back to reading multiple single bytes not one multiple byte read.
Well thanks again
I don't mind it not being my friend since I truly don't really understand whats happening
but i am understanding a ton more with all your/Allycats help
and someday I wish to succeed in the "one multiple byte read".

This the closest I have been able to get to
Code:
[color=Black]Main:                   [/color]
[color=Purple]Bptr [/color][color=DarkCyan]= [/color][color=Navy]9                      
                            [/color][color=Blue]Gosub [/color][color=Black]I2C_Start[/color]
[color=Purple]i2cDataByte [/color][color=DarkCyan]= [/color][color=Blue]I2C_ADR [/color][color=Black]| [/color][color=Navy]0 [/color][color=Black]: [/color][color=Blue]Gosub [/color][color=Black]SendByteAndReadAck                      [/color][color=Green]; Write to device $D0[/color]


[color=Purple]i2cDataByte [/color][color=DarkCyan]= [/color][color=Navy]$00         [/color][color=Black]: [/color][color=Blue]Gosub [/color][color=Black]SendByteAndReadAck                      [/color][color=Green]; Set address to $00
                            [/color][color=Blue]Gosub [/color][color=Black]I2C_Stop
                            [/color]
[color=Blue]for [/color][color=Purple]b1 [/color][color=DarkCyan]= [/color][color=Navy]0 [/color][color=Blue]to [/color][color=Navy]6                         
                            [/color][color=Blue]Gosub [/color][color=Black]I2C_Start                           [/color]
[color=Purple]i2cDataByte [/color][color=DarkCyan]= [/color][color=Blue]I2C_ADR [/color][color=Black]| [/color][color=Navy]1 [/color][color=Black]: [/color][color=Blue]Gosub [/color][color=Black]SendByteAndReadAck                      [/color][color=Green]; Read from device $D0
                            [/color][color=Blue]Gosub [/color][color=Black]ReadByteAndSendAck : [/color][color=Purple]@bptrinc [/color][color=DarkCyan]= [/color][color=Purple]i2cDataByte [/color][color=Green]; Read location $00[/color]
[color=Blue]next [/color][color=Purple]b1                           
                            [/color][color=Blue]Gosub [/color][color=Black]I2C_Stop                        
                            [/color][color=Blue]gosub [/color][color=Black]Sertxd_Time                       [/color][color=Green]'sertxd out all 6 bytes of data recieved by ds3231                  [/color]
[color=Blue]Goto [/color][color=Black]Main [/color]
 
Last edited:

hippy

Technical Support
Staff member
Its a sweet example Hippy ...but for some reason its stuck on reading seconds
I think I made a mistake in the 'ReadByteAndSendAck' routine. I was leaving SDA high when issuing the supposed ACK which therefore presents itself as a NAK. It probably should be -

Code:
ReadByteAndSendAck:
  Input SDA      
  For i2cBitCount = 0 TO 7
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    i2cDataByte = i2cDataByte * 2 | SDA_PIN            
    Low SCL                                  ; SCL = 0            
  Next
  [b]Low SDA                                    ; SDA = 0[/b]
  Input SCL                                  ; SCL = 1
  Do : Loop Until SCL_PIN = 1
  Low SCL                                    ; SCL = 0            
  [b]Input SDA[/b]      
  Return
 

newplumber

Senior Member
Thanks again hippy ...its getting closer
okay now I am getting a "one liner multi byte read" ...but I still need to figure out why the terminal
shows the correct time/date in every other sertxd...... even tho its data address is $00
but its good to know its reading the one liner.
"terminal"
----Start----
b9=secs = 39 ' 39 secs
b10=mins = 27 '27 mins
b11=hours = 0 ' 0 hours I restarted it so many times
b12=day = 1
b13=date = 1
b14=month = 1
b15=year = 0
----End----
----Start----
b9=secs = 15
b10=mins = 165
b11=hours = 165
b12=day = 255
b13=date = 165
b14=month = 165
b15=year = 165
----End----
----Start----
b9=secs = 41 ' 41 secs
b10=mins = 27 '27 mins
b11=hours = 0 ' 0 hours I restarted it so many times
b12=day = 1
b13=date = 1
b14=month = 1
b15=year = 0
----End----
 

newplumber

Senior Member
Okay here is the code I've been trying to produce of course 99% of it is from thanks to Hippy
After reading more in the DS3231 data sheet...it says on the last byte to read don't include a Ack bit
So after changing that ... it now reads beautiful every time.
Code:
 'I2C bit_banged to read the DS3231 RTC
#picaxe 20X2
'#NO_DATA
#terminal 38400
setfreq m32

     
        Symbol  i2cAdrLsb       = b2
        Symbol  i2cVal          = b4
        Symbol  i2cDataByte     = b5
        Symbol  i2cAckBit       = b6
        Symbol  i2cBitCount     = b7
  
        SYMBOL  secs            = b9 
        SYMBOL  mins            = b10   
        SYMBOL  hours           = b11
        SYMBOL  day             = b12     ' not used 
        SYMBOL  date            = b13  
        SYMBOL  month           = b14   
        SYMBOL  year            = b15 
  
  Symbol  I2C_ADR     = %11010000     ; Slave Address for DS3231
  
        Symbol  SDA             = B.1
        Symbol  SCL             = B.0
        Symbol  SDA_PIN         = pinB.1 
        Symbol  SCL_PIN         = pinB.0 
#Define BcdToDec(bcd) bcd / $10 * 250 + bcd 
pause 8000 
Power_Reset: 
Gosub I2C_Stop  
Main: '==========================Main Program====================================================
Bptr = 9 
    Gosub I2C_Start
i2cDataByte = I2C_ADR | 0 : Gosub SendByteAndReadAck                        ; Write to slave device $D0

i2cDataByte = $00         : Gosub SendByteAndReadAck                        ; Set address to $00

                            Gosub I2C_Start                
i2cDataByte = I2C_ADR | 1 : Gosub SendByteAndReadAck                        ; Read from slave device $DS
for b1 = 0 to 5                         
                            Gosub ReadByteAndSendAck     
                            @bptrinc = i2cDataByte                          ; Read location $00-$05
next b1 
                            Gosub ReadByteAndSendNOAck     
                            @bptrinc = i2cDataByte                          ; Read location $06 with out a Ack  
                            Gosub I2C_Stop 
          gosub Sertxd_Time                       'sertxd out all 6 bytes of data recieved by ds3231     
Goto Main 

Sertxd_Time:   
  secs  = BcdToDec( secs  )   
  mins  = BcdToDec( mins  )
  hours = BcdToDec( hours )
  date  = BcdToDec( date  )
  month = BcdToDec( month )
  year  = BcdToDec( year  )
 sertxd ("----Start----",cr,lf) 
 sertxd ("b9=secs = ",#secs,cr,lf)
 sertxd ("b10=mins = ",#mins,cr,lf) 
 sertxd ("b11=hours = ",#hours,cr,lf) 
 sertxd ("b12=day = ",#day,cr,lf) 
 sertxd ("b13=date = ",#date,cr,lf) 
 sertxd ("b14=month = ",#month,cr,lf) 
 sertxd ("b15=year = ",#year,cr,lf)
 sertxd ("----End----",cr,lf)
  pause 8000   
Return 
SendByteAndReadAck:      
  For i2cBitCount = 0 TO 7
    If i2cDataByte < $80 Then
      Low SDA                                ; SDA = 0
    Else
      Input SDA                              ; SDA = 1
    End If
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    Low SCL                                  ; SCL = 0            
    i2cDataByte = i2cDataByte * 2             
  Next     
  Input SDA
  Input SCL                                  ; SCL = 1
  Do : Loop Until SCL_PIN = 1
  i2cAckBit = SDA_PIN
  Low SCL                                    ; SCL = 0            
 Return 

 ReadByteAndSendAck:
  Input SDA      
  For i2cBitCount = 0 TO 7
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    i2cDataByte = i2cDataByte * 2 | SDA_PIN            
    Low SCL                                  ; SCL = 0            
  Next
  Low SDA                                    ; SDA = 0
  Input SCL                                  ; SCL = 1
  Do : Loop Until SCL_PIN = 1
  Low SCL                                    ; SCL = 0            
  Input SDA      
 Return

 ReadByteAndSendNOAck: 'after receiveing last byte it needs a no acknowledge bit 
  Input SDA      
  For i2cBitCount = 0 TO 7
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    i2cDataByte = i2cDataByte * 2 | SDA_PIN            
    Low SCL                                  ; SCL = 0            
  Next 
 Return
I2C_Start:   
;START a data transfer: A change in the state of the
;data line from high to low, while the clock line is high,
;defines a START condition.
                   Input SCL                       ; SCL = 1
                   Input SDA                       ; SDA = 1
                   Low SDA                         ; SDA = 0
                   Low SCL                         ; SCL = 0   
Return 
I2C_Stop:
;STOP a data transfer: A change in the state of the
;data line from low to high, while the clock line is high,
;defines a STOP condition.
              Low SDA                         ; SDA = 0
              Input SCL                       ; SCL = 1
              Input SDA                       ; SDA = 1
              Low SCL                         ; SCL = 0            
Return
FWIW... It feels I'm probably past the 100,000 download warranty :)...while studying this code
but I did learn some valuable lessons
 

hippy

Technical Support
Staff member
After reading more in the DS3231 data sheet...it says on the last byte to read don't include a Ack bit
You will probably find that it actually says send "Not ACK" (NAK/NACK) rather than "No ACK".

You currently aren't sending either, neither ACK nor NAK. It seesm to work but it is probably best to make the last "ReadByteSendNak" -

Code:
ReadByteAndSendNak:
  Input SDA      
  For i2cBitCount = 0 TO 7
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    i2cDataByte = i2cDataByte * 2 | SDA_PIN            
    Low SCL                                  ; SCL = 0            
  Next
  Input SCL                                  ; SCL = 1
  Do : Loop Until SCL_PIN = 1
  Low SCL                                    ; SCL = 0            
  Return
It has been a while since I have done bit-banged I2C and I wasn't sure if the last byte of a read should be ACK'd or NAK'd. My reading of the I2C spec is it should be an ACK but, either way, it shouldn't matter with a STOP and then a subsequent START, an explicit write which sets the read address before the next read, but it seems it does, at least here.

My preference is not to use '@bptr' to store data which is read. I am not sure why that started getting used but would guess it was an attempt to save program memory which it does. I don't believe it is worth it when there is no shortage of program memory. It just makes things more complicated and introduces the potential for problems for others using the code and modifying that.

If one is going to do that it makes sense to move '@bptrinc=i2cDataByte' into the actual 'ReadByte' routines to save program memory, and also change that to '@bptrinc=BcdToBin(i2cDataByte)', to save having to do the BCD to binary conversion later. One should probably take the byte reading part out of the two 'ReadByte' routines so there is just one set of common code to call to do that if saving program memory is the goal.
 

hippy

Technical Support
Staff member
Code:
I2C_Stop:
              Low SDA                         ; SDA = 0
              Input SCL                       ; SCL = 1
              Input SDA                       ; SDA = 1
              Low SCL                         ; SCL = 0            
Return
That's not right. After the STOP both SDA and SCL should be left high, made inputs. That could be why the chip wasn't handling the STOP and START as expected when the last byte read had an ACK rather than NAK.

I believe it should be -

Code:
I2C_Stop:
              Low   SCL                       ; SCL = 0            
              Low   SDA                       ; SDA = 0
              Input SCL                       ; SCL = 1
              Input SDA                       ; SDA = 1
Return
 

newplumber

Senior Member
hippy said:
My preference is not to use '@bptr' to store data which is read. I am not sure why that started getting used
It Started When I was testing a million different ways ...it (@bptr) was easier then to copy/paste different trial/error code before the "multi byte liner" was invented,
and your correct I will look over the code and make the changes so its in the simplest form

That's not right. After the STOP both SDA and SCL should be left high, made inputs
Yes I should have known ...since we use 4k7 ohm pullups .
 

newplumber

Senior Member
Hi
After testing,retesting,reading,rereading here is I2C bit-banged version AA
Code:
 'I2C bit_banged to read(only) time from the DS3231 RTC  Version AA 
#picaxe 20X2
#NO_DATA
#terminal 38400
setfreq m32

  [color=Blue]Symbol  [/color][color=Purple]i2cDataByte     [/color][color=DarkCyan]= [/color][color=Purple]b6     [/color][color=Green]' send/read byte
  [/color][color=Blue]Symbol  [/color][color=Purple]i2cBitCount     [/color][color=DarkCyan]= [/color][color=Purple]b7     [/color][color=Green]' loop for byte data (8)bits
  [/color][color=Blue]SYMBOL  [/color][color=Purple]secs            [/color][color=DarkCyan]= [/color][color=Purple]b8     [/color][color=Green]' $00-$59
  [/color][color=Blue]SYMBOL  [/color][color=Purple]mins            [/color][color=DarkCyan]= [/color][color=Purple]b9     [/color][color=Green]' $00-$59
  [/color][color=Blue]SYMBOL  [/color][color=Purple]hours           [/color][color=DarkCyan]= [/color][color=Purple]b10    [/color][color=Green]' $00-$23
  [/color][color=Blue]SYMBOL  [/color][color=Purple]day             [/color][color=DarkCyan]= [/color][color=Purple]b11    [/color][color=Green]' $01-$07   
  [/color][color=Blue]SYMBOL  [/color][color=Purple]date            [/color][color=DarkCyan]= [/color][color=Purple]b12    [/color][color=Green]' $01-$31
  [/color][color=Blue]SYMBOL  [/color][color=Purple]month           [/color][color=DarkCyan]= [/color][color=Purple]b13    [/color][color=Green]' $01-$12
  [/color][color=Blue]SYMBOL  [/color][color=Purple]year            [/color][color=DarkCyan]= [/color][color=Purple]b14    [/color][color=Green]' $00-$99

  [/color][color=Blue]Symbol  SCL             [/color][color=DarkCyan]= [/color][color=Blue]B.0    [/color][color=Green]' picaxe-B.0 to DS3231-SCL  with 4k7-ohm pullup resistor (+5vdc)
  [/color][color=Blue]Symbol  SDA             [/color][color=DarkCyan]= [/color][color=Blue]B.1    [/color][color=Green]' picaxe-B.1 to DS3231-SDA  with 4k7-ohm pullup resistor (+5vdc)
  [/color][color=Blue]Symbol  [/color][color=Purple]SCL_PIN         [/color][color=DarkCyan]= [/color][color=Purple]pinB.0 
  [/color][color=Blue]Symbol  [/color][color=Purple]SDA_PIN         [/color][color=DarkCyan]= [/color][color=Purple]pinB.1 [/color]
   
 
  Symbol  I2C_ADR     = %11010000             ;Slave Address for DS3231

[color=Navy]#Define [/color][color=Black]BcdToDec[/color][color=Blue]([/color][color=Black]bcd[/color][color=Blue]) [/color][color=Black]bcd [/color][color=DarkCyan]/ [/color][color=Navy]$10 [/color][color=DarkCyan]* [/color][color=Navy]250 [/color][color=DarkCyan]+ [/color][color=Black]bcd   [/color][color=Green];switch bcd to decimal
 [/color]
[color=Black]Power_Reset: 
 [/color][color=Blue]Gosub [/color][color=Black]I2C_Stop  
Main: [/color][color=Green]'==========================Main Program====================================================
                            [/color][color=Blue]Gosub [/color][color=Black]I2C_Start[/color]
[color=Purple]i2cDataByte [/color][color=DarkCyan]= [/color][color=Blue]I2C_ADR [/color][color=Black]| [/color][color=Navy]0 [/color][color=Black]: [/color][color=Blue]Gosub [/color][color=Black]SendByteAndReadAck                       [/color][color=Green]; Write to slave device $D0[/color]

[color=Purple]i2cDataByte [/color][color=DarkCyan]= [/color][color=Navy]$00         [/color][color=Black]: [/color][color=Blue]Gosub [/color][color=Black]SendByteAndReadAck                       [/color][color=Green]; Set address to $00

                            [/color][color=Blue]Gosub [/color][color=Black]I2C_Start                [/color]
[color=Purple]i2cDataByte [/color][color=DarkCyan]= [/color][color=Blue]I2C_ADR [/color][color=Black]| [/color][color=Navy]1 [/color][color=Black]: [/color][color=Blue]Gosub [/color][color=Black]SendByteAndReadAck                       [/color][color=Green]; Read from slave device $D1

                            [/color][color=Blue]Gosub [/color][color=Black]ReadByteAndSendAck :[/color][color=Purple]secs  [/color][color=DarkCyan]= [/color][color=Purple]i2cDataByte  [/color][color=Green]; Data Address $00         
                            [/color][color=Blue]Gosub [/color][color=Black]ReadByteAndSendAck :[/color][color=Purple]mins  [/color][color=DarkCyan]= [/color][color=Purple]i2cDataByte  [/color][color=Green]; Data Address $01
                            [/color][color=Blue]Gosub [/color][color=Black]ReadByteAndSendAck :[/color][color=Purple]hours [/color][color=DarkCyan]= [/color][color=Purple]i2cDataByte  [/color][color=Green]; Data Address $02                         
                            [/color][color=Blue]Gosub [/color][color=Black]ReadByteAndSendAck :[/color][color=Purple]day   [/color][color=DarkCyan]= [/color][color=Purple]i2cDataByte  [/color][color=Green]; Data Address $03                         
                            [/color][color=Blue]Gosub [/color][color=Black]ReadByteAndSendAck :[/color][color=Purple]date  [/color][color=DarkCyan]= [/color][color=Purple]i2cDataByte  [/color][color=Green]; Data Address $04
                            [/color][color=Blue]Gosub [/color][color=Black]ReadByteAndSendAck :[/color][color=Purple]month [/color][color=DarkCyan]= [/color][color=Purple]i2cDataByte  [/color][color=Green]; Data Address $05                         
                            [/color][color=Blue]Gosub [/color][color=Black]ReadByteAndSendNAk :[/color][color=Purple]year  [/color][color=DarkCyan]= [/color][color=Purple]i2cDataByte  [/color][color=Green]; Data Address $06 (last byte read) 
                            [/color][color=Blue]Gosub [/color][color=Black]I2C_Stop 
                            [/color][color=Blue]Gosub [/color][color=Black]Sertxd_Time     [/color][color=Green]'sertxd out all 6 bytes of time/date     [/color]
[color=Blue]Goto [/color][color=Black]Main [/color]

Sertxd_Time:   

 secs   = BcdToDec( secs  )
 mins   = BcdToDec( mins  )
 hours  = BcdToDec( hours )
 day    = BcdToDec( day   )
 date   = BcdToDec( date  )
 month  = BcdToDec( month )
 year   = BcdToDec( year  )

 [color=Blue] sertxd ([/color][color=Red]"----Start----"[/color][color=Black],  [/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf) 
  sertxd ([/color][color=Red]"secs  = "[/color][color=Black],#[/color][color=Purple]secs[/color][color=Black], [/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf) 
  sertxd ([/color][color=Red]"mins  = "[/color][color=Black],#[/color][color=Purple]mins[/color][color=Black], [/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf) 
  sertxd ([/color][color=Red]"hours = "[/color][color=Black],#[/color][color=Purple]hours[/color][color=Black],[/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf) 
  sertxd ([/color][color=Red]"day   = "[/color][color=Black],#[/color][color=Purple]day[/color][color=Black],  [/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf) 
  sertxd ([/color][color=Red]"date  = "[/color][color=Black],#[/color][color=Purple]date[/color][color=Black], [/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf) 
  sertxd ([/color][color=Red]"month = "[/color][color=Black],#[/color][color=Purple]month[/color][color=Black],[/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf) 
  sertxd ([/color][color=Red]"year  = "[/color][color=Black],#[/color][color=Purple]year[/color][color=Black], [/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf)
  sertxd ([/color][color=Red]"-----End------"[/color][color=Black], [/color][color=Blue]cr[/color][color=Black],[/color][color=Blue]lf)
  pause [/color][color=Navy]8000   [/color]
[color=Blue]Return [/color]
SendByteAndReadAck:   ' sending slave/data addresses to the DS3231   
  For i2cBitCount = 0 TO 7
    If i2cDataByte < $80 Then
      Low SDA                                ; SDA = 0
    Else
      Input SDA                              ; SDA = 1
    End If
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    Low SCL                                  ; SCL = 0            
    i2cDataByte = i2cDataByte * 2             
  Next     
  Input SDA
  Input SCL                                  ; SCL = 1
  Do : Loop Until SCL_PIN = 1
  Low SCL                                    ; SCL = 0            
Return 

ReadByteAndSendAck: ' reading data bytes from the DS3231
  Input SDA      
  For i2cBitCount = 0 TO 7
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    i2cDataByte = i2cDataByte * 2 | SDA_PIN            
    Low SCL                                  ; SCL = 0            
  Next
  Low SDA                                    ; SDA = 0
  Input SCL                                  ; SCL = 1
  Do : Loop Until SCL_PIN = 1
  Low SCL                                    ; SCL = 0            
  Input SDA                                  ; SDA = 1
Return

ReadByteAndSendNak: ' reading last data byte from the DS3231
  Input SDA                                  ; SDA = 1
  For i2cBitCount = 0 TO 7
    Input SCL                                ; SCL = 1
    Do : Loop Until SCL_PIN = 1
    i2cDataByte = i2cDataByte * 2 | SDA_PIN            
    Low SCL                                  ; SCL = 0            
  Next
  Input SCL                                  ; SCL = 1
  Do : Loop Until SCL_PIN = 1
  Low SCL                                    ; SCL = 0            
Return
I2C_Start:   
              Input SCL                       ; SCL = 1
              Input SDA                       ; SDA = 1
              Low SDA                         ; SDA = 0
              Low SCL                         ; SCL = 0   
Return 
I2C_Stop:
              Low SCL                         ; SCL = 0 
              Low SDA                         ; SDA = 0
              Input SCL                       ; SCL = 1
              Input SDA                       ; SDA = 1            
Return
 
Last edited:
Top