Servus, folgendes Problem: 2 AtMega16 mit integrierter I2C-Steuerung miteinander verbunden. Der eine schickt, der andere empfängt. Funktioniert soweit auch ganz gut. Er reagiert nur, wenn er auch per Adresse selektiert ist und gibt die richtigen Daten aus. Jedoch gibt der Empfäger partout den Bus nicht mehr frei, dh die Taktleitung bleibt low. Das ist lt. Datenblatt das Zeichen, dass der Controller noch mit der Bearbeitung der Befehle beschäftigt ist und bitte in Ruhe gelassen werden möchte. Aber ich kann den nur per Reset wieder freimachen, ich kapiers echt nicht. Der Controller ist längst fertig. Das ganze ist nur ein Test, deswegen ein sehr simpler Test und auch ohne Statuscontrolle. Lt. Datenblatt sollte der Code korrekt sein. Im Anhang ist das Sende-file (main.asm) und der Empfängercode (rec.asm). Was muss ich da wo reinmachen, damit der Bus wieder freigegeben wird, bzw die Leitung wieder auf high gelassen wird?
Ich glaub man muss das TWI einmal aus und wieder an machen oder der Master muss ein STOP senden.
wie meinst das? an und aus? Der Master sendet ein Stop, wenn ich eine andere Adresse nehme, aufdie keiner reagiert, dann funktioniert das auch. Erst wenn ein Slave drauf anspringt, dann gibt der den Bus nichmehr frei.
Nach ende der Transmission muss der Master ein STOP senden. Alternativ: Slave deaktiviert sein TWI und aktiviert es danach wieder (so auch im Fehlerfalle)
Hm, schaut euch bitte mal meine Codes an. Ist im Anhang des ersten Postings. Da wird doch in der richtigen Reihenfolge alles gesendet, und am Schluss noch eine Stop-Bedingung. Was ist denn da falsch?
'Nabend habe mir mal den Code angesehen. Beim Master scheint auf den ersten Blick alles ok zu sein. Aber beim Empfänger: hier benutzt Du den Interrupt. im Label "rec:" bestätigst du die 0x60 (Slaveadressrec+W) im label "rec1:" holst Du dir die Daten ab. Das funktioniert ja auch, wie du oben geschrieben hast. Nun musst Du, genau wie Du auf deinen Adressmatch geantwortet hast, auch den Datenempfang bestätigen.
1 | ... |
2 | ... |
3 | rec: cli ;Interrupts abschalten |
4 | ldi r16,(1 << TWINT) | (1 << TWEN) | (1 << TWEA) |
5 | out TWCR,r16 ;Daten holen |
6 | |
7 | rec1: in r16,TWCR ; |
8 | sbrs r16,TWINT ;und kontrollieren |
9 | rjmp rec1 ; |
10 | in r16,TWDR ;nach r16 |
11 | out PORTB,r16 ;dann PortB |
12 | ldi r16,(1 << TWINT) | (1 << TWEN) |
13 | out TWCR,r16 |
14 | sei ;Interrupts an |
15 | reti ;Rücksprung |
16 | .EXIT |
Ein ACK brauchst Du nicht senden, da das eine Datenbyte ja eh das letzte, weil einzigstes, war. Hoffe's hilft (und stimmt, habs jetzt nicht ausprobiert) AxelR.
Wenn der Slave SCL auf low hält, dann hat das seinen Grund, nämlich Du hast den Interrupt nicht bearbeitet. Das stimmt auch, da Du nach dem ersten Interrupt jeden weiteren Interrupt sperrst. Auch mußt Du die Daten lesen, bevor Du das Interruptflag löschst. Und zu allererst mußt Du den Status lesen und prüfen, ob das überhaupt ein Datenbyte ist, welches den Interrupt ausgelöst hat. Und schmeiß mal diesen ganzen cli/sei-Mist aus den Interrupts raus, das hat da nichts verloren (Datenblatt lesen). Peter
cli im Interrupt ist wahrlich nicht von nöten. Mcht er ja schon von
Hause aus.
Das der Interrupt abgeschaltet wird, habe ich auch geshen. Hat mich aber
nicht weiter interessiert, da das TWINT Flag auch ohne Int. kommt.
Das wird ja dann letztendlich gepollt.
Bisken kryptisch und ungewohnt erscheint mir die gemischte Nutzung von
Interrupt und Polling allerdings auch.
>nämlich Du hast den Interrupt nicht bearbeitet.
macht er jetzt spätestens, wenn er das TWINT Flag setzt
okay, danke euch allen. es lag an der anweisung von axel, soe bearbeitet den letzten interrupt. @peter: okay, sei/cli hat da nichts zu suchen. ich wollte damit nur folgendes verhindern: im slave receiver mode können u.a. folgende aktionen einen interrupt auslösen: Der Controller wurde angesprochen per eigener Adresse oder General Call und ACK ist gesendet worden. Daten sind empfangen worden, für die 2 Aktivierungsarten+nach ACK/NACK getrennt. JEDER dieser Aktionen würde ja dann den Interrupt auslösen. In meinem Slave-Programm werden ja folgende 3 Aktionen beantwortet: 1.Sla+Write empfangen 2.Daten empfangen 3.Stop erkannt. Wenn man die Interrupts anlässt, springt der Controller nicht bei jeder Aktion zum Anfang des Service-Programms zurück? Wartet er bis reti erreicht ist? Ich habe heute extra nochmal das Datenblatt durchgesehen, aber leider nichts gefunden.
Axel Rühl wrote: > Das der Interrupt abgeschaltet wird, habe ich auch geshen. Hat mich aber > nicht weiter interessiert, da das TWINT Flag auch ohne Int. kommt. > Das wird ja dann letztendlich gepollt. Ich sehe da nur:
1 | loop: rjmp loop |
Wenn also der Interrupt abgeschaltet ist, wird nichts gepollt. Peter
Florian Glaser wrote: > getrennt. JEDER dieser Aktionen würde ja dann den Interrupt auslösen. In > meinem Slave-Programm werden ja folgende 3 Aktionen beantwortet: > > 1.Sla+Write empfangen > 2.Daten empfangen > 3.Stop erkannt. So gehts nicht. Wenn ein Interrupt kommt, mußt Du ihn immer bearbeiten, auch wenn ein Status kommt, den Du nicht erwartest. Ansonsten bleibt SCL = low und kein weiterer Interrupt kann kommen. > Wenn man die Interrupts anlässt, springt der Controller nicht bei jeder > Aktion zum Anfang des Service-Programms zurück? Wartet er bis reti > erreicht ist? Ich habe heute extra nochmal das Datenblatt durchgesehen, > aber leider nichts gefunden. Siehe Status Register Bit 7: The I-bit is cleared by hardware after an interrupt has occurred, and is set by the RETI instruction to enable subsequent interrupts. The I-bit can also be set and cleared by the application with the SEI and CLI instructions, as described in the instruction set reference. Peter
Peter Dannegger wrote: > Axel Rühl wrote: > >> Das der Interrupt abgeschaltet wird, habe ich auch geshen. Hat mich aber >> nicht weiter interessiert, da das TWINT Flag auch ohne Int. kommt. >> Das wird ja dann letztendlich gepollt. > > Ich sehe da nur: > >
1 | > loop: rjmp loop |
2 | >
|
> > Wenn also der Interrupt abgeschaltet ist, wird nichts gepollt. > > > Peter erstmal springt er nach loop und häüngt dort. Dann kommt der erste Interrupt in der ISR wird der int abgeschaltet und das Flag gepollt Die ISR wird nicht mehr verlassen, bis die Daten für die LEDs angekommen sind. Jetzt werden die Interrupts wieder erlaubt und die ISR verlassen und sofort wieder bei Loppjmploop weitergearbeitet. Funktioniert schon so, wenn auch etwas kryptisch un ungewöhlich, da nicht alle Stati ausgewertet werden - auch nicht beim Pollen des TWINT Flag. Es kann schon sein, das zwischen der 60 und der 80(89) noch was anderes kommt. Dann hat er noch die alten Werte im TDR. Ich würde mir da auch 'ne statemaschine basteln, klar. Aber wenn das Programm sonst nichts weiter zu tun hat. Erinnert mich son bisken an Warteschleifen<->timer Diskussion. Gruß AxelR.
Axel Rühl wrote: > erstmal springt er nach loop und häüngt dort. > Dann kommt der erste Interrupt > in der ISR wird der int abgeschaltet und das Flag gepollt > Die ISR wird nicht mehr verlassen, bis die Daten für die LEDs angekommen > sind. > Jetzt werden die Interrupts wieder erlaubt und die ISR verlassen und > sofort wieder bei Loppjmploop weitergearbeitet. Nö:
1 | ldi r16,(1 << TWINT) | (1 << TWEN) | (1 << TWEA) |
2 | out TWCR,r16 ;Daten holen |
Es wird also TWIE gelöscht und damit sind weitere I2C-Interrupts gesperrt. Peter
Hallo Florian, hierzu habe ich mal ein kleines Beispiel für einen MASTER und einen SLAVE erstellt, 2 BYTE senden und empfangen, villeicht hilft es: Beitrag "TWI / I2C einf. MASTER SLAVE Beispiel(Assembler) ATmega8" Bernhard
Peter Dannegger wrote: > Axel Rühl wrote: > >> erstmal springt er nach loop und häüngt dort. >> Dann kommt der erste Interrupt >> in der ISR wird der int abgeschaltet und das Flag gepollt >> Die ISR wird nicht mehr verlassen, bis die Daten für die LEDs angekommen >> sind. >> Jetzt werden die Interrupts wieder erlaubt und die ISR verlassen und >> sofort wieder bei Loppjmploop weitergearbeitet. > > Nö: > >
1 | > ldi r16,(1 << TWINT) | (1 << TWEN) | (1 << TWEA) |
2 | > out TWCR,r16 ;Daten holen |
3 | >
|
> > Es wird also TWIE gelöscht und damit sind weitere I2C-Interrupts > gesperrt. > > > Peter Das TWINT Flag wird aber trotzdem gesetzt, auch wenn der Interrupt gesperrt ist. Dieses wird gepollt. Es ist vom Programmablauf nicht nötig, das ein neuer Interrupt ausgelöst wird - und auch nicht erwünscht. So sehe ich das...
Axel Rühl wrote: >>> Jetzt werden die Interrupts wieder erlaubt und die ISR verlassen und >>> sofort wieder bei Loppjmploop weitergearbeitet. ... > Das TWINT Flag wird aber trotzdem gesetzt, auch wenn der Interrupt > gesperrt ist. Dieses wird gepollt. Du solltest Dich mal entscheiden, wird der Interupt wieder erlaubt oder gepollt. In Loppjmploop wird jedenfalls nichts gepollt und wegen TWEA=0 auch kein Interupt mehr ausgeführt. Aber egal, ob pollen oder Interrupt, man muß TWINT immer zurücksetzten (also setzten), sonst hängt der I2C forever. > Es ist vom Programmablauf nicht nötig, das ein neuer Interrupt ausgelöst > wird - und auch nicht erwünscht. Dann muß man aber das TWI ganz abschalten (TWEN = 0), ansonsten hängt der I2C, wenn der Master wieder drauf zugreift und der Interrupt nicht bearbeitet wird. Peter
Danke euch allen. Zu der ganzen Interrupt-Diskussion: Mit der ersten Instruktion im Service-Programm wird in der Tat TWIE 0 gesetzt und hat somit keine Wirkung mehr. Aber da ja in SREG I beim betreten des Service-Programms sowieso 0 gesetzt wird, ist das egal. Das TWINT-Flag heißt zwar TWI-Interrupt, wird aber einfach nur nach jeder Aktion auf dem Bus gelöscht. Erst zusammen mit TWIE=1 löst es auch wirklich einen Interrupt aus, benutzen kann man es nach wie vor zur Steuerung. So richtig? Die ganze Statusüberprüfung werde ich noch einbauen.
habe mich entschieden: erst wird der int erlaubt (bis0x60), dann wird in der ISR verweilt und weiter das TWINT Flag gepollt und ordnungsgemäß gelöscht. Nach Vollendeter Datenübertragung wird der TWI Interrupt - jetzt gebe ich Dir ENDLICH Recht - NICHT wieder erlaubt und der Kerl bleibt in loppjmploop schleife hängen! Beim zweiten Versuch, irgentwas an den LEDs zu schalten, hängt der I2C Bus, da weder das TWI abgeschaltet wurde, noch das TWINT Flag zurückgesetzt werden kann, da ein setzen dieses nicht bemerkt wird (Kein Int aktiv und Loopjmploop). Also geht der Spass genau ein einziges mal :-)) Und wenn zwischendurch noch was anderes aufm Bus passiert, nicht mal das. Ich denke, jetzt ham was alle begriffen - auch ich. Viele Grüße AxelR.
falls du übrigens micht gemeint hast mit recht geben: ich habe die ganze zeit nur beobachtet, was ihr über die interrupts diskutiert. In meinem vorherigen Post war ich bereits deiner Meinung und das Problem wurde mir klar, dass man TWIE wieder anschalten muss, vor dem Rücksprung :)
Florian Glaser wrote:
> klar, dass man TWIE wieder anschalten muss, vor dem Rücksprung :)
Du hättest es garnicht erst ausschalten müssen, denn Du bist ja noch im
Interrupt und kannst Dich daher nicht selbst unterbrechen.
Generell würde ich pollen in einem Interrupt aber vermeiden, da ja nicht
klar ist, wann und ob überhaupt das Bit wieder gesetzt wird.
Pollen in Interrupts ist also eine gute Chance, auf ewig hängen zu
bleiben.
Eine Ausnahme wäre pollen auf Timerablauf oder ADC-fertig, die müssen ja
nach der definierten Zeit kommen.
Peter
Moment. Habe ich das richitg verstanden: Jedesmal, wenn ich TWCR lade und nicht explizit 1<<TWIE mache, wird es null? Und was meint ihr denn genau mit pollen? Was soll ich vermeiden, und warum kann man da auf ewig hängen bleiben? könnt ihr mir des pls erklären? edit: falls du mit pollen twint setzen meinst, das muss sein. anders kriegt man ja keine aktion an die TWI-Steuerung raus.
>Jedesmal, wenn ich TWCR lade und nicht >explizit 1<<TWIE mache, wird es null? Wenn ich die Frage (bzw. den ersten Teil der Frage) richtig verstehe: Alle Interrupts werden während der Ausführung einer ISR ausgeschaltet. Die Interrupts können zwar auftreten (wird durch Setzen der entsprechenden Interrupt-Flags gemacht), aber sie werden zu diesem Zeitpunkt nicht angesprungen. Das passiert frühestens nach Verlassen der aktuellen ISR. >Und was meint ihr denn genau mit pollen? Mit Pollen/Polling ist die Abfrage eines Zustandes gemeint. Es ist das ("manuelle") Gegenstück zur Interrupt-Programmierung. Das was der eingebaute Interrupt-Controller macht, macht man in diesem Fall in Software.
kay, die 2te sache ist mir jetzt klar. zum ersten: dass alle Interrupts während der ISR gesperrt sind, weiß ich. Meine Frage war lediglich, wenn ich in ein Register 2-3 Bits per obigem Lade-Befehl 1 setze, ob dann alle anderen Bits in diesem Register automatisch 0 werden, also setzt zb ldi r16,(1 << TWINT) | (1 << TWEN) | (1 << TWEA) out TWCR,r16 TWSTA, TWSTO und TWIE = 0? das war meine frage :)
>Meine Frage war lediglich..alle anderen Bits..automatisch 0 werden
Ja, dem ist so!
Du könntest das TWCR einlesen mit "in"
deine Bits in einem deiner Temp register setzen
mit deinem "einleseregister" verodern
und mit "out" ins TWCR zurückschreiben.
in r16,TWCR out TWCR, r16 sollte hierbei schon reichen. Das TWINT Bit ist bereits gesetzt, um es zu löschen musst Du es setzen. TWEN ist gesetzt und soll es bleiben, glieches gilt für TWEA. gibt also keine Notwendigkeit (meistens jedenfalls) an den Bits was zu ändern.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.