USART Interrupt ATMega

T

Thomas Mundhenke

Guest
Hallo NG,
ich habe folgendes Problem:
in meiner Haussteuerung setze ich ATMega8 oder 16 (gleiches Problem)
ein, die als Sensoren oder Aktoren über einen RS485-Full-Duplex-Bus
miteinander kommunizieren. Damit das Senden funktioniert, werden die
RS485-SendeTreiber vor den Senden ein- und danach wieder ausgeschaltet,
per Port-PIN ! Das Problem besteht darin, dass ich zum Ausschalten des
Senders den Zeitpunkt wissen muss, nachdem das letzte Zeichen den
Sendepuffer wirklich physisch verlassen hat. Gemäß meinem
Speicherscope werden aber sowohl TX-Empty wie auch Tx complete
Interrupt ausgelöst, bevor das Zeichen wirklich den Buffer verlassen
hat. Damit wird der Sender zu früh disabled und das letzte gesendete
Zeichen ruiniert.
Mach' ich da was falsch, habe ich was übersehen ?!?
Ich bin dankbar für jede brauchbare Idee, denn ansonsten funktionieren
meine Ringbufferroutinen wirklich astrein !

Gruß Thomas
 
Thomas Mundhenke schrieb:

Sendepuffer wirklich physisch verlassen hat. Gemäß meinem
Speicherscope werden aber sowohl TX-Empty wie auch Tx complete
Interrupt ausgelöst, bevor das Zeichen wirklich den Buffer verlassen
So als ľC neuling würde das mit dem Holzhammer lösen indem ich per Timer
einfach noch ein paar Takte abwarte, sofern der Timer nicht andersweitig
benutzt wird. Wenn die Timer belegt sind, kannst du eventuell derweile
erstmal eine Quadrahtwurzel ausrechnen.

Mir ist natürlich klar das das nicht gerade elegant gelöst wäre ;o))

bye uwe

--
AIM: hammernocker2000 ## ICQ: 115118874 ## www.pssgzudresden.de
Jürgen Gerkens in d.r.f. : "... gerade ein Polfilter ist als
Schutzfilter auch nicht viel schlauer, als die Frontlinse zum Schutz
vor Streulicht zu lackieren. ;-)"
 
On 17 Jan 2006 14:53:40 -0800, "Thomas Mundhenke" <nelke0816@gmx.de>
wrote:

in meiner Haussteuerung setze ich ATMega8 oder 16 (gleiches Problem)
<....>

Speicherscope werden aber sowohl TX-Empty wie auch Tx complete
Interrupt ausgelöst, bevor das Zeichen wirklich den Buffer verlassen
Also beim TX-Empty is das klar, weil ein neues Zeichen kann ja schon
zum Senden ins Senderegister geladen werden, während das letzte gerade
noch das Schieberegister am Verlassen ist.
Aber beim TX complete sollte das IMO nicht sein.

Ich würde das per "Probieren" rausfinden:
Bei fixer Baud-Rate weisst Du ja wie lange das Ausgeben des Zeichens
braucht. Zwecks Test würde ich folgendes machen:

0) UART config ;)
1) Timer starten
2) zu sendendes Zeichen in TX schreiben
3) mit dem TXcomplete den Timer auslesen
4) Differenz zwischen IST und SOLL überprüfen

Alternativ geht das natürlich auch mit einem Port-Pin und einem Oszi
(falls vorhanden). Ein Kanal (=Trigger) aufs Port-Bit, den zweiten auf
den Seriellen Ausgang. Und damits einfach zum messen wird einfach eine
Endlosschleife, in der Bytes auf die serielle ausgegeben werden.

Ich denke mal, dass du dir das Stop-Bit zerschiesst. Vielleicht ist
die Idee aus dem zweiten Posting (Holzhammer-Methode) ja gar nicht
sooo daneben. Einfach noch 10ms warten und dann erst den Treiber
abschalten. Wenn sonst nix zu tun is kann das ja sogar eine simple
"strohdumme" Loop sein. Sonst halt per Timer.

Heinz
 
Erstmal danke für die Vorschläge, die Delay Methode nehme ich, wenns
nicht anders geht. Da meine Software ohnehin Timergesteuert läuft ist
das kein Problem. Die Oszi-Messung mache ich ja schon wie beschrieben
und es wird definitiv unabhängig von der Baudrate mitten im Zeichen,
ungefährt bei Bit 3-5 der Interrupt ausgelöst. Was ich nicht
verstehe, ist dass beide Interrupts das gleiche Resultat liefern ?!?
Gruß Thomas
 
Thomas Mundhenke <nelke0816@gmx.de> wrote:
: Hallo NG,
: ich habe folgendes Problem:
: in meiner Haussteuerung setze ich ATMega8 oder 16 (gleiches Problem)
: ein, die als Sensoren oder Aktoren über einen RS485-Full-Duplex-Bus
: miteinander kommunizieren. Damit das Senden funktioniert, werden die
: RS485-SendeTreiber vor den Senden ein- und danach wieder ausgeschaltet,
: per Port-PIN ! Das Problem besteht darin, dass ich zum Ausschalten des
: Senders den Zeitpunkt wissen muss, nachdem das letzte Zeichen den
: Sendepuffer wirklich physisch verlassen hat. Gemäß meinem
: Speicherscope werden aber sowohl TX-Empty wie auch Tx complete
: Interrupt ausgelöst, bevor das Zeichen wirklich den Buffer verlassen
: hat. Damit wird der Sender zu früh disabled und das letzte gesendete
AFAIK sind TX-Empty oder Tx complete dafür gedacht, anzuzeigen, daß
der Empfänger wieder aufnahmebereit ist. Meist sind die Empfängerregister
gepuffert. Wenn Tx complete beim Stopbit ausgelöst wird, könnte es reichen,
2 Stopbits zu verwenden.
 
Hallo Thomas,

Thomas Mundhenke wrote:

Erstmal danke für die Vorschläge, die Delay Methode nehme ich, wenns
nicht anders geht. Da meine Software ohnehin Timergesteuert läuft ist
das kein Problem. Die Oszi-Messung mache ich ja schon wie beschrieben
und es wird definitiv unabhängig von der Baudrate mitten im Zeichen,
ungefährt bei Bit 3-5 der Interrupt ausgelöst. Was ich nicht
verstehe, ist dass beide Interrupts das gleiche Resultat liefern ?!?
Das kann/sollte auf keinen Fall so sein. Entweder hat Atmel ein Problem
oder Du bei Deiner Messung :). Da das aber eine extrem elementare
Funktion ist, tippe ich auf Dich :). Schreib doch mal, wie Du den
Interrupt erkennst und nach außen reichst (für den Scope).

Gruß, Kurt
--
Kurt Harders
MBTronik - PiN - Präsenz im Netz GITmbH
mailto:news@kurt-harders.de
http://www.mbtronik.de
 
Hallo,

kann es sein das du Transmit Compete Interrupt Enable (TXCIE) erst beim
senden setzt und das TXCI Flag noch vom vorherigen Byte gesetzt ist und
so der Interrupt sofort ausgelöst wird?


Gruß
 
In der Xmit-Interruptroutine werden die By<tes per Ringbuffer solange
rausgeschrieben, bis der Buffercounter Null ist. In diesem Zustand ist
das letzte Byte aber noch nichr 'rausgetaktet, wenn ich jetzt den
RS485-Treiber abschalte, wird das Byte mittendrin abgeschnitten, daher
ist auch der Vorschlag mit zwei Stopbits keine Lösung.
Aber deine Idee habe ich noch nicht verstanden !?!
Bestimmt habe ich den Mechanismus der Interrupts noch nicht richtig
begriffen und es muss mit Interrupts funktionieren, bei anderen ľC
gehts ja auch !
Gruß Thomas
Benjamin Muckelbach schrieb:

Hallo,

kann es sein das du Transmit Compete Interrupt Enable (TXCIE) erst beim
senden setzt und das TXCI Flag noch vom vorherigen Byte gesetzt ist und
so der Interrupt sofort ausgelöst wird?


Gruß
 
warum liest Du nicht einfach beim Senden gleichzeitig mit ein, dann weißt Du
a) ob irgendeiner, obwohl er nicht durfte, was zwischenreingefunkt hat
b) alles von Deinem Krempel raus ist, weil nur dann das Receive Interrupt
Flag gesetzt wird.

?
Carsten
 
Ich bin absolut der Meinung, dass es irgendwie gehen muss, nur ich
komme immer wieder zum gleichen Resultat, dass beide Interrupts mitten
im letzten Zeichen ausgelöst werden. Die vorgeschlagene Delaymethode
klappt natürlich, aber geht nicht gibt's doch wohl nicht ?
Quellcodeauszug wie folgt:

// TX Complete Interrupt Service
void UART_TX_Interrupt( void ){
........... Behandlung Ringbuffer, wenns nicht das letzte Zeichen ist !
.......... zum Schluß
// falls noch Zeichen im Ringbuffer sind
if(TX_Counter){
// enable Transmit Complete Interrupt
UCSRA |= (1<<TXC);
// falls Ringbuffer leer
}else{
// enable USART Data Register Empty Interrupt
UCSRB |= (1<<UDRIE); /* enable */
}
}// end of void UART_TX_Interrupt( void )

// USART Data Register Empty Interrupt
void UART_UDRE_Interrupt(void)
{
// disable USART Data Register Empty Interrupt
UCSRB &= ~(1<<UDRIE);
// disable RS485-Transmitter
RS485_TX_DISABLE;

}

Wie gesagt, die Interrupts werden brav ausgelöst, nur eben nicht am
Ende der phys. Ausgabe, die Messmethode ist ebenfalls richtig,
empfangen tue ich nichts, die Interrupts sind auch die einzigen die
auftreten. Wenn niemand mehr helfen kann ( trotzdem danke für Eure
Anregungen) nehm' ich halt den Delay und schäme mich ;-))
Gruß Thomas
 
Hallo

Thomas Mundhenke schrieb:
In der Xmit-Interruptroutine werden die By<tes per Ringbuffer solange
rausgeschrieben, bis der Buffercounter Null ist. In diesem Zustand ist
das letzte Byte aber noch nichr 'rausgetaktet, wenn ich jetzt den
RS485-Treiber abschalte, wird das Byte mittendrin abgeschnitten, daher
ist auch der Vorschlag mit zwei Stopbits keine Lösung.
Aber deine Idee habe ich noch nicht verstanden !?!
Welchen IRQ meinst Du jetzt mit Xmit, den "USART Data Register Empty"
oder "USART, Tx Complete"?

Ich verstehe das jetzt so:
Du verwendest den UDRE-Interrupt um ein neues Byte in UDR zu legen.
Beim letzten Byte aktivierst Du dann TXCIE um den "USART, Tx Complete"
Irq zu bekommen und dann dort denn Treiber abzuschalten.
Das TXC Bit was den Irq triggert wird jedoch auch gesetzt wenn du denn
Interrupt nicht aktivierst. Wenn Du jetzt also den UDRIE Aktivierst ist
TXC noch vom zuvor gesendeten Byte gesetzt und der Interrupt wird sofort
ausgelöst (bzw. nach dem verlassen der UDRE Irq-Routine).

Bist Du sicher das es wirklich das letze Byte ist das abgeschnitten wird?
Ich vermute hier ja eher ein timing oder zähl Problem, so wie ich das
Datenblatt verstehe sollte Dein Vorhaben sonst mit dem TXC-Irq
Funktionieren.

Gruß

Ben
 
Hi,

welchen Compiler hast Du denn? bei mir (winavr) sehen die Aufrufe der
IRQ-Funktionen anders aus.

Ich denke aber du musst auf jeden Fall die beiden IRQs tauschen.

// TX Complete Interrupt Service
void UART_TX_Interrupt( void ){
sollte aufgerufen werden wenn das Byte draussen ist und

// USART Data Register Empty Interrupt
void UART_UDRE_Interrupt(void)
sollte aufgerufen werden wenn UDR frei ist, also das erste BIT des
vorherigen Bytes gesendet wird.


dann gibt es aber noch das Problem Du das letzte Bit ins UDR schreibst
und du dann das TXC vom vorherigen Byte bekommst (das ja zeitgleich raus
gesendet wird). Der Controller sendet jetzt das nächste Byte und Du
schaltest ab.
Vielleicht solltest Du alles im TXC Irq machen, dann verlierst du zwar
etwas Zeit zwischen den einzelnen Byte aber das zählen wird einfacher.
oder zähl mal Probehalber die Bytes im TXC-Irq mit.

Gruß
 
Thomas Mundhenke wrote:

Hallo NG,
ich habe folgendes Problem:
in meiner Haussteuerung setze ich ATMega8 oder 16 (gleiches Problem)
ein, die als Sensoren oder Aktoren über einen RS485-Full-Duplex-Bus
miteinander kommunizieren. Damit das Senden funktioniert, werden die
RS485-SendeTreiber vor den Senden ein- und danach wieder ausgeschaltet,
per Port-PIN ! Das Problem besteht darin, dass ich zum Ausschalten des
Senders den Zeitpunkt wissen muss, nachdem das letzte Zeichen den
Sendepuffer wirklich physisch verlassen hat. Gemäß meinem
Speicherscope werden aber sowohl TX-Empty wie auch Tx complete
Interrupt ausgelöst, bevor das Zeichen wirklich den Buffer verlassen
hat. Damit wird der Sender zu früh disabled und das letzte gesendete
Zeichen ruiniert.
Mach' ich da was falsch, habe ich was übersehen ?!?
Ich bin dankbar für jede brauchbare Idee, denn ansonsten funktionieren
meine Ringbufferroutinen wirklich astrein !
Hallo Thomas,

hier nochmal meine Meinung. Erst bei Atmel die Errata zum Chip runterladen
und lesen. Wenn da alles in Ordnung ist, ist das sicherste:

1) alle Tx Interrupts ausschalten (bzw. auslassen)

2) die Daten in den Puffer schreiben
3) Treiber anschalten
4) UDREI setzen
5) im UDR-empty-Interrupt die Zeichen übertragen
6) nach dem letzten Zeichen
- TXC löschen (dazu mußt Du das Bit setzen!)
- TXCIE setzen
7) im TX-complete interrupt:
- Treiber ausschalten
- TXCIE löschen

Wenn das funktioniert kannst Du ein bißchen rumexperimentieren...

Viel Spaß
Jan-Hinnerk
 

Welcome to EDABoard.com

Sponsor

Back
Top