How to use TWI in atmega32A in assembler?

Go To Last Post
9 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi!
I'm never use TWI before, except tiny bit-banging nighty builds. I now need to program TWI eeprom from my atmega32A using dedicated h/w TWI engine. I carefully read TWI section in doc8155.pdf, but unfortunately this particularly section not contains working example (unlike USART section, etc., which completely well described). Ideally i search for complete working example in assembler, but at least can you please show me where search for these:
Q1. Many dual-purpose pins is exactly known where to be redefined, like USART rxd/txd; but not TWI: i can't find when exactly these pins lost their GPIO functionality and overriden to TWI hardware and becomes open-collector i/o (and in reverse order: TWI o/c i/o -> GPIO).
Q2. Is there atmega's TWI initialization (and finalization) sequence is standardised by Atmel or no? Where i can read about it?
Q3. Is there any assembler example to set SCK baud rate?
Thank you!
PS. Sorry, i can't understand in C code.

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

Why not just bit-bang the I2C if you have done this before?

Otherwise, TWI is just as easy to use in ASM as it is in C. You design appropriate primitive functions. These functions are each about 8 instructions.

Fleury has an ASM bit-bang implementation. It also illustrates how you choose sensible primitive functions.

You call the primitive functions in the regular way.

David.

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

I do this before on FPGA. Now i try to do it in atmega, so fpga solutions not useable, i must do all from scratch. And i think the better way is to use dedicated TWI h/w. I do some search. I know at least 99.9% people here uses C, but i still hope i'm not alone in assembler:) i will try to reverse engineering the C examples, if not find anything suitable in Asm. But i hope i can avoid software bit-banging.

Still wondering why atmel's twi section is so poor documented...

Thanks:)

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

Personally, I have always found the Atmel AVR data sheets to be well written. The app notes are not as good as other manufacturers.

As with any microcontroller, you write a value to a register, you set bits or read bits as required.

;***************************************
;func: data = i2c_read(void) // always NAK
;***************************************
i2c_read:
	clc			; comment out this for ACK if .cs
	ldi	temp,(1<<TWINT)|(1<<TWEN)
	brcc	i2c_nak
	ori	temp,(1<<TWEA)
i2c_nak:
	STORE	TWCR,temp
	rcall	i2c_wait
	LOAD	data,TWDR
	ret
	
;***** internal function wait for TWI operation to complete ***
i2c_wait:
	LOAD	temp,TWCR	; use register cos sfr is out of range
	sbrs	temp,TWINT
	rjmp	i2c_wait
	ret

;****************************
;func: void I2C_Stop(void)
;****************************
I2C_Stop: 
	ldi	temp,(1<<TWINT)|(1<<TWEN)|(1<<TWSTO)
	STORE	TWCR,temp
stop_w:	LOAD	temp,TWCR	; wait for TWSTO to clear
	sbrc	temp,TWSTO
	rjmp	stop_w
	ret

Personally, I would not call those subroutines complicated.

TWI is a very similar arrangement for other controllers too. i.e. set a command, wait for completion.

It is much the same with interrupts. You just avoid the wait.

Unless your application is VERY sensitive to efficiency, it makes NO difference if you bit-bang or poll hardware. Otherwise use hardware interrupts.

David.

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

Hi!
David, thank you for your asm example. I also see more your examples here http://8515.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&p=476294, in both h/w and s/w modes. I also found complete working example http://home.deds.nl/~cmon/i2casm.htm. Well, looks useable. But still none of the examples show me how i must prepare two TWI pins before use. So i try to configure these as inputs with pullups before twi functionality.

Quote:
Unless your application is VERY sensitive to efficiency, it makes NO difference if you bit-bang or poll hardware.
Sure. But it's still a bit strange, if i have enough hardware, but not use it and emulate it in s/w instead :)

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

With the regular AVR, setting the TXEN or TWEN bits automagically set the pins for their 'alternate function'. i.e. UART transmit or TWI.

You do not need to specifically set the DDR. It is overridden by the TWEN bit.

OTOH, the SPI peripheral needs you to set the DDR for each pin as well as you setting SPEN.

These points are very clearly described in the AVR data sheets.

Incidentally, with the XMEGA, you must set both TXEN and DDR for any usart TXD pin.

My comparison of bit-bang and polled TWI was simply because it is true. You claimed that you already experience of I2C bit-bang. I suggested that you started with what you know. Once that is running, you could attempt the TWI solution.

David.

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

So i test code examples (in h/w mode) from above link. It is strange, but it work:) Some remarks may be helpful for others:
1. TWI command sequence must exactly match slave's requirements. Or 'i2c_wait' never exit, especially when previous transfer wasn't ACK'ed.
2. Only small addition I made,

i2c_off:
; Added to prevent lock up TWI when power of slave is off.
; Power cycle is req'd by at17 series eeprom when read ID code.
; But when no power on slave, bus locks up, and 'i2c_wait' never return.
; So we switch off TWI hardware here.
; Dont worry, it automatically start again in 'I2C_Start'.
	ldi   temp, 0  ; twi full off 
	out   TWCR, temp
	ret

Thanks=)

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

I apologise. There are certain bit-wait loops that can never succeed with certain hardware conditions.

OTOH, the TWI commands generally complete regardless --- hence you get the IRQ bit set. It is up to you to interpret the TWSR status.

Yes. A Slave that holds the SCK line low indefinitely will hold off most commands.

You can simply decrement a timeout counter to stop you getting stuck.

David.

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

I beat my head against the AVR's TWI for awhile, and found this thread after a quick search.  Note that this thread is five years old, I'm just lighting it up again now.  My AVR is a mega8535, running flat out at 16MHz on an external crystal.  TWI clock speed is set to 140ish kHz.

 

My symptoms were somewhat more bizarre, in that it would run once, then hang up.  It would wait forever for a TWINT that never came after TWSTA on the second trip through the loop.  It would run once, fine, get the data, chuck it out the RS-232 port, and then lock up.

 

After liberally littering debugging code throughout the place, I found another interesting detail in TWSR (with prescalers zeroed):  It would give me $F8 as a status code.  $F8 is not a valid status code.  It gave me this while reading TWSR before TWINT fired.

 

Anyhow, my code doesn't lock up anymore, and I seem to be getting something from my TWI sensor, although the data's garbage (Bad sensor?  Not sure yet.  Sensor is a Sparkfun HIH6130 (p/n 1443945) temp/humidity sensor board, good to 400kHz clock). 

 

Here's two things I learned, partly from the code pasted (Thanks, David!) and partly from experience:

 

1) After you do anything to TWCR, except TWSTO, you must wait for TWINT before you do anything else.

2) TWSTO does not set TWINT when it's done.  After TWSTO you must wait for TWSTO, not TWINT, to go away.  This is not detailed well in the instructions.

 

Have fun, all of y'all,  Scr.