Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Help with receiving ACK from slave on i2c bus.

Status
Not open for further replies.

Steve311

Member
Hi All;

I'm stuck with receiving an ACK during i2c communication. I am using a PIC16F688 as the master and a Kionix KFTJ9 accelerometer as the slave. This PIC does not have i2c hardware built in, so I am doing it in software. The SCL and SDA lines are pulled high with a 2.1kohm resistor and I am using the PICs internal 31.25kHz clock.

Below is the code, Thank you all in advance.

S



;Define Constant Working Register Variables
cblock 0x20
i2c_transmit_byte
i2c_bit_counter
pw_counter
wait_startup_counter
ACK_counter
i2c_flags
Received_I2C_Byte
transmit_byte_rs232
bit_counter_rs232
delay_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 ;Sets bit RP0 in address STATUS to 1 (switches from bank 0 to 1).
movlw b'00000000'
movwf TRISC ;Assigns all TRISC as outputs.
movlw b'00000000'
movwf TRISA ;Assigns all TRISA as outputs. Note - RA2 must be bi-directional. Default is output.
movlw 0x03
movwf OSCCON ;Loads internal 31.25kHz clock
clrf ANSEL ;Clears default analog inputs and allows for digital I/O on analog pins
bcf STATUS, RP0 ;Moves back to bank 0 for execution

movlw b'00000111'
movwf CMCON0 ;Turns analog comparators off and allows for digital I/O on all pins


;......................................................................................................................
;.......................................................................................................................


;READ Register from accelerometer -- WHO_AM_I


call Wait_Startup ;Startup delay

call Start_Command


call SAD_W
call ACK

bsf PORTC, 4

done
goto done
end

;---------------------------------------------------------------------------------------
;i2c routines

Start_Command
call Clock_Pulse_Delay
call Set_SCL_Low
call Set_SDA_High
call Set_SCL_High
call Set_SDA_Low
call Clock_Pulse_Delay ;(S) - Sets SDA low while SCL is high
return
;----------------------------------
SAD_W
movlw 0x1C
; movlw 0x38
call Send_i2c_Byte ; Slave Address plus write.
call Clock_Pulse_Delay
return
;----------------------------------
SAD_R
movlw 0x1D
call Send_i2c_Byte
call Clock_Pulse_Delay
return
;----------------------------------
ACK
call Set_SDA_High
call Set_SCL_High
Get_ACK
bsf PORTC, 4
btfsc I2C_PORT, SDA
goto Get_ACK
bcf PORTC, 4
call Set_SCL_Low
return
;-----------------------------------

Set_SCL_High
bsf STATUS, RP0 ;Bank 1
bsf I2C_TRIS, SCL ;Sets SCL as an input
bcf STATUS, RP0 ;Bank 0
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
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
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
return

Send_i2c_Byte
movwf i2c_transmit_byte
movlw 0x08
movwf i2c_bit_counter
Send_i2c_Bit
call Clock_Pulse_Delay
call Set_SCL_Low
rrf i2c_transmit_byte, f
btfsc STATUS, C
call Set_SDA_High
btfss STATUS, C
call Clock_Pulse_Delay
call Set_SDA_Low
call Clock_Pulse_Delay
call Set_SCL_High
decfsz i2c_bit_counter, f
goto Send_i2c_Bit
return










end
 
Your code looks ok and so the only thing I can suggest is that your bus is getting out of sync. When you fail to communicate the bus can be in an intermediate state (eg half way through sending a byte) and needs to be reset. To do this you need to power down the whole circuit between attempts.

Alternatively, I do the following in software,
Code:
I2cInit		bcf	PORTC,SCK
		bcf	PORTC,SDA
		bsf	STATUS,RP0	;1
		bsf	TRISC,SCK
		bsf	TRISC,SDA
		bcf	STATUS,RP0
ClockLoop	btfsc	PORTC,SDA
		goto	BusFixed
		bcf	PORTC,SCK
		bsf	STATUS,RP0
		bcf	TRISC,SCK
		goto	$+1
		bsf	TRISC,SCK
		bcf	STATUS,RP0
		goto	ClockLoop
BusFixed

Basically, if the data line is being held low it sends clock pulses until it's released. Once the data line is released the slave can then recognize a start condition and so all is well again.

Are you sure it's a Kionix KFTJ9 as google doesn't find a single reference to such a device.

BTW, to post formatted code you type [code] before it and [/code] after it.

Edit, just had a closer look at your code and there are many mistakes. The first is in the start bit, a start condition simply pulls the data line low. You're doing Data Low, Clock high, Data high, Clock low!!!! That will produce spurious pulses that will mess up the communication. If you post code that is complete (especially the delay routine) then I may be able to fix it.

Mike.
 
Last edited by a moderator:
Hi Mike, Thanks for you help. I am actually using a Kionix KXTJ9 (This is a new version of the KXTF9, sorry I did make a typo previously). All of these digital accelerometers from Kionix use the same i2c digital engine. I have attached the datasheet for your reference.

In terms of my start command, I do set SCL Low, then both SCL and SDA high, the pull SDA Low. I guess I don't need to set SCL Low at all in this. Good catch, thanks for that.

I have also attached my .asm file for your review. If you could take a look that would be great.

It seems like a good idea to add in code to ensure the bus is in proper sync?

Thanks in Advance
Steve
 
Mike; Looks like the Kionix KXTJ9 datasheet did not attatch due to its size. Here is a link to the KXTJ2 (which I am waiting on eval boards for and will use in my end product) as they do use the same digital engine. (I think the KXTJ9 may now be obsolete).

**broken link removed**

Thank you Again.
 
If you can't get the I2C to work, try to talk to a memory IC or temperature IC or anything different. I have worked long hours then found "the data sheet is wrong".
 
Hi,

I've had a look at your code and changed a few things but as ron says, it could be the data sheet. Where did you get 0x1c as the address of the chip as I couldn't find it anywhere and if that is wrong then nothing will work. Do you have any other I²C devices to try it with?
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     _INTRC_OSC_CLKOUT & _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
	wait_startup_counter
	ACK_counter
	i2c_flags
	Received_I2C_Byte
	transmit_byte_rs232
	bit_counter_rs232
	delay_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		;Sets bit RP0 in address STATUS to 1 (switches from bank 0 to 1).
 	movlw 	b'00000011'		;keep i2c pins input
 	movwf 	TRISC			;Assigns all TRISC as outputs.
 	movlw	b'00000000'		
	movwf	TRISA			;Assigns all TRISA as outputs. Note - RA2 must be bi-directional. Default is output. 
	movlw	0x03
	movwf	OSCCON			;Loads internal 31.25kHz clock
	clrf	ANSEL			;Clears default analog inputs and allows for digital I/O on analog pins
	bcf	STATUS, RP0		;Moves back to bank 0 for execution

	movlw	b'00000111'
	movwf	CMCON0			;Turns analog comparators off and allows for digital I/O on all pins


;......................................................................................................................
;.......................................................................................................................


;READ Register from Kionix KXTJ9 accelerometer -- WHO_AM_I Register located at 0x0F

	call	Wait_Startup	;Startup delay 

	call	Start_Command	;Start Command
	call	SAD_W			;Address Slave plus write
	call	ACK				;Get Acknowledge from slave
	call	SendStop



	bsf		PORTC, 3		;TEST -- If program recieves ACK, set RC3 and loop forever
done
	goto	done

;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;Sub Routines for PIC

Send_i2c_Byte
	movwf	i2c_transmit_byte
	movlw	0x08	
	movwf	i2c_bit_counter
Send_i2c_Bit				
	call	Set_SCL_Low
	rlf	i2c_transmit_byte, f	;note MSB first	
	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
	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	
	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
	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
	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
	return	

;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;Delays
Clock_Pulse_Delay
	movlw	0xFF
	movwf	pw_counter
Clock_Pulse_Delay_Wait
	nop
	decfsz	pw_counter, f
	goto	Clock_Pulse_Delay_Wait
	return

Wait_Startup
	movlw	0x0F		
	movwf	WDTCON
	sleep
	movlw 	0x00
	movwf	WDTCON			;Sleeps for 1:4096 ratio of instruction cycle 
	return	

;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;i2c routines

Start_Command
	call	Clock_Pulse_Delay
;;;;;	call	Set_SCL_Low		;don't know why this was here but it will cause a spurious clock pulse
	call	Set_SDA_High		;ensure both are initially high
	call	Set_SCL_High
	call	Set_SDA_Low		;start signal
	call	Clock_Pulse_Delay			;(S) - Sets SDA low while SCL is high
	return
;----------------------------------
SAD_W
	movlw	0x1C
;	movlw	0x38
	call	Send_i2c_Byte	; Slave Address plus write.
	call	Clock_Pulse_Delay
	return
;----------------------------------
ACK
	call	Set_SCL_High		;must change clock first
	call	Set_SDA_High
stretched
	btfss	I2C_PORT,SCL		;wait for slave
	goto	stretched		;to release clock line
	bsf	PORTC, 4
	call	Clock_Pulse_Delay
	bcf	STATUS,C
	btfsc	I2C_PORT, SDA
	return				;return carry clear if NACK
	bsf	STATUS,C		;carry set for ACK
	bcf	PORTC, 4		;turn on LED?
;;;;;;;;call	Set_SCL_Low	;don't change anything here
	return
;-----------------------------------

SendStop
	call	Set_SCL_High
	call	Set_SDA_High
	call	Clock_Pulse_Delay
	call	Set_SCK_Low
	call	Clock_Pulse_Delay
	call	Set_SDA_Low
	return

	end
Note how I'm careful to only change the pins when necessary. Even setting them to output at the start will send a spurious clock pulse that will mess up the communication.

The ACK routine now returns with the carry indicating if an ACK or NACK was received and I added a stop routine.

All the above is not tested as I don't have the hardware but hopefully it's correct now.

Mike.
 
Wow Thank you very much Mike. Ill see if I can make it work with your changes. Ill look into getting another i2c sensor in the mean time.

I got the slave address from page 12 of the KXTJ2 datasheet. It is in the first paragraph.

Thank you again!
Steve
 
I got the slave address from page 12 of the KXTJ2 datasheet. It is in the first paragraph.
Found it and see that you need to have pin ADDR tied high for 0x1c or low for 0c18. Do you have it tied high?

Mike.
 
Hi mike. from the datasheet it says 0x1c for write and 0x1d for read.. I have the addr bit tied to ground. i believe im teceiving the ack now, i am trying to read the who_am_i register and am now having an issue with receiving.

is there any major differences in sending or receiving bytes? thanks again, much of help.
 
Hi mike. from the datasheet it says 0x1c for write and 0x1d for read.. I have the addr bit tied to ground. i believe im teceiving the ack now, i am trying to read the who_am_i register and am now having an issue with receiving.

is there any major differences in sending or receiving bytes? thanks again, much of help.
 
Hi Steve,

Yes, I misread the data sheet and it 0x1c with ADDR tied low.

To read the who am I register you would do the following,
Code:
		call	Start_Command
		movlw	0x1c
		call	Send_i2c_Byte
		movlw	0x0f
		call	Send_i2c_Byte
		call	ACK
		call	SendStop
		call	Start_Command
		movlw	0x1d
		call	Send_i2c_Byte
		call	ACK
		call	I2cReceiveByte
		call	I2cSendNack
		call	SendStop


I2cReceiveByte	clrf	I2cData
		bsf	I2cData,0	;will cause C when 8 bits received
ReceiveLoop	call	Set_SCL_High	;release clock
		call	Set_SDA_High	;release the data line
		call	Clock_Pulse_Delay
		bcf	STATUS,C
		call	Set_SCL_Low
		btfsc	I2C_PORT,SDA	;read port 
		bsf	STATUS,C	;move bit into carry
		rlf	I2cData,F	;move C into data
		call	Clock_Pulse_Delay
		btfss	STATUS,C	;Have we finished
		goto	ReceiveLoop	;no
		movfw	I2cData		;Return Received byte in W
		return

I2cSendNack	call	Set_SCL_High
		call	Clock_Pulse_Delay
		call	Set_SDA_Low
		call	Set_SCL_Low
		call	Clock_Pulse_Delay
		return
HTH

Mike.
 
Last edited:
Thank again mike, Why would I need to send a "Stop" then "Start" for the repeated start command? I thought the second start command took place of the stop?


Steve
 
I'm just going off some code that I wrote that I know works. When you get it working try removing the stop and let us know what happens.

Mike.
 
You wrote in your first post "SCL and SDA lines are pulled high with a 2.1kohm resistor"

My recollection of i2c is that it needs open collector (or open drain) transistors so it can do a "wired OR".

I'm not familiar with the PIC16F688, however, the PICs I have used, eg. 16F84, 16F88, 16F628, 16F877, etc. only have one i/o that has an open drain, RA4.

Therefore, if the 16F688 is the same, then the i/o will be driving at least one of the lines High when that i/o is set & therefore not letting the "wired OR" operate as it should.
 
Last edited:
Hi Len,

When driving an I²C bus with a pic pin you make it behave like an open collector by switching it to input. So the two conditions are output+low or input and held high by the pullup.

Mike.
 
Last edited:
Hi Mike; I'm at the point where I am trying to read the register _WHO_AM_I and transmit is via RS232 to Hypertermial. I know this portion of the code works perfectly, Ive used it many times before. I am able to watch on an oscilliscope the SCL and SDA pulses all the way up to when I should see the slave transmit the data (which for the WHO_AM_I should be 0x06). I do not see the SDA line or CLK line doing anything at this point. Which makes me believe maybe there is still something wrong with the slave addressing and ACK?

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     _INTRC_OSC_CLKOUT & _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
	ACK_counter
	i2c_flags
	Received_I2C_Byte
	transmit_byte_rs232
	bit_counter_rs232
	delay_counter
;	bit_delay
	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		;Sets bit RP0 in address STATUS to 1 (switches from bank 0 to 1).
 	movlw 	b'00000011'		 
 	movwf 	TRISC			;Assigns SDA and SCL Inputs.
 	movlw	b'00000000'		
	movwf	TRISA			;Assigns all TRISA as outputs. Note - RA2 must be bi-directional. Default is output. 
	movlw	0x03
	movwf	OSCCON			;Loads internal 31.25kHz clock
	clrf	ANSEL			;Clears default analog inputs and allows for digital I/O on analog pins
	bcf		STATUS, RP0		;Moves back to bank 0 for execution

	movlw	b'00000111'
	movwf	CMCON0			;Turns analog comparators off and allows for digital I/O on all pins


;......................................................................................................................
;.......................................................................................................................


;READ Register from Kionix KXTJ9 accelerometer -- WHO_AM_I Register located at 0x0F

	call	Wait_Startup	;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	Stop_Command
	call	Start_Command
	call	SAD_R
	call	ACK
	call	Receive_i2c_Byte
	call	NACK
	call	Stop_Command

	movf	Received_I2C_Byte, w
	call	Transmit_RS232

;TEST
	bsf		PORTC, 3
done
	goto	done

	goto	START_PROGRAM


;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;Sub Routines for PIC

Send_i2c_Byte
	movwf	i2c_transmit_byte
	movlw	0x08	
	movwf	i2c_bit_counter
Send_i2c_Bit
	call	Set_SCL_Low
	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
	return

;-------------------------------------

Receive_i2c_Byte
	clrf	Received_I2C_Byte
	movlw	0x08
	movwf	i2c_bit_counter
Get_i2c_Bit
	call	Set_SCL_High
	call	Set_SDA_High				;Release CLK and DAT 
	call	Clock_Pulse_Delay
	bcf		STATUS, C					
	call	Set_SCL_Low	
	btfsc	I2C_PORT, SDA				;Read port
	bsf		STATUS, C					;Move bit into carry
	rlf		Received_I2C_Byte, f		;move carry into data
;	call	Clock_Pulse_Delay

	decfsz	i2c_bit_counter, f
	goto	Get_i2c_Bit					;No

;Test
;	movlw	0x06
;	movwf	Received_I2C_Byte

	movf	Received_I2C_Byte, w			;Yes, move Received_I2C_Byte into w
	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	
	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
	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
	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
	return	

;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;Delays
Clock_Pulse_Delay
	movlw	0xFF
	movwf	pw_counter
Clock_Pulse_Delay_Wait
	nop
	movlw	0x03
	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

Wait_Startup
	movlw	0x0F		
	movwf	WDTCON
	sleep
	movlw 	0x00
	movwf	WDTCON			;Sleeps for 1:4096 ratio of instruction cycle 
	return	

;---------------------------------------------------------------------------------------
;---------------------------------------------------------------------------------------
;i2c routines

Start_Command
	call	Clock_Pulse_Delay
	call	Set_SDA_High
	call	Set_SCL_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	0x1C
	call	Send_i2c_Byte				; Slave Address plus write.
	call	Clock_Pulse_Delay
	return
;----------------------------------
SAD_R
	movlw	0x1D
	call	Send_i2c_Byte				; Slave Address plus write.
	call	Clock_Pulse_Delay
	return
;----------------------------------

ACK
	call	Set_SDA_High
	call	Set_SCL_High
Clock_Stretch
	btfss	I2C_PORT, SCL
	goto	Clock_Stretch		;Wait for slave to release clock line
	call	Clock_Pulse_Delay
	bcf		STATUS, C
	btfsc	I2C_PORT, SDA
	return						;Return Carry, clear if NACK
	bsf		STATUS, C			;Set carry for ACK	
	return

NACK
	call	Set_SCL_High
	call	Clock_Pulse_Delay
	call	Set_SCL_Low
	call	Set_SDA_Low
	call	Clock_Pulse_Delay
	return
;-----------------------------------
Stop_Command
	call	Set_SCL_High
	call	Set_SDA_High
	call	Clock_Pulse_Delay
	call	Set_SCL_Low
	call	Clock_Pulse_Delay
	call	Set_SDA_Low
	return
	

Who_Am_I_Reg
	movlw	0x0F
	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
	bcf		STATUS, RP0

	call	Clock_Pulse_Delay
	call	Clock_Pulse_Delay
	call	Clock_Pulse_Delay

	bcf		PORTA, 5
	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		PORTA, 5
	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		PORTA, 5
	btfsc	STATUS,  C
	bcf		PORTA, 5
	call	bit_delay
	decfsz	bit_counter_rs232, f		;Tests if all done
	goto	Send_Serial_Loop_RS232
	bcf		PORTA, 5 ;Is this needed to keep the line high??
	call	bit_delay
;	clrf	transmit_byte_rs232
	return

	end
{/code]
 
Hi Len,

When driving an I²C bus with a pic pin you make it behave like an open collector by switching it to input. So the two conditions are output+low or input and held high by the pullup.

Mike.
Thanks Mike, I had not thought of that.
 
You're not testing to see if you got a ACK or NACK. If you're not getting an ACK then something is wrong and there is no point trying anything further until that is working. Are you remembering to power down the circuit between attempts as once the bus gets out of sync it needs to be reset.

Mike.
 
I have not been powering down, I was sidetracked from that....So If I do not recieve an ACK after so many attempts (say 10?) then I should power down re-sync as your earlier post described?

Also, to check for ACK or NACK, this should be done before I send the Register Address of interest (in my example is WHO_AM_I)? And if the carry flag is clear then I should not move forward, correct?

Thanks Again
Steve
 
You only need to check for an ACK once. If it's not received then something is wrong. Have you double checked your wiring of the chip? I notice there are 4 pins that need connecting to Vdd.

Mike.
 
Status
Not open for further replies.

Latest threads

Back
Top