Forum: Mikrocontroller und Digitale Elektronik UART TXD nur aktivieren, wenn Daten gesendet werden?


von AVRli .. (avrli)


Lesenswert?

Hallo,

ich möchte den UART Transmitter eines ATmega2560 nur für die Zeit, wie 
auch wirklich Daten gesendet werden, einschalten.

Werden KEINE Daten ausgesendet, muss der Ausgang als Eingang hochohmig 
sein.

Der Grund ist der, das der µC an einem 1-Draht Bus hängt wo RXD und TXD 
miteinander verbunden sind. Es darf immer nur ein Teilnehmer senden, 
sonst hört er auf dem Bus.

Ich aktiviere den TXD Ausgang in der Routine, in der ich die zu 
sendenden Bytes in den UART_TX_BUFFER übertrage, wie folgt...
1
  SET_BIT(UART1_DDR, UART1_TXD_PIN);  // Output
2
  SET_BIT(UART1_PORT, UART1_TXD_PIN);  // PIN HIGH
3
  SET_BITS(UCSR1B, (1<<TXEN1));    // Enabled transmitter

...deaktiviert wird der UART Transmitter im "Data Register Empty" 
Interrupt, wenn keine weiteren Zeichen mehr im Buffer sind, mit...
1
  CLEAR_BIT(UART1_DDR, UART1_TXD_PIN);  // Input
2
  CLEAR_BIT(UART1_PORT, UART1_TXD_PIN);  // Pullup off
3
  CLEAR_BITS(UCSR1B, (1<<TXEN1));    // Disabled transmitter

Das ganze funktioniert auch so lange, wie die Zeichen die rausgehen 
sollen, direkt hintereinander folgen. Kommt es zu einer nur ganz kurzen 
Verzögerung bei der Ausgabe, gehen Bytes verloren. :-(

Ich habe die Vermutung das ich entweder zu spät einschalte oder aber zu 
früh wieder aus. Wo wäre der richtige Zeitpunkt um es dennoch 
realisieren zu können?

Gruß AVRli...

von Karl M. (Gast)


Lesenswert?

Hallo AVRli .. schrieb:

ich löse das nicht per Programm, denn der Zustand des TXD eines AVR ist 
direkt vom Ein- und Ausschalten des Sendezweigs des Uart abhängig.

Was einfach geht, ist per Logikschaltung über ein ODER-Gatter, das kann 
in diesem Fall eine Germanium oder Silizium Diode sein.

von Stefan F. (Gast)


Lesenswert?

Ich schätze, dass du einen Pull-Up Widerstand am Bus brauchst, damit die 
Leitung einen definierten Pegel hat, während der Tx-Ausgang deaktiviert 
ist.

von Amateur (Gast)


Lesenswert?

Wenn Du weißt, was Du tust, also Daten sendest und "Dir" selber zuhörst, 
ignoriere doch einfach den Schrott. Du weißt ja, wie es gemeint ist.
Ansonsten: UART-Eingang als "normalen" Eingang (I/O) konfigurieren.

von Georg A. (georga)


Lesenswert?

Es gibt ja zwei Möglichkeiten:

a) Du erzeugst beim Einschalten mit zuerst DDR und dann HIGH einen 
Low-Glitch, der das erste Sende-Byte ruiniert. Evtl. mal die Reihenfolge 
drehen. Hatte der AVR nicht einen schwachen Pullup, wenn man als Eingang 
den Ausgangsregister auf 1 gesetzt hat (oder verwechsle ich das mit 
einem der zig anderen CPUs, die ich schon mal misbraucht habe...)?

b) Du drehst zu früh ab, weil "Buffer empty" nur sagt, dass das 
Laderegister leer ist, aber das eigentliche Schieberegister noch ein 
paar Bits raustaktet.

Kannst du dir das nicht mal auf einem Oszi anschauen?

Oder ohne Oszi (jaja, ganz böse, aber es würde weiterhelfen...) vor dem 
Enable bzw. Disable ein delay() machen? Dann wüsste man wenigstens, 
welches Eck man anschauen muss.

von da1l6 (Gast)


Lesenswert?

Hallo,

Auf DRE warten reicht nicht, da wird noch gesendet ("double buffer").
Verwende den TXC interrupt zum deaktivieren des USARTs.

da1l6

von S. Landolt (Gast)


Lesenswert?

Wie von den Anderen bereits geschrieben, ist das DDR-Umschalten unnötig, 
evtl. sogar kontraproduktiv: 'TXENn: The Transmitter will override 
normal port operation for the TxDn pin when enabled'.
  Ich würde den TxD-Pin auf Eingang lassen und nur mit UART1_PORT den 
internen Pullup-Widerstand einschalten.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

da1l6 schrieb:
> Auf DRE warten reicht nicht, da wird noch gesendet ("double buffer").
> Verwende den TXC interrupt zum deaktivieren des USARTs.

Das kann ich nur so unterstreichen. Wenn das letzte Zeichen 
rausgeschickt wird, ist es noch lange nicht physikalisch vollständig auf 
der Leitung raus.

Der TX Complete Interrupt ist genau der richtige, um festzustellen, das 
wirklich auch das letzte Bit über den Draht ging.

: Bearbeitet durch Moderator
von S. Landolt (Gast)


Lesenswert?

> Du drehst zu früh ab ...
> Auf DRE warten reicht nicht, da wird noch gesendet

'The disabling of the Transmitter (writing TXENn to zero) will not 
become effective until ongoing and pending transmissions are completed, 
that is, when the Transmit Shift Register and Transmit Buffer Register 
do not contain data to be transmitted.'

von AVRli .. (avrli)


Lesenswert?

Georg A. schrieb:
> Oder ohne Oszi (jaja, ganz böse, aber es würde weiterhelfen...) vor dem
> Enable bzw. Disable ein delay() machen? Dann wüsste man wenigstens,
> welches Eck man anschauen muss.

Tcha ein "_delay_ms(1)" vor dem einleiten des Abschaltens bringt keine 
Fehler und somit ist...

da1l6 schrieb:
> Auf DRE warten reicht nicht, da wird noch gesendet ("double buffer").
> Verwende den TXC interrupt zum deaktivieren des USARTs.

Genau richtig! Das habe ich nun aktiviert, ich habe nicht mehr auf dem 
Schirm gehabt das es diesen Interrupt überhaupt gibt! :-(
1
ISR(USART1_TX_vect)
2
{
3
  if (uart1_pos_out_tx == uart1_pos_put_tx)
4
  {
5
    _uart1_txd_off();
6
  }
7
}

Klasse! Funktioniert 1A :-D

Vielen Dank, Gruß AVRli...

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Schön, dass es läuft, aber die Ursache war es nicht, diese liegt an 
anderer Stelle.

von AVRli .. (avrli)


Lesenswert?

Na jetzt schalte ich erst ab, wenn er über den USART1_TX Interrupt 
signalisiert, dass die Übertragung abgeschlossen ist. Damit drehe ich 
nicht mehr zu früh ab, wie zuvor bei dem USART1_UDRE.

von S. Landolt (Gast)


Lesenswert?

Haben Sie mein Zitat aus dem Datenblatt nicht gelesen? Sie können gar 
nicht "zu früh abdrehen", das macht der Controller selbsttätig richtig.
  Nachfolgendes Programm bringt auf dem Monitor:

mega48
mega48
mega48
...
...

1
.macro  disp
2
    ldi     tmp0,@0
3
disp_:
4
     lds    tmp1,UCSR0A
5
     sbrs   tmp1,UDRE0
6
    rjmp    disp_
7
    sts     UDR0,tmp0
8
.endmacro
9
10
main:
11
    ldi     tmp0,(1<<TXEN0)
12
    sts     UCSR0B,tmp0
13
    disp    'm'
14
    disp    'e'
15
    disp    'g'
16
    disp    'a'
17
    ldi     tmp0,0
18
    sts     UCSR0B,tmp0
19
    ldiw    Z,1843/4
20
wait100us:
21
     sbiw   ZL,1
22
    brne    wait100us
23
    ldi     tmp0,(1<<TXEN0)
24
    sts     UCSR0B,tmp0
25
    disp    '4'
26
    disp    '8'
27
    disp    '\r'
28
    disp    '\n'
29
    rcall   wait1s
30
 rjmp       main

von S. Landolt (Gast)


Lesenswert?

PS:
Die Übertragung läuft mit 115200 Bd, dieses wait100us ist also etwas 
mehr als 1 Zeichen.

von AVRli .. (avrli)


Lesenswert?

S. Landolt schrieb:
> Haben Sie mein Zitat aus dem Datenblatt nicht gelesen? Sie können gar
> nicht "zu früh abdrehen", das macht der Controller selbsttätig richtig.

Doch, das wird auch stimmen!
Nur kann ich wohl zu früh an den Ports "rumfummeln"? Also zu früh auf 
Eingang/Ausgang umschalten?

Eine andere Erklärung habe ich erst mal nicht, warum es denn nun 
funktioniert, wie ich es wollte.

von S. Landolt (Gast)


Lesenswert?

Zu dieser Umschaltung Ein-/Ausgang hatte ich ja auch etwas geschrieben, 
jedoch hängt das natürlich stark davon ab, was die Anwendung sonst noch 
macht.
  Aber wie gesagt, es läuft, und das ist schön. Eine Erklärung habe ich 
auch nicht, man sollte nur im Auge behalten, dass da eventuell noch ein 
Problem lauert.

von Stefan E. (sternst)


Lesenswert?

AVRli .. schrieb:
> Eine andere Erklärung habe ich erst mal nicht, warum es denn nun
> funktioniert, wie ich es wollte.

Ich vermute, dass du vorher in der Logik "Abschalten ja oder nein" einen 
Fehler hattest, und somit ganz früh (vielleicht schon nach dem ersten 
Byte) abgeschaltet hast.

AVRli .. schrieb:
> Das ganze funktioniert auch so lange, wie die Zeichen die rausgehen
> sollen, direkt hintereinander folgen.

Eben weil (wie S. Landolt ausgeführt hat) das Abschalten keinen Effekt 
hat, solange sich noch Daten in einem der Sende-Register befinden.

AVRli .. schrieb:
> Kommt es zu einer nur ganz kurzen
> Verzögerung bei der Ausgabe, gehen Bytes verloren. :-(

"Kurze Verzögerung" bedeutet dann vermutlich, dass die Sende-Register 
leer laufen. Das (im Code schon längst erfolgte) Abschalten findet an 
dem Punkt dann tatsächlich auch in der Hardware statt, und die 
restlichen Bytes gehen verloren.

von Stefan F. (Gast)


Lesenswert?

> man sollte nur im Auge behalten, dass da eventuell
> noch ein Problem lauert.

Jepp. Wenn man ein Problem gelöst hat, ohne die Lösung genau zu 
verstehen, kommt das Problem oft irgendwann wieder.

von AVRli .. (avrli)


Lesenswert?

Ich habe mir Eure Bedenken und Anmerkungen im Projekt hinterlegt und 
hoffe, dass ich das Problem nicht wieder hoch spüle. ;-)

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
Noch kein Account? Hier anmelden.