Forum: Mikrocontroller und Digitale Elektronik Atmega32U4 USART als SPI Master


von Thomas Frosch (Gast)


Lesenswert?

Hi Leute,

habe mal wieder ein seltsames Problem und zwar nutze ich den Atmega32U4 
um ein On-Screen-Display zu realisieren. Ich schreibe also ein BAS 
Signal. Dazu verwende ich die Funktion des U4´s die USART Schnittstelle 
als SPI Master zu verwenden (Ich brauch die andere zur Kommunikation mit 
anderen Geräten)

In der while Schleife des Programms wird ein Flag abgefragt. Ist dieses 
1 wird angefangen eine Zeile zu schreiben. Das heißt einlesen eines 
Bytes und senden per SPI und das ganze 40 mal hintereinander (per while 
Schleife).
Das einlesen des Bytes aus einem bestimmten Speicher dauert ungefähr 19 
Takte, so, dass ich Lese und sofort danach schreibe ohne darauf zu 
Achten ob SPI fertig ist. Da ich jedoch mit 16MHz und SPI Clock auf 
fclock/2 gestellt habe sollte SPI spätestens nach 2*8 + 2 = 18 Takten 
fertig sein. Dies funktioniert auch super es wird kein Byte ausgelassen. 
Vor dieser Prozedur werden per cli() alle Interrupts abgeschalten und im 
nachhinein per sei() wieder eingeschalten.

Dieser Programmabschnitt wird also durch ein Flag eingeleitet. Dieses 
Flag wird entweder durch einen Timer Interrupt oder einen externen 
Interrupt gesetzt.

Nun zum Problem: In dem Modus indem dieses Flag vom externen Interrupt 
gesetzt wird scheint es als würden die Bytes aus dem SPI nicht mit dem 
gleichen Abstand herauskommen. Das heißt ich schreibe immer nach genau 
19 Takten (Taktanzahl ermittelt durch zählen von Takten die jeder 
Assemblerbefehl braucht) ins SPI-USART Register jedoch kommen zwei 
aufeinanderfolgend Bytes manchmal um 2 Takte verschoben raus. (Messung 
per Oszi). Dies geschieht aber wie gesagt nur in dem einen Modus obwohl 
bei beiden das gleiche Programm abgearbeitet wird.

Was könnte der Fehler sein? Ist es möglich, dass der Controller 
zwischendrin einfach 2 Takte lang was anderes macht? Beim einlesen des 
Bytes verwende ich folgende Assembler Befehle:
ADD
ADC
SUBI
SBCI
CPC
CPI
BRNE
MOVW
LD
STS
LPM


nach instruction Set Liste brauchen diese Befehle immer eine konstante 
Anzahl an Takten (BRNE in der Schleife wohl immer 2.) Gibt es doch den 
Fall, das ein Befehl mehr Takte benötigt?

von Thomas Frosch (Gast)


Lesenswert?

Hat jemand zumindest irgendwelche Anregungen was ich noch testen könnte? 
Bin mit meinem Latein am Ende.

Vielleicht bringt mich das ja auf andere Ideen!!

Wäre super!

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Mit dem Mega8 funktioniert das im Anhang.

...

von Thomas Frosch (Gast)


Lesenswert?

Wie ich sehe misst du die Zeit der Impulse die der LM rausgibt. Das 
machst du aber nur um zwischen Zeilen und VSyncs zu unterscheiden oder? 
Habe mir auch schon überlegt ob es daran liegt, dass der LM zu ungenau 
ist und je nach Eingangssignal seine Schwelle mal früher oder später 
überschritten wird und deshalb die Zeilen wackeln.

Ist das Signal des LM's genau genug? Habe die Frage allerdings 
zurückgestellt, da es so aussieht als würde nicht eine komplette Zeile 
wackeln sondern die einzelnen Buchstaben je Spalte unabhängig 
voneinander.

Es handelt sich bei mir um ein Projekt, dass leider schon am Ende steht. 
Hardware ist bereits vorgegeben, kann also nicht auf anderen Aufbau und 
Software switchen. Software funktioniert bisher auch sehr gut. Das 
bewegen der Buchstaben ist meine einzige Sorge.

Nochmal die Frage: Können Befehle aus irgendwelchen Gründen mal einen 
Takt länger brauchen?

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Thomas Frosch schrieb:
> Wie ich sehe misst du die Zeit der Impulse die der LM rausgibt. Das
> machst du aber nur um zwischen Zeilen und VSyncs zu unterscheiden oder?

Ups, ich habe Dir versehentlich eine alte Version geschickt. Darin habe 
ich mir V-Sync selbst gebastelt, weil ich zu blöd war, Rset am richtigen 
Pin anzuschließen und daher kein V-Sync bekam.
In der neueren Version wird V-Sync berücksichtigt, Foto und Skizze 
enthält diese Drahtbrücke aber noch nicht. Siehe neuen Quelltext.

> Habe mir auch schon überlegt ob es daran liegt, dass der LM zu ungenau
> ist und je nach Eingangssignal seine Schwelle mal früher oder später
> überschritten wird und deshalb die Zeilen wackeln.

Nein, der LM1881 ist da recht genau. Etwas Jitter kann es durch die 
unterschiedliche Interrupt-Response-Time geben, das habe ich aber 
dadurch verhindert, dass der Interrupt den AVR immer im Sleep 
überrascht. Die übrigen Arbeiten werden grundsätzlich nur außerhalb des 
Bildaufbaus erledigt, also immer nach der letzten Zeile, und auch nicht 
zuviel auf einmal.

>
> Ist das Signal des LM's genau genug?

Ja, ist genau genug.

> Habe die Frage allerdings
> zurückgestellt, da es so aussieht als würde nicht eine komplette Zeile
> wackeln sondern die einzelnen Buchstaben je Spalte unabhängig
> voneinander.

Naja, ich nutze die SPI-Einheit und nicht USART. Diese braucht 16 Takte 
zum Ausschieben, das SPDR ist aber erst nach 2 weiteren Takten wieder 
beschreibbar. Das war mir aber recht, denn ich habe zusätzliche Takte 
eingefügt, um den Zeichenabstand zu vergrößern. Mein OSD wird im 
Amateurfunk (ATV-Relais) eingesetzt, da wird große, gut lesbare Schrift 
gebraucht. Der Textbereich wurde bewusst auf 10 Zeilen je 32 Zeichen 
begrenzt.

>
> Es handelt sich bei mir um ein Projekt, dass leider schon am Ende steht.
> Hardware ist bereits vorgegeben, kann also nicht auf anderen Aufbau und
> Software switchen. Software funktioniert bisher auch sehr gut. Das
> bewegen der Buchstaben ist meine einzige Sorge.

Nunja, Du benutzt USART, ich benutze SPI. Inwieweit USART für SPI taugt, 
weiß ich nicht, hat mich noch nie interessiert.

>
> Nochmal die Frage: Können Befehle aus irgendwelchen Gründen mal einen
> Takt länger brauchen?

Da ist mir nichts bekannt, zumindest, was ASM betrifft. Die 
Interrupt-Response-Time ist aber variabel, wenn sich die CPU nicht im 
Sleep befindet.

Du schreibst von Sperren des Interrupts durch cli() und sei(). Das mache 
ich nicht, Interrupt-Aufrufe sind immer erlaubt.

...

von Thomas Frosch (Gast)


Lesenswert?

Also ich benutze nicht direkt USART. Der Atmega32U4 bietet die 
Möglichkeit den UART als zusätzlichen SPI Master zu verwenden. Ich 
benötige den normalen SPI noch damit ich das OSD als Slave ansprechen 
kann.

Ich benutze auch den Sleep Modus!

Nach langem rumprobieren scheint es, dass wenn man vor dem senden über 
die USART-SPI das TXFlag löscht es besser funktioniert! Die Buchstaben 
hibbeln nun nicht mehr aufeinander zu. Allerdings hibbelt es trotzdem 
weiter. Dies führe ich jedoch eher auf die Syncs einer Zeile zurück. 
Ganz sicher kann ich mir dabei aber auch nicht sein. Vorallem wenn du 
schreibst das Signal über den LM ist ziemlich genau. Die Frage ist 
wieviel Jitter ist für dich wenig?

Ich sehe das Bild in meinem Grafikartenmodus (also nicht OSD sondern 
eigene Syncerzeugung) und das steht ohne kleinstes zittern und dann 
schalte ich um auf OSD und es jittert etwas. Das nächste ist auch, dass 
ich um das Flag zu löschen nun natürlich etwas länger brauche und 
dadurch der Abstand zwischen den Buchstaben größer wird. Zudem kann ich 
natürlich auch nicht mehr soviel Zeichen in eine Zeile bekommen (Anfangs 
42 nun noch 32). Ich lese über einige Pointer aus dem Programmspeicher 
da dort das Charset liegt.
Das SPI mehr als 16 Takte braucht ist klar + 2 für das "9te" Pseudo Bit

Also TXC1 aus UCSR1A löschen dann gehts wesentlich besser.
Seltsam ist nur, dass das nur was ausmacht, wenn der externe Interrupt 
an ist, ansonsten nicht????

Du hast nicht zufällig ein Video von deinem OSD Bild? mich würde mal 
interessieren wie gut dein Jitter ist. Vielleicht bin ich ja nur zu 
knausrig. Blöd ist halt der Vergleich zum Grakamodus. Da ists einfach 
perfekt.

von Hannes L. (hannes)


Lesenswert?

Thomas Frosch schrieb:
> Also ich benutze nicht direkt USART. Der Atmega32U4 bietet die
> Möglichkeit den UART als zusätzlichen SPI Master zu verwenden.

Das können die von mir verwendeten AVRs nicht, also kann ich dazu 
mangels Erfahrung nichts sagen. Ich werde mich auch nicht mit diesem U4 
beschäftigen, da ich ihn nicht auf selbstgeätzte Platinen löten kann. 
Man kann eben nicht alles haben...

> Ich
> benötige den normalen SPI noch damit ich das OSD als Slave ansprechen
> kann.
>
> Ich benutze auch den Sleep Modus!

Hmmm, das hier liest sich aber anders:
1
In der while Schleife des Programms wird ein Flag abgefragt. Ist dieses
2
1 wird angefangen eine Zeile zu schreiben. Das heißt einlesen eines
3
Bytes und senden per SPI und das ganze 40 mal hintereinander (per while
4
Schleife).

Das sieht bei mir anders aus. Der CPU-Takt ist aufgrund Sleep aus. Die 
Zeile wird per Interrupt vom H-Sync-Signal gestartet. Dadurch, dass die 
CPU im Sleep war, ist die Interrupt-Response-Time immer gleich. Würde 
der Interrupt während der Abarbeitung einer Endlosschleife auftreten, so 
wäre die Response-Time variabel, da ja die CPU erst ihren angefangenen 
Befehl fertig abarbeitet.

>
> Nach langem rumprobieren scheint es, dass wenn man vor dem senden über
> die USART-SPI das TXFlag löscht es besser funktioniert! Die Buchstaben
> hibbeln nun nicht mehr aufeinander zu. Allerdings hibbelt es trotzdem
> weiter. Dies führe ich jedoch eher auf die Syncs einer Zeile zurück.
> Ganz sicher kann ich mir dabei aber auch nicht sein. Vorallem wenn du
> schreibst das Signal über den LM ist ziemlich genau. Die Frage ist
> wieviel Jitter ist für dich wenig?

Der LM1881 arbeitet vermutlich genauer, als es der AVR erfassen kann. 
Denn die I/Os und auch die externen Interruprs (zu denen auch ICP zählt) 
werden vom Takt gesteuert. Somit wird das Eingangssignal im Takt des 
AVRs gerastert. Ein AVR-Takt ist aber immerhin 1/16 der Zeichenbreite. 
Somit ist ein Jitter von 1/16 der Zeichenbreite hinzunehmen. Da H-Sync 
aber nicht auf das Zeichen wirkt, sondern auf die Pixelzeile, gibt es 
keinen Jitter zwischen den Zeichen, sondern zwischen den Zeilen der 
Zeichen.

Mit meiner Interrupt-Methode rastere ich auf den Controllertakt, also 
1/16 Zeichenbreite. In einer Warteschleife

Label:
 sbis pin_x,bit_y   ;2 Takte wenn Skip, sonst 1 Takt
 rjmp Label         ;2 Takte
 ;Zeile ausgeben...

kann das Signal nur in jedem dritten Takt erfasst werden. Somit erhöht 
sich der Jitter auf 3/16 der Zeichenbreite.

>
> Ich sehe das Bild in meinem Grafikartenmodus (also nicht OSD sondern
> eigene Syncerzeugung) und das steht ohne kleinstes zittern und dann
> schalte ich um auf OSD und es jittert etwas. Das nächste ist auch, dass
> ich um das Flag zu löschen nun natürlich etwas länger brauche und
> dadurch der Abstand zwischen den Buchstaben größer wird. Zudem kann ich
> natürlich auch nicht mehr soviel Zeichen in eine Zeile bekommen (Anfangs
> 42 nun noch 32). Ich lese über einige Pointer aus dem Programmspeicher
> da dort das Charset liegt.

Einige Pointer?
Der AVR hat nur einen Pointer, der aus dem Flash lesen kann, nämlich den 
Z-Pointer. Das Charset umfasst 256 Zeichen, diese sind so angeordnet, 
dass in jeder 256-Byte-Page eine Pixelzeile aller Zeichen enthalten ist. 
Somit entscheidet ZH über die Pixelzeile und ZL über die 
(ASCII-)Zeichennummer. Beide Bytes des Pointers werden separat gesetzt, 
der Zugriff erfolgt (per LPM) über nur einen Pointer. Da ist nix mit 
"lese über einige Pointer aus dem Programmspeicher".

> Das SPI mehr als 16 Takte braucht ist klar + 2 für das "9te" Pseudo Bit
>
> Also TXC1 aus UCSR1A löschen dann gehts wesentlich besser.
> Seltsam ist nur, dass das nur was ausmacht, wenn der externe Interrupt
> an ist, ansonsten nicht????

Bei mir ist während der Ausgabe einer Videozeile kein externer Interrupt 
an. Der ICP (auch nur ein externer Interrupt mit Zusatzfeatures) 
detektiert das H-Sync-Signal, die Ausgabe der gesamten Pixelzeile 
erfolgt in seiner ISR. Während der ISR ist der Aufruf weiterer 
Interrupts gesperrt, es ist alsi nichts da, was das Timing zwischen den 
Zeichen stören könnte.

>
> Du hast nicht zufällig ein Video von deinem OSD Bild? mich würde mal
> interessieren wie gut dein Jitter ist.

Nein, habe ich nicht. Werde ich auch nicht machen, weil ich keine 
Hardware mehr habe und deswegen auch keine neue Hardware aufbauen werde. 
Die Hardware habe ich dem Funkamateur übergeben, für den ich das 
Programm schrieb. Die Sache ist seit fast 3 Jahren für mich erledigt, 
ich brauche selbst weder ein OSD noch eine "Grafikkarte" für AVRs. Denn 
ich bastele nicht mit TV, Video und ähnlichen Dingen, das ist einfach 
nicht mein Gebiet.

> Vielleicht bin ich ja nur zu
> knausrig. Blöd ist halt der Vergleich zum Grakamodus. Da ists einfach
> perfekt.

Das ist ja kein Wunder. Da erzeugst Du ja das Timing selbst und musst 
kein externes Timing synchronisieren.

Überprüfe doch bitte nochmal, ob (wie Du sagst) die ganzen Zeichen 
gegeneinander zittern, oder ob die ganzen Pixelzeilen gegeneinander 
zittern. Denn dass die ganzen Zeichen gegeneinander zittern, halte ich 
für sehr unwahrscheinlich. Es werden wohl die Pixelzeilen sein, die 
Ursache liegt vermutlich in der verschenkten Auflösung aufgrund der 
Abfrage in der While-Schleife.

...

von Thomas Frosch (Gast)


Lesenswert?

Meiner ist auch im Sleep. Ansonsten bekommt man noch ein wesentlich 
schlimmeres zittern


Ich konnte es noch nicht testen wie es sich auswirkt wenn ich das TX 
Flag lösche, aber davor (und das ist das seltsame) haben sich die 
Zeichen tatsächlich zueinander verschoben. Ich ließ mehrere kleine l´s 
schreiben und hab diese mit einem Oszi im Signal angesehen. Ab und zu 
sind diese um 2 Takte weiter auseinander.

Du hast recht es sind nicht einige Pointer aber einige 
Pointeroperationen da ich aus einem Array den Ascii Code lese den ich 
anzeigen möchte und dementsprechend mir die Bytes aus dem Charset im 
Flash hole.

Ich kann 40x33 Zeichen anzeigen. Und mit:

>>In der while Schleife des Programms wird ein Flag abgefragt. Ist dieses
>>1 wird angefangen eine Zeile zu schreiben. Das heißt einlesen eines
>>Bytes und senden per SPI und das ganze 40 mal hintereinander (per while
>>Schleife).

meinte ich den USART SPI und 40 mal pro Linie dann geht er in den Sleep.

...
Danke für die Antworten. Kann mir also sicher sein, dass es nicht am LM 
liegt. Werde nochmal per Oszi testen ob sich die Zeichen immer noch 
voneinander weg bewegen. Hab im moment nur keins hier.
Wenn das so wäre, wäre es ganz schön seltsam, denn das würde bedeuten 
die USART-SPI Hardware braucht zwischen zwei Bytes ab und zu zwei Takte 
länger.

Nach Assembler Code im Programm gibt es in diesem Abschnitt nichts wo er 
mal länger brauchen könnte...

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.