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?
Wimre setzen die meisten MC das TXC Flag bereits, wenn das Stopbit anfängt und nicht erst, wenn es fertig gesendet ist.
Gustav G. schrieb: > RE und DE habe ich zuammen an einem IO pin Hast Du an RXD des Controllers einen Pullup hängen oder den internen aktiviert? Gustav G. schrieb: > mindestens eine Millisekunde warte Du hast die verwendete Baudrate und das Abschaltkriterium nicht genannt.
Matthias S. schrieb: > Wimre setzen die meisten MC das TXC Flag bereits, wenn das Stopbit > anfängt und nicht erst, wenn es fertig gesendet ist. Mit dem Stopbit ist der Bus doch sowieso im Standy-Zustand. Wenn man da umschaltet, sollte doch alls gut sein.
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.
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.
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.
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.
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?
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
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.
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.