- MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad         
Ergebnis 1 bis 5 von 5

Thema: USI (als TWI slave) mit ATTINY x61

  1. #1
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    26.11.2004
    Beiträge
    451

    USI (als TWI slave) mit ATTINY x61

    Anzeige

    LiFePo4 Akku selber bauen - Video
    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

  2. #2
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Hallo,

    USI macht nix automatisch, wenn man ein ACK (0) senden will, muss man eben ein Bit mit dem entsprechenden Wert auf den Bus schieben.

    Für Bascom hatte ich mal was gemacht:
    https://www.roboternetz.de/phpBB2/viewtopic.php?t=25058

    Im Wiki ist auch etwas zu USI.
    https://www.roboternetz.de/wissen/in.../USI_%28Avr%29

  3. #3
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    26.11.2004
    Beiträge
    451
    Hi,

    die Links kenn ich beide schon, trotzdem danke.

    Im Wiki artikel werden größtenteils nur die Register beschrieben, was mir eigentlich nicht weiterhilft.


    Ich hab den Code oben Aktualisiert.

    Ich konnte den Fehler auch schon ausfindig machen. Die USIoverflow Routine wird nicht aufgerufen.

    Ich hab aber meiner Meinung nach alles richtig eingestellt.

    Der USI counter zählt bei steigender und fallender Flanke, also sollte nach 8 übertragenen Bits der Interrupt ausgelöst werden.

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.06.2007
    Ort
    München
    Alter
    61
    Beiträge
    199
    Hallo,

    ich hab einen funktionierenden Code für einen ATTiny26 als I2C Slave. Der ist zum ATTiny861 kompatible. Das ganze läuft bis 100 kHz SCL. Als Master nehme ich einen ATMega16.

    Siehe hier:

    http://freenet-homepage.de/uffmann/Ultrasonic2.html

    gruß, uffi

  5. #5
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    26.11.2004
    Beiträge
    451
    Hi,

    danke für deinen Code, er hat mir einiges gebracht.

    leider funktioniert das ganze immernoch nicht.

    Ich habe mitlerweile den Bustakt auf 40khz (fast minimum) runtergedreht. und mehrere wait schleifen eingebaut, damit alles schön langsam ist.

    Mein erfolg ist immerhin, dass meine Slave seine adresse erkennt, aber kein ACK zurücksendet.

    Meine routine um ein ACK zu senden habe ich von dir übernommen:
    Code:
    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
    Code:
    Timer_1Bit:
    	ldi temp1,0xee
    	out USISR,temp1			;timer für ACK zurückstellen und flags löschen
    	ret
    Als master verwende ich eine Mega 168 mit hadware TWI, je 10k pullups an SDA und SCL.

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Solar Speicher und Akkus Tests