Forum: Mikrocontroller und Digitale Elektronik Atmel SAM9 und die PDC am UART


von Mw E. (Firma: fritzler-avr.de) (fritzler)


Angehängte Dateien:

Lesenswert?

Die PDC zeigt bei meinem Projekt ein komisches verhalten und dazu steht 
nix in den Errata, villeicht kann mir ja wer helfen.
Sitze da jetzt schon länger dranne und komm nicht weiter.
Was solls also werden?

Ich hab hier nen Protokollstapel und dieser soll über UART mit dem 
passenden Gerät kommunizieren.
Da dabei ordentlich Daten geschaufelt werden sollen, muss der UART auf 
2MBaud aufgedreht werden.
Das Gerät kann bis 4 MBaud und die Baudrate ist auf 1% genau getroffen.
Weiterhin wird der Hardware Handshake (CTS/RTS) unbedingt benötigt.

Bei den hohen Baudraten macht DMA Sinn, bei den Atmel ARM CPUs gibt es 
dazu eine spezielle DMA, nämlich die PDC.
Ein DMA Controller für die Peripherie, diese steuert auch den 
Hardwarehandshake.
RX Puffer voll? -> RTS auf HIGH.
Der Protokollstapel hat auch nur Funktionen für DMA, diese müssen 
natürlich vom Benutzer (mir) mit Code speziell für diese CPU gefüllt 
werden.

Das Problem existiert nur beim Empfangen, also vom Gerät zur CPU.
In dieser Richtung können unterschiedliche Paketarten eintreffen.
Daher sind diese pakete so aufgebaut:TypByte - Header - Payload
Die Payloadlänge steht im Header und der Header ist je nach Pakettyp 
unterschiedlich lang.

Was macht der Protokollstapel also?
Er fordert ersteinmal 1 Byte per DMA an!
Das eine Byte kommt dann irgendwann über den UART, der RX Buffer der PDC 
ist nun voll und RTS der CPU geht auf HIGH.
Dadurch, dass die CPU RTS auf HIGH setzt, darf das Gerät nichts mehr 
senden, also Header und Payload müssen warten.

Nun ist dem Protokollstapel der Typ bekannt und er fordert 2 oder 4 Byte 
an für den Header, per PDC/DMA wieder natürlich.
Die PDC hat wieder einen Buffer und somit geht RTS auf LOW, die 
Headerbytes werden übertragen.
Headerbytes fertig übertragen und RX Buffer voll -> RTS auf HIGH.

Header kann jetzt interpretiert werden und die Payload wird per PDC/DMA 
angefragt.
Das können jetzt bis zu 1,6kbyte sein.
Bytes fertig übertragen und RX Buffer voll -> RTS auf HIGH.
Ist das fertig, beginnt das Spiel von vorn (TypByte anfordern).

Mit anfänglichen 115200baud funktionierte alles einwandfrei.
Dann auf 830kbaud erhöht. Das ist so krumm, weil das genau einen Teiler 
in der CPU getroffen hat.
Jetzt kamen die ersten Fehler.
So besagte ein TypByte, dass der Header jetzt 2 Byte lang ist, aber es 
werden 4 Byte angefordert. WAS ZUM?!

Ab jetzt Oszibilder!
Alle UART Signale sind so beschriftet wie am Gerät.
Also TXD: Gerät zu CPU und CTS ist RTS von der CPU

Hier funktionierts noch:
Schön zu sehen wie das TypByte kommt (04) und dann 2 Byte als Header 
angefordert werden (0E, 04), danach die Payload.
Es ist auch das Gewackel am CTS zu sehen.
--Hierzu gehört Bild 001.png---

Jetzt kommt der Fehler!
Zu beachten ist der kurze Abstand zwischen TypByte und Header als es 
noch funktionierte, dieser Abstand wird jetzt ziemlich groß und so lange 
sind Interrupts auch nie gesperrt.
Also der Abstand zwichen 04 und dann 13, 05, 01, 01
Der Interrupt wird ausgeführt wenn die mit TYP beschriftete Linie von 
LOW auf HIGH geht.
Nun ist das TypByte wieder 04, also müssten 2 Headerbytes angefordert 
werden, es werden aber 4 angefordert!
Es sieht so aus, als hätte die PDC die 04 NICHT in den RAM geschrieben.
Wie ich darauf komme? Das Paket davor (jetzt nicht abgebildet) hatte ein 
TypByte von 02, dieses braucht dann 4 Headerbytes.
Also wurde das erste Byte im Buffer des Protkollstapels nicht 
überschrieben?!
Dann habe ich einen Workaround eingebaut, wenn eh nur 1 Byte angefordert 
wurde, dann wird das ja noch im Receive Holding Register des UART 
liegen, also dieses dann imemr auslesen.
BINGO! nun funktionierts auch bei 830kBaud ohne Probleme.
Die PDC speichert also manchmal nicht in den RAM!
--Hierzu gehört Bild 006.png---

Jetzt kommts zu einem weiteren Problem, bei 2MBaud setzt die CPU dann 
die RTS Leitung zu spät auf HIGH wodurch das Gerät ein Byte zu viel 
sendet.
Wann setzt die CPU RTS auf HIGH?
1. Die PDC muss aktiv sein
2. Der Empfangspuffer der PDC muss voll sein (die PDC bekommt einen 
Pointer auf den RAM und einen Counter wieviel Bytes angefordert werden).
Ist der Counter = 0, so ist der Empfangspuffer voll und das Interrupt 
Flag RXBUFF wird gesetzt (RX Buffer voll).
3. RXBUFF ist gesetzt -> RTS auf HIGH

Wann bekommt die PDC mit, dass ein Zeichen empfangen wurde?
Das passiert nach dem halben Stopbit des UART laut diesem Diagramm, dann 
wird RXRDY gesetzt und die PDC holt das Zeichen ab.
nachdem die PDC das Zeichen abgeholt hat wird der Counter der PDC 
decrementiert.
--Hierzu gehört Bild rxrdy.png---

Laut diesem Bild aus dem Datenblatt sollte aber RTS schon viel früher 
auf HIGH gehen. Nämlich während das letzte in den RX Buffer passende 
Byte empfangen wird.
Während des Stopbits den RTS ändern ist ja auch recht spät.
--Hierzu gehört Bild rts.png---

Was sagt die Realität?
RTS (im Oszibild CTS) wird genau beim halben Stopbit auf HIGH gesetzt, 
was das Gerät am UART auch mitbekommt und dann kein weiteres Zeichen 
sendet.
Violett ist CTS und gelb ist TXD.
Die LOW -> HIGH Flanke von TXD ist der Anfang des Stopbits, danach ist 
dann TXT Idle.
--Hierzu gehört Bild scr02.png---

Und hier den sporadisch auftretenden Fehler!
Ab und zu wechselt RTS (im Oszibild CTS) zu spät auf HIGH, nämlich nicht 
zur halben Bitzeit des Stopbits, sondern eher im letzten Viertel.
Das bekommt das Gerät am UART nicht mit und sendet somit ein weiteres 
Byte.
Dieses Byte erwartet die CPU/PDC aber nicht wodurch es verloren geht.
--Hierzu gehört Bild scr01.png---

Dazu fällt mir jetzt kein Workaround mehr ein.
Hatte jemand schonmal son problem oder kennt die Lösung?

In den Erratas steht dazu nichts und das problem tritt auch nur auf, 
wenn der PDC nur 1 byte abverlangt wird.

: Bearbeitet durch User
von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Fällt dazu keinem was ein?
Ist schon sehr störend nicht über 1Mbaud gehen zu können.

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.