|
InitI2CBusMaster
;************************************************************ TxmtStartBit bsf Bus_Busy ; on a start condition bus is busy bsf STATUS, RP0 ; Select page 1 bsf _SDA ; set SDA high bsf _SCL ; clock is high call Delay40uSec ; This is necessary for setup time bcf _SDA ; This gives a falling edge on SDA while clock is high call Delay47uSec ; Necessary for START HOLD time return ;************************************************************ TxmtStopBit bsf STATUS, RP0 ; Select page 1 bcf _SCL ; clock is low bcf _SDA ; set SDA low bsf _SCL ; clock is pulled up call Delay40uSec ; Setup time for STOP condition bsf _SDA ; rising edge on SDA while CLOCK is high call Delay47uSec ; makes sure a START isn't sent immediately after a STOP bcf Bus_Busy ; The bus isn't busy anymore return ;************************************************************ AbortI2C call TxmtStopBit ; Send a stop bit bsf Abort ; set the abort bit return ;************************************************************ TxmtSlaveAddr movf SlaveAddr, w ; Move slave address to W bcf ACK_Error ; reset Acknowledge error bit movwf I2CData ; move W to I2C Data bcf I2CData, LSB ; Set for write btfsc Slave_RW ; If skip then write operation bsf I2CData, LSB ; Clear for read call SendData ; send the address btfss Txmt_Success ; skip if successful goto AddrSendFail ; Oops, we failed retlw TRUE ; return true AddrSendFail btfss ACK_Error ; was there an error acknowledging retlw FALSE ; No, so return 0 call TxmtStopBit ; Address not acknowleged, so send STOP bit retlw FALSE ; Unsuccessful, so return 0
;************************************************************ SendData ; We might should make a copy of the data here, the example does but I don't see why!!! bsf Txmt_Progress ; We are in the middle of transmitting bcf Txmt_Success ; reset success bit movlw 0x08 movwf I2CBitCount ; Set I2C Bit Count to 8 bsf STATUS, RP0 ; Select page 1 TxmtNextBit: bcf _SCL ; Set clock Low rlf I2CData, F ; MSB First, Note that I2CData is Destroyed bcf _SDA ; Set clock based on what the MSB is btfsc STATUS,C ; Was the MSB a 1 bsf _SDA ; Nope set it high call Delay47uSec ; guarantee min LOW TIME tLOW & Setup time bsf _SCL ; set clock high call Delay40uSec ; guarantee min HIGH TIME tHIGH decfsz I2CBitCount, F ; are we done yet goto TxmtNextBit ; nope, send the next bit ; ; Check For Acknowledge ; bcf _SCL ; reset clock bsf _SDA ; Release SDA line for Slave to pull down call Delay47uSec ; guarantee min LOW TIME tLOW & Setup time bsf _SCL ; clock for slave to ACK call Delay40uSec ; guarantee min HIGH TIME tHIGH bcf STATUS, RP0 ; Select PAGE 0 to test SDA pin btfsc SdaPin ; SDA should be pulled low by slave if OK goto TxmtErrorAck ; Uh oh, slave isn't behaving (or isn't there) bsf STATUS, RP0 ; Select PAGE 1 bcf _SCL ; reset clock bcf Txmt_Progress ; reset progress bit in Bus Status bsf Txmt_Success ; Transmission successful bcf ACK_Error ; ACK OK return TxmtErrorAck bsf STATUS,RP0 ; select page 1 bsf _SDA ; tristate SDA bsf _SCL ; tristate SCL bcf Txmt_Progress ; reset progress bit in Bus Status bcf Txmt_Success ; Transmission NOT successful bsf ACK_Error ; No ACK From Slave return
;************************************************************ GetData bsf Rcv_Progress ; set Bus status for txmt progress bcf Rcv_Success ; reset status bit movlw 0x08 movwf I2CBitCount RcvNextBit bsf STATUS, RP0 ; page 1 for TRIS manipulation bcf _SCL ; lower clock bcf _SDA ; lower data line call Delay47uSec ; guarantee min LOW TIME tLOW & setup time bsf _SCL ; clock high, data sent by slave call Delay40uSec ; guarantee min HIGH TIME tHIGH bcf STATUS, RP0 ; select page 0 to read Ports bcf STATUS, C ; 0 out Status btfsc SdaPin ; Check state of pin bsf STATUS, C ; Pin was high, set status rlf I2CData, F ; left Shift data (MSB first) decfsz I2CBitCount, F ; Are we done yet goto RcvNextBit ; Nope, go get the next one ; ; Generate ACK bit if not last byte to be read, ; if last byte Gennerate NACK ; do not send ACK on last byte, main routine will send a STOP bit ; bsf STATUS, RP0 ; Page 1 for TRIS manipulation bcf _SCL ; pull SCL low bcf _SDA ; ACK by pulling SDA low btfsc Last_Byte_Rcv ; Is it the last byte to receive bsf _SDA ; If so, send NACK by setting SDA high call Delay47uSec ; guarantee min LOW TIME tLOW & Setup time bsf _SCL ; Raise Clock back up call Delay40uSec ; guarantee min HIGH TIME tHIGH RcvEnd: bcf _SCL ; reset clock bcf Rcv_Progress ; reset bit in Bus Status bsf Rcv_Success ; transmission successful bcf ACK_Error ; ACK OK return
Delay47uSec: movlw ((_47uS_Delay-5)/3 + 1) ; move delay into W DlyK movwf DelayCount ; move what is in W to DelayCount decfsz DelayCount, F ; Decrement DelayCount goto $-1 ; Loop until 0 return ; return
Delay40uSec: movlw ((_40uS_Delay-8)/3 + 1) ; move delay into W goto DlyK ; goto DlyK loop
|