ich erleide herbe Rückschläge wegen den UARTs.
Beim Aufbau eines generellen Kommunikationstests traf ich auf Probleme.
Manchmal gings und manchmal nicht, je nach Codekonstellation. Und ich wußte nicht genau warum, der Code scheint i.O.
Momentan stelle ich fest, dass es funktioniert, wenn ich einzeln
Mega-UART1 > ... > ATtiny841-UART1 sende und ATtiny841-UART0 > ... > Mega-UART2 sende und an UART0 im Terminal anzeigen lasse.
oder
Mega-UART2 > ... > ATtiny841-UART0 sende und ATtiny841-UART1 > ... > Mega-UART1 sende und an UART0 im Terminal anzeigen lasse.
lasse ich beides im Sekundentakt abwechselnd ablaufen, kommt teilweise verstümmelter Code.
Das seltsame dabei ist, die zugehörige Antwort kommt genau eine Sekunde später und nicht sofort.
Ich weiß nicht warum. Irgendwas kommt sich ins Gehege zwischen den UARTs.
Mache ich das Paket komplett, dann sendet zwar der Mega fleißig, aber der ATtiny sendet nichts mehr zurück.
Ich sehe das auch mittels Logik Analyzer und serial Decoder.
Ich bin ratlos. Es muss doch möglich sein, wechselweise auf beiden Mega UARTs etwas zusenden und im Gegenüber
auf jeweils der anderen UART wieder auszugeben und im Mega dann auch auf der jeweils anderen UART einzulesen und anzeigen.
Die Nachricht sollte doch ohne nennenswerte Verzögerung die Runde machen.
Wenn ich alles einzeln teste funktioniert der Befehlsvergleich im ATtiny und die passende Antwort kommt umgehend, sehe ich im L.A.
Im anderen sieht man die Verzögerung.
Gesendet wird auf dem 2. und 4. Kanal vom Mega aus gesehen.
Deshalb müsste auf dem 3. Kanal umgehend eine Antwort kommen wenn auf dem 2. was gesendet wurde.
Genauso wenn auf dem 4. gesendet wird müßte auf dem 1. umgehen die umgeleitete Antwort kommen.
Sieht alles seltsam aus zeitlich gesehen.
genau eine sekunde ist schon seltsam, das ist das standard-timeout bei vielen funktionen der serial-library. sehe zwar jetzt keine in Deinem sketch, aber setz' es doch mal in beiden sketches am anfang für alle benutzten schnittstellen mit settimeout auf 500,
ob sich was ändert...
du meinst das hier https://www.arduino.cc/en/Serial/setTimeout
war ein Versuch wert, bringt leider keine Abhilfe.
Die zeitliche Verzögerung der Übertragung geht genau mit der eingestellten millis "toggle" Zeit mit.
Was eigentlich nicht sein darf, weil ja ohne Wartezeit jederzeit gelesen werden kann in loop.
Habs nochmal versucht besser darzustellen.
Wenn ich im Mega Sketch eine serielle in toggle auskommentiere, egal welche, dann geht nichts mehr, es kommt nichts zurück.
Irgendwie muss ein Bufferüberlauf stattfinden oder ein Abschluss kommt nicht an oder sowas, habe ich das Gefühl.
Weiß nur nicht wo ich ansetzen soll. Habe den Code schon tausendmal durchgeschaut.
wenn ich es wieder einzeln teste, zum Bsp. der Mega sendet nur auf Uart1 und der ATtiny liest nur von Uart1 und sendet damit nur auf Uart0 zurück (kommt im Mega auf Uart2 an), dann klappt alles. Die Antwort erfolgt umgehend sobald das Endezeichen '\r' erkannt wird. Genauso wie ich mir das vorstelle.
Meine Vermutung liegt nachwievor das sich die Buffer gegenseitig ins Gehege kommen. Nur wo und warum das weiß ich nicht.
Ich habe mir das mal angesehen.....
Der Mega Code scheint ja zu funktionieren.
Genau habe ich ihn nicht untersucht.....
Beim Tiny Code habe ich ein Problem gefunden.
Deine "Empfangen" Routinen sind blockierend.
Wenn also auf USART0 empfangen werden soll, aber nix kommt, dann geht alles auf USART1 verloren.
Bis auf 1 Byte.
Andersrum natürlich genau so.
Und auch beim senden, wird jeglicher Empfang blockiert.
Kann es das schon sein, was dir einen Streich spielt?
Auch das Timing scheint mir eng zu sein...
Innerhalb von 40µs muss ein Zeichen aus der USART abgeholt worden sein, sonst gehen Bytes/Zeichen verlustig.
Der Code ist aus den Datenblatt Beispielen. Ich hatte das so verstanden das die whiles immer nur unbedeutend kurz blockieren bis die Übertragungs selbst fertig ist. Wenn nichts da ist, wird es übersprungen.
Du meinst, sobald zum Bsp. UART0_empfangen() aufgerufen wird blockiert der gesamte Code bis wirklich irgendwas reinkommt?
Beim senden UART0_sendChar bin ich mir allerdings sicher das er nicht blockiert. Die while soll doch warten und prüfen ob der UART Buffer leer ist vor Neubefüllung. Da er ja meistens leer sein sollte, dürfte die while doch im Grunde genommen nicht wirklich blockieren.
Was du mit den 40µs meinst verstehe ich nicht. Was muss von wem innerhalb 40µs abgeholt werden?
Die Daten liegen doch solange im Buffer bis sie jemand abholt und bleiben solange unverfälscht bis sie von neuen reinkommenden Daten überschrieben werden. So hatte ich das jedenfalls verstanden.
Allerdings, wenn der Empfang den gesamten ATtiny Code blockiert,dann kann auch kein Buffer abgeholt werden und dann kommt schon der nächste Datenstrom rein. Das könnte die Verstümmelung erklären.
Also heißt das ich muss auf Interrupt Steuerung umbauen und darf keine Flags auswerten?
Beim senden UART0_sendChar bin ich mir allerdings sicher das er nicht blockiert.
Doch, tut es.
Zumindest bis zu 40µs.
So lange, bis das vorherige Zeichen im Schieberegister gelandet ist.
(zu den 40µs gleich mehr)
Aber du verwendest ja gar nicht: UART0_sendChar()
Sondern: UART0_sendString().
Und das blockiert bis der ganze String draußen ist(-2 Zeichen).
Bei 10 zu sendenden Zeichen, können auf den beiden seriellen Eingängen zusammen 14 Byte ins Nirvana wandern.
Auch, wenn es bei deiner Anwendung nicht ins Gewicht fällt, solltest du das doch im Hinterkopf behalten.
Denke ich mal....
Du meinst, sobald zum Bsp. UART0_empfangen() aufgerufen wird blockiert der gesamte Code bis wirklich irgendwas reinkommt?
So sehe ich das in deinem Code.
Was du mit den 40µs meinst verstehe ich nicht.
1 Byte wird zu 10Bit (8Daten+1start+1stopp)
Bei 250000Baud macht das also 25000Byte Pro Sekunde
1/25000 = 0.00004
40µs Pro Byte
Was muss von wem innerhalb 40µs abgeholt werden?
Für das "Wem" bist du verantwortlich.
Das "Was":
Da ein Byte selten alleine kommt, muss das jeweils fertig angekommene innerhalb von 40µs abgeholt werden, sonst verschwinden Daten im Nirvana.
Die Daten liegen doch solange im Buffer bis sie jemand abholt und bleiben solange unverfälscht bis sie von neuen reinkommenden Daten überschrieben werden. So hatte ich das jedenfalls verstanden.
Welcher Buffer?
Der USART Buffer?
Da passt 1 Byte rein.
Darum musst du ja bei 250000Baud schon etwas Gas geben, den rechtzeitig zu leeren.
Also heißt das ich muss auf Interrupt Steuerung umbauen und darf keine Flags auswerten?
Nunja...
Entweder Interrupts, oder ein rasend schnelles Polling, würde ich mal sagen....
jetzt wird mir einiges klarer.
Das mit dem Buffer ist schnell geklärt. Ich hatte auch beim ATtiny fälschlicherweise die 63Byte Ringbuffer im Hinterkopf wie wir sie beim Arduino haben. Deshalb dachte ich man hätte auch hier alle Zeit der Welt. Aber ist ja nur intern unsichtbar zwischengeschoben.
Das mit dem senden und empfangen meine ich nun auch verstanden zu haben, das dort das Problem liegt, wie du erkannt hast. Weil blockieren darf auch später nichts, auch wenn ich nur eine UART am Ende nutzen werde. Das wäre mir später mörderisch auf die Füße gefallen. Der Code wächst ja noch.
Wenn ich recht informiert bin, wird HardwareSerial auf einem Uno jeweils per Interrupt geweckt, wenn der UART sein Sendebyte frei hat und wenn im Empfangsbyte etwas ist, was in den "großen" 64 byte Empfangspuffer geschoben werden kann.
So werden da auch Reaktionszeiten unter 40 µs (250000 Baud) möglich.
Das fehlt bei deiner eigenen Implementation noch.
Nunja...
Entweder Interrupts, oder ein rasend schnelles Polling, würde ich mal sagen....
Ja nun, wer wollte da widersprechen
Ich frage mich:
Gibt es kein ordentliches HardwareSerial für attiny841, wo dieses Standard-Problem schon gelöst ist?
Hardware Serial kann der ATtiny schon. Da nun alles darauf hinausläuft das ich Interrupts verwenden muss, stand die Frage selber umbauen oder was fertiges suchen. Dabei stieß ich auf die uart Lib von Peter Fleury. Die Headerdatei habe ich um den ATtiny841 ergänzt und wollte nun ganz einfach anfangen. Ich scheitere aber schon an der Benutzung der Lib. Im Grunde stehen da nur Macros und Funktionen drin. Kein Konstruktor oder dergleichen. Ich weiß trotz der kompletten Beschreibung nicht wie ich eine UART nun wirklich initialisieren soll und die Baudrate einstellen. Einfachste Dinge und ich raff es nicht. Auch mit Google Hilfe kompilieren die gefundenen Schnipsel nicht.
#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <uart.h>
#define F_CPU 8000000UL // Systemtakt in Hz
#define UART_BAUD_RATE 9600
int main(void)
{
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
while (1)
{
}
}
Atmel Studio meldet
Fehler undefined reference to `uart_init(unsigned int)'
Fehler recipe for target 'ATtiny841_uart-Lib_001.elf' failed
Fehler ld returned 1 exit status
Die Macros erschlagen mich ehrlich gesagt. Kennt die Lib zufällig jemand von euch?
Edit:
Selbst sowas einfaches wie die RX-Buffergröße zu definieren klappt auch nicht. Default sind 32.
#include <avr/io.h>
#include <stdio.h>
#include <avr/interrupt.h>
#include <uart.h>
#define F_CPU 8000000UL // Systemtakt in Hz
#define UART_RX_BUFFER_SIZE 20
int main(void)
{
while (1)
{
}
}
Atmel Studio meldet:
Warnung "UART_RX_BUFFER_SIZE" redefined
Nachricht this is the location of the previous definition
Wenn er mit 8 oder 16 MHz läuft und Interrupts verwendet, sollte dessen HardwareSerial auch 250000 Bd können.
Was ist schlecht an diesem HardwareSerial?
Warum nimmst du es nicht?
Muss ich den ganzen Thread nochmal aufmerksam lesen, um das rauszufinden?
Hast schon seit Anfang auf der attiny Seite mit UART Registern rumgefummelt...
mal ganz sachte. Ich habe nie gesagt das Hardware Serial schlecht ist. Ich nutze sie ja auch nur eben ohne Interrupt derzeit.
Ich habe mich mit den ATtiny UARTs beschäftigt, das Datenblatt herangezogen und etwas Internetrecherche.
Ich hatte nicht weiter nachgedacht und Atmel vertraut das die Bsp. perfekt sind.
Nun wie festgestellt, muss ich Interrupts verwenden. Soweit ist alles klar.
An dem Punkt nun dachte ich, entweder schreibste alles nochmal um oder nimmst doch noch eine fremde Lib.
So wie ich dich nun verstehe soll ich meine Funktionen selbst auf Interrupt Nutzung umschreiben.
Eigentlich wollte ich die Lib nutzen.
Auch wenn ich jetzt ein bisschen pingelig erscheine...
Der Tiny hat keine UART.
Auch keine 2 UARTs.
Im Grunde ist die falsche Benennung kein Problem, wenn man das richtige tut.
Aber mich bringt es, beim lesen von (Programm)Texten, immer wieder zum straucheln.
Ich glaube, dass auch Google viel auskunftsfreudiger ist, wenn man nach den richtigen Begriffen sucht.
Also nicht UART, sondern USART
ihr drängt mich nun doch selbst umzuschreiben.
UART, USART, ja okay hat eine USART, wie der Mega.
Standardmäßig wird die im Arduino asyncron betrieben, wenn ich das richtig erkannt habe.
Ja, ein bisschen pingelig bin ich ja schon...
Sachte ich ja schon....
Standardmäßig wird die im Arduino asyncron betrieben, wenn ich das richtig erkannt habe.
Yes.
ihr drängt mich nun doch selbst umzuschreiben.
Kannste so nicht sehen....
Mir ist es recht wurscht, was du tust...
Also, "wurscht", nicht im Sinne von "Gleichgültig", sondern im Sinne von "Selbst verantwortlich".
Und, wenn du es selber schreibst, will ich da gerne mal drüber schauen...
Testen kann ich leider nicht, kein 841 im Haus.
mal ganz sachte. Ich habe nie gesagt das Hardware Serial schlecht ist.
Mein Einwand kam evtl. gestern abend falsch rüber:
Wenn es dein Ziel ist, das selber zu schreiben, sehr schön.
Man sollte sich aber schon ansehen, was es bereits gibt.
Und wenn das Ergebnis dann noch besser wird als das bereits vorhandene (in welcher Hinsicht auch immer), wären ich und wohl auch andere interessiert daran, was du combie zum Drüberschauen gibst.