PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Frage zu USI Schnittstelle



izaseba
26.09.2007, 20:39
Hallo,
Ich programmiere gerade einen I2C Slave auf einem Tiny24, und ich muß sagen, es klappt \:D/
Jetzt kommt aber das Problem/Frage
SCL hängt an PA4
SDA PA6
Pins PA0-PA3 sind als Ausgänge konfiguriert und hängen an Inputs von l293.
Jetzt will ich natürlich was an PA0-PA3 ausgeben um die Drehrichtung der Motoren zu bestimmen.
Eigentlich hatte ich es so vor:


in r16,PINA
andi r16,0xF0
or r16,r17
out PORTA,r16

Kein Hexenwerk also , in r17 ist der obere Nibble natürlich gelöscht.
Ich frage mich aber, was passiert, wenn in der Zeit zwischen in und out der Zustand an SCL SDA sich geändert hat, der Master komuniziert gerade mit einem anderen Slave, bzw. schickt/holt Daten von mir :-k
Würde ich jetzt Störungen am Bus verursachen, oder läßt es den Tiny kalt, wenn man USI aktiviert hat ?

Vielleicht weißt jemand eine Antwort drauf, sonst muß ich es per Brutal force ausprobieren.
Hab ich vielleicht das Datenblatt nicht gründlich genug studiert, ich meine aber, keine Antwort auf diese Frage gefunden zu haben.

Gruß Sebastian

Besserwessi
26.09.2007, 20:49
Die vorgeschlagene Methode würde wohl funktionieren, allerdings werden die internen Pullups abhängig vom Eingangssignal geschaltet. Besser wäre es am Anfang IN r16,porta zu benutzen. Wenn die I2C routine im Interrupt läuft eventuell noch CLI/SEI um den code setzen.

izaseba
26.09.2007, 20:59
Danke für die Antwort,
wieso denn in r16,porta, damit lese ich doch nicht die Pegel an den Pins, sondern die Pullups ?
Außerdem bringt cli/sei hier nicht viel, weil die Komunikation läuft ja weiter, auch wenn Interrupts ausgeschaltet sind bzw. kann der Master ja mit einem anderen Slave "reden"
Gruß Sebastian

izaseba
28.09.2007, 23:17
Hallo,
Ich habe heute mal einen Testaufbau gemacht bestehend aus:
Tiny 24 als Slave, M8 als Master und PC.

Ein kleines PC Programm sendet dann über UART fortlaufend 3 Bytes an dem M8, der wiederum alle 3 per I2C an den Tiny reicht, anschliessend alle 3 wieder vom Tiny holt und an den PC zurückschickt,
Der PC vergleicht, was er gesendet hat, und was zurückgekommen ist #-o

1. Versuch war ohne Veränderungen am Tiny PORTA, irgendwo bei Empfang von Byte 500000 hatte ich den PC angehalten und I2C Komunikation als erfolgreich erklärt.

2.Versuch : kleine Programmänderung am Tiny mit dem obengenannten Code^^^
Ergebnis : Bus hängt, nichts gesendet und nichts empfangen (das habe ich mir schon gedacht
](*,) )

Fazit: Ich muß den unteren Nibble mit sbi und cbi ändern, toll das spart nicht gerade Speicher alle Möglichkeiten auszuprogrammieren :-k
Da muß ich mir noch was einfallen lassen.
Spontane Idee den r17 insgesammt 4 Mal rechts schieben und je nachdem was in Carry steht sbi oder cbi am entsprechendem Pin anwenden.
Oder kennt jemand eine bessere Lösung ?

Gruß Sebastian

stb_haag
17.01.2008, 21:34
Hallo Sebastian,

ich versuche derzeit ohne Erfolg den I2C Bus beim Tiny24 in Betrieb zu nehmen. Ich vermute, dass ich bereits bei derInitialisierung etwas falsch mache, denn die beiden Busleitungen bleiben auf low (soll ein Master werden). Kannst du mir einen Code-Auszug senden?

Gruß
Stefan

izaseba
18.01.2008, 16:47
Hallo Stefan,

Kannst du mir einen Code-Auszug senden?
Das könnte ich gerne machen, aber Du schreibst

soll ein Master werden
und ich habe einen Slave implementiert...

Einen Master als USI lohnt nicht wirklich, den kann man genausogut in Software machen.

Hast Du schon die Appnote zum Thema durch ?
http://atmel.com/dyn/resources/prod_documents/doc2561.pdf

Am sonsten bleibt die Frage, zieht der µC die Leitungen auf LOW oder hast Du
die Pullup Widerstände vergessen ?

Gruß Sebastian

stb_haag
18.01.2008, 21:10
Hallo Sebastian,

die AN hilft mir nicht weiter. Dort ist ja der Code nicht ausformuliert, sondern nur das Prinzip der Kommunikation erklärt. Ich denke, das Prinzip des I2C Bus ist mir klar. Im Grunde genommen ist das Protokoll erst einmal unwichtig, denn es soll ja erst einmal ein Signal zu sehen sein.

Mein Problem: ich setze den TWI Mode und die Pullups sind vorhanden. Stehen die Portbits auf Ausgang, se sehe ich ein Low. Stehen sie auf Eingang, sehe ich ein Hign. Ich benutze den SE-Strobe. Toggeln vom USICLK oder USITC bringt nichts. Auch im Simulator werden die Daten im Register nicht geshiftet und der Counter bleibt auf Null. Auch im SPI Mode tut sich nichts.

Das entsprechende Kapitel im Datenblatt ist etwas verunglückt. Es gibt ein Buffer Register ohne Beschreibung, es wird Port E erwähnt...

Bei meiner Suche im Internet fand ich bisher nur dich mit einer Erfolgsmeldung.

Klar kann man den I2C-Bus auch in SW machen, aber das Interface wäre schon ein nettes Feature.

Gruß
Stefan

izaseba
18.01.2008, 21:57
Hallo Stefan,

Natürlich gibt es einen Code zu der Appnote, sorry, ich habe Dir den falschen Link kopiert ...
http://atmel.com/dyn/resources/prod_documents/AVR310.zip
Es ist zwar IAR C , es sollte aber normallerweise kein Problem sein Assembler
daraus zu machen, wenn nicht sag nochmal bescheid , dann helfe ich Dir gerne.

Ja das Dattenblatt ist wirklich zum Ko*** was USI angeht, ohne Appnote hätte ich es auch nicht geschafft.
So initialisiere ich z.B. den slave:


usi_twi_slave_init:
in tmp,USI_PORT
ori tmp,(1<<USI_SCL)|(1<<USI_SDA)
out USI_PORT,tmp
sbi USI_DDR,USI_SCL
ldi tmp,(1<<USISIE)|(1<<USIWM1)|(1<<USICS1)
out USICR,tmp
ldi tmp,0xF0
out USISR,tmp
ret

Man beachte, daß der SCL Pin als Ausgang gesetzt wird was für mich komisch ist, weil der Slave eigentlich den SCL als Eingang nutzen sollte.

Am sonsten klappt das ganze an sich gut, Master fährt mit 400 kHz der Tiny macht nebenbei noch Radencoder,Motorenansteuerung und eine einfache PI Regelung alles ohne Probleme.

Naja, versuch es bitte nochmal mit der Appnote, wenn es nicht klappt schauen wir mal, ich will bald einen Tiny 24 mit HP03 Drucksensor von Hope RF verheiraten, warum soll man nicht nebenbei einen USI Master implementieren.

Gruß Sebastian

P.S.

Auch im Simulator werden die Daten im Register nicht geshiftet und der Counter bleibt auf Null

Wenn Du AvrStudio Simulator meinst, vergiß es, das kann er nicht, steht aber auch irgendwo in der Help, es sei denn Du hast einen HW Debugger ala JTAG ICE mkII oder Dragon.

stb_haag
24.01.2008, 21:06
Hallo Sebastian,

erst einmal vielen Dank für die Mühe. Die AN kannte ich noch nicht. Ich habe mir den Code angesehen und bin etwas schockiert, da ich mit einem einfachen Interface gerechnet hatte. Der Code ist ja 10 mal länger wie mein Programm. Mein Einsatzgebiet für den I2C-Bus sollte eigentlich das Debuggen sein. Ich wollte zur Laufzeit Variablen an die Außenwelt senden. Geht so was nicht einfacher?

Gruß
Stefan

izaseba
24.01.2008, 21:40
Hallo Stefan,


Ich habe mir den Code angesehen und bin etwas schockiert, da ich mit einem einfachen Interface gerechnet hatte.
Ich hab Dich ja gewarnt, jetzt weißt Du hoffentlich, was ich mit

Einen Master als USI lohnt nicht wirklich, den kann man genausogut in Software machen.
meinte ;-)

Für Slave ist USI ganz O.K. aber Master....

Ja Alternative :-k Selber verbessern \:D/
sonst vielleicht http://homepage.hispeed.ch/peterfleury/avr-software.html
Es ist zwar eine C Lib aber im Assembler geschrieben, die nutzr ich gelegentlich...

Gruß Sebastian

P.S. Ich werde mich mit USI Master auseinander setzten, im Moment bin ich leider mit I2C Display beschäftigt, auch zu Debuggzwecken ;-)

izaseba
29.01.2008, 23:01
Hallo Stefan,
ich weiß zwar nicht, ob Du hier noch mitliest, aber egal.

Ich habe mich heute mit USI Master auseinandergesetzt und, es ist doch nicht ganz so wild, ich glaube die nackte Routine ergibt etwa 160 Bytes.

Testumgebung :

Tiny 25 als Master.
Mein I2C Display (http://www.izaseba.roboterbastler.de/index.php?popup=Projekte&section=i2cdisplay)als Slave Nr.1 zur Ausgabe
DS1621 I2C Temperatursensor als Slave Nr.2
Eine Real Time Clock als Slave Nr.3

Der Aufbau läuft seit einer Stunde und zeigt mir schön in Sekundentakt die Temeratur und Uhrzeit abweschseln an \:D/

Der Master läuft mit 1MHz und 100 kHz Bustakt

ich poste einfach mal das Program:


; USI_TWI_master Routinen
;************************************************* *


.macro TRANSFER_8_BIT
ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)
rcall USI_TWI_master_transfer
.endmacro

.macro TRANSFER_1_BIT
ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0xE<<USICNT0)
rcall USI_TWI_master_transfer
.endmacro

.equ WRITE = 0
.equ READ = 1
.equ ACK = 1
.equ NACK = 0


; I2C Master init
;keine Parameter, keine Rueckgabewerte
;************************************************* ***********************
USI_TWI_master_init:
ldi tmp1,(1<<PORT_USI_SDA)|(1<<PORT_USI_SCL);Pullups an SDA u. SCL an
out PORT_USI,tmp1
out DDR_USI,tmp1;SDA u. SCL als Ausgaenge
ser tmp1 ;Lade Dataregister mit High Bytes
out USIDR,tmp1
;USI Interrupts inaktiv, USI im 2 Wire Modus Software Clock
ldi tmp1,(1<<USIWM1)|(1<<USICS1)|(1<<USICLK)
out USICR,tmp1
ldi tmp1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC);Lösche USI Flags
out USISR,tmp1 ;und resete den Counter
ret
;************************************************* ***********************


; USI_TWI_master_start
; Sendet Startbedingung und die Slaveadresse
; Parameter, Slaveadresse im Register param1
; Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
;************************************************* ***********************
USI_TWI_master_start:
sbi PORT_USI,PIN_USI_SCL;zieht SCL High
USI_TWI_master_start_1:
sbis PIN_USI,PIN_USI_SCL;warte bis SCL High ist
rjmp USI_TWI_master_start_1
rcall delay
cbi PORT_USI,PIN_USI_SDA ; zieht SDA LOW
rcall delay
cbi PORT_USI,PIN_USI_SCL ;SCL wieder LOW
sbi PORT_USI,PIN_USI_SDA ;SDA High
out USIDR,param1; Slaveadresse/Data in den USI Dataregister schreiben
;mastertransfer aufrufen
TRANSFER_8_BIT
cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang
TRANSFER_1_BIT
ret
;************************************************* **********************


; USI_TWI_master_write
; Sendet ein Byte am den Master
; Parameter: Data im Register param1
; Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
;************************************************* **********************
USI_TWI_master_write:
out USIDR,param1; Data in den USI Dataregister schreiben
;mastertransfer aufrufen für die
TRANSFER_8_BIT ;Byte Uebergabe
cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang
TRANSFER_1_BIT;um ACK/Nack Abzuholen
ret
;************************************************* **********************

; USI_TWI_master_read
; Liest ein Byte vom Slave aus
; Parameter: Sende ACK/Nack im param1 1 == ACK senden; 0 == kein ACK senden(Nack)
; Rueckgabe gelesene Daten in param1
USI_TWI_master_read:
tst param1 ;Schaue ob zum Schluss NACK oder ACK soll
breq USI_TWI_master_read_prepare_NACK
set ;T Flag setzen
rjmp USI_TWI_master_read_1
USI_TWI_master_read_prepare_NACK:
clt ;T Flag loeschen
USI_TWI_master_read_1:
cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang setzen
TRANSFER_8_BIT
push param1 ;gelesene Daten sichern
brtc USI_TWI_master_read_send_NACK ;wenn T Flag geloescht ist erfolgt ein NACK
;sonst muss ein ACK erfolgen
clr param1
rjmp USI_TWI_master_read_end
USI_TWI_master_read_send_NACK:
ser param1
USI_TWI_master_read_end:
out USIDR,param1
TRANSFER_1_BIT
pop param1
ret
;************************************************* **********************


; USI_TWI_master_transfer
; sorgt für die Komunikation mit dem slave
;mit param1 wird übergeben ob ein Byte empfange/gesendet wird, oder nur 1 Bit für ACK/NACK

USI_TWI_master_transfer:
out USISR,param1;der Counter wird vorgeladen
USI_TWI_master_transfer_1:
rcall delay
sbi USICR,USITC ;Positive Flanke an SCL erzeugen
USI_TWI_master_transfer_2:
sbis PIN_USI,PIN_USI_SCL ; warten bis SCL High ist
rjmp USI_TWI_master_transfer_2
rcall delay
sbi USICR,USITC;negative Flanke an SCL erzeugen
sbis USISR,USIOIF;testen ob Counter ubergelaufen ist
rjmp USI_TWI_master_transfer_1 ;wenn nicht mit dem nächstem Bit
rcall delay ;wenn gelesen wird
in param1,USIDR;Daten holen
ldi tmp1,0xFF
out USIDR,tmp1
sbi DDR_USI,PIN_USI_SDA; SDA auf Ausgang stellen
ret
;************************************************* **********************


; USI_TWI_master_stop:
;Sendet die Stop Bedingung
;************************************************* **********************
USI_TWI_master_stop:
cbi PORT_USI,PIN_USI_SDA
sbi PORT_USI,PIN_USI_SCL
USI_TWI_master_stop_1:
sbis PIN_USI,PIN_USI_SCL
rjmp USI_TWI_master_stop_1
rcall delay
sbi PORT_USI,PIN_USI_SDA
rcall delay
ret
;************************************************* **********************

; delay
;Eine kurze Pause von insgesammt 10 Takten
;Bei 1 MHz ergibt das 100 kHz Mastertakt
;;keine Parameter, keine Rueckgabewerte
;************************************************* **********************
delay:
;Rcall hat 3 Takte gedauert
nop ;1 Takt
nop ;1 Takt
nop ;1 Takt
ret ; 4 Takte
;************************************************* **********************


Du mußt Dir 2 Register definieren tmp1, und param1, die nicht gesichert werden.

Ich habe es anhand der o.g. appnote geschrieben, aber so ziemlich umgekrämpelt, weil es mir nicht so gefallen hat.
Die ist etwa genauso zu benutzen, wie die Routine von Peter Fleury, da komm ich besser mit klar, als diese komische Pufferlösung von Atmel.
Ein Miniprogramm um den DS1621 Wandeln zu lassen und auszulesen könnte damit etwa so aussehen:


.include "tn25def.inc"

.equ PORT_USI = PORTB
.equ DDR_USI = DDRB
.equ PIN_USI = PINB
.equ PORT_USI_SDA = PORTB0
.equ PORT_USI_SCL = PORTB2
.equ PIN_USI_SDA = PINB0
.equ PIN_USI_SCL = PINB2

.equ I2C_DISPLAY = 0x14
.equ THERMO = 0x90
.def nachkomma = r1
.def tmp1 = r16
.def tmp2 = r17
.def param1 = r18
.def param2 = r19
.def temperatur = r21

.cseg

.org 0x0000
rjmp reset

reset:
clr ausgabe
ldi tmp1,RAMEND
out SPL,tmp1
rcall USI_TWI_master_init
;Thermometer einschalten
ldi param1,THERMO+WRITE
rcall USI_TWI_master_start
ldi param1,0xEE
rcall USI_TWI_master_write
rcall USI_TWI_master_stop
;Thermometer eingeschaltet

loop:
;Temperatur auslesen
ldi param1,THERMO+WRITE
rcall USI_TWI_master_start
ldi param1,0xAA
rcall USI_TWI_master_write
ldi param1,THERMO+READ
rcall USI_TWI_master_start
ldi param1,ACK
rcall USI_TWI_master_read
mov temperatur,param1
ldi param1,NACK
rcall USI_TWI_master_read
mov nachkomma,param1
rcall USI_TWI_master_stop
;Temperatur ausgelesen
loop1:
loop1

Noch etwas unaufgeräumt, ich denke bis zum Wochenende werde ich Zeit finden und alles besser dokumentieren.

Ich hoffe, das Du was mit tun kannst ;-)

Gruß Sebastian

stb_haag
03.02.2008, 23:32
Hallo Sebastian,

vielen Dank für deine Mühe.

Ich glaube, mir ist das zu kompliziert. Ich dachte an eine primitive Debug-Funktion. In meiner Anwendung ist der Speicher bereits recht voll. Da kann ich mir solchen Luxus nicht leisten. Außerdem kam ich bisher ohne bestens zurecht. Ich lege das Thema auf Eis und denke beim nächsten Projekt noch einmal darüber nach. Oder ich steige auf einen Controller mit UART um.

Gruß
Stefan

izaseba
05.02.2008, 20:28
Hallo Stefan,


vielen Dank für deine Mühe.

Naja, sagen wir mal so, es hat mir Spaß gemacht.
Ich wollte zwar I2C in Software nehmen, aber wenn man dabei was neues lernt ist kein Weg zu weit.

Ich habe mittlerweile die Routine etwas abgeändert, es werden keine Register verändert und ein paar Makros ersetzen die lästige rcalls.

Ich habe sie schon mehrere Tage im Einsatz und keine Probleme festgestellt

Gruß Sebastian

TottiW
05.09.2008, 09:49
Hi izaseba,

auch von mir erst mal ein Danke für deine Arbeit.
Ich bin noch recht neu in der MC Welt und mich interessiert, wie du deine Optimierungen gemacht hast.

Auch wenn der Post schon eine Weile her ist... Hast du deinen Code noch in Reichweite?

Wäre super, wenn du den noch mal posten könntest.

Danke!
Totti

TottiW
12.09.2008, 12:31
Habe den optimierten Code gefunden und poste ihn an dieser Stelle nochmal. Nochmal ein Danke an izaseba für die Arbeit!

Der Code stand hier:
https://www.roboternetz.de/phpBB2/printview.php?t=39337&start=0


; USI_TWI_master Routinen
;************************************************* *


.macro TRANSFER_8_BIT
ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)
rcall USI_TWI_master_transfer
.endmacro

.macro TRANSFER_1_BIT
ldi param1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC)|(0xE<<USICNT0)
rcall USI_TWI_master_transfer
.endmacro

.macro READ_ACK
set
rcall USI_TWI_master_read
.endmacro

.macro READ_NACK
clt
rcall USI_TWI_master_read
.endmacro

.macro START_I2C
ldi param1,(@0)
rcall USI_TWI_master_start
.endmacro


;USI Pin Konfiguration fuer tiny 24

.equ PORT_USI = PORTA
.equ DDR_USI = PORT_USI- 1
.equ PIN_USI = DDR_USI - 1
.equ PORT_USI_SDA = PORTA6
.equ PORT_USI_SCL = PORTA4
.equ PIN_USI_SDA = PINA6
.equ PIN_USI_SCL = PINA4


.equ WRITE = 0
.equ READ = 1


; I2C Master init
;keine Parameter, keine Rueckgabewerte
;************************************************* ***********************
USI_TWI_master_init:
ldi tmp1,(1<<PORT_USI_SDA)|(1<<PORT_USI_SCL);Pullups an SDA u. SCL an
out PORT_USI,tmp1
out DDR_USI,tmp1;SDA u. SCL als Ausgaenge
ser tmp1 ;Lade Dataregister mit High Bytes
out USIDR,tmp1
;USI Interrupts inaktiv, USI im 2 Wire Modus Software Clock
ldi tmp1,(1<<USIWM1)|(1<<USICS1)|(1<<USICLK)
out USICR,tmp1
ldi tmp1,(1<<USISIF)|(1<<USIOIF)|(1<<USIPF)|(1<<USIDC);Lösche USI Flags
out USISR,tmp1 ;und resete den Counter
ret
;************************************************* ***********************


; USI_TWI_master_start
; Sendet Startbedingung und die Slaveadresse
; Parameter, Slaveadresse im Register param1
; Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
;************************************************* ***********************
USI_TWI_master_start:
sbi PORT_USI,PIN_USI_SCL;zieht SCL High
USI_TWI_master_start_1:
sbis PIN_USI,PIN_USI_SCL;warte bis SCL High ist
rjmp USI_TWI_master_start_1
rcall delay
cbi PORT_USI,PIN_USI_SDA ; zieht SDA LOW
rcall delay
cbi PORT_USI,PIN_USI_SCL ;SCL wieder LOW
sbi PORT_USI,PIN_USI_SDA ;SDA High
out USIDR,param1; Slaveadresse/Data in den USI Dataregister schreiben
;mastertransfer aufrufen
TRANSFER_8_BIT
cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang
TRANSFER_1_BIT
ret
;************************************************* **********************


; USI_TWI_master_write
; Sendet ein Byte am den Master
; Parameter: Data im Register param1
; Rueckgabe 1 beim Erfolg 0 beim Fehler ueber Register param1
;************************************************* **********************
USI_TWI_master_write:
out USIDR,param1; Data in den USI Dataregister schreiben
;mastertransfer aufrufen für die
TRANSFER_8_BIT ;Byte Uebergabe
cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang
TRANSFER_1_BIT;um ACK/Nack Abzuholen
ret
;************************************************* **********************

; USI_TWI_master_read
; Liest ein Byte vom Slave aus
; Parameter: Sende ACK/Nack im param1 1 == ACK senden; 0 == kein ACK senden(Nack)
; Rueckgabe gelesene Daten in param1
USI_TWI_master_read:
cbi DDR_USI,PIN_USI_SDA ;SDA auf Eingang setzen
TRANSFER_8_BIT
push param1
brtc USI_TWI_master_read_send_NACK ;wenn T Flag geloescht ist erfolgt ein NACK
;sonst muss ein ACK erfolgen
out USIDR,null
rjmp USI_TWI_master_read_end
USI_TWI_master_read_send_NACK:
out USIDR,full
USI_TWI_master_read_end:
TRANSFER_1_BIT
pop param1
ret
;************************************************* **********************


; USI_TWI_master_transfer
; sorgt für die Komunikation mit dem slave
;mit param1 wird übergeben ob ein Byte empfange/gesendet wird, oder nur 1 Bit für ACK/NACK

USI_TWI_master_transfer:
out USISR,param1;der Counter wird vorgeladen
USI_TWI_master_transfer_1:
rcall delay
sbi USICR,USITC ;Positive Flanke an SCL erzeugen
USI_TWI_master_transfer_2:
sbis PIN_USI,PIN_USI_SCL ; warten bis SCL High ist
rjmp USI_TWI_master_transfer_2
rcall delay
sbi USICR,USITC;negative Flanke an SCL erzeugen
sbis USISR,USIOIF;testen ob Counter ubergelaufen ist
rjmp USI_TWI_master_transfer_1 ;wenn nicht mit dem nächstem Bit
rcall delay ;wenn gelesen wird
in param1,USIDR;Daten holen
out USIDR,full
sbi DDR_USI,PIN_USI_SDA; SDA auf Ausgang stellen
ret
;************************************************* **********************


; USI_TWI_master_stop:
;Sendet die Stop Bedingung
;************************************************* **********************
USI_TWI_master_stop:
cbi PORT_USI,PIN_USI_SDA
sbi PORT_USI,PIN_USI_SCL
USI_TWI_master_stop_1:
sbis PIN_USI,PIN_USI_SCL
rjmp USI_TWI_master_stop_1
rcall delay
sbi PORT_USI,PIN_USI_SDA
rcall delay
ret
;************************************************* **********************

; delay
;Eine kurze Pause von insgesammt 10 Takten
;************************************************* **********************
delay:
;Rcall hat 3 Takte gedauert
nop ;1 Takt
nop ;1 Takt
nop ;1 Takt
ret ; 4 Takte
;************************************************* **********************


das Ganze ist als usi_master.asm gespeichert und im Hauptprogramm eingebunden.

Mögliche Verwendung sieht dann so aus:

Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]


;EEPROM Slave Adresse von HP03
.equ HP03_sEEPROM = 0xA0

.org 0x0000
rjmp reset
.org OVF1addr
rjmp timer1
.include "usi_master.asm"

reset:
ldi tmp1,RAMEND
out SPL,tmp1
rcall USI_TWI_master_init
loop:
rcall HP03_EEPROM_read
rjmp loop


HP03_EEPROM_read:
;es sind insgesamt 18 Bytes zu empfangen und schoen der Reihe nach bei C1
;angefangen abzulegen
ldi tmp1,0x12 ;Readzaehler belegen
ldi XH,HIGH(C1)
ldi XL,LOW(C1)
START_I2C HP03_sEEPROM+WRITE ;Start an HP03 EEPROM senden
ldi param1,HP03_dEEPROM ;EEPROM Adresse einstallen
rcall USI_TWI_master_write
START_I2C HP03_sEEPROM+READ ;RepStart an HP03 EEPROM senden
HP03_EEPROM_read1:
cpi tmp1,2
brlo HP03_EEPROM_read2
READ_ACK
st X+,param1
dec tmp1
rjmp HP03_EEPROM_read1
HP03_EEPROM_read2:
READ_NACK
st X,param1
rcall USI_TWI_master_stop
ret


Was man anpassen muß ist das hier:
Code: [View More of this Code] [View Even More of this Code] [View Less of this Code] [Select All of this Code]

;USI Pin Konfiguration fuer tiny 24

.equ PORT_USI = PORTA
.equ DDR_USI = PORT_USI- 1
.equ PIN_USI = DDR_USI - 1
.equ PORT_USI_SDA = PORTA6
.equ PORT_USI_SCL = PORTA4
.equ PIN_USI_SDA = PINA6
.equ PIN_USI_SCL = PINA4[/code]