AVR assembly I2C xmit any port, any chip

Go To Last Post
97 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I2C Program

/*
This program runs 8 bit AVRs in assembly for sending I2C info using any chip, any port.
The ';nop' instructions are for running above 400khz clock freq 8Mhz/8 fuse. If you run this program at 400kHz or less you can eliminate the ';nop' instructions.(see first listing)
A 10 to 100k pull up is required on the SDA port only as the clock is mastered only and no receive clock timing is expected. 
No int. is required.
The routine runs DACs, digital pots, etc. very well.
This  routine is shown working with Analog's digital pots (AD5282 for example)

r17 = toggle used to write both instruction digits of pot, can be eliminated in some apps.
r18 = toggle to write both pots
r19 = data to go out to slave
r20 = 8 bit counter

PB2 = SCL
PB3 = SDA

*clr regs if used for other program apps

;**USE THIS FOR <400KHZ CLOCK FREQ.

StartI2C:

	;I2C start condition

	cli	;***Important to stop I2C corruption***		

	ldi	temp,0b01111100	;PortB,2,3 output
	out	DDRB,temp		;*needed after failed ACK*
	sbi	PortB,2		;clk hi
	sbi	PortB,3		;data hi
	cbi	PortB,3		;data low
	cbi	PortB,2		;end start

	;Address byte
Addr:
	ldi	temp,$58		;*load any address here you need for your app
	rcall	Loop		;Port4 Clk  (SLA)

	;Instruction byte
Instr:
	inc	r17		;toggle reg
	sbrs	r17,0
	ldi	temp,$00
	sbrc	r17,0
	ldi	temp,$80
	rcall	Loop	

	;Data byte
Data:
	mov	temp,r20
	sbic	PinC,5		;mute function
	clr	temp		;mute
	rcall	Loop		
Stop:
	cbi	PortB,2			;*needed after failed ack*
	ldi	temp,0b01111100	;PortB,2,3 output
	out	DDRB,temp		;*needed after failed ACK*			
	sbi	PortB,2		;clk hi
	sbi	PortB,3
	cbi	PortB,3
	cbi	PortB,2
	inc	r18
	sbrc	r18,0		;toggle bit set? Both pots set?
	rjmp	StartI2C
	ret
Loop:
	mov	r19,temp		;I^2 reg value to go out
Resume:
	andi	r19,0b10000000
	sbrc	r19,7
	sbi	PortB,3			;data (SDA)   PB3 data bit hi
	sbrs	r19,7
	cbi	PortB,3			;data bit low
	sbi	PortB,2			;set CLK (SCL)  PB4
	cbi	PortB,2			;clr clk
	cbi	PortB,3			;clr data
	lsl	temp			;get ready for the next bit test	
	mov	r19,temp		;reload shifted reg
	inc	r20
	sbrs	r20,3			;done?
	rjmp	Resume
	clr	r20
ACK:
	ldi	temp,0b01110100	
	out	DDRB,temp		;PortB,3 (SDA) input
	sbi	PortB,2			;set clk hi
	sbi	PortB,3			;data hi, waiting for ack to pull low
		;wait for ACK		****USE DATA PORT PULL UP**** 10 to 100k ****
ACKwait:		
	sbic	PinB,3			;ACK from Slave?	
	rjmp	Stop			;No ACK end I2C
	ldi	temp,0b01111100	;PortB,2,3 output
	out	DDRB,temp
	cbi	PortB,3			;clr Data
	cbi	PortB,2			;clr clock
	ret

;********************************************************8
;***USE THIS for 1mHZ CLOCK FREQ**


.def temp = r16

StartI2C:

	;I2C start condition

	cli	;***Important to stop I2C corruption***		

	ldi	temp,0b01111100	;PortB,2,3 output
	out	DDRB,temp		;*needed after failed ACK*
	sbi	PortB,2		;clk hi
	;nop
	;nop
	sbi	PortB,3		;data hi
	;nop
	;nop
	cbi	PortB,3		;data low
	;nop
	;nop
	cbi	PortB,2		;end start

	;Address byte
Addr:
	ldi	temp,$58		;*load any address here you need for your app
	rcall	Loop		;Port4 Clk  (SLA)

	;Instruction byte
Instr:
	inc	r17		;toggle reg
	sbrs	r17,0
	ldi	temp,$00
	sbrc	r17,0
	ldi	temp,$80
	rcall	Loop	

	;Data byte
Data:
	mov	temp,r20
	sbic	PinC,5		;mute function
	clr	temp		;mute
	rcall	Loop		
Stop:
	cbi	PortB,2			;*needed after failed ack*
	ldi	temp,0b01111100	;PortB,2,3 output
	out	DDRB,temp		;*needed after failed ACK*			
	sbi	PortB,2		;clk hi
	;nop
	;nop
	sbi	PortB,3
	;nop
	;nop
	cbi	PortB,3
	;nop
	;nop
	cbi	PortB,2
	inc	r18
	sbrc	r18,0		;toggle bit set? Both pots set?
	rjmp	StartI2C
	ret
Loop:
	mov	r19,temp		;I^2 reg value to go out
Resume:
	andi	r19,0b10000000
	sbrc	r19,7
	sbi	PortB,3			;data (SDA)   PB3 data bit hi
	sbrs	r19,7
	cbi	PortB,3			;data bit low
	;nop
	;nop
	sbi	PortB,2			;set CLK (SCL)  PB4
	;nop
	;nop
	cbi	PortB,2			;clr clk
	;nop
	;nop
	cbi	PortB,3			;clr data
	lsl	temp			;get ready for the next bit test	
	mov	r19,temp		;reload shifted reg
	inc	r20
	sbrs	r20,3			;done?
	rjmp	Resume
	clr	r20
ACK:
	ldi	temp,0b01110100	
	out	DDRB,temp		;PortB,3 (SDA) input
	sbi	PortB,2			;set clk hi
	sbi	PortB,3			;data hi, waiting for ack to pull low
	;nop
		;wait for ACK		****USE DATA PORT PULL UP**** 10 to 100k ****
ACKwait:
	;nop		
	sbic	PinB,3			;ACK from Slave?	
	rjmp	Stop			;No ACK end I2C
	ldi	temp,0b01111100	;PortB,2,3 output
	out	DDRB,temp
	cbi	PortB,3			;clr Data
	;nop
	;nop
	cbi	PortB,2			;clr clock
	ret

		:*END*
/*
***************************************************************
----------------------------------------------------------------------------------
*/

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Nice. Is it on github or google code?
You could improve it by having a single version of the code with a conditionally compiled rcall to a delay loop, with the number of delay loop cycles determined by cpu frequency (i.e. #define F_CPU 8000000).

I have no special talents.  I am only passionately curious. - Albert Einstein

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your I2C is seriously wrong. You should never drive the SDA line high. And you should not really drive SCL high either.

Look at AVR156 or Fleury "i2cmaster.S" to see how to do the job properly.

Many other correct implementations are out there.

DAvid.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Your I2C is seriously wrong. You should never drive the SDA line high. And you should not really drive SCL high either.

Look at AVR156 or Fleury "i2cmaster.S" to see how to do the job properly.

Many other correct implementations are out there.

DAvid.

Driving the CLK when you are not using the I2C for receiving data from the peripheral device is not a problem, in fact you get faster control. Driving the SDA is not a problem either in this configuration. The only time the SDA direction is not set to 'out' is when the master is looking for an 'ack'. no harm to the peripheral is done on either port just as long as you don't exceed the input voltage of the external device. This is a write application, not a read. In reading apps I would set port direction to input.

I din't see other apps, please direct me to a couple of the "several" you mention.

Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ralphd wrote:
Nice. Is it on github or google code?
You could improve it by having a single version of the code with a conditionally compiled rcall to a delay loop, with the number of delay loop cycles determined by cpu frequency (i.e. #define F_CPU 8000000).

It is only a single version, I cut and past the one I need for the AVR clock speed.

Delay loops use more instructions. You can use one if you want but usually I run at either 1 Meg (8meg/8) or an internal 128k osc on my digital pot apps.

Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Driving SCL high will cause problems with slave clock stretching.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Driving the CLK when you are not using the I2C for receiving data from the peripheral device is not a problem, in fact you get faster control. Driving the SDA is not a problem either in this configuration.

It is against the I2C spec.

Yes, driving SCL is ok in a Single-Master bus. It is not allowed on a Multi-Master bus.

Any I2C Slave can and often does write to the bus. Think about every ACK. Or any READ operation.

It is simple enough to use 'Open-Drain' rather than "Push-Pull" output on an AVR or any MCU. This ensures that you don't damage either Master or Slave by conflicting outputs.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Yes, driving SCL is ok in a Single-Master bus.

No, it isn't. If the slave device implements clock stretching there will be contention.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
Driving SCL high will cause problems with slave clock stretching.

I disagree.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Quote:
Driving the CLK when you are not using the I2C for receiving data from the peripheral device is not a problem, in fact you get faster control. Driving the SDA is not a problem either in this configuration.

It is against the I2C spec.

Yes, driving SCL is ok in a Single-Master bus. It is not allowed on a Multi-Master bus.

Any I2C Slave can and often does write to the bus. Think about every ACK. Or any READ operation.

It is simple enough to use 'Open-Drain' rather than "Push-Pull" output on an AVR or any MCU. This ensures that you don't damage either Master or Slave by conflicting outputs.

David.

You don't get an ACK from a device that's not addressed. When this program waits for an ACK the port is open drain.
Once again, this is a WRITE algorithm.

I have yet to destroy a port or an external device.

Where are the "several" programs you want me to see?

Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I disagree.

OK.
You win.

You may never have to worry about clock stretching, but why not just do it properly?

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would have the same view. i.e. just implement the spec properly. It costs nothing!

The title of the thread was interesting.
Fleury "i2cmaster.S" requires some reader effort to use with any AVR at any clock speed.
The "twimaster.c" just works painlessly.

So a "universal" ASM file that copes with F_CPU, Tiny, Mega, Xmega would be nice to see.
Especially if it copes with the spec properly.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
Quote:
I disagree.

OK.
You win.

You may never have to worry about clock stretching, but why not just do it properly?

Speed.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
I would have the same view. i.e. just implement the spec properly. It costs nothing!

The title of the thread was interesting.
Fleury "i2cmaster.S" requires some reader effort to use with any AVR at any clock speed.
The "twimaster.c" just works painlessly.

So a "universal" ASM file that copes with F_CPU, Tiny, Mega, Xmega would be nice to see.
Especially if it copes with the spec properly.

David.

OK, so you don't have "several" ASM's then?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Even at 400KHz, speed should not be much of an issue! I would rather see standard compliance than the last nanosecond of speed.

Jim

 

Until Black Lives Matter, we do not have "All Lives Matter"!

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
RobDD Please see https://www.avrfreaks.net/index.p...

OK, thanks for the tip!

Here's the code with open drain for those of you 'unsettled' by driven outputs. Again, delete the "nops" for <400khz; you can simply add more "nops" as the freq. goes up.

Rob

; use 4.7k pull up resistors on SDA and SCL
;I2C Program
StartI2C:
	;I2C start condition

	cli	;***Important to stop I2C corruption		

	ldi	temp2,0b01110000	;PortB,2,3 output
	out	DDRB,temp2		;*needed after failed ACK*
	sbi	PortB,2		;clk hi
	nop
	nop
	sbi	PortB,3		;data hi
	nop
	nop
	cbi	PortB,3		;data low
	nop
	nop
	cbi	PortB,2		;end start

	;Address byte
Addr:
	ldi	temp2,$58	;B01011000
	rcall	Loop		;Port4 Clk  (SLA)

	;Instruction byte
Instr:
	inc	r17		;toggle reg
	sbrs	r17,0
	ldi	temp2,$00
	sbrc	r17,0
	ldi	temp2,$80
	rcall	Loop	

	;Data byte
Data:
	mov	temp2,r20
	sbic	PinC,5		;mute function
	clr	temp2		;mute
	rcall	Loop		
Stop:
	cbi	PortB,2			;*needed after failed ack*
	ldi	temp2,0b01110000	;PortB,2,3 output
	out	DDRB,temp2		;*needed after failed ACK*			
	sbi	PortB,2		;clk hi
	nop
	nop
	sbi	PortB,3
	nop
	nop
	cbi	PortB,3
	nop
	nop
	cbi	PortB,2
	inc	r27
	sbrc	r27,0		;toggle bit set? Both pots set?
	rjmp	StartI2C
	rcall	HexToBCD
	ret
Loop:
	mov	r21,temp2		;I^2 reg value to go out
Resume:
	andi	r21,$80
	sbrc	r21,7
	sbi	PortB,3			;data (SDA)   PB3 data bit hi
	sbrs	r21,7
	cbi	PortB,3			;data bit low
	nop
	nop
	sbi	PortB,2			;set CLK (SCL)  PB4
	nop
	nop
	cbi	PortB,2			;clr clk
	nop
	nop
	cbi	PortB,3			;clr data
	lsl	temp2			;get ready for the next bit test	
	mov	r21,temp2		;reload shifted reg
	inc	r23
	sbrs	r23,3			;done?
	rjmp	Resume
	clr	r23
ACK:
	ldi	temp2,0b01110000	
	out	DDRB,temp2		;PortB,3 (SDA) input
	sbi	PortB,2			;set clk hi
	sbi	PortB,3			;data hi, waiting for ack to pull low
	nop
		;wait for ACK		****USE DATA PORT PULL UP****
ACKwait:
	nop
	nop		
	sbic	PinB,3			;ACK from Slave?	
	rjmp	Stop			;No ACK end I2C
	ldi	temp2,0b01110000	;PortB,2,3 output
	out	DDRB,temp2
	cbi	PortB,3			;clr Data
	nop
	nop
	cbi	PortB,2			;clr clock
	ret
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
UNFORMATTED code is unreadble and people tend to stay away from these threads.

Rather absolute statements you make in that post. Personally I find function & variable naming, logic flow, etc. contribute far more to the readability of code.

I would agree if you re-wrote the post to say:
Formatting with [code] will help with the readability of your code.

I have no special talents.  I am only passionately curious. - Albert Einstein

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

By the way I guess you are aware of avr300 master and avr302 slave I2C application notes from Atmel, they have been around since about 1997. :wink:

I have used avr300 once for a project with a Tiny2313.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

RobDD wrote:
js wrote:
RobDD Please see https://www.avrfreaks.net/index.p...

OK, thanks for the tip!

Here's the code with open drain for those of you 'unsettled' by driven outputs. Again, delete the "nops" for <400khz; you can simply add more "nops" as the freq. goes up.

Rob

Since you have a lot of 2-cycle nops, I'd do something like the following (change as required if not using gcc):

#define nop2 rjmp +0

I have no special talents.  I am only passionately curious. - Albert Einstein

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I would agree if you re-wrote the post to say:
It's NOT my post, I have simply made it a sticky and it has been very helpful for some time.

Pity you weren't around earlier, you could have fixed all of our issues here :) (Bazinga...)

And just for the heck of it I don't agree with you.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Here's the code with open drain for those of you 'unsettled' by driven outputs.

I don't want your code. I've got perfectly good I2C routines that I wrote myself, that do the job properly. Why would I want your eforts?

:D

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
By the way I guess you are aware of avr300 master and avr302 slave I2C application notes from Atmel, they have been around since about 1997. :wink:

I have used avr300 once for a project with a Tiny2313.

Not any chip, any port. I use 13A's often, especially with digital pots.
Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
Quote:

Here's the code with open drain for those of you 'unsettled' by driven outputs.

I don't want your code. I've got perfectly good I2C routines that I wrote myself, that do the job properly. Why would I want your eforts?

:D

Right! You're the only one I'm addressing!

But let's see your code.

Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ralphd wrote:
RobDD wrote:
js wrote:
RobDD Please see https://www.avrfreaks.net/index.p...

OK, thanks for the tip!

Here's the code with open drain for those of you 'unsettled' by driven outputs. Again, delete the "nops" for <400khz; you can simply add more "nops" as the freq. goes up.

Rob

Since you have a lot of 2-cycle nops, I'd do something like the following (change as required if not using gcc):

#define nop2 rjmp +0

OK.

I originally wrote this code for a 13A at 128K internal osc.
for an AD5282 or AD5262?
What it does is writes one digital pot, then changes the add. to write the other pot in the chip.

here's the code closer to its original form with open drain,.

;I2C Program
StartI2C:
	;I2C start condition

	cli	;***Important to stop I2C corruption		

	ldi	temp2,0b01110000	;PortB,2,3 output
	out	DDRB,temp2		;*needed after failed ACK*
	sbi	PortB,2		;clk hi
	sbi	PortB,3		;data hi
	cbi	PortB,3		;data low
	cbi	PortB,2		;end start

	;Address byte
Addr:
	ldi	temp2,$58	;B01011000 load your address here
	rcall	Loop		;Port4 Clk  (SLA)

	;Instruction byte
Instr:
	inc	r17		;toggle reg
	sbrs	r17,0
	ldi	temp2,$00
	sbrc	r17,0
	ldi	temp2,$80
	rcall	Loop	

	;Data byte
Data:
	mov	temp2,r20
	sbic	PinC,5		;mute function
	clr	temp2		;mute
	rcall	Loop		
Stop:			
	sbi	PortB,2		;clk hi
	nop
	nop
	sbi	PortB,3
	nop
	nop
	cbi	PortB,3
	nop
	nop
	cbi	PortB,2
	inc	r27
	sbrc	r27,0		;toggle bit set? Both pots set?
	rjmp	StartI2C
	rcall	HexToBCD
	ret
Loop:
	mov	r21,temp2		;I^2 reg value to go out
Resume:
	andi	r21,$80
	sbrc	r21,7
	sbi	PortB,3			;data (SDA)   PB3 data bit hi
	sbrs	r21,7
	cbi	PortB,3			;data bit low
	sbi	PortB,2			;set CLK (SCL)  PB4
	cbi	PortB,2			;clr clk
	cbi	PortB,3			;clr data
	lsl	temp2			;get ready for the next bit test	
	mov	r21,temp2		;reload shifted reg
	inc	r23
	sbrs	r23,3			;done?
	rjmp	Resume
	clr	r23
ACK:	
	out	DDRB,temp2		;PortB,3 (SDA) input
	sbi	PortB,2			;set clk hi
	sbi	PortB,3			;data hi, waiting for ack to pull low
		;wait for ACK	
ACKwait:
	nop
	nop		
	sbic	PinB,3			;ACK from Slave?	
	rjmp	Stop			;No ACK end I2C
	out	DDRB,temp2
	cbi	PortB,3			;clr Data
	nop
	nop
	cbi	PortB,2			;clr clock
	ret

This should be pretty close, some of you, not J. Brown, might want to tweak it. (J. Brown wrote his own ASM code which I'm waiting to see)

Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Deleted some double posts, the forum goes crazy at times.

Quote:
Not any chip, any port
What stops anyone using AVR300 on any AVR and on any port? It was written for the AT90Sxx chips and it just worked with the T2313.
Quote:
;**** A P P L I C A T I O N N O T E A V R 3 0 0 ************************
;*
;* Title : I2C (Single) Master Implementation
;* Version : 1.0 (BETA)
;* Last updated : 97.08.27
;* Target : AT90Sxxxx (any AVR device)
;*

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Rob,

As I said earlier, a "universal" I2C bit-bang would be very useful. E.g. select SDA, SCL, F_CPU with #defines. Share a suitable API for your functions with respected TWI libraries.

You can create delay macros to cope with F_CPU.

Or even write the whole bit-bang in C. With a simple way to configure it.

I don't see that speed has any relevance at all. A 100kHz bus is 100kHz! There is no point in running it at 101kHz because it stops being 100kHz.

Obviously with an interrupt-driven TWI implementation, efficiency is relevant. You are probably doing multiple other tasks.

Note that most I2C hardware slave chips respond very promptly to a Master. Nowadays, many I2C 'devices' might have an AVR or M*crochip inside. They obey the I2C spec but there are often gaps in the ACK response. After all, there is a certain amount of interrupt latency.

If you really want me to post links to 'other' bit-bang code, I can do so. However, you can always Google them for yourself.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:
Rob,

As I said earlier, a "universal" I2C bit-bang would be very useful. E.g. select SDA, SCL, F_CPU with #defines. Share a suitable API for your functions with respected TWI libraries.

You can create delay macros to cope with F_CPU.

Or even write the whole bit-bang in C. With a simple way to configure it.

I don't see that speed has any relevance at all. A 100kHz bus is 100kHz! There is no point in running it at 101kHz because it stops being 100kHz.

Obviously with an interrupt-driven TWI implementation, efficiency is relevant. You are probably doing multiple other tasks.

Note that most I2C hardware slave chips respond very promptly to a Master. Nowadays, many I2C 'devices' might have an AVR or M*crochip inside. They obey the I2C spec but there are often gaps in the ACK response. After all, there is a certain amount of interrupt latency.

If you really want me to post links to 'other' bit-bang code, I can do so. However, you can always Google them for yourself.

David.

David,
You're right, I just ran the routine with the ports open and 4.7k to ground. I don't like the signal as much but it still runs pretty fast.

Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

David,
I take that back, I like the way my routine looks and works better. I guess I could tweak it to fit the 'standard' profile but I looked at the Ad5282. In low is right on the edge with 4.7k resistors running open drain at 540mV. Setting the ports as out gives me over 4 volts for hi level and, of course, 0 volts for low level. Less glitches running a 5 volt digital pot.

Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
Deleted some double posts, the forum goes crazy at times.
Quote:
Not any chip, any port
What stops anyone using AVR300 on any AVR and on any port? It was written for the AT90Sxx chips and it just worked with the T2313.
Quote:
;**** A P P L I C A T I O N N O T E A V R 3 0 0 ************************
;*
;* Title : I2C (Single) Master Implementation
;* Version : 1.0 (BETA)
;* Last updated : 97.08.27
;* Target : AT90Sxxxx (any AVR device)
;*

John,
Good point, I wasn't aware the app. was universal. I'll look into it further but right now my routine works so well in my design that I think I'll leave well enough alone.

Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I never offered code. I was simply trying to be helpful, and point you in the right direction.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
I never offered code. I was simply trying to be helpful, and point you in the right direction.

A couple of other people did that...... a lot more diplomatically.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

RobDD wrote:
David,
I take that back, I like the way my routine looks and works better. I guess I could tweak it to fit the 'standard' profile but I looked at the Ad5282. In low is right on the edge with 4.7k resistors running open drain at 540mV. Setting the ports as out gives me over 4 volts for hi level and, of course, 0 volts for low level. Less glitches running a 5 volt digital pot.

Rob

David, here's open drain with 10k pull down, compare it to original scope image.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

RobDD wrote:
RobDD wrote:
David,
I take that back, I like the way my routine looks and works better. I guess I could tweak it to fit the 'standard' profile but I looked at the Ad5282. In low is right on the edge with 4.7k resistors running open drain at 540mV. Setting the ports as out gives me over 4 volts for hi level and, of course, 0 volts for low level. Less glitches running a 5 volt digital pot.

Rob

David, here's open drain with 10k pull down, compare it to original scope image.

Here's a better view of the driven CLK port.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Pull down?
Maybe that's your problem.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And please tell me where I was undiplomatic. I merely pointed out that clock stretching by slave devices wouldn't work with a driven high scl. Who pointed this out "more diplomatically"?

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
Pull down?
Maybe that's your problem.

I think it depends on the state of the port. Are you guys using tri-state with the PUD set or PUD = 0 (disabled)?

It seems to me that with internal pull up's there's no need for external pull up's.
Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
And please tell me where I was undiplomatic. I merely pointed out that clock stretching by slave devices wouldn't work with a driven high scl. Who pointed this out "more diplomatically"?

"I don't want your code. I've got perfectly good I2C routines that I wrote myself, that do the job properly. Why would I want your eforts?"

Rude at the worst, myopic at best.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Check out the resistance of the internal pull-ups.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

RobDD wrote:
John_A_Brown wrote:
And please tell me where I was undiplomatic. I merely pointed out that clock stretching by slave devices wouldn't work with a driven high scl. Who pointed this out "more diplomatically"?

"I don't want your code. I've got perfectly good I2C routines that I wrote myself, that do the job properly. Why would I want your eforts?"

Rude at the worst, myopic at best.

Myopic? In what sense? You think it's short-sighted of me not to want your flawed code? I notice you didn't quote your post that I was responding to there.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

RobDD wrote:
Here's the code with open drain for those of you 'unsettled' by driven outputs.
I think it's fair to say no-one has had an emotional reaction to your code. It's hard to care much with so many broken re-implementations have come and gone over the years.

Attributing emotion to your critics doesn't fix the code. Making it standards-compliant fixes it. It was non-compliant to the I2C standard w.r.t open-drain lines, and that was pointed out to you many times. You have remedied that. Let's move on, yes?

EDIT: sp

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Fri. Mar 14, 2014 - 12:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
RobDD wrote:
John_A_Brown wrote:
And please tell me where I was undiplomatic. I merely pointed out that clock stretching by slave devices wouldn't work with a driven high scl. Who pointed this out "more diplomatically"?

"I don't want your code. I've got perfectly good I2C routines that I wrote myself, that do the job properly. Why would I want your eforts?"

Rude at the worst, myopic at best.

Myopic? In what sense? You think it's short-sighted of me not to want your flawed code? I notice you didn't quote your post that I was responding to there.

It said, "Those of you unsettled ....", first it was addressed to the group, not specifically you. Secondly it was meant to address concerns about my code and offer a balance. You saw it as a direct remark to you..... myopic.

Now let it go, it's about code, we all have something to learn.
Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
RobDD wrote:
Here's the code with open drain for those of you 'unsettled' by driven outputs.
I think it's fair to say no-one has had an emotional reaction to your code. It's hard to care much with so many broken re-implementations have come and gone over the years.

Attributing emotion to your critics doesn't fix the code. Making it standards-compliant fixes it. It was non-compliant to the I2C standard w.r.t open-drain lines, and that was pointed out to you many times. You have remedied that. Let's move on, yes?

EDIT: sp

I already did, I was attempting to see the configuration of the ports.
The basic code is solid, setting up the ports is minimal. That's where I'm going.
Now is the PUD set or not? It looks to me like the ports go out tri-state (PUD = 1) and pull up resistors go on the SDA and clock. Is this correct?
Thanks,
Rob

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With the best will in the world, I have nothing to learn from your code. Since you posted flawed code, I guess several people felt obliged to point out the flaws. I would wager that most of the people responding here have no use at all for your code. Anyone who's worked with microcontrollers for any length of time probably has code they know and trust for I2C. I'm sorry if I misunderstood your reasons for starting this thread - I thought you were looking for feedback.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

RobDD wrote:
It seems to me that with internal pull up's there's no need for external pull up's.
Internal pull-ups on the AVR are in the range of 20K to 50K. The I2C standard doesn't stipulate a specific value for pull-ups, but it does specify signal characteristics to which any compliant design should adhere.

Here's a short examination of how to arrive at a good value for a pull-up. Since the goal is to get acceptable edges on the signals, the ideal value of the pull-up will depend of other factors like bus capacitance.

For a very short on-PCB bus, and little parasitic capacitance contributed by the PCB traces, the major contributing factor is the capacitance of the pins on the packages of the devices on the bus. In these cases, and with only two devices, it may be ok to use the internal pull-ups, but it may be 'on the edge'. It's generally a good idea to build in some margin so that infrequent but extreme operating conditions won't cause problems.

Also, using the internal pull-ups means that for most AVR you need a two-step process to go from driving low to pulling high. This can leave the bus floating, even if only for a cycle or two. In harsh conditions this can be a problem. Some AVR have independent control of pull-ups and drive. For these devices it wouldn't be an issue, but the pull-up strength still would be.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok guys...just kiss and make up :-) let's not overload the forum's HDDs or it may die. (Moderator hat on)

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
RobDD wrote:
It seems to me that with internal pull up's there's no need for external pull up's.
Internal pull-ups on the AVR are in the range of 20K to 50K. The I2C standard doesn't stipulate a specific value for pull-ups, but it does specify signal characteristics to which any compliant design should adhere.

Here's a short examination of how to arrive at a good value for a pull-up. Since the goal is to get acceptable edges on the signals, the ideal value of the pull-up will depend of other factors like bus capacitance.

For a very short on-PCB bus, and little parasitic capacitance contributed by the PCB traces, the major contributing factor is the capacitance of the pins on the packages of the devices on the bus. In these cases, and with only two devices, it may be ok to use the internal pull-ups, but it may be 'on the edge'. It's generally a good idea to build in some margin so that infrequent but extreme operating conditions won't cause problems.

Also, using the internal pull-ups means that for most AVR you need a two-step process to go from driving low to pulling high. This can leave the bus floating, even if only for a cycle or two. In harsh conditions this can be a problem. Some AVR have independent control of pull-ups and drive. For these devices it wouldn't be an issue, but the pull-up strength still would be.

OK, thanks for the help. I figured it out. I simply added this to the beginning of my code:

ldi temp1,(1<<PUD)
out MCUCR,temp

This tri-states the ports and gives this output with 4.7k resistors (pull up).
I'll revamp the code for those interested.

Thanks for the help,
Rob

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That's a useful link, Joey. Worth a bookmark.

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:

And just for the heck of it I don't agree with you.

Yes, you're the world expert on readable code...

I have no special talents.  I am only passionately curious. - Albert Einstein

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

:mrgreen:

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The "I2C sniffer" in the project section (by danni) is quite interesting but dense assembler code for the USI section of TinyAVRs. I built one and it worked, but the output was inverted. I spent hours trying to understand what would be needed to get the output correct through software code, but eventually just added a 35-cent 74HC04 inverter chip to the device instead.

I have assembler code for the TWI section of mega AVRs that seems to work OK. It even has the error codes implemented and displayed to a degree.

I have been able to get several I2C devices to respond to AVR commands using the same style of 'bit-banging' that you've done here, but I2C is the kind of thing that is better left to dedicated hardware. Even if you have to change devices and go to, say, a Tiny48 to get access to the internal TWI.

All in all, the easiest way by far to get I2C working on an AVR is use an Arduino board and just call the included 'Wiring' library procedures.

Pages