www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik sehr schnelle Signale messen


Autor: Shin (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich versuche mithilfe des Atmega32 ein Signal zu Analysieren. Ich 
benutze dafür den 16-bit timer und das Input Capture feature. Ich 
triggere nur auf die positiven flanken da mich nur die abstände zwischen 
den Pulsen und nicht die Pulslängen interessieren.

Es funktioniert eigentlich recht alles gut. Nur manchmal gilt es 
schnelle Signale zu messen (ca. 2.7 us) und da stosse ich an die 
grenzen. Ich habe nur noch falsche Messwerte. Nun ich denke in meinem 
programm gibt es noch vieles dass man "besser" bzw schneller 
programmieren kann (ich mache sowas zum ersten mal) und frage mich nun 
wie ich die berechnung mit Overflow und Zählerstände am besten mache um 
keine Pulse zu verpassen.

Der Atmega habe ich mit 16Mhz getaktet und den timer habe ich ohne 
prescaler (0) geschaltet (es muss ziemlich genau sein, und deshalb ist 
das nötig)

Im Anhang findet ihr den Code (nur was damit zu tun hat, den rest habe 
ich weggelöscht)

Ich hoffe ihr könnt mir Tipps geben wie ich "Messung" verschnellern 
kann.

gruss shin

Autor: 6640 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Viel mehr ist mit einen 16MHz Controller nicht machbar. Das ist eine 
Aufgabe fuer ein CPLD. Eine Capture Einheit besteht aus ein paar 
Zaehlern und ein paar Flipflops. Den Takt kann man auf ueber 100MHz 
haben und dabei die 6 fache Aufloesung eines 16MHz Clocks erreichen.

Autor: Knut Ballhause (Firma: TravelRec.) (travelrec) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn Du kein EEPROM brauchst, kannst Du versuchen, den ATMEGA 
höherzutakten um so noch etwas zu gewinnen, 20-22Mhz sollten drin sein.

Autor: Shin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, danke für die antworten. Trotzdem möchte ich das programm noch so 
schnell machen wies geht.

Autor: Armada (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, da stösst der Atmega wirklich an seine Grenzen.

Autor: Schwurbl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du solltest den Aufruf von Messen() vermeiden, da hierbei der komplette 
Registersatz des AVR gerettet werden muß, was Zeit kostet.

Außerdem ist mir unverständlich, warum in der Interruptbehandlung die 
Interrupts disabled werden, was sie bereits sind. Kostet Zeit und birgt 
Fehler (vor allem das wieder einschalten bei sei)

Warum im else-Zweig auf 1 Prüfen? Es gibt keine andere Möglichkeit.

Warum nach Prüfung auf 1 wieder die Zuweisung der 1? Das kostet nur 
Zeit.

Ich hoffe, die Array-Größe von Messung[] ist 101, nicht 100 ;-)

Autor: Dietmar E (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  solltest den Aufruf von Messen() vermeiden, da hierbei der komplette
Registersatz des AVR gerettet werden muß

Nicht unbedingt, bei Funktionen, die nur einmal verwendet werden, kann 
man eigentlich davon ausgehen, dass der Compiler die "inline" 
compiliert, ohne Aufruf (zur Sicherheit ein inline-Attribut vor den 
Namen der Funktion).

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> ...bei Funktionen, die nur einmal verwendet werden, kann
> man eigentlich davon ausgehen, dass der Compiler die "inline"
> compiliert...

Wohl kaum, wenn die Funktion nicht mal als static deklariert ist.

Autor: Unbekannter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wohl kaum, wenn die Funktion nicht mal als static deklariert ist.

Kommt auf die Optimierungs-Flags an.

Wenn der Compiler Code vergrößern darf um Speed zu gewinnnen (z.B. -O3 
beim gcc), dann kann er die Funktion zweimal einbauen. Einmal als inline 
und einmal normal.

Ob der Compiler das macht, und bis welchen Funktionsgrößen, ist 
Einstellungssache.

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hm. Ok, dann soll's mir recht sein :-)

Was mich sonst noch beunruhigt ist die Tatsache, dass 'overflow' 
asynchron inkrementiert wird und möglicherweise nicht zusammen gehörende 
Paare aus 'overflow' und ICR1 verarbeitet werden. Da fällt mir nicht mal 
eine Abhilfe ein.

Die optimierte Version könnte derzeit so aussehen:
unsigned long Messung[100];
unsigned char M_Nr = 0;
unsigned long overflow = 0;
unsigned int capture1 = 0,capture2;

SR(TIMER1_CAPT_vect)
{
    capture2 = ICR1;
    Messung[M_Nr++] = overflow + (capture2 - capture1);
    if (M_Nr == 100)
        M_Nr = 0;
    overflow = 0;
    capture1 = capture2;
}

ISR(TIMER1_OVF_vect)
{
    overflow += 65536UL;
}

Wohl wissend, dass die erste Flanke so oder so kein gültiges Ergebnis 
liefern könnte. Also weg mit dem 'i'-Flag. Mit der Klammerung wird eine 
16 Bit Operation erzwungen.

Autor: ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man könnte Teile in ASM schreiben. Besonders beim overhead der 
Interrrupts kann man da einiges sparen. Zumindestens GCC ist da gerade 
nicht sehr effektiv. Wenn man alles, oder zumindestens den ganzen Teil 
der während der Messung läuft in ASM schreibt, kann man noch etwas mehr 
sparen, denn in ASM kann man seperate Register für das Hauptprogramm und 
die ISR nehmen. Das spart einem dann das retten der meisten Register. 
Außerdem kann man in ASM ggf. mit 24 Bit Integers rechenen.
Die 2,7 us sollten noch machbar sein, auch mit 16 Mhz Takt.

Wegen der Taktrate könnte man eventuell auf einen Mega64x ausweichen, 
der bis 20 MHz geht.

Das Problem mit dem nicht syncronen overflow läßt sich lösen. Der Fall 
der vorkommen kann, ist das die ICP ISR läuft, obwohl erst die overflow 
routine dran ist. Erkennen kann man diese ausnahme daran, das das 
overflow Interruptflag gesetzt ist und der ICP Wert klein (z.B. kleiner 
als 0x800) ist. In diesem Ausnahmefall muss man halt erst den overflow 
abarbeiten und dann den ICP.

Autor: Entwickler (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Verstehe. Ich sehe zwei Fälle und schlage vor:
unsigned long Messung[100];
unsigned char M_Nr = 0;
unsigned long overflow = 0;
unsigned int capture1 = 0,capture2;

SR(TIMER1_CAPT_vect)
{
    if (TIMER1_OVF)
    {
        // Timer-Überlauf während Sprung in Capture-Interrupt
        overflow += 65536UL;
        RESET_TIMER1_OVF();
        capture2 = ICR1;
    }
    else
    {
        capture2 = ICR1;
        if (ICR1 < capture2)
        {
            // Timer-Überlauf zwischen Prüfung auf
            // Capture-Interrupt und Auslesen von ICR1
            overflow += 65536UL;
            RESET_TIMER1_OVF();
        }
    }
    Messung[M_Nr++] = overflow + (capture2 - capture1);
    if (M_Nr == 100)
        M_Nr = 0;
    overflow = 0;
    capture1 = capture2;
}

ISR(TIMER1_OVF_vect)
{
    overflow += 65536UL;
}

Keine Ahnung, wie man die Interrupt-Flags konkret abfragt und rücksetzt, 
aber im Prinzip...

Autor: ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es reicht nicht, nur das interruptsflag abzufragen, man muss auch noch 
testen ob der ICP klein ist. Wenn das TimerOverflow flag gesetzt ist, 
kann der ICP Wert eigentliich nur sehr groß oder sehr klein sein. Wenn 
der ICP sehr groß ist, ist der Timer overflow erst nach dem ICP 
passiert, und es muss nichts mehr vorgezogen werden.

Da Testen der Flags geht über das entsprechende Bit im 
TimerInterruptFlag Register. Zum Löschem wird da seltsamerweise eine 1 
reingeschrieben.

Autor: Shinaha (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke für die vielen hilfreichen antworten, ich denke damit kann ich 
schon vieles verbessern. Leider kann ich erst am Montag wieder daran 
arbeiten.

shin

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.