ADC blockiert Interrupts?
Montag, 21. Mai 2012
 
 

PIC Mikrocontroller Forum  |  PIC Mikrocontroller  |  CCS Compiler  |  AD-Wandler (CCS)  |  ADC blockiert Interrupts? « vorheriges nächstes »
Seiten: [1] Nach unten Drucken
Autor Thema: ADC blockiert Interrupts?  (Gelesen 2475 mal)
 
Nuke
Newbie
*
Offline Offline

Beiträge: 6


Profil anzeigen
« am: Mai 02, 2007, 19:12:39 »

Hallo,
die Überschrift passt nur halb zu meinem Problem, genauer gesagt kämpfe ich mit einem für
mich unerklärlichen Effekt:

Eine externe Taktung löst bei mir alle 30uS einen Interrupt aus. Ich nutze diesen Interrupt an EXT0 um eine A/D Wandlung zu starten.

Alle 525 Interrupst kommt ein anderer Interrupt auf EXT1.

Soweit alles super. Ich mache allerdings nicht auf jeden Interrupt an EXT0 eine Wandlung, sondern nur jeden 64ten. Außerdem incrementiere ich einen Counter, so dass ich wenn der andere Interrupt kommt, überprüfen kann, ob ich alle Interrupst mitbekommen habe (525).

Das klappt. Was ich absolut nicht verstehen kann, ist: Wenn ich in der Zeit öfter AD Wandeln möchte, verpasse ich die hälfte meiner Interrupts.

Und genau hier liegt die Schwierigkeit. Wie kann es sein, dass die Zeit völlig ausreicht um eine Wandlung abzuschließen, so dass er den nächsten wieder ohne Probleme mitbekommt, ich ihm aber trotzdem jede menge Zeit zur Erholung lassen muss?

Eigentlich müsste so doch bei jedem Interrupt eine Wandlung möglich sein, denn die Interruptschleife ist ja definitiv vor dem nächsten verlassen.

Ach ja.
PIC18F4680 @ 20MHz und CCS Compiler.

Danke schonmal für Eure Bemühungen.
peter
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #1 am: Mai 02, 2007, 19:45:33 »

Es wäre ganz hilfreich, wenn Du Deinen Code (und die Taktfrequenz des PICs) posten würdest. Wenn ich von den 20MHz aus einem Deiner letzen Posts ausgehe, entsprechen die 30µs einem Interrupt alle 150 Befehlszyklen.

Grob geschätzt gehen beim CCS 30-40 Befehlszyklen für die Sicherung/Rücksicherung drauf, so daß nur noch etwas über 100 Befehlszyklen zwischen den Interrupts für die eigentliche Codeabarbeitung zur Verfügung stehen.


Viele Grüße

Bernd
Gespeichert

mr_mpeg
Newbie
*
Offline Offline

Beiträge: 1


Profil anzeigen
« Antworten #2 am: Mai 02, 2007, 20:41:39 »

Ich versuch das in Nukes Auftrag (der grad unterwegs ist) zu klären:

Config:
Code: (cpp)
setup_adc_ports(AN0_TO_AN7|VSS_VREF);
setup_adc(ADC_CLOCK_DIV_16|ADC_TAD_MUL_0);
set_adc_channel(7);

Dann gibts da die Interrupt-Routine, da wird in regelsaessigen Abständen ein Wert gelesen:
Code: (cpp)
void EXT_isr()
{
 if (counter == 32)  r[0] = read_adc();
 else if (counter == 96)  r[1] = read_adc();
 else if (counter == 160) r[2] = read_adc();
 else if (counter == 224) r[3] = read_adc();
 else if (counter == 288) r[4] = read_adc();
 else if (counter == 352) r[5] = read_adc();
 else if (counter == 416) r[6] = read_adc();
 else if (counter == 480) r[7] = read_adc();
 counter++
}

counter zählt von 1 bis 525 und wird dann wieder zurückgesetzt; das passiert genau 60 mal in der Sekunde also wird die Routine 31500mal in der Sekunde aufgerufen. Das funktioniert.

Sobald jedoch eine weitere Zeile dabeikommt (also 9) werden Interrupts geschluckt und der counter kommt nicht mehr bei 525 an.
Gespeichert
Bernd
Globaler Moderator
Hero Member
*****
Offline Offline

Beiträge: 3815



Profil anzeigen
« Antworten #3 am: Mai 03, 2007, 19:05:53 »

Zitat
Sobald jedoch eine weitere Zeile dabeikommt (also 9) werden Interrupts geschluckt und der counter kommt nicht mehr bei 525 an.

Jeder zusätzliche else if Abfrage benötigt Zeit, wenn der vorangegangene Vergleich false ist. Die Interrupts gehen "verloren", weil die Abarbeitung der ISR dann mehr Zeit benötigt, als zwischen den Interrupts zur Verfügung steht.

Die "regelmäßigen Abstände" sind bei Euch zur Zeit wohl 64. Das praktische daran ist, daß es sich dabei um einer Zweierpotenz handelt. Somit kann man ganz leicht feststellen, ob counter ein vielfaches von 64 (oder 0) ist. Grundlegender Gedanke:

Code:
void EXT_isr()
{
    if ((counter & 0x3F ) == 0)    // "true" für counter==0, counter==64, counter==128, ...
    {
        r[index] = read_adc();
        index++;
    }
    counter++;
}

Damit wird die Abarbeitungszeit auf jeden Fall schon einmal unabhängig von der Anzahl der ursprünglichen else if Abfragen. Wenn z.B. alle 32 Interrupts eine Wandlung erfolgen soll, muß das 0x3F nur durch 0x1F ersetzt werden. counter bräuchte bei der obigen Vorgehensweise auch nicht mehr zurückgesetzt werden (und müßte nur 8 Bit aufnehmen können), da ein Überlauf überhaupt keine Auswirkungen hat.
 
index muß zurückgesetzt werden, außer wenn der Wertbuffer ebenfalls eine Anzahl von Werten aufnehmen soll, die einer Zweierpotenz entsprechen. Dann könnte man z.B. entsprechend schreiben:

Code:
r[index & 0x0F] = read_adc();   // r nimmt 16 Werte auf (0-15)


Generell sehe ich aber ein Problem in Eurem Ansatz. Die Interrupt-Häufigkeit ist (zumindest für den CCS-Compiler) viel zu hoch. Ich habe mir mit der neuesten Demo-Version noch mal das Dissassembly-Listing der ISR angesehen. Für die Sicherung und Rücksicherung von Registern beim Auslösen eines Interrupts benötigt der CCS über 60 Befehlszyklen. Diese Befehlszyklen werden bei jedem auftretenden Interrupt benötigt. Zusammen mit den Einsprung in die ISR, dem Rücksprung aus der ISR und der Abfrage von den Interrupt-Bits verbringt der PIC 50% (wenn nicht mehr) der zur Verfügung stehenden "Rechenzeit" damit, auf Interrupts zu reagieren (ohne jegliche sinnvolle Aufgabe auszuführen). Dabei gehe ich von 20MHz Taktfrequenz aus (die wirkliche Taktfrequenz wurde nicht genannt).

Die einzig wirklich sinnvolle Möglichkeit, die ich sehe, ist es (wie schon zuvor in einem anderen Thread erwähnt), das externe Signal nicht an INT0 anzuschließen, sondern an T1CKI. Dann das CCP-Modul im "Compare Mode, Trigger Special Event" verwenden, welches die AD-Wandlung startet (und auf den AD-Interrupt reagieren). Damit erfolgt ein Interrupt nur, wenn auch wirklich ein Ergebnis vorliegt. Ihr müßt Euch klarmachen, daß durch Euren Ansatz 63 sinnlose Interrupts generiert werden, welche die "Verfügbarkeit" des Prozessors drastisch einschränken.


Viele Grüße

Bernd
Gespeichert

Seiten: [1] Nach oben Drucken 
« vorheriges nächstes »
Gehe zu:  

Powered by MySQL Powered by PHP Made for Mozilla (Firefox) Made for Internet Explorer
Seite erstellt in 0.033 Sekunden mit 18 Zugriffen.
 
Top! Top!