Hallo,
erst einmal möchte ich mich für das tolle Forum und die umfangreichen
Tutorials bei der Community, also euch, bedanken. Ihr habt mir den
Einstieg in die Programierung von uCs sehr vereinfacht.
Mittlerweile konnte ich schon einiges auf verschiedenen Atmegas
implementieren, doch stehe ich aktuell vor einem Problem bzw. bräuchte
eure Hilfe.
Für mein aktuelles Projekt benötige ich 3 ineinander verschachtelte
Schleifen, welche per UART eintreffende Daten verarbeiten und an einen
zweiten uC per UART senden. Was genau dort passiert ist erstmal
unrelevant, denn ich musste feststellen, dass mein Atmega1284P mit
externem 18,432MHz Quarz irgendwie mit Handbremse läuft.
Zum Testen der Geschwindigkeit habe ich folgenden C-Code verwendet:
1
#include"bitOperations.h"
2
#include"uart1284P.h"
3
#include<avr/io.h>
4
#include<stdlib.h>
5
#include<util/setbaud.h>
6
7
intmain(void)
8
{
9
uint8_tx=255;
10
uint8_ty=255;
11
uint8_tz=3;
12
13
set_bit(DDRB,0);
14
15
while(1)
16
{
17
set_bit(PORTB,0);
18
19
do{
20
do{
21
do{
22
23
}while(--z);
24
}while(--y);
25
}while(--x);
26
27
clear_bit(PORTB,0);
28
uart0_data(x);
29
}
30
}
Das Programm macht nichts anderes, als:
1. den PINB0 als Ausgang zu definieren und den Ausgang zu togglen
(set_bit und clear_bit). Am PINB0 hängt eine LED mit Vorwiderstand.
2. Die do-while Schleifen zu durchlaufen
3. Eine Null (x ist nach Durchlauf der do-while-Schleifen gleich Null)
per UART zu senden. Die Null wird ordnungsgemäß am PC empfangen; UART
funktioniert.
PROBLEM: Das Durchlaufen der do-while-Schleifen dauert extrem lange. Ich
empfange am PC circa alle 3 Sekunden ein Zeichen, was bedeutet, dass der
Atmega1284P mit 18,432MHz für die 3 popeligen verschachtelten Schleifen
ganze 3 Sekunden braucht.
Nach meiner Berechnung mit x,y,z sollten das doch ungefähr
Schrittanzahl= 255*255*3= 195075 Schritte sein, oder? Gut, noch ein paar
zusätzliche Schritte, also mal grob das doppelte angenommen =390150
Schritte bei 18,432MHz sein. Sprich die kompletten Schleifen sollten
nach meiner worst-case-Rechnung innerhalb von ungefähr 0,02S durchlaufen
sein.
(1/18,432MHz)*390150 = ~0,02s
Die Fuse-Bits sind richtig gesetzt und der Takt wurde an Pin B1 per
Oszilloskop geprüft.
Nun zu meinen Fragen:
a) Ist es normal, dass der Atmega1284P für solche 3 Schleifen so extrem
lange, sprich 3 Sekunden benötigt?
b) Läuft der Atmega vielleicht irgendwo mit Handbremse, wenn ja wie kann
ich diese lösen?
c)Stromsparmodi müssten doch explizit gesetzt werden, damit diese
greifen, oder?
Für Hilfestellungen möchte ich mich vorab schon einmal bedanken.
Viele Grüße.
Daniel
Hallo,
Daniel M. schrieb:> Nach meiner Berechnung mit x,y,z sollten das doch ungefähr> Schrittanzahl= 255*255*3= 195075 Schritte sein, oder?
Nach dem ersten Durchlauf mag das so sein, aber im 2.ten sind alle
Variabel x,y,z = 0 und dann ?
Kannst Du bestimmt selbst Rechnen ?
Ticks = 256³
Hallo Uwe,
ja na klar...das Zurücksetzen von x,y,z habe ich nicht in der
while(1)-Schleife gehabt. Habe es nun so angepasst, dass x,y,z nach dem
senden von x=0 per uart zurück auf 255,255,3 gesetzt werden.
1
#include"bitOperations.h"
2
#include"uart1284P.h"
3
#include<avr/io.h>
4
#include<stdlib.h>
5
#include<util/setbaud.h>
6
7
intmain(void)
8
{
9
uint8_tx=255;
10
uint8_ty=255;
11
uint8_tz=3;
12
13
set_bit(DDRB,0);
14
15
while(1)
16
{
17
set_bit(PORTB,0);
18
19
do{
20
do{
21
do{
22
23
}while(--z);
24
}while(--y);
25
}while(--x);
26
27
clear_bit(PORTB,0);
28
uart0_data(x);
29
30
x=255;
31
y=255;
32
z=3;
33
}
34
}
Ändert aber nichts daran, dass er trotzdem für das Durchlaufen der
Schleifen etwa 3s benötigt. :-(
Daniel M. schrieb:> Ändert aber nichts daran, dass er trotzdem für das Durchlaufen der> Schleifen etwa 3s benötigt. :-(
das sollte in 0 Sekunden erledigt sein, hast du die optimierung
eingeschaltet? Dann sollte nichts mehr von den schleifen übrig bleiben.
c) Ist meine Annahme, dass der uC 255*255*3 Ticks für die Schleifen
benötigt falsch?
Die z-Schleife wird von 3 runter auf 0 gezählt und das genau 255mal
(y-Schleife) und das Ganze wird dann nochmal 255mal gemacht
(x-Schleife).
@Peter II
Ich verwende das AtmelStudio 6 mit allen updates, und ASF Version 3.4.1
(weiss nicht, ob das wichtig ist).
In der Toolchain habe ich Optimization Level = Optimize (-O1).
Viele Grüße,
Daniel
@Oliver
Wenn ich den uart rausnehme, dann ändert sich daran nichts, die LED
blinkt genauso langsam.
Habe gerade mal die Schleifen rausgenommen und sobald diese raus sind,
rennt der uart und die LED glimmt nur noch (verständlich).
Die Schleifen werden auch bei der höchsten Optimierung (-O3) nicht
wegoptimiert. Ob ohne oder mit Optimierung, Programm läuft genauso
langsam.
Der limitierende Faktor sind die Schleifen, aber wieso? Wieso braucht
der uC für die 3 Schleifen so lange?
Viele Grüße,
Daniel
Daniel M. schrieb:> Der limitierende Faktor sind die Schleifen, aber wieso? Wieso braucht> der uC für die 3 Schleifen so lange?
wie schnell läuft denn der µC? Welcher Quarz welche Fuse sind gesetzt?
Und bitte mal das LSS file senden, dort steht drin was er macht.
Nachtrag:
hast du nach der umstellung der Optimierung auch mal die anwendung
neu compilieren lassen? Wenn du nicht weiter am quellcode änderst, dann
wird es nicht neu compiliert weil die änderung der Option keine
wirkliche änderung ist. Am besten "make clean" machen!
Guck noch mal gut, du machst die x=255;y=255;z=3; jetzt irgendwo anders
aber noch nicht auf der gute stelle.
Vielleicht wird es dir mehr deutlich wenn du die x,y,z werte zum uart
sendest und dir die mal anschaust
Entweder du findest aus wo die am besten stehen oder wenn du x und y
beiden 255 lasst kannst du es umdrehen :
do{
do{
do{
} while(--x);
}while(--y);
}while(--z);
> do{> do{> do{>> } while(--z);> }while(--y);> }while(--x);
Die innerste Schleife wird rund 16.5 Millionen mal durchlaufen. Also ich
finde 3 Sekunden dafür nicht schlimm. Zähl du doch mal soweit!
> c) Ist meine Annahme, dass der uC 255*255*3 Ticks für die> Schleifen benötigt falsch?> Die z-Schleife wird von 3 runter auf 0 gezählt und das genau> 255mal (y-Schleife) und das Ganze wird dann nochmal 255mal> gemacht (x-Schleife).
Jau. Das ist falsch. Die innerste (z) Schleife wird einmal von 3 auf 0
runtergezählt und danach 255*255 mal von 255 bis auf 0
Tu dir selbst einen Gefallen und schreib 'for', wenn du 'for' meinst.
@Peter II
Optimierung auf -Os geändert; Make clean gemacht und neu compiliert;
keine Veränderung
1) wie schnell läuft denn der µC? 18,432MHz
2)Welcher Quarz welche Fuse sind gesetzt? 18,432MHz Quarz
Low Fuse = 0xFF (Ext.Crystal Osc.:Freq 8.0- MHz), kein Divide clock by 8
High Fuse = 0xD9
Extended Fuse = 0xFF
Lockbits = 0xFF
LSS-File ist angehängt
Daniel M. schrieb:> @Peter II>> Optimierung auf -Os geändert; Make clean gemacht und neu compiliert;> keine Veränderung
Nochmal: das passt schon alles.
(Trotzdem solltest du auf -Os bleiben)
Du hast einen Programmfehler gemacht.
Du hast dich verrechnet. Deine innerste Schleife wird run 16.5 Millionen
mal durchlaufen und nicht, wie du fälschlich ausgerechnet hast,
195tausend mal.
Und für 16.5 Millionen Durchläufe sind 3 Sekunden angemessen.
Deine Zähler
Durchlauf x y z
1 255 255 3
2 255 255 2
3 255 255 1
4 255 255 0
5 255 254 255 <- hier liegt dein Fehler!
6 255 254 253
7 255 254 252
Schreib "for", wenn du "for" meinst!. Dann vergisst du auch nicht, dass
du die Zähler vor Beginn einer Schleife neu initialisieren musst.
Speziell dann, wenn Schleifen ineinander geschachtelt sind und die
innere Schleife eine spezielle Initialisierung braucht.
Karl Heinz Buchegger schrieb:> Daniel M. schrieb:>> @Peter II>>>> Optimierung auf -Os geändert; Make clean gemacht und neu compiliert;>> keine Veränderung>> Nochmal das passt schon alles.
ja der code sieht schon etwas optimiert aus, aber warum der compiler
nicht erkennt das die schleife komplett weg kann ist mir nicht ganz
klar.
Hallo,
Ich habe gestern mit Daniel an dem Quelltext gesessen. Dass die
do-Schleifen murks sind sehe ich jetzt auch ein, aber vorher waren das
for-Schleifen mit dem selben Laufzeitverhalten von ca. 3 Sekunden. Wir
hatten nur irgendwo noch als Optimierung gelesen, dass do-Schleifen
performanter sind und das darum geändert.
Peter II schrieb:> ja der code sieht schon etwas optimiert aus, aber warum der compiler> nicht erkennt das die schleife komplett weg kann ist mir nicht ganz> klar.
Das wird dir nur Johann L. sagen können. Mag sein, dass der Optimizer
diesen Fall einfach nicht mitkriegt, weil das die Mehrzahl der
Programmierer so nicht schreiben würden und es bisher niemandem
aufgefallen ist.
Daniel M. schrieb:> @Karl Heinz Buchegger>> das neu initialisieren habe ich mittlerweile korrigiert;
Nein, hast du nicht
sieh dir nochmal die Zählerwerte an, die ich dir tabellarisch angegeben
habe! Aber diesmal GANZ GENAU!
Durchlauf x y z
1 255 255 3
2 255 255 2
3 255 255 1
4 255 255 0
5 255 254 255 <- hier liegt dein Fehler!
6 255 254 253
7 255 254 252
Warum geht es mit dem z-Wert im Durchlauf 5 bei 255 weiter (nachdem y
das erste mal runtergzählt wurde)?
Karl Heinz Buchegger schrieb:> Daniel M. schrieb:>> @Karl Heinz Buchegger>>>> das neu initialisieren habe ich mittlerweile korrigiert;>> Nein, hast du nicht>> sieh dir nochmal die Zählerwerte an, die ich dir tabellarisch angegeben> habe! Aber diesmal GANZ GENAU!>> Durchlauf x y z> 1 255 255 3> 2 255 255 2> 3 255 255 1> 4 255 255 0> 5 255 254 255 <- hier liegt dein Fehler!> 6 255 254 253> 7 255 254 252>>> Warum geht es mit dem z-Wert im Durchlauf 5 bei 255 weiter (nachdem y> das erste mal runtergzählt wurde)?
Antwort:
Weil das genau das ist, was bei
1
y=255;
2
z=3;
3
4
do{
5
do{
6
}while(--z);
7
}while(--y);
zu erwarten ist. Du WOLLTEST zwar z immer wieder bei 3 beginnen lassen,
also so
@Karl Heinz Buchegger
Du hast absolut Recht ... ich initialisiere die Werte in der
darüberliegenden Schleife nicht neu! Asche auf mein Haupt.
Das werde ich nun mal einfügen und testen .. bis gleich :-)
Und das nächste mal schreibst du es so
for( x = 255; x > 0; x-- )
{
for( y = 255; y > 0; y-- )
{
for( z = 3; z > 0; z-- )
{
}
}
}
und dann passiert dir deser Fehler nicht mehr. Denn durch das for musst
du dir automtisch Gedanken über Schleifenstartwerte machen.
-- Das war die Lösung, vielen Dank an Karl Heinz und alle anderen für
die schnelle Hilfe!
Viele Grüße,
Daniel
ps: der Atmega ist ja doch nicht so langsam...und ich hab geschimpft
grml :-D
Daniel M. schrieb:> ps: der Atmega ist ja doch nicht so langsam...und ich hab geschimpft> grml :-D
In mehr als 95% aller Fälle sitzt das Problem vor dem Bildschirm
@ Karl Heinz
Der µC soll empfangene DMX-Daten auf 4 Kanälen auswerten und diese für
192 (8x8 RGB-)LEDs aufbereiten. Die aufbereiteten Daten sollen dann an
einen zweiten µC per UART gesendet werden, welcher die LEDs per PWM
ansteuert.
Karl Heinz Buchegger schrieb:> In mehr als 95% aller Fälle sitzt das Problem vor dem Bildschirm
Da kann ich dir nur zustimmen, davon sind wir zum Anfang auch
ausgegangen und haben den Fehler einfach nicht gesehen ... Also war zu
späterer Stunde (heute Nacht 3Uhr) der Atmega schuld ;-)
Daniel M. schrieb:> @ Karl Heinz>> Der µC soll empfangene DMX-Daten auf 4 Kanälen auswerten und diese für> 192 (8x8 RGB-)LEDs aufbereiten.
Du wirst doch nicht 195-kByte in einem Rutsch übertragen! Oder doch?
Daniel M. schrieb:> Der µC soll empfangene DMX-Daten auf 4 Kanälen auswerten und diese für> 192 (8x8 RGB-)LEDs aufbereiten.
Und dafür willst du ihn so aufwändig Däumchen drehen lassen?
Nein, das muss natürlich noch alles angepasst werden. Aber wie gesagt,
gestern haben wir erstmal an dem Problem gehangen und sind einfach nicht
darauf gekommen. Vielen Dank nochmal dafür.
Wer keine Probleme hat, der schafft sich welche ;-)
Viele Grüße,
Daniel