Hi All; I am trying to receive a byte on an i2c bus using a pic16f684. I am receiving the 3 required ACK's from the slave, then when I try to read the data bits (and I can see on an oscope), that the DATA line stays high during all of the clock pulses that the pic provides. I am trying to read a register that should return 0x55 so I know this is definately wrong. The output of the project is to a hyperterminal. This part of the code I know works I have used it man times before and have tested it in this application.
Any help is greatly appreciated,
Steve
Any help is greatly appreciated,
Steve
Code:
;.......................................................................................................................
;.......................................................................................................................
;Call proper header, include and source files to initialize PIC
LIST p=16F684 ; Tells Assembler what PIC is used
#INCLUDE <p16f684.inc> ; Includes factory defaults for the PIC
;.......................................................................................................................
;Configure PIC optional properties
__CONFIG _WDT_OFF & _MCLRE_OFF ; Enables CLKOUT, WDT, and Digital I/O on MCLR/RA3
;.......................................................................................................................
;errorlevel -302, -207, -305
;.......................................................................................................................
;.......................................................................................................................
;Define Constant Working Register Variables
cblock 0x20
i2c_transmit_byte
i2c_bit_counter
pw_counter
pw_counter1
wait_startup_counter
Received_I2C_Byte
transmit_byte_rs232
bit_counter_rs232
delay_counter
osc_counter
endc
;.......................................................................................................................
;.......................................................................................................................
;Define Global Deifnitions:
I2C_PORT equ PORTC
I2C_TRIS equ TRISC
#define SDA 2
#define SCL 3
;.......................................................................................................................
;.......................................................................................................................
START_PROGRAM
;Initialize Inputs/Outputs, and Registers on the PIC16F684.
;Initialize TRISA and TRISB registers.
bsf STATUS, RP0 ;Bank 1
movlw b'00001100'
movwf TRISC ;Assigns SDA and SCL Inputs.
movlw b'00000000'
movwf TRISA ;Assigns all TRISA as outputs.
movlw 0x03
movwf OSCCON ;Loads internal 31.25kHz clock
bcf STATUS, RP0 ;Bank 0
clrf CCP1CON
call Sleep_Routine
;......................................................................................................................
;.......................................................................................................................
;READ Register from Kionix KXTJ9 accelerometer -- DCST_RESP Register located at 0x0C
;BusFixed
call Clock_Pulse_Delay
call Clock_Pulse_Delay
call Clock_Pulse_Delay ;Startup Delay
; call Transmit_RS232
bcf PORTC, 0
call Start_Command ;Start Command
call SAD_W ;Address Slave plus write
call ACK ;Get Acknowledge from slave
call Who_Am_I_Reg
call ACK
call Start_Command
call SAD_R
call ACK ;Successful ACK received up to this point
call Receive_i2c_Byte
call Transmit_RS232
call NACK
call Stop_Command
done
bsf PORTC, 0
goto done
goto START_PROGRAM
;---------------------------------------------------------------------------------------
;Sub Routines for PIC
;---------------------------------------------------------------------------------------
;i2c Routines
;----------------------------------
Start_Command
call Set_SCL_High ;Release SCL
call Set_SDA_High ;Release SDA
call Clock_Pulse_Delay ;Delay
call Set_SDA_Low ;Set SDA Low
call Clock_Pulse_Delay ;Delay
return
;----------------------------------
SAD_W
movlw 0x1E
call Send_i2c_Byte ;(SAD+W)Slave Address plus write.
return
;----------------------------------
SAD_R
movlw 0x1F
call Send_i2c_Byte ;(SAD+R)Slave Address plus read.
return
;----------------------------------
ACK
call Set_SCL_High ;Release SCL
call Set_SDA_High ;Release SDA
call Clock_Pulse_Delay ;Delay
Clock_Stretch
btfss I2C_PORT, SCL
goto Clock_Stretch ;Wait for slave to release clock line (if "stretching")
call Clock_Pulse_Delay ;Delay
bcf STATUS, C ;Initally clears the carry bit
btfsc I2C_PORT, SDA ;Checks if slave is pulling SDA low (giving its ACK)
goto _Error ;Clear carry for NACK
bsf STATUS, C ;Set carry for ACK
btfss STATUS, C ;Check carry bit to ensure ACK
goto START_PROGRAM ;Start over if NACK
return ;If ACK received, continue
;----------------------------------
NACK
call Set_SCL_High ;Release SCL
call Clock_Pulse_Delay ;Delay
call Set_SCL_Low ;Set SCL Low
call Set_SDA_High ;Release SDA
call Clock_Pulse_Delay ;Delay
return
;----------------------------------
Stop_Command
call Set_SCL_High ;Release SCL
call Clock_Pulse_Delay ;Delay
call Set_SDA_High ;Release SDA
call Clock_Pulse_Delay ;Delay
call Clock_Pulse_Delay ;Delay
return
;----------------------------------
Send_i2c_Byte
movwf i2c_transmit_byte ;Moves whatever value is in the working register into i2c_transmit_byte
movlw 0x08
movwf i2c_bit_counter ;Sets 8 bits to be sent out
Send_i2c_Bit
call Set_SCL_Low ;Ensure SCL is low initially
call Clock_Pulse_Delay ;Delay
rlf i2c_transmit_byte, f ;MSB is now in carry (MSB is sent first)
btfsc STATUS, C
call Set_SDA_High
btfss STATUS, C
call Set_SDA_Low ;Sets either 0 or 1 to be sent out. (Checks carry bit)
call Clock_Pulse_Delay ;Delay
call Set_SCL_High ;Trigger Clock; set SCL high
call Clock_Pulse_Delay ;Delay
decfsz i2c_bit_counter, f ;Checks if 8 bits have been sent out
goto Send_i2c_Bit ;No
call Set_SCL_Low ;Yes; Set SCL Low
call Clock_Pulse_Delay ;Delay
return
;-------------------------------------
Receive_i2c_Byte
clrf Received_I2C_Byte ;Clears previous received byte
bsf Received_I2C_Byte, 0
Get_i2c_Bit
call Set_SCL_Low
call Set_SDA_High ;Set SCL Low
call Clock_Pulse_Delay ;Delay
bcf STATUS, C ;Defaults to incoming bit = 0 (sets carry = 0)
call Set_SCL_High ;Release SCL
call Clock_Pulse_Delay
btfsc I2C_PORT, SDA ;Read port, skip if clear
bsf STATUS, C ;If incoming bit = 1, set carry flag to 1
rlf Received_I2C_Byte, f ;move carry into data (MSB first)
call Clock_Pulse_Delay
btfss STATUS, C
goto Get_i2c_Bit ;No
;Test to ensure hypertermianl works correctly.
; movlw 0x55
; movwf Received_I2C_Byte
call Set_SCL_Low
movf Received_I2C_Byte, w ;Moves result to the working register
return ;Yes, return
;Routines to Set SDA and SCL High/Low
Set_SCL_High
bsf STATUS, RP0 ;Bank 1
bsf I2C_TRIS, SCL ;Sets SCL as an input
clrf ANSEL
bcf STATUS, RP0 ;Bank 0
movlw 0x07
movwf CMCON0
return
Set_SCL_Low
bcf I2C_PORT, SCL ;Sets SCL port pin low
bsf STATUS, RP0 ;Bank 1
bcf I2C_TRIS, SCL ;Sets SCL as an output
clrf ANSEL
bcf STATUS, RP0 ;Bank 0
movlw 0x07
movwf CMCON0
return
Set_SDA_High
bsf STATUS, RP0 ;Bank 1
bsf I2C_TRIS, SDA ;Sets SDA as an input (high impedance)
clrf ANSEL
bcf STATUS, RP0 ;Bank 0
movlw 0x07
movwf CMCON0
return
Set_SDA_Low
bcf I2C_PORT, SDA ;Sets SDA port pin low
bsf STATUS, RP0 ;Bank 1
bcf I2C_TRIS, SDA ;Sets SDA as an output
clrf ANSEL
bcf STATUS, RP0 ;Bank 0
movlw 0x07
movwf CMCON0
return
;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;Delays
Clock_Pulse_Delay
movlw 0xFF
movwf pw_counter
Clock_Pulse_Delay_Wait
nop
movlw 0x01
movwf pw_counter1
Clock_Pulse_Delay_Wait1
decfsz pw_counter1, f
goto Clock_Pulse_Delay_Wait1
decfsz pw_counter, f
goto Clock_Pulse_Delay_Wait
return
bit_delay
movlw 0x16
movwf delay_counter
bit_wait
nop
decfsz delay_counter, f
goto bit_wait
return
Osc_Stablize
movlw 0xFF
movwf osc_counter
Osc_Wait
nop
nop
nop
decfsz osc_counter, f
goto Osc_Wait
return
I2cInit
call Set_SCL_Low
call Set_SDA_Low
call Set_SCL_High
call Set_SDA_High
ClockLoop
btfsc PORTC,SDA
; goto BusFixed
bcf PORTC,SCL
bsf STATUS,RP0
bcf TRISC,SCL
goto $+1
bsf TRISC,SCL
bcf STATUS,RP0
goto ClockLoop
Who_Am_I_Reg
movlw 0x0C ; - Substitute for DSCT_RESP
call Send_i2c_Byte
return
;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;Sub routines for PIC to Hyperterminal
;****SENDS INVERSE LOGIC TO PROLIFIC RS-232 TO USE CONVERTER
Transmit_RS232
movwf transmit_byte_rs232 ;moves W to transmit_byte
bsf STATUS, RP0
movlw 0x65
movwf OSCCON
movlw 0x00
movwf TRISC
movlw 0x00
movwf TRISA
bcf STATUS, RP0
; movwf transmit_byte_rs232 ;moves W to transmit_byte
call Osc_Stablize
; movlw 0x55
; movwf transmit_byte_rs232
bcf PORTC, 5
; movlw 0x55
; movwf Received_I2C_Byte
; movf Received_I2C_Byte, w
movlw 0x08
movwf bit_counter_rs232 ;sets 8 bits to send out
bsf PORTC, 5
call bit_delay
Send_Serial_Loop_RS232
rrf transmit_byte_rs232, f ;Send one bit
btfss STATUS, C
bsf PORTC, 5
btfsc STATUS, C
bcf PORTC, 5
call bit_delay
decfsz bit_counter_rs232, f ;Tests if all done
goto Send_Serial_Loop_RS232
bcf PORTC, 5
call bit_delay
call bit_delay
bsf STATUS, RP0
movlw 0x03
movwf OSCCON
; movlw 0x00
; movwf TRISC
; movlw 0x00
; movwf TRISA
bcf STATUS, RP0
return
_Error
movlw 0x45
call Transmit_RS232
movlw 0x52
call Transmit_RS232
movlw 0x52
call Transmit_RS232
movlw 0x4F
call Transmit_RS232
movlw 0x52
call Transmit_RS232
goto START_PROGRAM
Sleep_Routine
movlw 0x07
movwf WDTCON
sleep
movlw 0x00
movwf WDTCON
return
end