Hallo Mikrocontroller.net Forum,
ich denke derzeit über eine einfache Möglichkeit nach, mit einem Atmega
möglichst "schnell" (in Atmega-Zeitskalen, Samplingfrequenz von mehreren
100 kHz, evtl sogar. 1 MHz?) über einen externen, parallelen ADC ein
analoges Signal mit 8 bit Genauigkeit aufzunehmen. Dabei soll ein
Datenblock von z.B. 12k Messpunkten aufgenommen werden. Da die
Samplingraten ja schon nicht mehr so weit von der Taktfrequenz (20 MHz)
entfernt sind, und ich mich damit schwertue die Zyklenzahlen für
Operationen abzuschätzen (bin eher mit C unterwegs als mit Assembler)
würde ich mich vorm "physischen Basteln" über Meinungen zu meinem
Projekt freuen um es ggf. zu verwerfen. Gibt es eigentlich Möglichkeiten
die benötigten Rechenzyklen aus dem C-Code heraus zu simulieren?
Grober Plan:
* Die Schaltung basiert z.B. auf einem Atmega 1284P, hauptsächlich
aufgrund der 16k SRAM. Der sollte mit 20 MHz laufen.
* Da der Atmega ADC wohl zu langsam ist, würde ich einen schnellen (> 20
MHz) 8 bit ADC verwenden, der kontinuierlich arbeitet und den digitalen
Output parallel bereitstellt (D0-D7). Diesen würde ich bspw. an PA0 -
PA7 des Atmegas hängen.[Hätte jemand da einen Tip für einen ADC IC?]
* Wenn ich Karl Heinz' Post in
Beitrag "max. Eingangssignal für ISR" richtig verstehe, sind
Interrupts zur Taktgebung solch einer Messung eher ungeeignet, da
langsam. Daher würde ich einen Pin des Atmegas (z.B. PC0) an einen
TTL-Taktgeber klemmen (z.B. Quarzoszillator, oder ein
Atmega-Timer-generiertes Signal), der die Messfrequenz von einigen 100
kHz - 1 MHz vorgibt.
* Die Aufnahme eines 12 kiB Datenblocks soll über einen Triggerpuls,
(z.B. an PC1) gestartet werden.
Das Programm sollte nicht viel können, und (ohne Interrupts) etwa so
ablaufen ("Pseudocode"):
1. Initiiere Buffer:
1
chardata[12288];// (12kiB, hier sollen die ADC Bytes rein).
2. Warte auf ein definiertes char über den UART, bspw. '\n'. Wenn char
da, dann:
1
inti=0;// Zähler
3. Warte auf ein Triggersignal PC1 (polling) ->
1
while(!(PINC&0x02));// Wenn Trigger da, dann weiter:
4. Warte auf pos. Flanke an Taktgeberpin / PA auslesen und in
data-Buffer Zähler hochsetzen Warte auf neg. Flanke an Taktgeberpin
/ Warte auf pos. Flanke an Taktgeberpin / usw.
1
while((PINC&0x01));
2
while(i<12288){
3
while(!(PINC&0x01));
4
data[i]=PINA;
5
i++;
6
while((PINC&0x01));
7
}
5. Wenn 12 kiB aufgenommen wurden, schreibe data binär an den UART, zur
Auswertung mit PC / etc.
6. Zurück zu 2.
Meine Fragen wären nun:
- Ist der Plan einigermaßen sinnvoll?
Falls ja:
- Ich kann mir vorstellen, dass das Programm einen recht überschaubares
Timing hat. Auch sollten keine störenden Interrupts Verzögerungen
hervorrufen können. Wie schnell könnte der Takt an PC0 guten Gewissens
gewählt sein, um verlässlich Daten abzuspeichern und keine Punkte zu
verlieren?
- Bei Halbierung der Punkteanzahl könnten ja pro Mess-Taktsignal 2 Bytes
abgelegt werden, etwa durch:
1
dataA[i]=PINA;
2
dataD[i]=PIND;
Hierdurch sollte bei Verwendung eines geeigneten (etwa 16 bit) ADC an
PINA und PIND die Bittiefe erhöht, oder durch einen weiteren 8 bit ADC
an PIND ein zweiter Kanal aufgenommen werden können. Würde dies die
mögliche Sampling Rate deutlich verringern?
Vielen Dank im Voraus!
Hendrik schrieb:> ich denke derzeit über eine einfache Möglichkeit nach, mit einem Atmega> möglichst "schnell" (in Atmega-Zeitskalen, Samplingfrequenz von mehreren> 100 kHz, evtl sogar. 1 MHz?) über einen externen, parallelen ADC ein> analoges Signal mit 8 bit Genauigkeit aufzunehmen.
1MHz ist sehr sportlich, sollte aber noch im Bereich des möglichen sein.
Hendrik schrieb:> Hierdurch sollte bei Verwendung eines geeigneten (etwa 16 bit) ADC an> PINA und PIND die Bittiefe erhöht, oder durch einen weiteren 8 bit ADC> an PIND ein zweiter Kanal aufgenommen werden können. Würde dies die> mögliche Sampling Rate deutlich verringern?
Ja
Einfach mal rechnen: Bei 20MHz Taktfrequenz und 1MHz Samplingrate
bleiben 20 Takte je Messwert. In diesen 20 Tkten müssen die Messwerte in
den µC rein und ins RAM geschrieben werden. Viel Zeit bleibt da nicht.
Hendrik schrieb:> * Wenn ich Karl Heinz' Post in> Beitrag "max. Eingangssignal für ISR" richtig verstehe, sind> Interrupts zur Taktgebung solch einer Messung eher ungeeignet, da> langsam. Daher würde ich einen Pin des Atmegas (z.B. PC0) an einen> TTL-Taktgeber klemmen (z.B. Quarzoszillator, oder ein> Atmega-Timer-generiertes Signal), der die Messfrequenz von einigen 100> kHz - 1 MHz vorgibt.
Müll. Die Takterzeugung muss, wenn es schnell gehen soll direkt von der
Taktfrequenz des Prozessors abgeleitet werden. Der Rest ist Software,
ich würde mir mal Assembler ganz genau anschauen, da erkennt man besser
was der µC gerade macht und wie lange er dafür benötigen wird.
Auf einem STM32F4 habe ich einen 16bit ADC parallel angestöpselt und
schaufle die Daten mit 200kHz per Ethernet als Livestream raus, da
geht's ohne Probleme. 1MHz müsste da auch noch drin sein, Blockweise
rausschieben bestimmt noch mehr.
Falls das eine Alternative für dich wäre und Interesse besteht kannst du
dich auch gerne bei mir melden, kann dir da unter die Arme greifen beim
Einarbeiten in den STM32.
> im Bereich des möglichen
Das denke ich auch.
> recht überschaubares Timing
Der Kern der Aufnahmeschleife sieht in Assembler wohl irgendwie so aus:
1
loop:
2
in tmp,PINA
3
st x+,tmp
4
cpi XH,high(data_end)
5
brne loop
Das sind 6 Takte, bleiben für etwelche allfällige Synchronisierungen 14
Takte (bei 20 / 1 MHz).
> Atmega 1284P ... Der sollte mit 20 MHz laufen
So steht es im Datenblatt, man könnte es aber auch mit etwas mehr
probieren, z.B. 22. Bei mir läuft einer seit Monaten problemlos mit 25
MHz.
Vielen Dank für die Antworten!
Das klingt dann ja doch recht positiv, ich denke dann werde ich die
Bastelei demnächst mal angehen.
@Schreiber:
> Einfach mal rechnen: Bei 20MHz Taktfrequenz und 1MHz Samplingrate bleiben 20
Takte je Messwert. In diesen 20 Tkten müssen die Messwerte in den µC rein und ins
RAM geschrieben werden. Viel Zeit bleibt da nicht.
Genau diese Überlegung war mein Ausgangspunkt für diesen Thread.
> Müll. Die Takterzeugung muss, wenn es schnell gehen soll direkt von der
Taktfrequenz des Prozessors abgeleitet werden. Der Rest ist Software, ich würde
mir mal Assembler ganz genau anschauen, da erkennt man besser was der µC gerade
macht und wie lange er dafür benötigen wird.
Wenn möglich, würde ich gerne bei dem externen "Clock Signal" zur
Taktung der Messungen bleiben, dieses hätte auch den Vorteil, dass ich
mehrere Atmega/ADC Kombis synchronisiert messen lassen könnte.
@Reginald Leonczuk:
16 bit live mit 200 kHz über Ethernet klingt sehr gut, ich möchte über
kurz oder lang auch gerne auf das Angebot zurückkommen und mich mit dem
STM32 beschäftigen, allerdings würde ich dieses Projekt zunächst erst
einmal mit den mir bekannten Atmegas umsetzen (sofern möglich).
@S. Landolt:
>
1
loop:
2
in tmp,PINA
3
st x+,tmp
4
cpi XH,high(data_end)
5
brne loop
> Das sind 6 Takte, bleiben für etwelche allfällige Synchronisierungen 14 Takte
(bei 20 / 1 MHz).
Danke für die Umsetzung in ASM - das klingt für mich jetzt so, als
würden sogar mit 20 MHz Takt die maximal angepeilten 1 MHz Sampling Rate
erreicht werden können und vermutlich noch genug Zeit für das Polling
des externen Clock-Pins bleiben (?).
Selbst wenn ich zusätzlich noch PIND auslesen würde (für 16 Datenbits
pro Messung) müsste es doch immernoch passen (<=12 Takte pro Messung?)?
Wäre es in diesem Fall sinnvoll (in C) die Bytes von PINA und PIND
abwechselnd in den gleichen Buffer zu schreiben, oder zwei Buffer mit
halber Größe anzulegen (wie in meinem ersten Post vorgeschlagen)? Oder
wäre es egal, weil der C-Compiler es optimiert?
Hendrik schrieb:>> Müll. Die Takterzeugung muss, wenn es schnell gehen soll direkt von der> Taktfrequenz des Prozessors abgeleitet werden. Der Rest ist Software,> ich würde> mir mal Assembler ganz genau anschauen, da erkennt man besser was der µC> gerade> macht und wie lange er dafür benötigen wird.>> Wenn möglich, würde ich gerne bei dem externen "Clock Signal" zur> Taktung der Messungen bleiben, dieses hätte auch den Vorteil, dass ich> mehrere Atmega/ADC Kombis synchronisiert messen lassen könnte.
Das kann man auch erreichen, indem man diese mit einem gemeinsamen
Prozessortakt versorgt.
Die AVRs kann man nicht nur mit einenem normalen Quarz, sondern auch mit
einem richtigen Quarzoszillator mit ihrem Takt versorgen. Letzterer hat
den Vorteil, dass er mehrere AVRs versorgen kann, die dann syncron
laufen
Moin,
Ich bin ja durchaus ein Freund der digitalen Signalverarbeitung auf AVR.
Aber das scheint mir doch etwas zu ambitioniert, bzw. zu sehr mit
Beschraenkungen verbunden. Da wuerd' ich doch aufn Prozessor eine Nummer
groesser umsteigen, also irgendein STM32 oder sowas in der
Leistungsklasse.
Gruss
WK
@ H-G Sch:
> Soll der externe ADC 20MHz Samplingrate haben oder nur die 1MHz die der> AVR ausgeben soll ?
Meine Überlegung war einen ADC zu verwenden, der einfach deutlich
schneller ist als meine Messung, damit die parallelen Bits an PINA/PIND
immer "aktuell genug" sind, und der ADC den Messvorgang nicht limitiert.
Ich könnte den ADC dann natürlich auch einfach mit dem Mess-Clock-Signal
füttern, und so dafür sorgen, dass vor jedem Abfragen von PINA/PIND eine
Wandlung initiiert wird. So ergäbe sich dann eine SR von z.B. 1 MHz.
Dabei müsste dann natürlich die Conversion Time unterhalb der Zeit
zwischen Clock-Signal Flanke und Abfrage der PIN-Bytes liegen, was aber
auf jeden Fall gegeben sein sollte, wenn der ADC schneller ist als der
Atmegatakt.
@ Schreiber:
Was spricht denn letztendlich gegen einen externen Messtakt, wenn es vom
Timing her zeitlich passt?
Klar kann man Atmegas über einen gemeinsames Taktsignal synchronisieren,
aber dann müsste ich ja (zumindest in C) immernoch über ein
Timerinterrupt/etc. die Messung auslösen(?), welches - so wie ich es im
oben zitierten Thread verstanden habe - auch einige Taktzyklen kostet.
Über eine schnelle Alternative zum Timerinterrupt (am liebsten in C)
würde ich mich natürlich freuen!
@ Stefan Us:
> Irgend etwas willst du mit den eingelesenen Daten auch anstellen. Bis zu>sicher, dass der µC dafür schnell genug ist?
Ich möchte den (oder mehrere) µC eigentlich nur als "dummen" und
einfachen Datenrekorder verwenden. Wie im Pseudocode oben soll dieser
über UART/RS232 aktiviert werden, nach einem TTL Triggersignal >10 k
Datenpunkte aufnehmen und diese dann wieder unbearbeitet als Binärblock
seriell an einen Messcomputer senden. Die Bearbeitung der Signale findet
dann nach der Messung auf dem Rechner mit Python/Matlab/etc. statt.
Meine Überlegung war, dass ein so "einfaches" Programm, ohne viel
Schnickschnack, auf einem Atmega vorhersagbar ablaufen sollte und mir
die Möglichkeit gibt einen simplen, günstigen Datenrekorder zu bauen.
@ Dergute Weka:
Wie oben geschrieben, wenn der Atmega das packt, wüsste ich nichts was
dagegen spricht. Würde mich aber auch trotzdem gerne für weitere
Projekte mit dem STM32 beschäftigen - scheint ja deutlich
Leistungsfähiger zu sein. Gibt es eine Empfehlung für den Einstieg? Ich
fand z.B. die AVR Tutorials hier für den Einstieg in Atmega sehr
hilfreich.
> ... (für 16 Datenbits pro Messung) ...> ... >10 k Datenpunkte aufnehmen ...
Also das schafft ein ATmega1284P mit seinen 16 KiB RAM natürlich nicht
mehr vom Volumen her, auch wenn es rein zeitlich problemlos ginge.
Bei 128k Flash oder 64k Befehle und 4 Befehle pro Durchlauf:
12k * 4 -> 48k (96kB) mit 1+2+1+2 -> 6 Takten komm ich auf 3.33.. MHz
Abtastrate.
Normalerweise bin ich ja für C++, aber vereinzelt braucht man eben
Assembler ;-)
Update:
Es passen natürlich keine 12k int's ins RAM, noch nicht mal 8k, es sei
denn, man kann sonst komplett auf RAM verzichten. D.h. kein Stack, kein
call, keine Interrupts, ...
Ich habe mit dem STM32F4 Discovery angefangen. Da ist der
Programmer/Debugger schon dabei.
Bei IDEs ist fast alles möglich, Eclipse oder aber auch Visual Studio.
Bei deinem Vorhaben und den erwähnten Anforderungen würde ich wechseln.
Wenn man nachträglich doch noch ne kleine Erweiterung implementieren
möchte, wäre es schade, wenn es dann am Speed mangelt.
Mein Angebot steht ;)
@ Carl Drexler (jcw2):
> Es passen natürlich keine 12k int's ins RAM, noch nicht mal 8k, es sei> denn, man kann sonst komplett auf RAM verzichten. D.h. kein Stack, kein> call, keine Interrupts, ...
...die >10 k Datenpunkte (sollte eigentlich ~10 k werden) bezogen sich
natürlich auf 8 bit/Messung - bei 16 bit würde ich etwa 5 k Datenpunkte
anpeilen, je nachdem wieviel SRAM vom Rest des Programms belegt wird.
> Ich habe mit dem STM32F4 Discovery angefangen. Da ist der> Programmer/Debugger schon dabei.> Bei IDEs ist fast alles möglich, Eclipse oder aber auch Visual Studio.
@Reginald Leonczuk:
Ich habe gerade mal
https://www.mikrocontroller.net/articles/STM32F4-Discovery überflogen
und festgestellt, dass es ja offenbar linuxlauffähige Compiler und Tools
gibt - Eclipse ja sowieso - das werde ich demnächst mal angehen und dann
gerne auf das Angebot zurückkommen. :) Ich hatte sowieso vor mich mit
leistungsfähigeren µC zu beschäftigen...
Zusammenfassend scheint mein ursprünglicher Atmega - 1 MHz (8/16 bit)
Sampling-Plan dann ja zwar am Limit aber durchaus möglich - daher werde
ich trotzdem als Erstes diese Variante aufbauen (muss mich dann nicht
neu einarbeiten), testen und berichten!
Ich weiß nicht, wie das in C aussehen könnte, aber falls Sie in Erwägung
ziehen, zumindest die Aufnahmeschleife in Assembler zu schreiben, so
wären auch 12 bit bei 10 k Datenpunkten recht einfach möglich.
Ach was muss Langeweile doch schön sein!
Üblicherweise ist das Messen doch kein Selbstzweck!
Ja, es mag ja, mit hängen und würgen, möglich sein diese Messung
durchzuführen, aber:
In null Komma nichts ist der Speicher voll.
Natürlich nur, wenn ununterbrochen (Interrupt: Nein Danke) gearbeitet
werden kann.
Keine "Zeit" zum Arbeiten, d.h. die Messwerte können nur durchgereicht
werden. Wohin eigentlich.
Oder ist das ganze doch nur Selbstzweck? Weil keine Verarbeitung möglich
ist, weil die Speichertiefe ein Witz ist?
Sicher theoretisch ist es möglich!
Sebastian S. schrieb:> Üblicherweise ist das Messen doch kein Selbstzweck!
Richtig.
> Ja, es mag ja, mit hängen und würgen, möglich sein diese Messung> durchzuführen
Natürlich ist es möglich. Und zwar nicht mit "Hängen und Würgen",
sondern einfach nur mit dem Werkzeug, welches Profis zumindest auch
beherrschen sollten: Assembler, denn nur damit ist (beweisbar und
reproduzierbar) die effizienteste Lösung jedes Problems für ein
gegebenes Zielsystem möglich. Möglich wird das u.A. durch das
deterministische Zeitverhalten, was höheren Programmiersprachen leider
ziemlich abgeht...
> aber:> In null Komma nichts ist der Speicher voll.
Na sicher. Es ist ja hier gerade das Ziel, den verfügbaren Speicherf
möglichst schnell vollzuschreiben, du Nase!
> Keine "Zeit" zum Arbeiten, d.h. die Messwerte können nur durchgereicht> werden. Wohin eigentlich.
Zum Speicher. Der tut nämlich das, was der Name verspricht: er
speichert.
> Weil keine Verarbeitung möglich> ist
Wieso sollte keine Verarbeitung möglich sein? Wenn der Messzyklus
beendet ist, ist doch der Speicherinhalt immer noch da, oder nicht? Man
kann ihn dann verarbeiten bis zum Abwinken. Schlimmstenfalls muss man
halt dann, wenn's nicht mehr zeitkritisch ist, langsameren externen
Speicher zu Hilfe nehmen.
Und übrigens ist das Prinzip, die Daten von
Hochgeschwindigkeitsmessungen erstmal in schnellen Speicher zu puffern
und hinterher zu verarbeiten so alt wie die Digitaltechnik selbst. Und
es wird auch heute noch angewendet, nur die Grenze für den Einsatz
dieses Prinzips hat sich im Laufe der Jahre immer weiter nach oben
verschoben. Das ist alles.
Ein STM32 oder ähnlich wäre hier wirklich ein Vorteil. Je nach
Ausführung schafft da der interne ADC sogar irgendwas im Bereich 5 MHz.
Mehr RAM sollte man auch finden.
Bei der AVR Version kann man es sogar noch etwas schneller machen, indem
an die Schleife entrollt, also in der Schleife 2 oder mehr Werte
aufnimmt und so die Zeit für den Sprung und Vergleich am Ende auf mehr
Durchläufe Verteilt. Im mittel bleibt dann nur 1 Zyklus dafür und man
könnte ggf. noch etwa 2 Zyklen sparen.
Den externen ADC könnte man z.B. über einen PWM Ausgang des AVRs
triggern / takten.
Lurchi schrieb:> Ein STM32 oder ähnlich wäre hier wirklich ein Vorteil. Je nach> Ausführung schafft da der interne ADC sogar irgendwas im Bereich 5 MHz.> Mehr RAM sollte man auch finden.>> Bei der AVR Version kann man es sogar noch etwas schneller machen, indem> an die Schleife entrollt, also in der Schleife 2 oder mehr Werte> aufnimmt und so die Zeit für den Sprung und Vergleich am Ende auf mehr> Durchläufe Verteilt. Im mittel bleibt dann nur 1 Zyklus dafür und man> könnte ggf. noch etwa 2 Zyklen sparen.>> Den externen ADC könnte man z.B. über einen PWM Ausgang des AVRs> triggern / takten.
Maximales Entrollen hatte ich schon vorgeschlagen. Schafft 6,66..MB/s
und hat keinen "Jitter".
> die Schleife entrollt
Das liegt nahe und wurde von Carl Drexler ja auch schon vorgeschlagen;
allerdings ist mir nicht ganz klar, welchen Vorteil ein teilweises
Entrollen bringt, und ob ein vollständiges bei 10 k Datenpunkten in dem
128 KiB Flash Platz hat, hängt davon ab, wie diese Triggerung aussieht.
Zur Zeit aber sehe ich noch keine Notwendigkeit für eine solche Aktion.
Auch noch nicht dafür, etwas Fetteres zu nehmen, dem ubiquitären
Trend folgend nach der Devise 'fatter is better'.
Die vorherigen Beiträge haben ja schon gezeigt, dass dein
Vorhaben ohne Übertaktung und sonstigem Blödsinn möglich
ist, wenn du dafür sorgst, dass in diesem Zeitraum der µC
vollkommen ungestört dem Byte-Schaufeln nachkommen kann:
Alle (!) Interrupts müssen für die erforderlichen 1,23 ms
disabled sein, da das Byte-Schaufeln im Freilauf geschehen muss:
Also, (Sampletakt an PINX, BitY) :
1
di ; KEINE INTERRUPTS!
2
3
loop: ; Takt
4
in tmp0, PINX ; 0 Sampletakt, Daten bereit?
5
andi tmp0, BITMASK_Y ; 1 Maske für BitY
6
breq loop ; 3 (2) Polling-Rate: 4 Takte
7
8
in tmp0, PINA ; 3...7
9
st x+, tmp0 ; 5...9
10
cpi XH, high(data_end) ; 7..11 (Klappt nur an 256-er Grenze)
11
brne loop ; 8..12 Umlauf: 8...12 Takte
12
13
sei ; Interrupts wieder erlaubt
Hier gibt es aber eine Falle:
Ich gehe mal davon aus, dass der Sampletakt von 1 MHz
symmetrisch ist: 0,50 µs Hi, 0,50 µs Lo. µC-Takt = 0,05 µs
Im schlechtesten Fall (der Sampletakt geht gleich nach seiner
Abfrage auf High) braucht die Auslesung 12 µC-Takte, OK. Im
günstigsten Fall braucht die Auslesung nur 8 µC-Takte - bei
der nächsten Abfrage des Sampletakts (nach 0,40 µs) erwischt man
noch den selben Takt:
Der selbe ADC-Wert wird nochmal eingelesen!
Die Schleife darf also nicht zu schnell sein!!!
Besser (Sampletakt an PINX, BitY):
1
di ; KEINE INTERRUPTS!
2
3
loop: ; Takt
4
in tmp0, PINX ; 0 Sampletakt, Daten bereit?
5
andi tmp0, BITMASK_Y ; 1 Maske für BitY
6
breq loop ; 3 (2) Polling-Rate: 4 Takte
7
8
in tmp0, PINA ; 3...7
9
st x+, tmp0 ; 5...9
10
nop ; 6..10
11
nop ; 7..11
12
nop ; 8..12
13
cpi XH, high(data_end) ; 9..13 (Klappt nur an 256-er Grenze)
14
brne loop ; 11..15 Umlaufzeit: 11...15 Takte
15
16
sei ; Interrupts wieder erlaubt
Interessant wäre für mich eher die Wahl des ADC.
Hast du da schon einen in der Auswahl?
Hendrik schrieb:> loop:> in tmp,PINA> st x+,tmp> cpi XH,high(data_end)> brne loop
Wie wärs mit
in tmp,PINA
st x+,tmp
in tmp,PINA
st x+,tmp
in tmp,PINA
st x+,tmp
in tmp,PINA
st x+,tmp
in tmp,PINA
st x+,tmp
...
in tmp,PINA
st x+,tmp
@ c-hater, Sebastian S:
> Wieso sollte keine Verarbeitung möglich sein? Wenn der Messzyklus> beendet ist, ist doch der Speicherinhalt immer noch da, oder nicht? Man> kann ihn dann verarbeiten bis zum Abwinken. Schlimmstenfalls muss man> halt dann, wenn's nicht mehr zeitkritisch ist, langsameren externen> Speicher zu Hilfe nehmen.
Genau das ist der Plan, die Daten sollen nach getaner Messung ganz in
Ruhe über den UART/RS232 o.ä. als Binärblock an einen Rechner gesendet
werden (evtl. von mehreren Trigger und Messtakt-synchronisierten
Atmega/ADC Kombis) und dann weiter ausgewertet werden (Python etc.). Der
Atmega soll einfach nur messen und die Daten zur Verfügung stellen.
@ Carol:
> Im günstigsten Fall braucht die Auslesung nur 8 µC-Takte - bei> der nächsten Abfrage des Sampletakts (nach 0,40 µs) erwischt man> noch den selben Takt:
Ich hatte oben im C-Entwurf angedacht in der Schleife erst durch Polling
zu überprüfen ob der Messtakt-Pin auf low ist, um anschließend mit
Polling zu prüfen ob er auf high ist. Das würde vermutlich wieder 4
Takte mehr kosten (?) aber sicher die pos. Flanke erwischen. Da ich die
Messtakt-Frequenz (duty cycle wäre dann ja auch mehr oder weniger egal)
aber gerne variabel (und bei Bedarf deutlich langsamer) halten würde,
komme ich um die Abfrage vermutlich nicht herum?
In Deinem Beispiel wird soweit ich sehe nur PINA ausgelesen (8 bit
Fall). Wieviele Takte würde es kosten zusätzlich noch PIND (o.ä.)
auszulesen um auf 16 bit pro Messung zu kommen? Vermutlich kratzt das
dann in Summe schon an der 20? Ich habe mich leider bisher noch
überhauptnicht mit ASM auseinandergesetzt - vermutlich ist dieses
Projekt ein guter Anlass das zu tun. :) - daher kann ich aber derzeit
leider nur ahnen was Zeile für Zeile passiert.
Gibt es eigentlich die Möglichkeit den zeitunkritischen Teil des
Programms in C zu realisieren und den zeitkritischen Teil mit der
Messung in ASM zu coden? "inline assembler"?
> Interessant wäre für mich eher die Wahl des ADC.> Hast du da schon einen in der Auswahl?
Noch nicht - ich wollte erstmal die Machbarkeit klären. Da es mir
scheint, dass sowohl die ~10k Punkte bei 8 bit als auch die ~5k Punkte
bei 16 bit realistisch sind, würde ich auch nach zwei verschiedenen ADCs
Ausschau halten. Ich hatte beim schnellen Suchen den AD876 gesehen, der
hat nur 10 bit und ich würde dabei dann halt 6/16 unnötige Bits
aufnehmen (im 16 bit Modus). >12 bit wären schon ganz gut. Ich werde
noch suchen und abwägen bzgl. Bittiefe, Kosten und Verfügbarkeit.
Vielleicht hat jmd. einen Vorschlag?
Wenn Du möglichst schnell abtasten willst, solltest Du:
1. einen AVR mit externem Adress-Datenbus verwenden. Dann wird einiges
wie die Erzeugung des Read-Impulses per Hardware gemacht, was Takte
spart. Außerdem kannst Du dann ein externes SRAM anschließen. Mit
Bankswitching sind 512kByte kein Problem.
Als AVR empfiehlt sich dann ein Mega1280/1281, je nachdem, wie viele
IO-Pins Du brauchst.
2. einen FIFO verwenden. Beispielsweise zwei von den hier:
https://www.idt.com/node/36925
Zwei deswegen, um auf 16 Bit Breite zu kommen. Der ADC schreibt parallel
hinein, mit seinem festen Sampletakt. Der AVR muss nur das HALF-FULL
Flag auswerten, und wenn das gesetzt ist, kann er die halbe
FIFO-Kapazität in einem Rutsch ohne weitere Abfragen einlesen. Und dafür
ist zusätzlicher, externer Speicher ganz hilfreich. Ohne externes RAM
muss er nur warten, bis der FIFO voll ist und kann dann die volle
FIFO-Kapazität in aller Ruhe abholen. Das können bis zu 128 kByte sein.
Diese Bausteine können in der 25ns-Version (Standard) alle 25 ns einen
Wert aufnehmen, was 40 MHz entspricht. Man kann die auch kaskadieren, um
eine größere Tiefe zu erhalten. Mit diesem Ansatz kann man schon einiges
erreichen.
Es gibt auch noch schnellere FIFOs, aber 40 MHz sind auch schon nicht
schlecht. Da brauchst Du erstmal einen ADC, der das mitmacht. Und ein
ordentliches Leiterplattenlayout.
fchk
Ein kleines FPGA, resp CPLD, entweder mit internem, oder externem RAM
kann so eine Aufgabe um einiges besser. Da sind auch 50Ms kein Problem.
Das rumsenden kann dann immer noch ein AVR machen.
> Ein kleines FPGA, resp CPLD,
Mit solchen Extravaganzen darfst du den AVRern nicht kommen.
Die kennen nur Nagel und Hammer.
Wenn sie denn überhaupt über ihren Anduinotellerrand kommen.
Eine echte Schraube wäre ein TMS320F2809.
Der hat genug RAM und 12,5 MSPS-ADs schon an Bord.
Aber wie gesagt, lass sie sich quälen...
Klar kann man das Auswerte-Programm in C, oder BASIC, oder
COBOL, ... schreiben - nur die Ausleseroutine muss in
(Inline)-ASM laufen.
PinD auslesen und speichern kostet weitere 3 Takte. Damit
werden die 3 "nop" zum Verzögern überflüssig.
- Ergibt also maximal 16 Takte
Besser: Du sicherst vorher alle Register und machst dich nicht
von einer 256-er Grenze abhängig. Dann muss nur noch die
Startadresse deines 12 K Speicherbereichs BUFFER bekannt sein.
- Ergibt maximal 17 Takte in der Auslese-Schleife.
Wenn die Sampletakt-Pegel abgefragt werden, geht das noch
in 17 Takten für 1 Byte und 20 Takten für 2 Byte. Aber bei
2 Byte willst du es ja im 0,5 MHz Takt (40 Takte) machen.
Da kommt es hiermit nicht zu Doppel-Auslesungen.
Bei 1 MHz Takt gibt es hiermit nur 5 K 16-Bit-Werte, will man
10 K 8-Bit-Werte, müssen die Zeilen mit "High-Byte" weggelassen
werden - am besten baut man da 2 Routinen mit passendem Code.
1
push r16 ; Register sichern
2
push r17
3
push r18
4
push xl
5
push xh
6
7
ldi xl, low(BUFFER) ; Register initialisieren
8
ldi xh, high(BUFFER)
9
ldi r17, low(BUFFER+12288)
10
ldi r18, high(BUFFER+12288)
11
12
di ; KEINE INTERRUPTS!
13
14
loop: ; Takt
15
in tmp0, PINX ; 1 Sampletakt, Low?
16
andi tmp0, BITMASK_Y ; 2 Maske für BitY
17
breq loop ; 3 / 6 Nein, High: Bereit, (4 Noch nicht bereit)
Hendrik schrieb:> mit einem Atmega möglichst "schnell" (1 MHz?)> über einen externen, parallelen ADC ein> analoges Signal mit 8 bit Genauigkeit aufzunehmen.
Habe ich vor ca. 10 Jahren schon mal gebaut: Ein Atmega32 mit 18,4 MHz
und zwei parallelen 8-Bit-ADCs dran zeichnet zwei analoge Kanäle mit
max. 1MHz auf bis der RAM voll ist. Dann werden die Daten per UART an
einen PC geschickt und dort in einem eigenen Programm angezeigt. Ich
habe nie genau überprüft ob bei 1MHz noch alle Datenpunkte genau
aufgezeichnet werden aber die Kurven am PC sahen immer richtig aus. Das
Programm auf dem Atmega war in ASM geschrieben und über Timer1
gesteuert.
Als ADC hatte ich wenn ich mich recht erinnere zwei MAX153, einen an
Port A und einen an Port C. Dann noch 2x CS und 2x RD an PortB.
Prinzipiell ist das Projekt also machbar.
@Carol:
> Wenn die Sampletakt-Pegel abgefragt werden, geht das noch> in 17 Takten für 1 Byte und 20 Takten für 2 Byte.
Nach Carol braucht der Mega dann ja max. 17/20 Takte für 8/16 bit.
Nachdem das Mess-Takt Signal den ADC getriggert hat, hat der Mega dann
grade eben genug Zeit die Daten abzuholen und in den SRAM zu schreiben.
Damit sollten ja 8 bit (~10 k Samples) @ 1 MHz möglich sein. Bei 16 bit
(~5 k Samples) würde ich dann sicherheitshalber eher knapp unter einem
MHz (900 kHz o.ä.) bleiben.
Da der Mega sich ja deterministisch verhalten sollte, ist es knapp,
sollte aber laufen. Und so wird dem Mega dann auf jeden Fall nicht
langweilig. Ich werde das Projekt dann demnächst mal praktisch angehen
und hier berichten, was rausgekommen ist.
@reggie, daybyter
Ich finde allerdings den STM32, wie u.a. reggie u. daybyter
vorgeschlagen haben, auch immer interessanter. Ich habe mir mal den
STM32F411RET6 (auf den Nucleoboards bei R) angesehen, der hat ja schon
einen >2 MHz ADC (12 bit) an Board, und 128 kByte SRAM (finde ich
besonders interessant, da sind die Megas ja deutlich drunter), wordurch
wesentlich längere Datenblöcke gespeichert werden könnten.
Kostentechnisch liegt der ja auch in etwa beim Atmega mit 16k SRAM und
soweit ich sehe kann man ihn (LQFP) auch grade noch so von Hand löten
(letzteres wäre ein weiteres wichtiges Kriterium). Ich denke ich werde
mir bei der nächsten Gelegenheit so ein Board zum rumtesten
mitbestellen (soweit ich hier lesen konnte gibt es keine signifikaten
Unterschiede zwischen Nucleo und Discovery, außer weniger Peripherie?).
Interessanter als die Verwendung des internen ADC fände ich dann - um
noch ne Schippe draufzupacken - wiederum die analoge Überlegung der
Verwendung eines exterenen, parallelen ADC. Da müssten mit dem STM32F4
(@100 MHz) ja gut 16 bit und Sampleraten >4 MHz drin sein (bei
Blocklängen von 50k-60k Samples, wenn man sonst an SRAM spart)? (Die
Fragestellung passt dann thematisch allerdings nicht mehr so richtig
unter den Titel dieses Threads).
@fchk
Ich habe mir die FIFOs mal angesehen, wenn ich mich nicht vertan habe
scheinen die aber recht teuer zu sein (grade wenn man dann in Richtung
64k/128k Speicher wie beim o.g. STM32 möchte (da scheint man dann pro 9
bit FIFO schon so vier STM32F4 mit je 128k SRAM, zu bekommen). Wie du
schreibst wäre das dann ja wohl mit externem RAM, grade wenns schneller
sein soll, die bessere Lösung. Bei den angepeilten Samplingraten würde
ich so aber erstmal in Richtung STM gucken...
@Mooskopf / Schlaubischlumpf
Mir ist bewusst, dass FPGAs für schnelle Signalverarbeitung genutzt
werden - ich hätte nur erwartet, dass ich bei den angepeilten <10 MHz
bzw. <5 MHz Samplingraten noch ohne auskomme. Ich habe bisher zwar
hauptsächlich mit AVRs gebastelt, bin aber nicht darauf festgenagelt und
gucke mir auch gerne andere Systeme an. Allerdings wollte ich mir den
Einstieg in FPGAs doch für später aufheben. :)