Forum: Mikrocontroller und Digitale Elektronik 35kHz zu schnell für Hardware Interrupt?


von gast (Gast)


Lesenswert?

Hallo,

ich benutze einen Mica2dot Mote von Crossbow, der mit dem Atmega 128L 
bestückt ist. Der Prozessor wird mit 4MHz getaktet. Als 
Programmierplattform nehme ich tinyOS. Ich möchte eine Frequenzmessung 
eines Rechtecksignals vornehmen, das am INT0 angeschlossen ist und bei 
jeder aufsteigender Flanke einen HardwareInterrupt auslöst. Die 
aufsteigenden Flanken sollen jeweils 15ms lang gezählt werden (ich 
brauche das resultat nicht in Hz). Die Zählwerte werden zunächst im 
Speicher gehalten und am Ende gemeinsam über UART ausgegeben.
Das Problem, das ich habe, ist, dass das Ganze nur bis ~30kHz 
funktioniert, ich möchte aber bis 100kHz messen.
Laut Datenblatt können die I/O-Pins des ATmegas Impulse mit bis zu 50ns 
Dauer detektieren, daher nehme ich an, dass rein physikalisch 2MHz die 
Grenzfrequenz für den Hardwareintzerrupt wäre. Liege ich mit der 
Überlegung richtig oder habe ich da noch einen denkfehler gemacht ?
Kann mir jemand sagen, ob ich den Chip überfordere? Oder liegt es daran, 
dass ich tinyOS verwende und ich käme mit Assembler hin?

... Hier ist der Sourcecode in nesC:
1
#include <printf.h>
2
3
module UltraMicP {
4
  uses {
5
    interface Boot;
6
    interface HplAtm128Interrupt as SignalRead;
7
    interface Timer<TMilli> as Timer;
8
    interface Timer<TMilli> as Timer2;
9
  }
10
}
11
12
implementation {
13
  
14
  uint32_t zaehler[255];
15
  uint8_t index;
16
17
  event void Boot.booted() {
18
  /* legt ein array an, in dem die zählwerte gespeichert sind */
19
    for (index = 0;index<255;index++) 
20
  zaehler[index] = 0;
21
    index = 0;
22
  /* Initialiserung vom Hardware-Interrupt */
23
    call SignalRead.edge(TRUE);
24
    call SignalRead.enable();    
25
  /* Timer starten */
26
    call Timer.startPeriodic(15);
27
  }
28
29
  async event void SignalRead.fired() {
30
  /* Zählt die Flanke an der aktuellen Speicherstelle*/
31
    zaehler[index]++;  
32
  }
33
 
34
  event void Timer.fired(){
35
    atomic {
36
      /* wählt die nächste Speicherstelle aus */
37
      if (index<255) index++;
38
      else {
39
      /* oder startet die Ausgabe der Zählwerte*/
40
           call SignalRead.disable();
41
           call SignalRead.clear();
42
           call Timer.stop();
43
           index = 0;
44
           call Timer2.startPeriodic(200);
45
      }
46
    }
47
  }
48
49
  event void Timer2.fired() {
50
    printf("%ld ",zaehler[index]);
51
    printfflush();
52
    if (index < 255) index++;
53
    else call Timer2.stop();
54
  }
55
}

Vielen Dank schon mal für sachdienliche Hinweise

von Matthias L. (Gast)


Lesenswert?

>Der Prozessor wird mit 4MHz getaktet

>Ganze nur bis ~30kHz
> ich möchte aber bis 100kHz messen.

Rechne mal nach, wieviele ASM-Befehle du so dazwischen bearbeiten 
kannst!


Zu deinem Code kann ich nichts sagen. Ist das C?


>können die I/O-Pins des ATmegas Impulse mit bis zu 50ns
>Dauer detektieren

Ja, ABER

Die Software muss bis zum nächsten eingehenden Impuls geeignet darauf 
reagieren können! Ein Interrupteinsprung dauert mindestens 4Takte, also 
bei 4MHz mindestens 1µs. Dann bist du in der ISR, hast aber noch nichts 
gemacht..

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Mach sowas besser in Assembler:
1
  async event void SignalRead.fired() {
2
  /* Zählt die Flanke an der aktuellen Speicherstelle*/
3
    zaehler[index]++;  
4
  }

Da gibt es einiges zu berechnen:
1) Erstmal die Adresse vom Zähler holen
2) den Offset (Index) draufaddieren
3) den Inhalt dieser Speicherzelle holen
4) Eins dazuaddieren
5) wieder in die Speicherzelle zurückschreiben
und das Ganze mit longs bei einem langsam getakteten 8-Bit Prozessor.
Das kann dauern :-/

Mein Tipp:
Überleg dir, ob du tatsächlich 32Bit-Zähler brauchst.

von gast (Gast)


Lesenswert?

@ lippy:

>Rechne mal nach, wieviele ASM-Befehle du so dazwischen bearbeiten
>kannst!

Im Datenblatt steht "Most Single Clock Cycle Execution" - dann rechne 
ich bei 100kHZ vs 4 MHz mit 40 Befehlen ... eigentlich genug Zeit, oder?

>Zu deinem Code kann ich nichts sagen. Ist das C?

das ist nesC. Damit programmiert man in tinyOS. Außer dem Initialisieren 
mit diesen interface-Zeux ist es C-ähnlich, finde ich, drum hab' ich es 
gepostet.

>Ein Interrupteinsprung dauert mindestens 4Takte

oops! das hatte ich schon mal nicht beachtet ...

@lkmiller:

OK. Ist natürlich blöd, wenn man nicht genau weiss, in wie viele 
Einzelbefehle der nesC-Code übersetzt wird ... ich hatte schon 
befürchtet, dass ich das in Assembler machen muss. Da das ganze im 
Moment nur ein Geschwindigkeitstest ist und ich den Rest des Programms 
gerne in nesC weiter verwenden würde - kann mir jemand hier im Forum 
sagen, wie ich Assembler Code in tinyOS einbinden kann?

> Überleg dir, ob du tatsächlich 32Bit-Zähler brauchst.

Stimmt. Das maximale Zählergebnis kann ja nur 1500 werden. Da geht auch 
noch was.

... danke schon mal an euch beide, das hat mich schon ein bisschen 
weiter gebracht!

thx

von Karl H. (kbuchegg)


Lesenswert?

gast wrote:

> Im Datenblatt steht "Most Single Clock Cycle Execution" - dann rechne
> ich bei 100kHZ vs 4 MHz mit 40 Befehlen ... eigentlich genug Zeit, oder?

max 40 Assembler Befehle. In C sind das wesentlich weniger 
'Hochsprachenbefehle'


>>Ein Interrupteinsprung dauert mindestens 4Takte
>
> oops! das hatte ich schon mal nicht beachtet ...

mach dich auch mal auf die Suche, ob dein TinyOs da auch noch einen 
Overhead mit einbringt. Bei 40 Takten Zeit zählt jede Anweisung.

von Peter (Gast)


Lesenswert?

Du hast doch bestimmt eine Mögleichkeit den erzeugen ASM-Code 
anzuzeigen, dann könnte man ja einfach mal zählen.

von Falk B. (falk)


Lesenswert?

@gast (Gast)

>ich benutze einen Mica2dot Mote von Crossbow, der mit dem Atmega 128L
>bestückt ist. Der Prozessor wird mit 4MHz getaktet. Als
>Programmierplattform nehme ich tinyOS. Ich möchte eine Frequenzmessung
>eines Rechtecksignals vornehmen, das am INT0 angeschlossen ist und bei
>jeder aufsteigender Flanke einen HardwareInterrupt auslöst. Die
>aufsteigenden Flanken sollen jeweils 15ms lang gezählt werden (ich
>brauche das resultat nicht in Hz).

Soll das ein Aprilscherz sein?

Betriebssysdtem auf nem AVR, C++? und dann einen Frequenzzähler REIN in 
Software bauen? Du raust zu viel. Und das Falsche.

> Die Zählwerte werden zunächst im
>Speicher gehalten und am Ende gemeinsam über UART ausgegeben.
>Das Problem, das ich habe, ist, dass das Ganze nur bis ~30kHz
>funktioniert, ich möchte aber bis 100kHz messen.

Na dann mach dich mal mit dem Timer und dess Fähigkeit, externe Pulse zu 
zählen vertraut. Das erzeugt keine 100 kHz Interrupts.

Leute gibts.

>Kann mir jemand sagen, ob ich den Chip überfordere? Oder liegt es daran,
>dass ich tinyOS verwende und ich käme mit Assembler hin?

Ich empfehle wie immer Brain 2.0. Fürs erste reicht auch Datenblattlesen 
1.2.

MFg
Falk

von gast (Gast)


Lesenswert?

Hmmm. Was hattest du denn gestern im Tee? Und wer hat es dir da 'rein 
getan?

von Matthias L. (Gast)


Lesenswert?

>Ich empfehle wie immer Brain 2.0.

Hihi. Das erinnert mich immer an das nichtmögliche Downgrade von Frau 
1.0 auf Freundin 7.5

;-)

von Patrick W. (seennoob)


Lesenswert?

Falk gibts schon Brain 2.1. beta (alpha) ?

Und Datenblattlesen 1.5.6. könnt ich auch gut gebrauchen.


ggg

MFG Patrick

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.