ADM3070 RE/DE Leitung

OP #7619232
Lesenswert?

Ich habe ein Problem mit einem Atmega und einem ADM3070, welcher über Half Duplex als slave arbeitet.

RE und DE habe ich zuammen an einem IO pin und bevor ich Daten senden möchte muss ich den IO pin auf High setzen. Allerdings habe ich immer Kommunikationsprobleme wenn ich zwischen Senden und abschalten des Senders nicht mindestens eine Millisekunde warte. Der Bus ist jeweils auf ca 350mV gebiast und abgeschlossen. Wo kann ich bei der Suche ansetzen?

#7619322
Lesenswert?

Rahul D. schrieb:

Mit dem Stopbit ist der Bus doch sowieso im Standy-Zustand. Wenn man da umschaltet, sollte doch alls gut sein.

Mit Bias-Widerständen, die viele vergessen, ja. Aber das scheint hier ja nicht das Problem zu sein.

Da es ab 1ms Wartezeit funktioniert, sagt meine Glaskugel, dass der TO mit 9600bps arbeitet, die Zeit ab Befüllen des UDR misst und somit ziemlich genau die Zeit erwischt, die der UART braucht, um das Byte zu senden.

OP #7619529
Lesenswert?

Hier nochmal die fehlenden Informationen.

Ich arbeite mit 9600 Baud mit Einem Startbit und einem Stopbit. Es handelt sich um ein simples request response Protokoll.

An RXD des Controllers hängt kein Pullup. Bevor ich etwas sende und die RE/DE Leitung auf 1 setze schalte ich das RXE Bit im Kontrollregister des UART aus um in der Zeit nichts zu empfangen.

Es handelt sich bei dem Controller um einen Atmega328P. Zum empfangen benutze ich den Interrupt aber gesendet werden Nachrichten blockierend, da die Nachrichten immer gleiche Länge haben.

Senden geht dann so:

1
    txEnable(true);
2
    _delay_ms(1);
3
    
4
    for(unsigned int i = 0;i < size;++i) {
5
      UDR0 = data[i];
6
      while ( !( UCSR0A & (1<<UDRE0)) );                  
7
    }
8
    
9
    _delay_ms(1);
10
    txEnable(false);

Das heißt das Byte müsste auch ohne das Delay am Schluss vollständig gesendet sein wenn der Transmitter wieder abgeschaltet wird.

Die Abschaltung/Einschaltung des Empfängers erfolgt in der txEnable Routine.

#7619532
Lesenswert?

Gustav G. schrieb:

Das heißt das Byte müsste auch ohne das Delay am Schluss vollständig gesendet sein wenn der Transmitter wieder abgeschaltet wird.

Teste am Ende deiner ("geklauten") Senderoutine das TXC-Bit deines UART. Was das ist, und wo das zu finden ist, steht im Datenblatt des Controllers (was man beim Embedded-Programmieren vorliegen haben sollte). Bei STM-Controllern gilt das für das (etwas umfangreicherer) Referencemanual.

Die Abschaltung/Einschaltung des Empfängers erfolgt in der txEnable Routine.

Die leider komplett unsichtbar ist und auch gar nicht interessiert, weil es die "falsche" Richtung ist: Du willst aus dem TX-Modus in den RX-Modus wechseln.

OP #7619673
Lesenswert?

Rahul D. schrieb:

Teste am Ende deiner ("geklauten") Senderoutine das TXC-Bit deines UART. Was das ist

Die Routine ist nicht geklaut. ich denke, dass ich langsam das Problem sehe. Bisher habe ich nicht mit RS485 im Half-Duplex Modus gearbeitet.

Es ist ein unterschied, ob man UDRE (Also ob man das nächste byte in UDR schreiben kann) abfragt oder TXC abfragt. Das funktioniert sehr gut bis zum letzten byte, wo UDRE schon 1 ist obwohl das ende einer Frame noch nicht komplett gesendet wurde.

Die txEnable Routine sieht so aus:

1
void txEnable(bool value) {
2
    if(value) {
3
      UCSR0B  &= ~(1 << RXEN0);
4
      PORTD |= (1 << PIND2);
5
    }else{
6
      PORTD &= ~(1 << PIND2);
7
      UCSR0B |= (1 << RXEN0);
8
    }
9
  }

Ich müsste also nach der for Schleife noch einmal TXC abfragen. Was mich eben nur wundert ist, dass es auch beim senden per Interrupt nur mit Wartezeit am Ende funktioniert hat.

#7619751
Lesenswert?

Gustav G. schrieb:

An RXD des Controllers hängt kein Pullup.

Eleganter wäre es, trotz des beim Senden deaktivierten RXE den integrierten Pullup zu aktivieren, um das Floaten von RXD zu verhindern.

Gustav G. schrieb:

Es ist ein unterschied, ob man UDRE (Also ob man das nächste byte in UDR schreiben kann) abfragt oder TXC abfragt.

Ja, der UART schiebt nicht direkt UDR raus, sondern übernimmt es in ein Schieberegister, so dass es wieder beschrieben werden kann, bevor der Frame komplett gesendet wurde.

Gustav G. schrieb:

Was mich eben nur wundert ist, dass es auch beim senden per Interrupt nur mit Wartezeit am Ende funktioniert hat.

Welchen Interrupt hast Du denn genommen?

OP #7619774
Lesenswert?

Hmmm schrieb:

Eleganter wäre es, trotz des beim Senden deaktivierten RXE den integrierten Pullup zu aktivieren, um das Floaten von RXD zu verhindern.

Das habe ich jetzt einfach mal gemacht. Es kostet nichts.

Hmmm schrieb:

Ja, der UART schiebt nicht direkt UDR raus, sondern übernimmt es in ein Schieberegister, so dass es wieder beschrieben werden kann, bevor der Frame komplett gesendet wurde.

Mich verwirrt noch etwas folgende Aussage aus dem Datenblatt: "The TXCn flag bit is automatically cleared when a transmit complete interrupt is executed, or it can be cleared by writing a one to its bit location. The TXCn flag can generate a transmit complete interrupt (see description of the TXCIEn bit)."

Im grunde wäre es doch besser in der for schleife auf TXC zu prüfen um sich den Schritt am Ende zu sparen. Damit wäre wirklich sichergestellt, dass man immer ein Byte mit Stopbit sendet.

Hmmm schrieb:

Welchen Interrupt hast Du denn genommen?

Es gibt beim Atmega328 für ein Interrupt für Transmit complete und das ist USART, Tx complete Vector 21

#7620364
Lesenswert?

Gustav G. schrieb:

Mich verwirrt noch etwas folgende Aussage aus dem Datenblatt: "The TXCn flag bit is automatically cleared when a transmit complete interrupt is executed, or it can be cleared by writing a one to its bit location. The TXCn flag can generate a transmit complete interrupt (see description of the TXCIEn bit)."

Was verwirrt Dich daran?

Wenn Du den Interrupt nutzt, musst Du Dich um nichts kümmern. Wenn nicht, musst Du das Flag wie beschrieben clearen, sonst bleibt es gesetzt, was natürlich wenig hilfreich ist.

Gustav G. schrieb:

Im grunde wäre es doch besser in der for schleife auf TXC zu prüfen um sich den Schritt am Ende zu sparen.

Eigentlich ist es ganz einfach: Für das UDR-Befüllen ist UDRE relevant, für das Abschalten des Treibers TXC.

Gustav G. schrieb:

Es gibt beim Atmega328 für ein Interrupt für Transmit complete

Mit dem hätte es eigentlich funktionieren müssen. Wenn nicht, einfach mal Oszi oder Logic Analyzer dranhängen und ansehen, was tatsächlich passiert.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren