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.

I²C Send Byte problem with PIC

Status
Not open for further replies.

hantto

Member
Hello! I have written my own I²C routines. They all work except the send byte routine. I have looked it over and over and over again, but I can't see the flaw. If I replace it with a cruder routine (which takes more space) it works fine.

Here's the code:
Code:
I2C_Send_Byte	movwf	I2C_Temp		;Move W to Temp
		movlw	d'8'			;Move 8 to W
		movwf	I2C_Count		;Move W to Counter
		call	I2C_SDA_Output		;Set SDA as Output
I2C_Send_Bit	bcf	I2C_SDA			;SDA Low
		rlf	I2C_Temp,	f	;Rotate Temp trough carry
		btfsc	status,	c		;Test carry
		bsf	I2C_SDA			;If set, set SDA High
		call	I2C_Pulse_SCL		;Pulse SCL (~10µS total time)
		decfsz	I2C_Count,	f	;Decrease counter
		goto	I2C_Send_Bit		;Do next bit
		return				;Quit if done (if counter = 0)

Can you see something wrong with it? If you need aditional info about the called routines in the code, please let me know.

Sincerely Hantto
 
No ideas what so ever?

Or maybe there is no fault here, because I think someone would already have given me input if they soptted a fault. I will look for the fault elsewhere in the code.
 
i dont know anything about assembly and i use C for PIC, so i cant suggest anything to your program. i also have problems before with I2C protocol driving for an EEPROM device. I did a whole day debugging, but nothing happened.

It worked when I remembered that SCL and SDA lines require pull-up resistors in order for I2C to work properly. :shock:
 
GraveYard_Killer said:
It worked when I remembered that SCL and SDA lines require pull-up resistors in order for I2C to work properly. :shock:

Actually, for a single master system (the majority of I2C systems!) you don't really NEED a pullup on the SCL, only the SDA - although it's good practice to fit them both anyway. The reason for the pullups is that I2C is an open-collector bus, and you release the bus to let other devices take it over - but in a single master system only the master ever drives the SCL line.
 
[quote="Nigel GoodwinActually, for a single master system (the majority of I2C systems!) you don't really NEED a pullup on the SCL, only the SDA - although it's good practice to fit them both anyway. The reason for the pullups is that I2C is an open-collector bus, and you release the bus to let other devices take it over - but in a single master system only the master ever drives the SCL line.[/quote]

I thought that the I2C protocol requires both SCL and SDA to be open collector and therefore require a pullup resistor. Just had a quick look at the 16F876 data sheet and Microchip state that both require pullups.

HTH

Mike.
 
Pommie said:
[quote="Nigel GoodwinActually, for a single master system (the majority of I2C systems!) you don't really NEED a pullup on the SCL, only the SDA - although it's good practice to fit them both anyway. The reason for the pullups is that I2C is an open-collector bus, and you release the bus to let other devices take it over - but in a single master system only the master ever drives the SCL line.

I thought that the I2C protocol requires both SCL and SDA to be open collector and therefore require a pullup resistor. Just had a quick look at the 16F876 data sheet and Microchip state that both require pullups.
[/quote]

As I explained above, for a single master system it's not really required, as ONLY the master controls the SCL line - for a multiple master system you MUST have a pullup on the SCL though, as any of the masters can control the SCL line. In all cases, you MUST have a pullup on the SDA line.

As I also mentioned above, it's good practice to include both pullups though!.
 
Even with a single master the pullup is still required as the outputs are open collector i.e. the collectors of the output transistors are not connected to anything. If you don't have a pull up resistor then you can never get a high signal.

If however, the protocol is implemented in software with a normal output pin then no pullup is required as the pin will drive the clock line high. The hardware implementation in the pics is open collector and so does require pullups.

Mike.
 
Pommie said:
Even with a single master the pullup is still required as the outputs are open collector i.e. the collectors of the output transistors are not connected to anything. If you don't have a pull up resistor then you can never get a high signal.

If however, the protocol is implemented in software with a normal output pin then no pullup is required as the pin will drive the clock line high. The hardware implementation in the pics is open collector and so does require pullups.

Quite true - but the thread was started about software routines.

Also, obviously, you can implement open-collector style in software routines as well (if you wanted to), as you already have to do for the SDA line.
 
Also, obviously, you can implement open-collector style in software routines as well (if you wanted to), as you already have to do for the SDA line.

I don't know this method, how do you implement open collector in software?

Mike.
 
Pommie said:
Also, obviously, you can implement open-collector style in software routines as well (if you wanted to), as you already have to do for the SDA line.

I don't know this method, how do you implement open collector in software?

Same as you do it for SDA, you alter TRIS to make the pin an input - in fact (if I remember correctly?) my tutorials do this all the time - you never actual switch the polarity of the output pin, you leave it permanently LOW - then use TRIS to switch between INPUT (HIGH) and OUTPUT (LOW). I can't claim any originality for the idea, I stole it :lol:

It's not a 'true' open collector output (in that you can't connect it to a higher voltage, but then you probably can't on normal I2C either?), but it works exactly the same.
 
ARGH! I have wrestled with the code for some time now with no results whatsoever. Could someone please take a look at the I²C routines? I've tried to replace my send byte with Nigel's I²C send, but with no result. Thus I think that the problem is elswhere, but WERE?

The strange thing is if i replace the I2C_Send_Byte with this
Code:
I2C_SEND:

	movwf I2C_TEMP		;I2C send 8 bits of working register (W)
				;to the bus.
	bsf STATUS,RP0
	bcf I2C_SDA
	bcf STATUS,RP0

	bcf I2C_SDA
	btfsc I2C_TEMP,7
	bsf I2C_SDA
	bsf I2C_SCL
	call I2C_DELAY
	bcf I2C_SCL
	
	bcf I2C_SDA
	btfsc I2C_TEMP,6
	bsf I2C_SDA
	bsf I2C_SCL
	call I2C_DELAY
	bcf I2C_SCL

	bcf I2C_SDA
	btfsc I2C_TEMP,5
	bsf I2C_SDA
	bsf I2C_SCL
	call I2C_DELAY
	bcf I2C_SCL

	bcf I2C_SDA
	btfsc I2C_TEMP,4
	bsf I2C_SDA
	bsf I2C_SCL
	call I2C_DELAY
	bcf I2C_SCL

	bcf I2C_SDA
	btfsc I2C_TEMP,3
	bsf I2C_SDA
	bsf I2C_SCL
	call I2C_DELAY
	bcf I2C_SCL

	bcf I2C_SDA
	btfsc I2C_TEMP,2
	bsf I2C_SDA
	bsf I2C_SCL
	call I2C_DELAY
	bcf I2C_SCL

	bcf I2C_SDA
	btfsc I2C_TEMP,1
	bsf I2C_SDA
	bsf I2C_SCL
	call I2C_DELAY
	bcf I2C_SCL

	bcf I2C_SDA
	btfsc I2C_TEMP,0
	bsf I2C_SDA
	bsf I2C_SCL
	call I2C_DELAY
	bcf I2C_SCL

	return

it works.

The code is supposed to set up the temperature sensor, read it and display it on a LCD. I get only the result 255 with my code, which naturally means that the sensor isn't responding because it hasn't received the commands which are supposed to be sent by the I2C_Send_Byte or someting.

If someone could take a look at my code I would be grateful. I think i have structured the code to look cuite nice, so I hope there will be no trouble understanding what i'm trying to do :)
 

Attachments

  • temperature.txt
    16.9 KB · Views: 283
It's probably a timing issue. The last version where you've unrolled the loop runs much faster. If the bit is 1 you are only pulling I2C_SDA low for 2 cycles, compared to 3 cycles for the loop version. That's a difference of 50%, which is huge in the scheme of things.

Also the loop version calls I2C_Pulse_SCL which takes much, much longer (at least a dozen cycles) than your unrolled version, which pulses SCL inline without the subroutine or delay calls.

So I would guess the difference is in timing. Make your loop version run at the same speed as (or at least closer to) the unrolled version and see if it works.

Dan East
 
Thank you very much for your reply Dan East.

I got it to work with this code
Code:
I2C_Send_Byte	movwf	I2C_Temp		;Move W to Temp
		movlw	d'8'			;Move 8 to W
		movwf	I2C_Count		;Move W to Counter
		call	I2C_SDA_Output		;Set SDA as Output
		bcf	I2C_SCL			;SCL Low
I2C_Send_Bit	bcf	I2C_SDA			;SDA Low
		rlf	I2C_Temp,	f	;Rotate Temp trough carry
		btfsc	status,	c		;Test carry
		bsf	I2C_SDA			;If set, set SDA High
		call	I2C_Delay		;Wait 2.4µS
		bsf	I2C_SCL			;Set SCL High
		call	I2C_Delay		;Wait 2.4µS
		call	I2C_Delay		;Wait aditional2.4µS
		bcf	I2C_SCL			;Set SCL Low
		call	I2C_Delay		;Wait 2.4µS
		decfsz	I2C_Count,	f	;Decrease counter
		goto	I2C_Send_Bit		;Do next bit
		return

What I did was that I don't call the I2C_Pulse_SCL routine, but do it directly it in the loop.

I find this very strange, the jump to there and back only takes 0.8µS longer I doubt that that could have been the problem. Maybe stack overflow? I would be very intrested in hearing your comments about this. (NIGEEEL!!!! :D)

Btw, how can I check if a stack owerflow happens?
 
hantto said:
Btw, how can I check if a stack owerflow happens?

There's nothing to indicate a stack overflow on a pic, But it should be easy to check for yourself. The pic's stack is 8 levels deep. Just check your code and see how deep it goes (including interrupts !).
 
hantto said:
I find this very strange, the jump to there and back only takes 0.8µS longer I doubt that that could have been the problem. Maybe stack overflow? I would be very intrested in hearing your comments about this. (NIGEEEL!!!! :D)

Btw, how can I check if a stack owerflow happens?

As already suggested, simply count your stack usage - you should also be VERY careful with interrupt routines, if you are already using all of your stack space and an interrupt is called then the stack will obviously overflow.

It's also a very good idea NOT to call subroutines from within an interrupt routine for the same reason, it limits the stack depth available to your main program.
 
Once again I have a question.

I did some counting and according to my stack level tracing the program only goes as deep as to level 4. So there was no stack overflow.

I'm curious about what could have caused the problem, in order to avoid it in the future. Any theories? I do not use interrupts (yet).
 
Take a careful look at the I2C_Pulse_SCL subroutine. If I am not completely mistaken there is a small typing error in 3rd last line of a subroutine.

Line: bcf I2C_SDA ; SCL Low
Command and comment don't match. Instead of resetting clock signal, data line is resetted.
 
PICcie said:
Take a careful look at the I2C_Pulse_SCL subroutine. If I am not completely mistaken there is a small typing error in 3rd last line of a subroutine.

Line: bcf I2C_SDA ; SCL Low
Command and comment don't match. Instead of resetting clock signal, data line is resetted.

How about that :D It was al along just a small typo. Thank you VERY much PICcie. :)
 
i2c

you dont say what pic you are using ?

this line
goto I2C_Send_Bit ;Do next bit

shouldnt it be next I2C_Send_byte

phill
 
Status
Not open for further replies.

Latest threads

Back
Top