Forum: Mikrocontroller und Digitale Elektronik Interrupt latency - kleiner 4us MSP430F1612


von Andreas H. (msp430-fan)


Lesenswert?

Hi,

ich möchte mit meinem MSP430F1612 alle 2us den Port 6.1-6.7 einlesen und 
in einen Buffer schreiben (Triggerung mit Interrupt an Port 2.1). Der 
MSP430 läuft mit einer Frequenz von ca. 12MHz. Clock-Initialisierung 
hier

void SpeedUpClock(void)
{
  BCSCTL2 |= DCOR;                          // Rosc
  BCSCTL1 = RSEL0 + RSEL1 + RSEL2;          // XT2on, max RSEL
  DCOCTL = 0xff;
  _BIS_SR(OSCOFF);                          // XTAL not used
}

Mit Hilfe folgender Interrupt-Routine wird der Port 6 eingelesen und der 
Wert in einen Buffer geschrieben.

// Port 2 interrupt service routine
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
//  P4OUT ^= 0x08;                         // Toggle P4.3
  *(PORTCODES + a) = P6IN;                 // Port 6 einlesen
  P2IFG &= ~0x02;                          // P2.1 IFG cleared
  a++;
}

Mit dieser Methode kann ich die Interrupt-Routine sicher mit einem 
Triggersignal von 4us an Port 2.1 "anspringen"!

Fragen:
1. Hat jemand eine Idee wie ich das noch optimieren kann, um auf ca 2us 
zu kommen?

Mfg

MSP430-FAN

von Kai G. (runtimeterror)


Lesenswert?

Ich kenne die Architektur nicht, aber u.U. geht Polling noch was 
schneller... der Controller kann bei deiner Taktung wahrscheinlich eh 
nichts wirklich Sinnvolles mehr nebenher machen.

Ansonsten auf Assembler umsteigen, da lässt sich mit Sicherheit noch was 
rausholen.

Ansonsten das 'a++' in '*(PORTCODES + a) = P6IN;' reinziehen. Vielleicht 
spart das nochmal einen Cycle beim Optimieren.

Oder 'a' mit 'PORTCODES' statt mit 0 initialisieren, spart u.U. eine 
weitere Addition.

Nur ein par Ideen - ob das was du da tust sinnvoll ist sei mal 
dahingestellt...

von Kai G. (runtimeterror)


Lesenswert?

Ach ja,

was macht
P2IFG &= ~0x02;                          // P2.1 IFG cleared
aktiviert das die Interrupts wieder? Macht der Controller das nicht 
automatisch beim Verlassen des Handlers?

Lass in diesem Falle die Zeile besser weg. Die paar Zyklen, die der 
Interrupt-Handler früher wieder verfügbar ist, rächen sich mit einem 
Stack-Overflow, wenn der Controller wirklich davon Gebrauch macht!

von Christian R. (supachris)


Lesenswert?

12MHz bei einer CPU die für max 8MHz spezifiziert ist? Mutig.

Naja, in den Interrupt springen benötigt 6 Zyklen (bei 12MHz 500ns), 
Interrupt verlassen benötigt 5 Zyklen (416ns). Sind zusammen 11 Zyklen 
bzw. knapp 1µs.

Sooo...dann hast du für die Abarbeitung deiner Befhle da nur noch 13 
Zyklen Zeit. Allerhöchstens, denn ich weiß nicht, ob der ohne 
Verzögerung nach dem RETI wieder den neuen Interrupt anspringt.
Das wird haarig.

Und ja, das Pin-Interrupt Flag muss man selbst löschen, das ist nur die 
Anzeige, welcher Pin ausgelöst hat, nicht das Interrupt Enable.

von Andreas H. (msp430-fan)


Lesenswert?

Danke für die Infos!

Hat jemand eine Assembler Referenz mit der Angabe von Clock-Zyklen pro 
Befehl?

von MSP (Gast)


Lesenswert?

TI auf alle Fälle !

von Stefan (Gast)


Lesenswert?

Ich würd mal sagen: Vergiss es per IRQ!
Wie schon gesagt wurde, hast Du 24 Taktzyklen (TZ) zur Verfügung
(2µs bei 12MHz -> 24TZ)
11 TZ verbrät allein die Interruptanforderung + RETI, bleiben Dir also 
effektiv noch 13TZ übrig.
Meine schnellste Assemblerlösung lautet:
1
; Rx: beliebiges Register, muss einmal mit 0 initialisiert werden
2
; Rx darf sonst nirgends verändert werden, nur in ISR!
3
; BUF: Anfangsadresse des Buffers
4
MOV &P6IN, BUF(Rx)    ; P6IN in Buffer kopieren (6TZ)
5
ADD #0x01, Rx         ; Index erhöhen (1TZ)
6
BIC #0x02, &P2IFG     ; IRQ-Flag löschen (4TZ)
Macht zusammen 11TZ

Bleiben Dir also noch ganze 2TZ übrig!

Da aber nach Rücksprung aus der ISR mindestens ein Befehl im "normalen" 
Programm ausgeführt wird, bevor wieder in die ISR gesprungen wird, und 
dieser Befehl durchaus länger als 2TZ dauern kann, ist Dein gefordertes 
Timing meines Erachtens so nicht zu erreichen!
Selbst MSP430F2xxx @ 16MHz scheint mir recht knapp bemessen!

von Stefan (Gast)


Lesenswert?

Mögliche Ansatz mit Polling (ohne Gewähr)
1
LOOP:  BIT #0x02, &P2IFG     ; IRQ-Flag pollen (4TZ)
2
       JEQ LOOP              ; Loop, solagen kein IRQ (2TZ)
3
       MOV &P6IN, BUF(Rx)    ; P6IN in Buffer kopieren (6TZ)
4
       ADD #0x01, Rx         ; Index erhöhen (1TZ)
5
       BIC #0x02, &P2IFG     ; IRQ-Flag löschen (4TZ)
6
       CMP #N, Rx            ; Abbruch nach N durchläufen (1 oder 2TZ)
7
       JNE LOOP              ; Loop (2TZ)
8
       ...                   ; weiter nach Abbruch...

wären dann 20 oder 21TZ (je nach N).
Könnte vielleicht klappen :-)

von Andreas H. (msp430-fan)


Lesenswert?

Hi,

ich kam auch schon auf die Idee die ISR in assembler zu implementieren. 
Mit dem IAR kann ich CPU Register freihalten (z.B R4 und R5). Dieses 
Prozessorregister kann ich dann für den INC im Buffer verwenden.

Wie sollte die ISR in Assembler aussehen?

// Port 2 interrupt service routine
#pragma vector=PORT2_VECTOR
__interrupt void Port_2(void)
{
  *( PORTCODES + a ) = P6IN;                 // Port 6 einlesen
  P2IFG &= ~0x02;                          // P2.1 IFG cleared
  a++;
}

Vorallem wie bringe ich es dem IAR als inline assembler bei?

Ciao und Danke

von Christian R. (supachris)


Lesenswert?

Was ist überhaupt mit einer Abbruch-Bedingung? Irgendwo muss der 
Interrupt ja mal freigegeben und gesperrt werden? Der Prozessor soll ja 
sicher noch andere Sachen machen und nicht unendlich lange den 
Port-Status in ein Register sortieren. Oder wie dachtest du das? Das 
sind ja auch nochmal Befehle, die abgearbeitet werden müssen.

Und wieso gerade einen MSP430 für sowas schnelles? Den 50% über seiner 
max. Taktfrequenz zu betreiben wird eh nicht sehr zuverlässig 
funktionieren, der Prozessor macht dann manchmal komische Sachen.

von Andreas H. (msp430-fan)


Lesenswert?

Zur Info was ich gerade probieren möchte:

1. Ich habe einen PC der mir auf dem LPC-Bus Port 80h ausgaben macht.

2. Am LPC-Bus hängt ein PLD der die Ausgaben decodiert und an einer 
7-Segment-Anzeige die Port 80h codes anzeigt.

3. Mit dem MSP möchte ich die Codes an Port 6 einlesen

4. Über die serielle Schnittstelle des MSPs möchte ich dann die Port 80h 
Codes an einen Host-Rechner senden

Ciao

von Stefan (Gast)


Lesenswert?

>Wie sollte die ISR in Assembler aussehen?
Beratungsresistent ? ;-)
Ich habe doch schon dargelegt, warum eine ISR-Lösung nicht funktionieren 
kann!
Und 'ne Alternative hab ich Dir auch schon vorgeschlagen...

von msp430-fan (Gast)


Lesenswert?

Hi Stefan,

ich habe deine Assembler Beispiele gesehen. Ich möchte es auch so 
probieren. Aber wie bringe ich es dem IAR compiler bei? Ich wollte 
"inline assembler" Befehle verwenden. Mein Hauptprogramm sollte schon in 
C codiert sein. Ich will nur die ISR in assembler.

Ciao

von Stefan (Gast)


Lesenswert?

>Aber wie bringe ich es dem IAR compiler bei?
Schon mal den "C/C++ Compiler Reference Guide" konsultiert?
Stichwort "Inline Assembler"

von Christian R. (supachris)


Lesenswert?

Wie wäre es denn mit der DMA-Engine des MSP430. Einmal einstellen, und 
dann schießt der DMA die Daten vom Port in den Puffer, kümmert sich ums 
inkrementieren und bei Bedarf kannst du die mit einem weiteren DMA Kanal 
gleich auf dem UART schicken.

Wenn du vorher weißt, wieviele Bytes diese Karte an den MSP sendet, 
kannst du das als transfer size dem DMA Controller gleich geben, der 
Rest läuft in Hardware dann ab.

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.