Forum: Mikrocontroller und Digitale Elektronik MSP430 Timer-Interrupt löst RESET aus


von Norman F. (nofreak)


Lesenswert?

Hallo, ich arbeite an einem Projekt, wo mit einem MSP430F2274 u.a. eine 
Phasenanschnittsteuerung (Einquadrantensteller) realisiert werden. Die 
Hardware ist schon fertig, desshalb gibt es da nichts mehr zu verändern.
Zum Programmieren haben wir TIs Code Composer Studio v4.2.4 und 
SpiBiWire zum flashen und debuggen. Der MCLK und SMCLK sind auf 1MHz 
eingestellt. Programmiert wird in C.


Die Voraussetzungen sind folgende:

Am Port 4.4-4.7 sowie Port 2.0-2.2 hängt ein Textdisplay. An den Ports 
2.3, 2.4, 3.6 und 3.7 ließt der A/D-Wandler Werte ein, wobei an 3.7 über 
ein Poti der Zündwinkel alpha eingestellt wird. Die Zündimpulse für die 
Thyristoren werden an Port 4.0-4.3 ausgegeben, dabei sind 4.0/4.3 bei 
positivem Sinus an bzw. 4.1/4.2 bei negativem Sinus an.

Am Port1 ist eine 4x4-Matrix-Tastatur angeschlossen, mit der man durch 
ein Bedienmenü navigiert. Bei Tastendruck wird der Interrupt von Port1 
und dessen ISR aktiv. Sobald man im entsprechenden Betriebsmenu ist, 
wird der Port1-Interrupt ausgeschalten und es ist keine eingabe mehr 
möglich, was so gewollt ist.

In der Endloseschleife in main() werden die 4 A/D-Kanäle ausgelesen und 
auf dem Display dargestellt.

An Port 2.5 kommt eine netzsynchrone Rechteckspannung an, die bei 
positiver Sinushalbwelle LOW und bei negativer Sinushalbwelle HIGH 
ergibt. Entsprechend wird von mir in der Port2-ISR, das Interrupt Edge 
Select Flag getoggelt, ebenso wird dies hier in eine globale Variable 
geschrieben. um die Spannungsnulldurchgäng der Netzspannung zu erfassen. 
Zwischen den Interrupts liegen exakt 10ms (50Hz = 20ms, davon jede 
HALBwelle also 10ms).
In der P2-ISR wird dann vom A/D-Wandler das alpha abgefragt und in die 
Verzögerungszeit umgerechnet, diese Wert weise ich dem 
Capture/Compare-Register0 vom Timer A (TACCR0) zu, der Timer läuft los. 
P2-ISR ist zuende und es geht ins Hauptprogramm (LCD beschreiben).

Bei alpha=90° muss nach 5ms+Offset der TimerA0-Interrupt kommen und in 
dessen ISR werden die Tyristor-Ports 4.0/4.3 bzw. 4.1/4.2 auf OUT 
gesetzt und nach einem delay nach 500µs wieder gelöscht.

Alpha<10 bzw. >170 starten den Timer nicht und es die Zündsignale 
bleiben aus. Damit die TimerA0-ISR immer fertig ist, wenn Port 2.5 den 
Interrupt zum Flankenwechsel bekommt.


Soweit die Theorie.
Leider kommt der µC irgendwie mit dem Timer nicht zurecht und verursacht 
ein RESET, wobei alles von vorne beginnt.


In der Initialisierung wird
1
void timerA_Init(void)
2
{
3
  TACCR0 = 0x0000;
4
  TACTL = TASSEL_2 + ID_0 + MC_1;
5
}

aufgerufen. Die P2-ISR und die TimerA0_ISR sind:
1
#pragma vector=PORT2_VECTOR
2
__interrupt void P2_ISR(void)
3
{
4
  P2IFG &= ~BIT5;
5
        port2_irf();
6
}
7
8
UCHAR port2_irf(void)
9
{
10
  volatile UINT alphaADC, alpha_time1;
11
  volatile const float alfl= 9.765625;
12
  alphaADC=0;
13
  alpha_time2=0;
14
  
15
  if(P2IES&BIT5)
16
  {
17
    thy14out=1;
18
  }
19
  else
20
  {
21
    thy14out=0;
22
  }
23
  P2IES ^= BIT5;
24
25
  if(menuvar & F_m1m)
26
  {
27
    alphaADC=adc_get_value(3);
28
    if((alphaADC>=57)&&(alphaADC<972))
29
    {
30
      alpha_time1=(UINT) ((float) (1022-alphaADC)*alfl);
31
      TACTL |= TAIE;
32
      TACCTL0 = CCIE;
33
      TACCR0 = alpha_time1;
34
    }
35
    else
36
    {
37
      P4OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
38
      TACCTL0 &= ~CCIE;
39
      TACTL &= ~TAIE;
40
      TACCR0 = 0x0000;
41
      P2IFG &= ~BIT5;
42
      return 0;
43
    }
44
  }
45
46
  return 1;
47
}
48
49
50
#pragma vector=TIMERA0_VECTOR
51
__interrupt void Timer_A0_ISR(void)
52
{
53
  TACTL &= ~TAIE;
54
  //TACTL &= ~TAIFG;
55
  //TACCTL0 &= ~CCIFG;
56
  //TACCR0 = 0x0000;
57
  timerA0_irf();
58
}
59
60
void timerA0_irf(void)
61
{
62
63
  if((thyon==0)&&(thy14out==1))
64
  {
65
    P4OUT |= BIT0 + BIT3;
66
    thyon=1;
67
    delay_us(500);
68
    P4OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
69
  }
70
  else if((thyon==0)&&(thy14out==0))
71
  {
72
    P4OUT |= BIT1 + BIT2;
73
    thyon=1;
74
    delay_us(500);
75
    P4OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
76
  }  
77
78
}

Ob ich die oben ich die auskommentierten Zeilen wieder aktiviere oder 
nicht, spielt keine Rolle, der RESET finde trotzdem statt.
Meine Vermutung ist, dass der Stack-Pointer irgendwie durcheinanderkommt 
und dann die Reißleine zieht.

von Norman F. (nofreak)


Lesenswert?

Ein Koriosum für mich ist, das es mit folgender Programmierung zu laufen 
scheint, wenn auch nicht ganz sauber(manche Zündimpulse sind 
gelegentlich verschoben, trotz konstantem alpha).
1
#pragma vector=PORT2_VECTOR
2
__interrupt void P2_ISR(void)
3
{
4
  port2_irf();
5
}
6
7
UCHAR port2_irf(void)
8
{
9
  volatile UINT alphaADC, alpha_time1;
10
  volatile const float alfl= 9.765625;
11
  alphaADC=0;
12
  alpha_time2=0;
13
  
14
  if(P2IES&BIT5)
15
  {
16
    thy14out=1;
17
  }
18
  else
19
  {
20
    thy14out=0;
21
  }
22
  P2IES ^= BIT5;
23
  if(menuvar & F_m1m)
24
  {
25
    alphaADC=adc_get_value(3);
26
    if((alphaADC>=57)&&(alphaADC<972))
27
    {
28
      alpha_time1=(UINT) ((float) (1022-alphaADC)*alfl);
29
30
31
      TACCTL1 = CCIE;
32
      TACTL |= TAIE;
33
      TACCTL0 = CCIE;
34
      TACCR1 = alpha_time1;
35
      TACCR0 = alpha_time1 + 500;
36
    }
37
    else
38
    {
39
      P4OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
40
      TACCTL1 &= ~CCIE;
41
      TACCTL0 &= ~CCIE;
42
      TACTL &= ~TAIE;
43
      TACCR0 = 0x0000;
44
      TACCR1 = 0x0000;
45
      P2IFG &= ~BIT5;
46
      return 0;
47
    }
48
  }
49
  return 1;
50
}
51
52
53
#pragma vector=TIMERA1_VECTOR
54
__interrupt void Timer_A1(void)
55
{
56
  TACTL &= ~TAIFG;
57
  TACCTL0 &= ~CCIFG;
58
  timerA1_irf();
59
}
60
61
void timerA1_irf(void)
62
{
63
  switch (TAIV)
64
    {
65
         case  2:
66
                 if((thyon==0)&&(thy14out==1))
67
                 {
68
                         P4OUT |= BIT0 + BIT3;
69
                         thyon=1;
70
                         delay_us(500);
71
                         P4OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
72
                         TACCR0 = 0x0000;
73
                 }
74
                 else if((thyon==0)&&(thy14out==0))
75
                 {
76
                         P4OUT |= BIT1 + BIT2;
77
                         thyon=1;
78
                         delay_us(500);
79
                         P4OUT &= ~(BIT0 + BIT1 + BIT2 + BIT3);
80
                         TACCR0 = 0x0000;
81
                 }  
82
                 break;
83
         case  4:
84
                 break;
85
         case 10:
86
                 break;
87
        }
88
}
89
90
91
#pragma vector=TIMERA0_VECTOR
92
__interrupt void Timer_A0_ISR(void)
93
{
94
       //bleibt hier leer
95
}

D.h. hier läuft der Timer bis zum CCR1-Event, der µC macht in der 
TimerA1-ISR was er soll, löscht dann aber das Endziel. Nach außen 
scheint alles dann in Ordnung.

Ursprünglich sollte nach alpha_time1+500µs also in der TimerA0-ISR die 
Zündimpulse wieder gelöscht werden, was auch nur unzuverlässig geklappt 
hat. Die Zündimpulsbreite (ZIB) hat permanent geschwankt, nur das 
delay_us(500) hat die ZIB "stabilisiert" auf kosten freier 500µs 
Rechenrechenzeit also 5% vom 10ms-Intervall.

von Roland H. (batchman)


Lesenswert?

Funktioniert

> Der MCLK und SMCLK sind auf 1MHz
> eingestellt.

mit einem "busy wait" von ...

> Bei alpha=90° muss nach 5ms+Offset der TimerA0-Interrupt kommen und in
> dessen ISR werden die Tyristor-Ports 4.0/4.3 bzw. 4.1/4.2 auf OUT
> gesetzt und nach einem delay nach 500µs wieder gelöscht.

... 500µs in der ISR? Ich würde die "busy delay" durch eine kleine 
"state machine" in der Timer-ISR ersetzen.

Das mag Ansichtssache sein, aber die andere ISR ist m. E. auch etwas 
überfrachtet. Da gehört "floating point" nicht unbedingt rein, vor allem 
angesichts der Taktfrequenz. Auch das Auslesen des ADCs.

Wofür ist "volatile const" gut?
Und das erste "volatile" in der port2_irf?

Den Timer-Interrupt würde ich erst dann aktivieren, wenn die anderen 
Register vorher beschrieben wurden.

Wenn ich das richtig sehe, aktivierst Du zwei Timer-Interrupts: Eine mit 
CCIE, die andere mit TAIE (overflow). Wie sieht die dazu gehörende ISR 
aus?

von Norman F. (nofreak)


Lesenswert?

Roland H. schrieb:
> Funktioniert
>
>> Der MCLK und SMCLK sind auf 1MHz
>> eingestellt.
>
> mit einem "busy wait" von ...
>
>> Bei alpha=90° muss nach 5ms+Offset der TimerA0-Interrupt kommen und in
>> dessen ISR werden die Tyristor-Ports 4.0/4.3 bzw. 4.1/4.2 auf OUT
>> gesetzt und nach einem delay nach 500µs wieder gelöscht.
>
> ... 500µs in der ISR? Ich würde die "busy delay" durch eine kleine
> "state machine" in der Timer-ISR ersetzen.
>
> Das mag Ansichtssache sein, aber die andere ISR ist m. E. auch etwas
> überfrachtet. Da gehört "floating point" nicht unbedingt rein, vor allem
> angesichts der Taktfrequenz. Auch das Auslesen des ADCs.
>
> Wofür ist "volatile const" gut?
> Und das erste "volatile" in der port2_irf?
>
> Den Timer-Interrupt würde ich erst dann aktivieren, wenn die anderen
> Register vorher beschrieben wurden.
>
> Wenn ich das richtig sehe, aktivierst Du zwei Timer-Interrupts: Eine mit
> CCIE, die andere mit TAIE (overflow). Wie sieht die dazu gehörende ISR
> aus?

Danke erstmal für die Anwort.
Die "volatiles" habe ich nur reingeschrieben, weil ich beim debuggen 
festgestellt habe, Wetzuweisungen wie
1
alphaADC=0;
2
alpha_time2=0;
in der P2-ISR nicht funktionierten. Nach den Zeilen waren die Variablen 
eben nicht Null, mit volatile aber schon.
Gleiches gilt für die
1
const float alfl= 9.765625;
, Wert blieb war nicht der zugewiesene.


Das delay in der Timer-ISR wollte ich ja, wie im 2. Beitrag (unten) 
beschrieben, durch die Nutzung von CCR1=alpha_time (Thyristoren ein) und 
CCR0=alpha_time+500 (Thyristoren aus) lösen. Aber auf dem Oszilloskop 
war der Abstand zwischen der steigen und der fallenden Flanke an den 
oben erwähnten Thyristor-Ports keine konstanten 500µs. Die Zündimpulse 
"zitterten". Keine Ahnung warum.

Zu den Fließkommazahlen in der P2-ISR: Irgendwie muss ich ja aus dem 
A/D-Wert für alpha die Zeitverzögerung berechnen und das geht nicht mit 
ganzen Zahlen. Weil 180° 10ms=10000µs entsprechen. Die Subtraktion macht 
0 A/D-digit = 180° bzw. 1024 = 0°, d.h. Poti nach links kleine Drehzahl, 
Poti nach recht große Drehzahl. Ich bekomme bei 150° am Poti vom 
A/D-Wandler einen Wert von 853, bei 30° = 171 usw. und multipliziere 
dann mit
10000µs/1024digit = 9.765625 = alfl, dadurch bekomme ich die genaue Zeit 
die ich den Teimer übergebe. Nur mit Integer geht das nicht, denke ich 
zumindest.

Wenn ich TAIE nicht aktiviere komme ich doch nie in die TimerA0_ISR, 
weil diese ja im Up-Mode auf CCR0 triggert. Ein TAIV-Ereignis für CCR0 
gibt es ja nicht.

von Norman F. (nofreak)


Lesenswert?

Roland H. schrieb:
>...
>
> ... 500µs in der ISR? Ich würde die "busy delay" durch eine kleine
> "state machine" in der Timer-ISR ersetzen.
>


Welche Zustand soll ich denn auswerten, wenn ein Ereignis exakt 500µs 
nach einem anderen eintreten soll, außer durch ein weiteren 
Timerinterrupt?


Aufbauend auf dem Quellcode aus meinem zweiten Beitrag oben, also mit 
TimerA1_ISR und TimerA0_ISR:

Wie gerade oben beschrieben klappt das nicht in Hardware. Mit dem "Oszi" 
erkenne ich, das die Zündimpulse zwar einigermaßen extakt beginnen, aber 
enden tun sie nie konstant nach der gleichen Zeit.

von Stefan (Gast)


Lesenswert?

Hab' mir Deinen Code jetzt nicht genau angeschaut.
Hatte jedoch mal ein ähnliches Problem, das ich nur dadurch in den Griff 
bekommen habe, indem ich den Port-IRQ (Trigger auf 50Hz) in der ISR 
sperren musste, da durch diverse Störungen beim Zünden des Thyristors 
die ISR gleich wieder angesprungen wurde.

Bei Lust und Laune kannst Dir das ja mal anschauen:
Beitrag "MSP430 NiCd-Ladegerät mit -dU"

von Roland H. (batchman)


Lesenswert?

> Wenn ich TAIE nicht aktiviere komme ich doch nie in die TimerA0_ISR,
> weil diese ja im Up-Mode auf CCR0 triggert. Ein TAIV-Ereignis für CCR0
> gibt es ja nicht.

Doch. Eben nur mit CCIE. Das genügt. Es sind zwei verschiedene 
Interrupts, welche in derselben ISR landen.

Entferne: TACTL |= TAIE;

In der Timer-ISR: Statt //TACCTL0 &= ~CCIFG;
-> sinngemäß: TACCTL0 &= ~CCIE;

In der ISR wird dann nach dem CC-Interupt der "overflow interrupt" 
abgeschaltet. D. h. beim nächsten CC-Interrupt wird diese ISR wieder 
betreten, welche dann u. U. noch in der delay() hängt.

> Zu den Fließkommazahlen in der P2-ISR: Irgendwie muss ich ja aus dem
> A/D-Wert für alpha die Zeitverzögerung berechnen und das geht nicht mit
> ganzen Zahlen.

Schon. Aber nicht in der ISR, sondern in main(). In der ISR die Eingabe 
des Users festhalten, und dann alles in main auswerten (float + ADC). 
Spielt hier aber vermutlich keine Rolle.

> Welche Zustand soll ich denn auswerten, wenn ein Ereignis exakt 500µs
> nach einem anderen eintreten soll, außer durch ein weiteren
> Timerinterrupt?

Die Lösung hast Du eben selbst im Nachsatz beschrieben. Als Status 
genügt eine bool.

von Norman F. (nofreak)


Lesenswert?

Es gab ein Verständnisproblem meinerseits. Ich hatte schon das TACTL |= 
TAIE; gelöscht bevor ich die letzten Beiträge oben gelesen hatte. Das 
RESET-Problem ist erstmal weg.

Ich füttere jetzt wieder das TACCR1 mit alphatime und TACCR0 mit 
alpha_time+500:

In der TimerA1-ISR werden die Thyristoren gezündet und TACCTL1 &= ~CCIE 
sowie TACCR1 = 0x0000 gesetzt und in der TimerA0-ISR werden die 
Thyristoren wieder gelöscht und TACCTL1 &= ~CCIE sowie TACCR0 = 0x0000 
gesetzt.

Leider zucken die Zündimpulse auf dem "Oszi" vorallem im mittleren 
Bereich (alpha ca. 90°) stark und ungleichmäßig hin und her. Dies gilt 
für die steigenden Flanken (TimerA1-ISR) als auch bei fallenden Flanken 
(TimerA0-ISR).

Wenn ich in der Endlosschleife der main() (LCD beschreiben mit einigen 
delays) alles auskommentiere wird das Zittern wesentlich ruhiger, ist 
aber nicht ganz weg.
Wie kann denn die Hauptschleife die ISRs verzögern, wenn dort die 
Interrupts nie gesperrt werden?


Ein weiterer Punkt von "batchman":
Die A/D-Wandlerabfrage und Berechnung der Verzögerungszeit von der 
P2-ISR in die Hauptschleife zu verlegen.
Das ist ein Riesenproblem, weil ich nach jedem Nulldurchgang des Netzes 
als dem Interrupt auf Port 2.5 immer die neuesten Werte vom A/D-Wandler 
brauche, um darauf zu reagieren zu können.

In den hier einfachen Phasenanschnittsmodus mag dein Vorschlag noch in 
Ordnung sein, aber ich muss noch zwei weitere Betriebsmodi 
programmieren. Einen mit PI-Regler und einen mit PI-Regler und 
unterlagerter Stromregelung. D.h. Drehzahl und Strom, die ADC-Kanal 4 
und 6 aufgenommen werden, haben unmittelbaren Einfluss auf alpha und der 
Verzögerungszeiten, die in TACCR1 und TACCR0 geschrieben werden müssen.

von Roland H. (batchman)


Lesenswert?

> Leider zucken die Zündimpulse auf dem "Oszi" vorallem im mittleren
> Bereich (alpha ca. 90°) stark und ungleichmäßig hin und her. Dies gilt
> für die steigenden Flanken (TimerA1-ISR) als auch bei fallenden Flanken
> (TimerA0-ISR).

Ich verstehe es fachlich (= Motoransteuerung) nicht. Ich kann es nur von 
der SW her beurteilen.

Ich bleibe bei meiner Einschätzung: M. A. nach ist es für 1 MHz Takt "zu 
viel" in den ISRs. Insbesondere mit "float", ADC und delays. Das ist 
nicht viel Luft. Hat Deine CPU einen NVIC?

Ich werde mich nicht durch die Menusteuerung wühlen: Ist dafür gesorgt, 
dass diese "entprellt" ist?

> Wenn ich in der Endlosschleife der main() (LCD beschreiben mit einigen
> delays) alles auskommentiere wird das Zittern wesentlich ruhiger, ist
> aber nicht ganz weg.

Wundert mich nicht bei 1 MHz und 500µs delay in einer der ISRs.

Welche Interrupts sind denn nun alle aktiv? Damit meine ich auch 
diejenigen, die versehentlich aktiv sind. Wäre nicht das erste Mal ...

> Wie kann denn die Hauptschleife die ISRs verzögern, wenn dort die
> Interrupts nie gesperrt werden?

Wie sind die "delays" in main() implementiert? Zeige mal bitte den 
Quelltext der delay-Funktionen.

von Norman F. (nofreak)


Lesenswert?

> Ich verstehe es fachlich (= Motoransteuerung) nicht. Ich kann es nur von
> der SW her beurteilen.

An der Schaltung hängt noch kein Motor, sondern erstmal nur "Potis", die 
quasi die Ist-Drehzahl und die Ist-Strostärke simulieren, damit der 
A/D-Wandler einen brauchbaren Wert bekommt. Im aktuellen Betriebsmodus 
ist aber nur das Stellpoti für alpha interessant. Un wenn ich von 
Zündimpulsen schreibe, dann meine ich die High-Signale, die an den Ports 
4.0-4.3 ausgegeben werden. Die Zündimpulsbreite heißt dann die Zeit vom 
Einschalten bis zum Ausschalten der Signale, die ja idealerweise 500µs 
lang sein sollte.


> Hat Deine CPU einen NVIC?

Ich kenne die Abkürzung "NVIC" nicht, gibts dafür einen anderen Begriff?


> Ich werde mich nicht durch die Menusteuerung wühlen: Ist dafür gesorgt,
> dass diese "entprellt" ist?

Das man eine Menüsteuerung entprellen muss wusste ich nicht, aber die 
Tastatur ist entprellt. Der Port1 an dem die Tastatur hängt ist nach der 
Betriebsmodiauswahl, also wärend des eigentlichen Betriebs gesperrt. 
Port 1 hat in der IRQ-Tabelle sowieso die niedrigste Priorität.


> Wie sind die "delays" in main() implementiert? Zeige mal bitte den
> Quelltext der delay-Funktionen.

Da gibt es keinen Quellcode. __delay_cycles() ist eine 
Intrinsic-Funktion des Compilers in CCSv4, die sich nach dem MCLK also 
Master Clock richtet.

An dem µC ist ein 8MHz-Quarz angeschlossen und mit
1
BCSCTL2 = SELM_3 + DIVM_3 + SELS + DIVS_3;
wurde MCLK = SMCLK = ACLK/8 = 8MHz/8 = 1MHz festgelegt.

__delay_cycles(1) entsprechen also exakt 1µs und __cycle_delay(1000) = 
1ms usw., was ich auch messtechnisch nachgeprüft habe.

von Norman F. (nofreak)


Lesenswert?

Ich habe jetzt mal etwas anderes probiert. Indem ich die Berechnung aus 
der P2-ISR rausgenommen habe und statt dessen ein array erzeugt mit 
[1024][2] Dimensionen. Leider braucht sowas viel Speicher, aber ich bin 
damit ja erst bei rund 10kB von 32kB möglichen.

Jede Zeile steht dabei für einen Stellenwert das 10Bit-ADC. In Spalte 1 
sind die Zeiten für den Timer und in Spalte 2 die alpha zum Anzeigen für 
das LCD eingetragen. Es wird also nichts mehr gerechnet, sondern nur 
noch der Wert assoziert.
1
TACCR1 = alpha_table[adc_get_value(ALPHA)][0];
2
TACCR0 = alpha_table[adc_get_value(ALPHA)][0]+500;

Mit leerer Endlosschleife in der main() ist aber immernoch ein leichtes 
Zucken zu erkennen. Ich befürchte fast, dass das am "Oszi" (Triggerung) 
bzw. an den Messleitungen liegen könnte.

von Roland H. (batchman)


Lesenswert?

>> Hat Deine CPU einen NVIC?
>
> Ich kenne die Abkürzung "NVIC" nicht, gibts dafür einen anderen Begriff?

"Nested [vectored] interrupt controller"

> Das man eine Menüsteuerung entprellen muss wusste ich nicht

Die Frage ist, ob irgendwelche zusätzlichen Interrupts entstehen.

>> Wie sind die "delays" in main() implementiert? Zeige mal bitte den
>> Quelltext der delay-Funktionen.
>
> Da gibt es keinen Quellcode.

Dann halt Assembler ...

> An dem µC ist ein 8MHz-Quarz

Dann nimm' mal die 8 MHz und teste nochmals. Da ist schon manches 
Problem "verschwunden".

Ich tippe weiterhin darauf, dass die Zeit in den ISRs zu lang ist, und 
evtl. Interrupts verloren gehen.

> Ich habe jetzt mal etwas anderes probiert. Indem ich die Berechnung aus
> der P2-ISR rausgenommen habe und statt dessen ein array erzeugt mit
> [1024][2] Dimensionen.

Aha. Soso. Oh, Du wirst noch viel ändern müssen ...

Testweise float entfernen, und ADC mit dummy-Werte (= Konstante).

Wenn es dann im Oszi nicht mehr "zuckt", liegt's vermutlich an der 
Rechen-Last (sofern alle busy-delays daraus entfernt wurden). Ansonsten 
vielleicht am Messaufbau.

von Norman F. (nofreak)


Lesenswert?

Roland H. schrieb:
>>> Hat Deine CPU einen NVIC?
>>
>> Ich kenne die Abkürzung "NVIC" nicht, gibts dafür einen anderen Begriff?
>
> "Nested [vectored] interrupt controller"

Nein so langsame µC wie der MSP430 haben keinen NIC, die flotten ARMs 
haben welche laut google-Suche.




>> Da gibt es keinen Quellcode.
>
> Dann halt Assembler ...

Texas Instruments MSP430 Optimizing C/C++ Compiler v 3.3 User's Guide
http://www.ti.com/lit/ug/slau132e/slau132e.pdf
S.115
"6.7.2 The __delay_cycle Intrinsic
The __delay_cycles intrinsic inserts code to consume precisely the 
number of specified cycles with no side effects. The number of cycles 
delayed must be a compile-time constant."

Mehr kenne ich auch nicht, aber es funktioniert.



>> An dem µC ist ein 8MHz-Quarz
>
> Dann nimm' mal die 8 MHz und teste nochmals. Da ist schon manches
> Problem "verschwunden".

Das dauert erstmal, dafür muss ich das Array überarbeiten.


>> Ich habe jetzt mal etwas anderes probiert. Indem ich die Berechnung aus
>> der P2-ISR rausgenommen habe und statt dessen ein array erzeugt mit
>> [1024][2] Dimensionen.
>
> Aha. Soso. Oh, Du wirst noch viel ändern müssen ...

Den Speicher voller riesiger Arrays zu laden, ist aber auch nicht die 
Lösung, wenn es ein bis zwei Berechnungen auch tun.

von 16Bit (Gast)


Lesenswert?

Norman Freitag schrieb:
> Den Speicher voller riesiger Arrays zu laden, ist aber auch nicht die
> Lösung, wenn es ein bis zwei Berechnungen auch tun.

Zwischen Wunsch und Wirklichkeit zu unterscheiden, bedeutet Wissen!

Wie schon mehrfach angedeutet, ist der Takt zu gering, um die 
rechenintesiven Ausdrücke zu verarbeiten. Also hast du die Wahl, einen 
anderen Algorithmus, einen höheren Takt, oder anderen µC zu wählen.

von Norman F. (nofreak)


Lesenswert?

Ich habe die Probleme weitgehend gelöst. Das Zittern der Zündsignale ist 
auf ein Minimum reduziert. Das Minimum  meist +/- 8-12µs mit ein paar 
seltenen Ausreißern von bis zu 67µs.

Das größte Problem waren in der Hauptschleife, das gegenseitige 
Aussperre der LCD-Signale und der Thyristor-Zündsignale auf dem Port4, 
da ja, wie oben beschrieben Zündsignale auf dem Low-Nibble und LCD auf 
dem High-Nibble liegen. Wenn nun ein Interrupt an einer sehr ungünstigen 
Stelle der LCD-Routine ausgelöst wurde, dann wurde auf Port4 letzlich 
etwas Falsches ausgegeben.

Eine andere Ursache für Störungen der beiden Timer-ISR ist bedingt durch 
die Abfrage des A/D-Wandlers. Hier kam es in regelmäßigen Abständen zum 
aussetzen von ganzen Zündsignalen, obwohl der A/W-Wandler keinen 
Intterupt bemüht.

Meine Lösung:
P2.5 detektiert Flankenwechsel ==> P2-ISR ==> P2IES toggle BIT5
==> frage A/W-Wandler ab ==> berechne Zeitverzögerung
==> füttere CCR1 und CCR0 ==> CCR1 erreicht
==> Timer_x1-ISR Zündimpulse auf ein ==> Timer_x0-ISR Zündimpulse aus
==> zurück zum Hauptprogramm (Anzeigewerte berechnen ==> LCD 
beschreiben)

Wenn ich den MCLK auf 2MHz setze, kann ich bei 500µs Zündimpulsbreite 
(CCR0-CCR1) im Intervall von alpha=9°-170° sauber arbeiten (bei 
MCLK=1MHz sind es nur alpha=18-170°). Das genügt mir so.
Theoretisch sind bei MCLK=16MHz und kürzeren Zündimpulsen (300µs) 
wahrscheinlich sogar alpha=1°-174° möglich.

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.