Hi,

ich habe einen ATTiny 861, der als TWI slave arbeiten soll.

Ich habe aus dem sehr bescheidenen APNotes von Atmel zum thema USI als TWI slave (AVR:312) und dem Datenblatt des Tinys einen Code erstellt.

Jedoch wird mir aus keinem der beiden pdfs klar, was ich machen muss, damit die USI ein ACK sendet.

Codes zur ansteuerung finde ich meistens nur in C und für andere controller (C is nicht so meine stärke).

Hier mal mein Code:

Hauptcode:


Code:
.include "Tn861def.inc"
.include "Bezeichnung.asm"

	rjmp Init

.org 0x0007	rjmp USI_START 	; USI Start Handler
.org 0x0008 rjmp USI_OVF 	; USI Overflow Handler

	.include "init.asm"

main:
	out porta,USI_Status
	rjmp main
	rjmp main

USI_START:	
	push temp1				;temp1 sichern
	
	ldi USI_Status, 0x00	;Status auf 0 setzen (adresse empfangen)

wait:
	sbic pinb,2				;warten bis scl low ist,da sonst der counter erhöht wird
	rjmp wait

	SBI USICR,6				;USI Overflow interrupt aktivieren
	rcall timer_8bit		;counter reseten, flags löschen	

	pop temp1				;temp1 zurückholen
	reti


USI_OVF:
	push temp1
	push temp2	

	;Status auslesen

	cpi USI_Status,0
	breq Status0			;adresse
	cpi USI_Status,1
	breq Status1			;Slave soll senden
	cpi USI_Status,2
	breq Status2			;
	cpi USI_Status,3
	breq Status3			;
	cpi USI_Status,4
	breq Status4			;Slave soll empfangen
	cpi USI_Status,5
	breq Status5			;
	rjmp reset_USI

Status0:	;Adresse empfangen
	in temp2,USIDR 		;kann auch USIBR/USIDR sein, sollte egal sein
	mov temp1,temp2		;Empfangene Adresse sichern (wegen R/W)
	andi temp1,0xfe		;Adresse Maskieren
	cpi temp1, ((Slave_adr*2));Eigene Adresse?
	breq Status01		;Wenn JA, Springe zu Status01
	rjmp reset_USI		;Wenn nein, USI reseten (interrupt deaktivieren)

Status01:	;Eigene Adresse erkannt
	rcall sende_ACK		;ACK senden
	Andi temp2,0x01		;R/W auslesen und entsprechend Status wählen
	SBRC temp2,0		;Wenn 1 = Read
	LDI USI_Status,1	;Wenn 0 = Write
	SBRS temp2,0
	LDI USI_Status,4
	rjmp ende

Status1:	;Master will Byte empfangen (Slave soll senden)
	out USIDR,data		;Daten in Datenregister laden ,kann auch durch laden von daten aus einer Tabelle ersetzt werden
	sbi PORTB,0			;Port transparent machen
	LDI USI_Status,2
	rjmp ende

Status2:	;Slave hat gesendet, empfangen von ACK vorbereiten
	cbi DDRB,0			;Empfangen von ACK vorbereiten
	cbi PORTB,0			;
	LDI USI_Status,3	;Status ändern
	rcall Timer_1Bit	;Timer auf das erhalten von 1 Bit einstellen
	rjmp ende

Status3:	;ACK oder NACK erhalten?
	in temp1,USIDR		;Empfangene daten einlesen
	Andi temp1,0x01		;ACK/NACK maskieren
	sbi DDRB,0			;SDA auf low ziehen	
	SBRS temp1,0		;Wenn ACK, siehe Status1
	rjmp Status1			
	rjmp reset_USI		;Wenn NACK, reset

Status4:	;Slave soll Empfangen
	rcall Zuruckstellen_ACK
	LDI USI_Status,5	;Status ändern
	rjmp ende

Status5:	;Byte empfangen, ACK senden
	in data,USIDR			;Daten einlesen
	rcall sende_ACK
	rcall Timer_1Bit
	ldi USI_Status,4
	rjmp ende

sende_ACK:
	cbi	PORTB,0 			;prepare to send "0" on SDA
	sbi	DDRB,0				;setup the SDA line as output

	rcall Timer_1Bit		;timer für ACK zurückstellen
	ret

Zuruckstellen_ACK:
	cbi DDRB,0				;SDA wieder als eingang
	ret

TImer_8Bit:
	ldi temp1,0xe0			;flags löschen, counter resetten könnte auch 0xf8 sein
	out USISR,temp1
	ret

Timer_1Bit:
	ldi temp1,0xee
	out USISR,temp1			;timer für ACK zurückstellen und flags löschen
	ret

reset_USI:
	cbi USICR,(USIOIE)		;interrupt deaktivieren
	ldi USI_STATUS,6								;TESTZWECK
	rjmp ende

Ende:		
	sbi USISR,(USIOIF)		;Interrupt flag löschen

	pop temp2	;Stack zurückholen
	pop temp1	;
	reti
und die Init:

Code:
init:
init:

	;Stack
	ldi temp1, LOW(RAMEND)      ; LOW-Byte der obersten RAM-Adresse
    out SPL, temp1
    ldi temp1, HIGH(RAMEND)     ; HIGH-Byte der obersten RAM-Adresse
    out SPH, temp1

	
	;I/O einstellen
    ldi temp1, 0xFF			; Port A = Ausgang
    out DDRA, temp1

	Ldi temp1, 0x00			;PortB = Eingang
    out DDRB, temp1

	ldi temp1, 0x00			;Pullups bei TWI pins deaktivieren
	out PORTB,temp1

	;TWI Slave mit interrupt
	cbi DDRB,0				;SDA als Input


	ldi temp1,0x00			;Pinbelegung von TWI bei 0x01 PA, bei 0x00 PB
	out USIPP,temp1			;
	
							;TWI modus aktivieren (ohne Clockstreching), 
	Ldi temp1,(1<<USISIE)+(0<<USIOIE)+(1<<USIWM0)+(1<<USIWM1)+(1<<USICS1)+(0<<USICS0)+(0<<USICLK) 
	out USICR,temp1			;
	
	ldi temp1,0xf0			;flags löschen, counter resetten
	out USISR,temp1
	
	ser temp1									;TESTZWECK
	mov data,temp1								;

	LDI USI_Status,0xFF							;TESTZWECK

	sei						;interrupts aktivieren

rjmp main
Als master verwende ich einen Mega8, mit hardware TWI. Dieser bekommt nach dem senden der Adresse kein ACK zurück, die Adresse stimmt aber, hab sie schon mehrfach gedreht, hat nie geklappt.


Das Problem dass ich habe ist, dass ich nicht weis, wie ich mit der Slave ein ACK Signal erzeugen kann, oder falls USI das automatisch macht, warum keins beim Master ankommt.

Könnte vlt. jemand drüberschaun, ich such schon den ganzen tag nach fehlern und find keine mehr, auser die sache mit dem ACK.

mfg robin