Hallo zusammen,
ich bin momentan ein wenig ratlos.
Ich habe folgendes Problem: Für eine kleine Spielerei wollte ich eine
Soft-DDS mit einem ATTINY2313 und dem MCP4921 D/A-Wandler
implementieren. Im Rahmen des ursprünglichen Projekts habe ich
festgestellt, dass die Ausgabe des MCP4921 sehr viele periodische
Störungen aufgewiesen hat.
Nach einigem Messen hatte ich schließlich die Software im Verdacht und
eine reine Soft-DDS geschrieben - das Ergebnis war zwar (weitestgehend)
vernünftig, es traten aber weiterhin einzelne sehr starke periodische
Störungen auf.
Geprüft habe ich:
- +5 Volt Spannungsversorgung (sauber)
- Taktsignale (Flanken waren tadellos und das Timing war auch richtig)
- Spannungsreferenz (sauber)
- Lötverbindungen der Chips
- Datensignale (Flanken waren auch tadellos, die Daten an sich aber
stellenweise fehlerhaft)
Disclaimer Ja, ich weiß, im Schaltplan ist PB5 mit dem Serial-In des
MCP 4921 verbunden - das ist mir bereits aufgefallen und musste daher
auf dem Board die bestehende Verbindung auftrennen (die ist auch
WIRKLICH getrennt) und habe dann die Verbindung mit ein paar Centimetern
Lackdraht gemacht. Foto vom Aufbau kann ich bei Bedarf nachreichen.
Ich habe dann den Logic-Analyzer (ein 10 Euro Saleae-Klon) an die
Datenleitungen gehängt und festgestellt, dass die
übertragenenen/mitgeschnittenen Daten passen exakt zu den Störungen auf
den Bildern.
Ich habe dazu eine CSV-Datei mit den mitgeschnittenen Daten angehängt
und in der Spalte "Sinus" die gesendeten Daten von den
Konfigurationsbits bereinigt, sodass man die eigentlichen Daten sieht.
Offensichtlich werden also schon die falschen Daten zum DA-Wandler
übertragen...
Ich habe bereits testweise mit der Optimierung herumgespielt, aus dem
Array ein Const gemacht.
Ich habe offensichtlich ein großes Brett vor'm Kopf, aber ich brauche
einfach mal einen Anstoß, nachdem ich bereits mehrere Abende in dieses
Problem versenkt habe.
Hier ist mein Quick-And-Dirty-Code für das reine Testen der Soft-DDS:
Tja, ein ATTINY2313 hat aber nur 128 Byte SRAM. Das ist durch das 128
Byte große Array schon komplett belegt. Für die lokalen Variablen und
Funktionsaufrufe werden aber noch ein paar Bytes für den Stack
gebraucht, und damit werden dann die letzten 12 Byte des Array
überschrieben.
Bernd B. schrieb:> Für die lokalen Variablen und> Funktionsaufrufe werden aber noch ein paar Bytes für den Stack> gebraucht, und damit werden dann die letzten 12 Byte des Array> überschrieben.
Ich Hornochse! Natürlich!
Ich habe mich so darin verrannt, dass mich der Compiler nicht von sich
aus gewarnt hat, dass mein RAM überbelegt ist.
Normalerweise meckert Atmel Studio schon von sich aus, wenn der RAM mehr
als 100 % belegt ist.
Ich habe das Array mal in den Flash verschoben - und siehe da: Alles
funktioniert tadellos!
Jetzt interessiert mich aber doch irgendwie eines: Ich programmiere mit
Atmel Studio 6.2 und dem GCC Compiler - wird bei der Angabe
Stefan S. schrieb:> wird bei der Angabe Program Memory Usage : 970 bytes 47,4 %> Full> Data Memory Usage : 0 bytes 0,0 % Full> der Stack nicht mit berücksichtigt?!
Nein. Weder der Compiler noch der Linker wissen, wieviel Stack benötigt
wird; dazu ist eine tiefere Analyse der Programmstruktur nötig, als ein
Compiler normalerweise macht. Programme zur statischen Codeanalyse, wie
z.B. Lint, können die benötigte Stackgröße bestimmen.
Stefan S. schrieb:> Jetzt interessiert mich aber doch irgendwie eines: Ich programmiere mit> Atmel Studio 6.2 und dem GCC Compiler - wird bei der Angabe>
1
> Program Memory Usage : 970 bytes 47,4 % Full
2
> Data Memory Usage : 0 bytes 0,0 % Full
3
>
> der Stack nicht mit berücksichtigt?!
Weil zur Compilezeit unmöglich für den allgemeinen Fall die maximale
Stacknutzung zur Laufzeit berechnet werden kann.
Das geht nur für sehr einfache Programme, die obendrein von vorherein
besonderen Bedingungen genügen müssen. Solche trivialen Programme
stellen aber so eine große Ausnahme dar, dass es den Compilerbauern
nicht lohnend erschien, eine entsprechende Analyse zu integrieren. Zumal
eine solche Analyse wiederum die Gefahr der Rekursion in sich birgt,
d.h.: schon der Compiler schmiert dann ab, es kommt also garnicht mehr
zu einem lauffähigen Code. Und das selbst dann, wenn der Code zur
Laufzeit niemals tatsächlich ein Problem hätte. Allein das Potential,
eines verursachen zu können, würde dem Compiler bereits zum Verhängnis
werden...
Vielen Dank euch beiden für die konstruktiven Antworten!
Ich habe mich bereits wieder mit meinen alten Unterlagen und den
Artikeln hier beschäftigt und da ist es mir wie Schuppen von den Augen
gefallen.
In diesem Sinne: Das Brett vor meinem Kopf ist in den Ofen gewandert und
ich habe meine zugegebenermaßen etwas eingerosteten Kenntnisse wieder
etwas schmieren können.
Hallo,
Wird mit der Deklaration das Array grundsätzlich im RAM vorgehalten?
"uint8_t sine[128] ="
Wäre es mit const davor anders gewesen? Oder ist nur die Deklaration mit
Progmem hier die richtige, damit das Array im Flash residiert?
z.B. const uint8_t PROGMEM [128]= .....
Mit freundlichem Gruß
Christian S. schrieb:> Oder ist nur die Deklaration mit Progmem hier die richtige, damit das> Array im Flash residiert?
Dies ist meines Wissens nach die einzig richtige Lösung, um das ganze in
den Flash zu schieben.
Ein "const" alleine macht nicht viel, außer dass es den Compiler dazu
veranlasst, dich zu warnen, wenn du die Variable/Array doch nachträglich
verändern willst.
Du bist übrigens nicht der erste mit dieser Frage - in diesem Thread
wird das ganze gut erklärt:
Beitrag "der gcc, das const-Schlüsselwort und der Speicher..."
Christian S. schrieb:> Oder ist nur die Deklaration mit Progmem hier die richtige, damit das> Array im Flash residiert?
Dies ist meines Wissens nach die einzig richtige Lösung, um das ganze in
den Flash zu schieben.
Ein "const uint8_t" alleine macht nicht viel, außer dass es den Compiler
dazu veranlasst, dich zu warnen, wenn du die Variable/Array doch
nachträglich verändern willst.
Du bist übrigens nicht der erste mit dieser Frage - in diesem Thread
wird das ganze gut erklärt:
Beitrag "der gcc, das const-Schlüsselwort und der Speicher..."
@Mods: Kann bitte jemand meinen Doppelpost bitte löschen. Hatte Probleme
mit dem Netz...
Ich muss mich doch nochmals an euch wenden, ich habe mittlerweile die
Ursache dafür gefunden, dass in meinem ursprünglichen Code der Sinus nur
mit schlechter Qualität ausgegeben wurde:
Wenn ich die Optimierung DEAKTIVIERE - wie ich es bei dem DDS-Beispiel
gemacht hatte - dann sieht der Sinus sauber aus, ich kriege aber nur ca.
670kHz Taktrate.
Wenn ich die Optimierung AKTIVIERE (-O1 und aufwärts) bekomme ich zwar
meine gewünschte Taktrate von 4MHz, die Datensignale sind aber leicht
versetzt und der ausgegebene Sinus .
In den Bildern sieht man es ganz gut, bei deaktiviere, sieht der Sinus
"sauber" aus (von den obligatorischen Stufen abgesehen) und die
Datensignale sind zur steigenden Taktflanke stabil.
Bei aktivierter Optimierung sind liegt die Änderung der Datensignale mit
der steigenden Flanke des Taktes zusammen - was wohl die miese Qualität
des Sinus erklärt.
Mein Oszi scheint wohl damit klarzukommen, aber der DAC wohl -
verständlicherweise - nicht, was mich zu der ursprünglichen und irrigen
Annahme verleitet hatte, dass die Datensignale in Ordnung seien.
Liegt es wirklich an der Optimierung?! - Habe ich mal wieder ein völlig
offensichtliches Brett vor meinem Kopf?!
Hm.
Jetzt bin ich endgültig verwirrt:
Ich habe mit verschiedenen Codes aus diversen Quellen herumgespielt.
Das Ergebnis ist wie folgt:
Wenn ich das Assembler-Beispiel aus dem Datenblatt für High-Speed-SPI in
C übernehme, dann funktioniert alles wie es soll (auch mit Optimierung):
Auf Basis dieses Codes habe ich mir gedacht, dass ich einfach die obige
Schleife "entrolle" und habe einfach pro Byte den Teil des USICR 16 Mal
kopiert.
Nur dies funktioniert nur, wenn die Optimierungen deaktiviert sind:
>Eigentlich sollte es doch bei den letzten beiden Varianten keinen>nennenswerten Unterschied geben?!
Doch, am Ende der Schleife hast du eine Abfrage und einen Sprung
zum Beginn der Schleife. Das ergibt ein kleines Delay.
holger schrieb:>> Eigentlich sollte es doch bei den letzten beiden Varianten keinen>>>nennenswerten Unterschied geben?!>> Doch, am Ende der Schleife hast du eine Abfrage und einen Sprung> zum Beginn der Schleife. Das ergibt ein kleines Delay.
Das war auch bereits mein Gedanke... Daran muss es offensichtlich
liegen.
Im Datenblatt gibt es die gleiche Schleife in Assembler, da wird auch
zyklisch eine Abfrage gemacht.
Interessant...