ATTiny26 TWI slave operation

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View

I am trying to get a ATMega8 and ATTiny26 to communicate over a two wire
bus but can't get it to work properly. At this stage all I am trying to do is get
the ATTiny26 (Slave Rx) to acknowledge the ATMega8 (Master Tx). I either
get NACK back at the Mega8 status register or 0x00 (bus error) depending
on what I do. I have looked at the signals with a CRO and am confident it is
not a hardware problem.

I have been stuck on  this problem for 2 days now and I am just going around
in circles. I have rewritten it so many times I have lost count.

This is what I have at the moment. It is based on the C code in AVR312
application note from Atmel.

Please, can someone who is familiar with this system show me the error of my
ways :)


This is the USI setup routine:

 ldi sTmp1,(1<<USISIE)|(1<<USIWM1)|(1<<USICS1)
 out USICR,sTmp1
 ldi sTmp1,0x0F
 out USISR,sTmp1

Here are the 2 interrupt routines:

USI_STRT:  ; USI Start handler
 ; Enable TWI Counter overflow and interrupts
 ldi iTmp1,(1<<USISIE)|(1<<USIOIE)|(1<<USIWM1)|(1<<USIWM0)|(1<<USICS1)
 out USICR,iTmp1
 ; Set counter & clear start interrupt flag
 ldi iTmp1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)
 out USISR,iTmp1

USI_OVF:  ; USI Counter Overflow handler
 clr iTmp1
 out USIDR,iTmp1 ; generate ACK
 sbi DDRB,SDA    ; enable SDA
 ldi iTmp1,(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0xE<<USICNT0)
 out USISR,iTmp1
 in iTmp1,USISR
 andi iTmp1,(1<<USISIF)|(1<<USIOIF)
 cpi iTmp1,0
 brne WaitACK
 cbi DDRB,SDA ; Release SDA
 ldi iTmp1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0x0<<USICNT0)
 out USISR,iTmp1

Re: ATTiny26 TWI slave operation
In SetTWISlave:
Quoted text here. Click to load it

That should be 0xF0, or in Atmel-ese:

They sure do love that shift operator. The code from AppNote 312 was painful to
look at.

In WaitACK:
Quoted text here. Click to load it

I think your branch condition is wrong. You should be waiting for either bit to
change to 1.

breq WaitACK

I kind of question having the SCL pin setup as an output on a slave, but I
assume those Atmel guys know what they are doing and actually tested the code
in their App Note.

Re: ATTiny26 TWI slave operation
Hi Gary,

Thanks for replying.

Quoted text here. Click to load it

Good, thanks.

Ah, yes. That mistake too. I'm making silly mistakes now. But it still doesn't
work. I've also tried setting USIWM1=1 and 0<<USIWM0=1 so SCL is
held low during a counter overflow but no change. That's how I meant to have
it anyway.

Now I'm wondering if I've done something silly in the master code.

What is happening at the moment is that with the code as it is, the master never
receives an interrupt at the point marked (*NOTE 1*). If I remove the line:
sbi DDRB,SDA    ; enable SDA
from the slave code (which should cause a NACK), the master returns and
uTxDataL=0x48 and uTxDataL=0xA7.

The 0xA7 means the code hit an error at the MT_DATA_ACK section and
the 0x48 is a status value meaning NACK was received according to the
datasheet .


Master send code (ATMega8)
Trimmed slightly - The actual code is peppered with LED controls to help
me find the points where the program is stopping.

;  Send a data byte (uRxDataL) to device (uRxDataH) on TWI
 clr sTmp2 ; Temp status
 ser sTmp3 ; Temp status

TWStart: ; transmit start condition
 ldi sTmp1,(1<<TWINT)|(1<<TWSTA)|(1<<TWEN)
 out TWCR,sTmp1

 rcall TWWaitForINT  ; wait for start condition
 sbr sTmp2,0x01 ; Temp return status

 ; check value of TWI status
 in sTmp1,TWSR
 andi sTmp1,0xF8 ; Mask out prescaler bits
 mov sTmp3,sTmp1 ; **********  READ RETURN VALUE **********
 cpi sTmp1,MT_START
 brne TWtxError
 sbr sTmp2,0x02 ; Temp return status

TWAddr: ; load Slave Addr + R/W into TWDR
 lds sTmp1,uRxDataH
 out  TWDR,sTmp1
 ; clear TWINT flag to start transmission of address
 ldi sTmp1,(1<<TWINT)|(1<<TWEN)
 out TWCR,sTmp1

 rcall TWWaitForINT  ; Wait for TWINT flag set (transmission complete)
;(*NOTE 1*)  never gets a TWINT unless slave is reset even though
; a CRO shows SDA and SCL to be high
 sbr sTmp2,0x04 ; Temp return status

 in sTmp1,TWSR
 mov sTmp3,sTmp1 ; **********  READ RETURN VALUE **********
 andi sTmp1,0xF8 ; Mask out prescaler bits
 cpi sTmp1,MT_SLA_ACK
 brne TWtxError

TWData: ; Load uRxDataL into TWDR
 lds sTmp1,uRxDataL
 out TWDR,sTmp1
 ldi sTmp1,(1<<TWINT)|(1<<TWEN)
 out TWCR,sTmp1

 rcall TWWaitForINT  ; Wait for TWINT flag set
 sbr sTmp2,0x08 ; Temp return status

 in sTmp1,TWSR
 andi sTmp1,0xF8 ; Mask out prescaler bits
 mov sTmp3,sTmp1 ; **********  READ RETURN VALUE **********
 cpi sTmp1,MT_DATA_ACK
 brne TWtxError

TWStop: ; transmit stop
 ldi sTmp1,(1<<TWINT)|(1<<TWEN)|(1<<TWSTO)
 out TWCR,sTmp1

 sbr sTmp2,0x20 ; Temp return status  *******
 ldi sTmp1,0x11
 sts uTxCmd,sTmp1
 rjmp EndDoTWSend
 sbr sTmp2,0x80    ; Error FLAG *******
 rjmp TWStop

 ; Switch back to slave mode
 rcall SetTWSlaveMode
 lds sTmp1,uRxDataH
 sts uTxDataL,sTmp2 ; Temp status return
 sts uTxDataH,sTmp3 ; Temp status return
 rcall uTxSend

 ; This device does not recognise general call
 ldi sTmp1, (ID_SYSTEM<<1) ; DevID in Slave mode - left shifted 1 bit
 out TWAR,sTmp1
 ldi sTmp1,0xFF
 out TWDR,sTmp1
 ldi sTmp1,(1<<TWEA)|(1<<TWIE);|(1<<TWINT)
 out TWCR,sTmp1

TWWaitForINT:  ; Wait for TWINT flag to be set
 in sTmp1,TWCR
 sbrs sTmp1,TWINT
 rjmp TWWaitForINT

Re: ATTiny26 TWI slave operation
As far as I can tell, you are doing things right and should get a TWINT at
NOTE1. You do have some sbr instructions that I assume are skipping around some
of the debug code you left out. I'm wondering if your debug code is messing you

As far as I can see, the TWI Module shouldn't even care if anything is out
there. If you put something in the data register and clear the TWINT flag (with
TWEN set), it should shift out the bits and then set TWINT. So, something very
strange is happening.

Re: ATTiny26 TWI slave operation
Quoted text here. Click to load it

Yes, The registers iTmp2 and iTmp3 in the master are just for debug. I'll
try removing all the debug code just for fun and see what happens.

Quoted text here. Click to load it

Perhaps I just need some sleep. :) I have never had something that seems so
simple cause me so much grief. I can't help feeling there is some minor thing I
am missing.

Thanks for looking at it.

- Mike

Re: ATTiny26 TWI slave operation
Quoted text here. Click to load it
I am missing.

I know that feeling! I think many of us here have had that. I have found it's
never good to code when you are sleepy. I can't tell you how many times after a
good sleep that the solution comes to me.

Re: ATTiny26 TWI slave operation

Quoted text here. Click to load it

I've done some of my best debugging during my morning shower.  And no,
I don't take a listing in with me...


Change is inevitable, progress is not.

Re: ATTiny26 TWI slave operation
I've solved the problem.

It was what I believe to be a  misleading statement in the ATTiny26

Where it talks about wire mode bits USIWM1 and USIWM0 on
page 66, it says:

"The Serial Data (SDA) and the Serial Clock (SCL) pins are
bidirectional and uses open-collector output drives. The output
drivers are enabled by the DDRB0/2 bit in the DDRB Register."


"When the SCL pin output driver is enabled the SCL line will be
forced low if the PORTB2 bit in the PORTB Register is zero, or
by the start detector. Otherwise the SCL line will not be driven."


"The SCL line is held low when a start detector detects a start
condition and the output is enabled."

In my slave set-up I was doing:


Does that not enable the SCL line?

Anyway, the SCL line in not held low when start is detected. This
caused the bit counter to end up overflowing half a clock pulse too soon.

To cure it, I now wait in the start detect routine for SCL to go low,
then set the counter. It seems to work so far.

Now, maybe I can move on to making it actually do something. :)


Re: ATTiny26 TWI slave operation
Quoted text here. Click to load it

This is just a random thing - I don't use I2C... er... I mean 2-wire
interface. But, do you have handlers for all interrupts? On AVR I
vector all unused interrupts to a routine that sets an "invalid IRQ
detected" flag and either halts or sets a bit that communicates the
spurious interrupt condition back to the master.

Re: ATTiny26 TWI slave operation
Quoted text here. Click to load it

Yes. I always create handlers for all the interrupts. It's in my template
for new projects.

Anyway, I seem to have solved it. See my latest reply to Gary.


Site Timeline