Forum: Mikrocontroller und Digitale Elektronik max. Eingangssignal für ISR


von leluno (Gast)


Lesenswert?

Ich bitte um Unterstützung. Ich möchte das 8-bit Datensignal von einem 
ov7670 durch einen 16Mhz-Atmega1284 auswerten. Wie hoch darf der 
Eingangstakt maximal sein, damit diese ISR noch funktioniert:
1
//SIGNAL( SIG_INTERRUPT0 )
2
ISR(INT0_vect)
3
{
4
//cli();
5
  buffer[i]=((PIND&0xf)>>4)|((PINA&6)<<3)|((PINB&12)<<4);
6
  i++;
7
//sei();
8
}

Was bringt es an Geschwindigkeitszuwachs, buffer auf einen Port zu 
legen?
1
buffer[i]=PINA;

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

leluno schrieb:
> (PIND&0xf)>>4)

Der teil wird schon mal verdächtig wenig rechenzeit brauchen :-)

von leluno (Gast)


Lesenswert?

Michael Reinelt schrieb:
>>
Danke, da fehlt die 0
(PIND&0xf0)>>4)

von Rainer B. (rainer_b59)


Lesenswert?

Wenn du mit "Eingangstakt" die Interruptfrequenz meinst:
Einfacher Ansatz: Im Assembler-Listing, das der Compiler auswirft, den 
Assemblercode für deine ISR suchen, im ATMega-Manual dazu die jeweiligen 
Ausführungszeiten für die einzelnen Instruktionen, diese aufaddieren.
Dann noch die Anzahl Clock Cycles, die der Prozessor benötigt, um bei 
Interrupt den normalen Kontext zu sichern und zur ISR zu springen, 
draufaddieren.

Sagen wir mal du, kommst auf 64 Clock Cycles, d.h. bei 16 MHz sind das 4 
µS. D.h. theoretische maximale Interruptfrequenz sind 250kHz.
Aber nur, wenn kein anderer Interrupt dazukommt und wenn main() 
überhaupt nix macht. Deine ISR sieht aber nicht so aus, also musst du 
noch abschätzen, was in main() je ausgelöstem Interrupt an Aufwand 
getrieben werden muss. D.h. deine max. Interruptfrequenz wird deutlich 
niedriger liegen.

Gruss, Rainer

von Oliver R. (orb)


Lesenswert?

Was bringt es, die ISR-Frequenz auf die Laufzeit der ISR-Routine 
abzustimmen, wenn dann keine Rechenzeit mehr übrig bleibt um die Daten 
im Hauptprogramm zu verarbeiten?

von leluno (Gast)


Lesenswert?

Oliver R. schrieb:
> Was bringt es, die ISR-Frequenz auf die Laufzeit der ISR-Routine
> abzustimmen, wenn dann keine Rechenzeit mehr übrig bleibt um die Daten
> im Hauptprogramm zu verarbeiten?
1
//qcif 176*144*2=50688
2
v u16 zl_buf;
3
void getPic(void){
4
if(!vsync)while(!vsync);
5
while(vsync);
6
zl_buf=0;
7
while(!vsync){//start frame
8
  while(!href);
9
  sei();
10
    while(href){//start row
11
      ;
12
    }//row
13
  cli();
14
}//frame
15
}//getPic

Das Hauptprogramm macht während des Füllens des Buffers nichts und 
wartet nur ab.

Rainer B. schrieb:
> theoretische maximale Interruptfrequenz sind 250kHz.

Danke für die Antwort. Ich werde mal versuchen, ob die PCLK soweit 
runtergesetzt werden kann. Aber im Prinzip ist die ISR-Lösung für den 
avr damit schon tot weil zu langsam. Ich brauche wohl einen fifo al422. 
Problem, wie bekomme ich den auf eine Streifenrasterplatine?

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

was weh tut ist das <<3, die anderen shifts macht er per swap.

Komischerweise kriegt man auch besseren assembler-code (ich zumindest) 
wenn man das aufdröselt:
1
    uint8_t x = ((PIND&0xf0)>>4);
2
    uint8_t y = ((PINC&6)<<3);
3
    uint8_t z = ((PINB&12)<<4);
4
    zz = x | y | z;

Deswegen ist es bei so zeitkritischen Sachen sehr wichtig, den erzeugtn 
Assembler-Code zu betrachten (und dann wie oben beschrieben takte 
zählen)

Hilfreich ist,k wenn man Assembler zumindest lesen kann :-)

von Oliver S. (oliverso)


Lesenswert?

leluno schrieb:
> Was bringt es an Geschwindigkeitszuwachs, buffer auf einen Port zu
> legen?

Ich versteh zwar den Satz nicht, aber wenn es bei der Aufgabe darum 
geht, wenige Daten so schnell wie möglich aufzunehmen, dann ist ist es 
natürlich deutlich schneller, die drei Ports in der ISR einfach nur 
abzuspeichern, und die Bitschieberei hinterher zu machen. Voraussetzung 
ist halt, daß das alles ins SRAM passt.

Wenn das dagehen eine durchlaufende Messung werden soll, ist es egal, 
dann musst du die Auswertung sowieso in Echtzeit machen.

Oliver

: Bearbeitet durch User
von leluno (Gast)


Lesenswert?

was ist denn mit umlöten auf
1
buffer[i]=PINA;

von leluno (Gast)


Angehängte Dateien:

Lesenswert?

zwecks Erläuterung: Ich kann die 20-pin-Schnittstelle relativ einfach so 
umlöten, dass ein ganzer Port für den Datenbus zur Verfügung steht. Dann 
brauche ich die Bitschieberei nicht. Der Sram geht bis 30k, also 
praktisch ein halbes QCIF-Bild.

von Karl H. (kbuchegg)


Lesenswert?

leluno schrieb:

> Das Hauptprogramm macht während des Füllens des Buffers nichts und
> wartet nur ab.

Das ist dann aber ein Argument dafür, nicht über Interrupts zu gehen. 
Denn den bewussten Pin, der sonst den Interrupt auslösen würde, per 
Polling auf Flankenwechsel abzufragen, geht schneller als wenn die 
Flanke einen Interrupt auslöst, woraufhin der µC erst mal einen Jump in 
den Interruptvektor und dort dann durch die Push/Pop Orgie einer ISR 
samt anschliessenden Return muss.

Denn sowas
1
if(!vsync)while(!vsync);
2
while(vsync);
wird auf einem AVR dank Bitoperationen, die direkt am Port arbeiten, 
recht effizient umgesetzt. Was sich hier in C recht langatmig 
präsentiert sind auf Maschinencodeebene gerade mal (wenn ich mich im 
Kopf nicht verzählt habe) 4 Instruktionen.
Und dasselbe kannst du auch mit deinem (jetzt noch) Interrupt 
auslösenden Pin machen.

Nebeneffekt:
Dadurch ermöglichst du dann auch dem Compiler, hier
1
  buffer[i]=((PIND&0xf)>>4)|((PINA&6)<<3)|((PINB&12)<<4);
2
  i++;
in der Optimierung zuzuschlagen, weil er das i nicht mehr laufend im 
SRAM sichern bzw. sich holen muss, sondern ganz bequem die Operation 
mehr oder weniger komplett in der Schleife in den Registern abwickeln 
kann. Wobei ich dann sogar erwarten würde, dass er das i komplett 
rauswirft, sich die Adresse von buffer in den Z-Pointer holt und dann 
mit einem STS++ arbeitet.

Unter diesen Voraussetzungen sehe ich dann auch für die 350kHz nicht 
mehr schwarz. 350kHz sind bei 16Mhz 45 Takte von einer Flanke zur 
nächste. Ohne das jetzt kompiliert zu haben, sollte das locker 
ausreichen um
1
    while( href )
2
    {
3
       while( !(PINx & (1<<TRIGGER) )
4
         ;
5
       while( (PINx & (1<<TRIGGER) )
6
         ;
7
8
       buffer[i]=((PIND&0xf)>>4)|((PINA&6)<<3)|((PINB&12)<<4);
9
         i++;
10
     }

mit 350kHz Triggerfrequenz durchzubringen.

(Ich weiss jetzt nicht, auf welchem Pin beim 1284 der INT0 Eingang 
liegt, daher hab ich PINx geschrieben. Auch weiss ich nicht, ob du die 
fallende oder die steigende Flanke brauchst - gegebenenfalls anpassen)

: Bearbeitet durch User
von leluno (Gast)


Lesenswert?

Karl Heinz schrieb:

Danke für diesen Beitrag, das bringt das Projekt ein gutes Stück weiter:
1
#define pclk    (PINA>>6)
2
...
3
4
void getPic(void){
5
if(!vsync)while(!vsync);
6
while(vsync);
7
zl_buf=0;
8
while(!vsync){//start frame
9
  while(!href);
10
    while(href){//start row
11
      //Warten aufsteigende Flanke
12
      while(!pclk);
13
      buffer[zl_buf]=((PIND&0xf0)>>4)|((PINA&6)<<3)|((PINB&12)<<4);
14
      //buffer[zl_buf]=PIND;
15
      zl_buf++;
16
      while(pclk);
17
    }//row
18
}//frame
19
}//getPic

Die PixelClock kann man bis ca. 500Khz herabsetzen. Die M32-Boards 
http://www.ebay.de/itm/190440692143 sind in der Lage, den Pixel-output 
bei 24Mhz PLLO ohne Fifo auf eine SD-Karte zu schreiben. Sie verwenden 
dafür als zusätzliche Hardware nur einen HC245-Bustreiber und ein NAND 
74VC10.

Prinzipiell muss die Verarbeitung der Daten mit dem AVR also gehen. Ich 
habe als Alternative zum AVR noch einen LPC1768 mit SSP. Wenn es mit dem 
OV7670 funktioniert, soll dieser durch einen MT9D ersetzt werden. Der 
hat eine Auflößung von 2MP.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.