Hallo zusammen,
ich möchte in einem Projekt Temperatursensoren (DS18B20) über das Maxim
1-wire Protokoll benutzen.
Da der Mikrocontroller, ein ATmega1284P, noch eine ganze Menge anderer
Aufgaben übernimmt, möchte ich den zweiten USART Port des Controllers
verwenden, um das USART Modul asynchron mit den Temperatursensoren
kommunizieren zu lassen. Atmel hat in dem Dokument AVR318 beschrieben,
wie man das realisieren kann. Ich habe das Dokument und den von Atmel
veröffentlichten Quellcode nachfolgend verlinkt.
http://www.atmel.com/Images/doc2579.pdfhttp://www.atmel.com/Images/AVR318.zip
Ich habe die Schaltung von Seite 3 aus der PDF auf einem Steckbrett
nachgebaut. RXD geht bei mir zu Pin 16 und TXD zu Pin 17.
Da der Quellcode von Atmel ein wenig alt ist, habe ich ihn ein wenig
angepasst (richtige includes und die Interruptroutinen angepasst). Den
Modifizierten Quellcode habe ich angehängt.
Der uC ist mit 4MHz getaktet. An Port A habe ich 8 LEDs gehängt, um eine
Ausgabe produzieren zu können.
Nun zum eigentlichen Problem:
der uC scheint einzufrieren, denn sobald
1
OWI_DetectPresence();
einmal aufgerufen wird, passiert gar nichts mehr.
Die letzte Funktion die ausgeführt wird, ist
1
ISR(OWI_UART_UDRE_VECT)
in OWIIntFunctions.c, Zeile 246. Um das festzustellen habe ich den Port
A in Zeile 263 derselben Datei auf 0xFF gesetzt. Die LEDs flackern
einmal ganz kurz auf, dann passiert nichts mehr.
Ich besitze leider keinen Hardware-Debugger, daher fällt mir die
Diagnose sehr schwer. Ich konnte keine Programmierfehler finden, obwohl
ich den gesamten Quellcode mehrfach durchgegangen bin. Ich habe das
Gefühl, dass mit den Interruptroutinen irgend etwas nicht ganz richtig
ist.
Für Hilfestellung wäre ich sehr dankbar!
Viele Grüße
Christian
Christian Rudolph schrieb:> Da der Mikrocontroller, ein ATmega1284P, noch eine ganze Menge anderer> Aufgaben übernimmt, möchte ich den zweiten USART Port des Controllers> verwenden, um das USART Modul asynchron mit den Temperatursensoren> kommunizieren zu lassen.
Ist lächerlich, wenn du denkst, dass du den ATmega1284P mit ein paar
1-Wire Sensoren "überlasten könntest".
Fall der doch - ich glaube es aber nicht - doch an seine Grenzen käme,
wäre es immer noch die leichteste Übung, dem ein 16 oder 20 MHz Quarz zu
verpassen.
Ich habe mir den von dir verwendeten Code nicht angeschaut.
Während der 1-wire-Kommunikation musst du die IRQs sperren, sonst stimmt
das Timing nicht mehr. Hast du das berücksichtigt?
Kübelkotzer schrieb:> Ist lächerlich, wenn du denkst, dass du den ATmega1284P mit ein paar> 1-Wire Sensoren "überlasten könntest".
es geht nicht ums überlasten, sondern darum, dass der uC andere Aufgaben
erledigt, die blocken. Und da ich noch einen USART Port frei habe,
möchte ich diesen gerne nutzen, um die 1-wire Kommunikation asynchron zu
erledigen.
Thomas R. schrieb:> Während der 1-wire-Kommunikation musst du die IRQs sperren, sonst stimmt> das Timing nicht mehr. Hast du das berücksichtigt?
Sobald die Kommunikation stattfindet wird das UDRIE1 (Data Register
Empty Interrupt) Flag entfernt.
Der Interrupt Receive Complete wird, soweit ich es beobachten konnte,
nicht ausgelöst. Der sollte ja theoretisch auch erst ausgelöst werden,
wenn ein Byte übertragen wurde.
Was mich wundert ist, dass der uC nach Verlassen der Interruptroutine
und dem Versenden von einem Byte nicht mehr ansprechbar ist.
Viele Grüße
Christian
Hast Du den Code selbstgeschrieben (bzw. von Atmel übernommen)?
Wenn ja, schau doch einfach mal in die Codesammlung, dort gibt es guten,
stabilen Code, der sich sicher einfacher einbauen lässt, als jetzt den
Fehler zu suchen.
Ich habe den Code von Atmel übernommen und einige Anpassungen an meine
Plattform vorgenommen.
Ich werde mal in die Codesammlung schauen und sehen, ob mir das
weiterhilft.
Noch eine Frage: ist es problematisch, dass die Ausgabe vom TX Port
direkt auf den RX Port wieder ankommt?
Edit: der Ansatz in der Codesammlung ist auch ein reiner Softwareansatz.
Mir geht es darum mittels UART-Modul 1-wire zu "reden".
Ich habe jetzt die Atmel-Version vom Quellcode mit Polling statt mit
Interrupts gewählt. Damit kann ich die Temperatursensoren auslesen.
Also scheint das Problem irgendwie mit den Interrupts zusammenzuhängen.
Kann mir vielleicht irgendjemand einen Hinweis geben, was in dem oben
geposteten Code falsch läuft? Die Interruptroutinen befinden sich in der
Datei OWIIntFunctions.c
Danke und viele Grüße
Christian
Inwiefern sollten die 4 MHz Taktrate ein Problem darstellen? Die per
UART gesendeten Signale liegen alle locker im Toleranzbereich der
1-wire-Spezifikation, auch wenn die Abweichung der Baudrate bei bis zu
8,5% liegt.
Christian Rudolph schrieb:> es geht nicht ums überlasten, sondern darum, dass der uC andere Aufgaben> erledigt, die blocken.
Also wenn das so ist, dann ist das Hauptproblem ja erkannt.
Lösung: nicht blockierenden Code schreiben, z.B. Scheduler verwenden.
Das Problem mit einem Scheduler ist aber, dass die "parallel" laufenden
Tasks auch recht präzises Timing benötigen, welche ich dann
wahrscheinlich nicht mehr einhalten kann.
Ich weiche auch schon weitestgehend auf Timer mit Interrupts aus, aber
es geht eben nicht überall.
Zu den 4MHz nochmal: falls das das Problem wäre, hätte auch der Code mit
Polling nicht funktioniert.
>Zu den 4MHz nochmal: falls das das Problem wäre, hätte auch der Code mit>Polling nicht funktioniert.
250ns pro Taktzyklus. Bei den 1 Zyklus Befehlen schafft er da
gerade mal 4 Befehle pro 1us.
Hast du ne Ahnung wie lange es dauert bis der ATMega bei 4MHz
überhaupt mal im Interrupt landet?
Dann noch ein paar PUSHs usw. Da geht schon einiges ab.
Versuchs doch einfach mal mit 16MHz Takt.
Ansonsten hab ich aber auch nur geraten.
Christian Rudolph schrieb:> es geht nicht ums überlasten, sondern darum, dass der uC andere Aufgaben> erledigt, die blocken.
Dann solltest du die Code-Teile mal überdenken.
holger schrieb:>>Zu den 4MHz nochmal: falls das das Problem wäre, hätte auch der Code mit>>Polling nicht funktioniert.>> 250ns pro Taktzyklus. Bei den 1 Zyklus Befehlen schafft er da> gerade mal 4 Befehle pro 1us.>> Hast du ne Ahnung wie lange es dauert bis der ATMega bei 4MHz> überhaupt mal im Interrupt landet?> Dann noch ein paar PUSHs usw. Da geht schon einiges ab.>> Versuchs doch einfach mal mit 16MHz Takt.
Ich habe hier leider nur einen 8MHz Oszillator, damit werde ich es noch
einmal versuchen.
Aber trotzdem habe ich noch ein Verständnisproblem. Für den Code mit
Polling stimme ich zu, da hätte es Probleme geben können, wenn die
Taktung zu niedrig wäre.
Ich dachte, dass das UART Modul im uC zwar durch den Haupttaktgeber
getaktet wird, aber von der Hauptrecheneinheit unabhängig ist und echt
parallel arbeitet.
Die zu sendenden und empfangenen Daten landen einfach in einem Register,
auf welches dann bei Gelegenheit zugegriffen wird (ob durch Interrupt
oder zyklische Prüfung ausgelöst ist dabei ja erstmal egal).
Um die erforderliche Taktrate im UART Modul zu erzielen, reichen 2,17MHz
bereits aus. Die von mir errechnete Baudrate liegt bei 125kbit/s, was
für einen High- oder Low-Takt bedeutet, dass er 8us lang ist. Damit
lassen sich die mindestens 15us langen Takte problemlos treffen.
Christian Rudolph schrieb:> Ich habe hier leider nur einen 8MHz Oszillator, damit werde ich es noch> einmal versuchen.
Ein 16MHz Quarz würde ja das Budget sprengen. Die lassen sich ja jedes
Hz extra bezahlen.
Hi,
ich finde es traurig, dass hier der Großteil der Kommentare
unqualifiziert ist. Ich habe doch noch einen 16MHz Oszillator gefunden,
mit dem sich das Problem allerdings auch nicht löst - nichtsdestotrotz
macht es keinen Sinn Oszillatoren in großer Stückzahl vorzuhalten, die
nicht meiner Zieltaktfrequenz von 4MHz entsprechen...
In diesem Sinne viele Grüße
Christian
Christian Rudolph schrieb:> ich finde es traurig, dass hier der Großteil der Kommentare> unqualifiziert ist.
Liegt wohl an der unqualifizierten Fragestellung. Hättest Du
beispielsweise Deine Interpretation der AN als .c/.h angehängt, könnte
man auch von 'nem Tablett 'nen Blick drauf werfen, ohne erst enzippen zu
müssen. Aber so halt nicht.
Dann gab's Vorschläge, dass vielleicht das Timing des restlichen Codes
überdacht werden sollte, da gab's auch keine qualifizierte Antwort von
Dir. Was erwartest Du ? Ein Thread ist zur Diskussion gedacht, und nicht
dass Dir einer den Knecht macht.
Wenn man die Flussdiagramme der RXD/TXD ISR's aus der AN ansieht, stellt
man fest, dass die Ausführung linear ist, also kein Warten auf eine
Bedingung stattfindet. Damit kann zumindest die ISR nicht blockieren.
Möglich wäre allerdings, dass Du das falsche UDR abholst, in so einem
Fall wird die ISR bis St. Nimmerlein aufgerufen, da das richtige UDR
nicht geleert wird.
Aber wie gesagt, in ein Zip seh' ich jetzt nicht rein.
Der Trick an der UART ist doch, daß sie immer funktioniert ohne lange
Interruptsperren. Die 10 UART-Bits machen das 1wire-Timing.
Der Nachteil ist aber, daß man externe Hardware braucht, da die UART
nicht Open-Drain kann.
MWS schrieb:> Liegt wohl an der unqualifizierten Fragestellung. Hättest Du> beispielsweise Deine Interpretation der AN als .c/.h angehängt, könnte> man auch von 'nem Tablett 'nen Blick drauf werfen, ohne erst enzippen zu> müssen. Aber so halt nicht.
Dass Entzippen so kompliziert ist, war mir nicht bewusst. An meinem
Rechner öffnet sich 7-Zip automatisch und nach einem Doppelklick auf die
darin enthaltene Datei kann ich mir den Quellcode ansehen. Und der
Quellcode ist doch nur im Ganzen sinnvoll.
> Dann gab's Vorschläge, dass vielleicht das Timing des restlichen Codes> überdacht werden sollte, da gab's auch keine qualifizierte Antwort von> Dir.
Das geht doch vollkommen an meiner Fragestellung vorbei... Der Code
funktioniert komplett ohne dass anderen Aufgaben vom uC erledigt werden
schon nicht. Ich habe begründet, warum ich einen Hardware-Ansatz möchte
und keinen Softwareansatz, worauf die Änderung des Timings des anderen
Codes abzielt.
> Was erwartest Du ? Ein Thread ist zur Diskussion gedacht, und nicht> dass Dir einer den Knecht macht.
Ich habe von niemandem verlangt mir den Knecht zu machen. Ich habe meine
Analysen geschrieben, darauf hingewiesen, dass ich glaube, dass es an
den Interrupts liegt, weil ein Pollingbasierter Ansatz funktioniert und
geschrieben, in welcher Datei sich die Interruptroutinen befinden, sogar
inklusive Zeilenangabe.
> Wenn man die Flussdiagramme der RXD/TXD ISR's aus der AN ansieht, stellt> man fest, dass die Ausführung linear ist, also kein Warten auf eine> Bedingung stattfindet. Damit kann zumindest die ISR nicht blockieren.> Möglich wäre allerdings, dass Du das falsche UDR abholst, in so einem> Fall wird die ISR bis St. Nimmerlein aufgerufen, da das richtige UDR> nicht geleert wird.
Der Hinweis, dass ich vielleicht die falsche UDR abhole ist ganz gut.
Ich habe daraufhin noch einmal meine gerätespezifischen Angaben zu den
Registern etc. überprüft und irgendwann bin ich dann darauf gekommen,
dass der Fehler in der Bezeichnung der Receive Complete ISR lag. Denn
der Interrupt heißt nicht USART1_RXC, sondern nur USART1_RX.
Ich habe den funktionierenden Quellcode nochmal als Zipdatei
hochgeladen. Vielleicht kann ihn ja jemand gebrauchen.
Christian Rudolph schrieb:> MWS schrieb:>> man auch von 'nem Tablett 'nen Blick drauf werfen, ohne erst enzippen zu> Dass Entzippen so kompliziert ist, war mir nicht bewusst. An meinem> Rechner öffnet sich 7-Zip automatisch und nach einem Doppelklick auf die
Musst lesen, ich schrieb Tablett und Tablett <> PC, da gibt's
Einschränkungen, das bedeutet nicht "unmöglich", sondern komplizierter.
Und dann ist die Neigung reinzuschauen eben geringer.
Ein passend gemachtes kleines Beispiel passt in ein paar Dateien, die
man nicht unbedingt verzippen muss.
Ansonsten, schön dass es geht ;-)
MWS schrieb:> Musst lesen, ich schrieb Tablett und Tablett <> PC, da gibt's> Einschränkungen, das bedeutet nicht "unmöglich", sondern komplizierter.> Und dann ist die Neigung reinzuschauen eben geringer.
Jetzt hab ichs verstanden. Ich habe bei Tablett nicht an ein Tablet
gedacht, sondern an an ein Gerät, auf dem man Speisen serviert ;-)
Komischerweise tauchte in meinem Kopf dann die Redewendung "auf dem
Silbertablett servieren" auf, was mich zu der Annahme verleitete, dass
die Zipdatei zu kompliziert zu bedienen sei.
Was mich auch noch wundert ist, dass man im Internet recht wenig zu
1wire über UART findet. Der Ansatz erscheint mir doch recht elegant,
sofern man noch einen UART Port frei hat. Die Kosten für die benötigte
zusätzliche Hardware hält sich ja auch in Grenzen (dürften etwa 10 Cent
sein: ein zusätzlicher Widerstand und zwei Standardtransistoren).
Maxim hat dazu übrigens auch ein Tutorial (TUTORIAL 214), allerdings
ohne Quellcode.
Christian Rudolph schrieb:> Jetzt hab ichs verstanden. Ich habe bei Tablett nicht an ein Tablet> gedacht, sondern an an ein Gerät, auf dem man Speisen serviert ;-)
Diese Assoziation ist trotz meiner nicht-angelsächsische Schreibweise
recht interessant. ;D
> Was mich auch noch wundert ist, dass man im Internet recht wenig zu> 1wire über UART findet. Der Ansatz erscheint mir doch recht elegant,> sofern man noch einen UART Port frei hat. Die Kosten für die benötigte> zusätzliche Hardware hält sich ja auch in Grenzen (dürften etwa 10 Cent> sein: ein zusätzlicher Widerstand und zwei Standardtransistoren).
Aber da's auch ohne externe Beschaltung, an jedem Pin und ohne
zusätzliches UART geht, wird eben die klassische Vorgehensweise
bevorzugt.