Hi all; I am stuck receiving data on an i2c bus using a pic16f684 and kionix kxtj2 accelerometer. I have two issues:
1) I can receive an ACK from the slave only if I don't check the CLK line for stretching. I see the DAT line being pulled low signaling an ACK when I address the slave correctly, and don't see it if I dont. I have a PC Digital O-Scope for a visual reference on the CLK and DAT lines. So I do know the accelerometer is pulling the DAT line low. I should be able to test the CLK line here for stretching but I'm not sure why I can't?
2) When receiving a byte from the accelerometer, I see the clock pulses that the pic generates and I see the data line toggling high and low which is the expceted value I'm looking to read (0x55). However, when I test the "Received_I2C_Byte", it is always = 0x00. I have an output routine to send the received byte to my PC via hyperterminal in ASCII characters. I know this section of the code works as I have used it plenty of times and have verified its functionality.
Below is my code, any help is much appreciated.
Steve
1) I can receive an ACK from the slave only if I don't check the CLK line for stretching. I see the DAT line being pulled low signaling an ACK when I address the slave correctly, and don't see it if I dont. I have a PC Digital O-Scope for a visual reference on the CLK and DAT lines. So I do know the accelerometer is pulling the DAT line low. I should be able to test the CLK line here for stretching but I'm not sure why I can't?
2) When receiving a byte from the accelerometer, I see the clock pulses that the pic generates and I see the data line toggling high and low which is the expceted value I'm looking to read (0x55). However, when I test the "Received_I2C_Byte", it is always = 0x00. I have an output routine to send the received byte to my PC via hyperterminal in ASCII characters. I know this section of the code works as I have used it plenty of times and have verified its functionality.
Below is my code, any help is much 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 0
#define SCL 1
;.......................................................................................................................
;.......................................................................................................................
START_PROGRAM
;Initialize Inputs/Outputs, and Registers on the PIC16F684.
;Initialize TRISA and TRISB registers.
bsf STATUS, RP0 ;Bank 1
movlw b'00000011'
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
;......................................................................................................................
;.......................................................................................................................
;READ Register from Kionix KXTJ9 accelerometer -- DCST_RESP Register located at 0x0C
;BusFixed
; call Set_SCL_High
; call Set_SDA_High
call Clock_Pulse_Delay
call Clock_Pulse_Delay
call Clock_Pulse_Delay ;Startup Delay
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
call Receive_i2c_Byte
call NACK
call Stop_Command
;Test to check the value of the received byte
; movlw 0x00
; subwf Received_I2C_Byte, 0
; btfsc STATUS, Z
; bsf PORTC, 4
call Transmit_RS232
;TEST
bsf PORTC, 3
done
goto done
goto START_PROGRAM
;---------------------------------------------------------------------------------------
;Sub Routines for PIC
;---------------------------------------------------------------------------------------
;i2c Routines
;----------------------------------
Start_Command
call Set_SCL_High
call Set_SDA_High
call Clock_Pulse_Delay
call Set_SDA_Low
call Clock_Pulse_Delay ;(S) - Sets SDA low while SCL is high
return
;----------------------------------
SAD_W
movlw 0x1E
call Send_i2c_Byte ;(SAD+W) Slave Address plus write.
return
;----------------------------------
SAD_R
movlw 0x1F
call Send_i2c_Byte ; Slave Address plus write.
; call Clock_Pulse_Delay
return
;----------------------------------
ACK
call Set_SCL_Low ;Ensure SCL is low
call Set_SDA_High ;Release SDA
call Clock_Pulse_Delay ;Wait (Slave will normally pull down the SDA line by this time)
call Set_SCL_High ;Set SCL High for ACK pulse
Clock_Stretch
; call Clock_Pulse_Delay
; btfss I2C_PORT, SCL
; goto Clock_Stretch ;Wait for slave to release clock line (if "stretching")
call Clock_Pulse_Delay
bcf STATUS, C
btfsc I2C_PORT, SDA
goto _Error ;Clear carry for NACK
bsf STATUS, C ;Set carry for ACK
btfss STATUS, C
goto START_PROGRAM
call Set_SCL_Low
return
;----------------------------------
NACK
call Set_SCL_High
call Clock_Pulse_Delay
call Set_SCL_Low
call Set_SDA_High
call Clock_Pulse_Delay
return
Stop_Command
call Set_SCL_High
call Clock_Pulse_Delay
call Set_SDA_High
call Clock_Pulse_Delay
call Clock_Pulse_Delay
return
;Send i2c Byte:
Send_i2c_Byte
movwf i2c_transmit_byte
movlw 0x08
movwf i2c_bit_counter
Send_i2c_Bit
call Set_SCL_Low
call Clock_Pulse_Delay
rlf i2c_transmit_byte, f ;MSB is now in carry
btfsc STATUS, C
call Set_SDA_High
btfss STATUS, C
call Set_SDA_Low
call Clock_Pulse_Delay
call Set_SCL_High
call Clock_Pulse_Delay
decfsz i2c_bit_counter, f
goto Send_i2c_Bit
call Set_SCL_Low
call Clock_Pulse_Delay
return
;-------------------------------------
Receive_i2c_Byte
clrf Received_I2C_Byte
movlw 0x08
movwf i2c_bit_counter
Get_i2c_Bit
call Set_SCL_High ;Release SCL
call Set_SDA_High ;Release SDA
bcf STATUS, C ;Defaults to incoming bit = 0 (sets carry = 0)
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, 1 ;move carry into data (MSB first)
; call Clock_Pulse_Delay
call Set_SCL_Low
call Clock_Pulse_Delay
decfsz i2c_bit_counter, f ;Have 8 bits been received?
goto Get_i2c_Bit ;No
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
bcf STATUS, RP0 ;Bank 0
call Clock_Pulse_Delay
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
bcf STATUS, RP0 ;Bank 0
call Clock_Pulse_Delay
return
Set_SDA_High
bsf STATUS, RP0 ;Bank 1
bsf I2C_TRIS, SDA ;Sets SDA as an input (high impedance)
bcf STATUS, RP0 ;Bank 0
call Clock_Pulse_Delay
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
bcf STATUS, RP0 ;Bank 0
call Clock_Pulse_Delay
return
;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;Delays
Clock_Pulse_Delay
movlw 0x09
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
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
bsf STATUS, RP0
movlw 0x65
movwf OSCCON
; movlw 0x00
; movwf TRISC
; movlw 0x00
; movwf TRISA
bcf STATUS, RP0
call Osc_Stablize
bcf PORTC, 2
; movlw 0x55
; movwf Received_I2C_Byte
movf Received_I2C_Byte, w
movwf transmit_byte_rs232 ;moves W to transmit_byte
movlw 0x08
movwf bit_counter_rs232 ;sets 8 bits to send out
bsf PORTC, 2
call bit_delay
;TEst
; movlw 0x55
; movwf transmit_byte_rs232
Send_Serial_Loop_RS232
rrf transmit_byte_rs232, f ;Send one bit
btfss STATUS, C
bsf PORTC, 2
btfsc STATUS, C
bcf PORTC, 2
call bit_delay
decfsz bit_counter_rs232, f ;Tests if all done
goto Send_Serial_Loop_RS232
bcf PORTC, 2 ;Is this needed to keep the line high??
call bit_delay
call bit_delay
; clrf transmit_byte_rs232
return
_Error
movlw 'E'
call Transmit_RS232
movlw 'R'
call Transmit_RS232
movlw 'R'
call Transmit_RS232
movlw 'O'
call Transmit_RS232
movlw 'R'
call Transmit_RS232
goto START_PROGRAM
Sleep_Routine
movlw 0x07
movwf WDTCON
sleep
movlw 0x00
movwf WDTCON
return
end