Forum: Mikrocontroller und Digitale Elektronik Interrupt-Problem beim C167


von Andreas (Gast)


Lesenswert?

Hallo zusammen!

Ich nutze einen C167CS auf Phytec MiniModul mit dem Tasking Compiler. 
Mein Programm soll periodisch (alle 20 ms) Ports (3.0-3.3) in 
Abhängigkeit von CAN-Daten schalten. Dazu nutze ich den Timer T6. Der 
Code ist erprobt und sollte eigentlich funktionieren. Mein Problem ist, 
dass die Interrupt Routine nicht von T6 nicht ausgelöst wird und ich 
nicht dahinter komme, warum. Vielleicht sieht jemand einen Fehler. Ich 
habe schon mehrere Tage erfolglos danach gesucht. Mein Main-Programm 
sieht wie folgt aus:
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
#include <reg167.h>
5
#include "can_ext.h"
6
#include "global.h"
7
8
void main (void)
9
{
10
11
 /* Interrupts zulassen */
12
 //IEN = 1;
13
14
 /* Watchdog-Timer wurde bereits in cstart initialisiert (watchdog time = 419 ms); hier erstmals bedienen */
15
 //WDTsrv();
16
17
 /* Voreinstellungen */
18
 /* ================ */
19
20
 /* CAN-Controller */
21
 C167.CAN_fehler = FALSE;
22
 C167.CAN_rdy    = FALSE;
23
24
 /* Taktzeitueberschreitung */
25
 C167.zeitfehler = FALSE;
26
27
 /* Egofahrzeug-Daten */
28
 //EgoFzg.v = 0;
29
 //Regler.einschalten = FALSE;
30
31
32
 /* Initialisierung der Timer, Interupts, etc. */
33
 /* ========================================== */
34
35
 /* Initialisieren des kurzen Haupttimers : Timer 3 ist ein 16bit-Timer mit einer Zeitaufloesung von 6.4 us */
36
 // Gesamtdurchlaufzeit: 419 ms; raufzählend
37
 T3     = 0;      /* Timer 3 auf Null setzen */
38
 T3CON  = 0x44;      // binaer : 00 00 1 000 100; 0x44
39
40
 /* Watchdog-Timer wurde bereits in cstart initialisiert (watchdog time = 419 ms); hier nochmals bedienen */
41
 WDTsrv();
42
43
 /* Initialisierung CAN1 und CAN2 mit 500 kBit/s */
44
 StartCAN(0);
45
 //StartCAN(1);
46
47
 /* Watchdog-Timer wurde bereits in cstart initialisiert (watchdog time = 419 ms); hier nochmals bedienen */
48
 WDTsrv();
49
50
 /* Takt-Timer initialisieren : Timer 6 ist ein 16-bit Timer mit einer Zeitaufloesung von 3.2 us */
51
 T6CON  = 0;              /* Timer 6 stoppen */
52
 T6     = (unsigned int)6250;            /* Taktzeit 20 ms */
53
 CAPREL = (unsigned int)6250;            /* Taktzeit als Reload-Wert */
54
 T6CON  = 0x80C4;                        /* binaer : 1 0000 00 011 000 100 */
55
 T6IC   = 0x39;                          // Einstellen des Interruptlevels fuer Takt-Interrupt : enable, Level 14, Gruppenlevel 1 */39
56
 T6IE   = 1;                             /* Interrupt enablen */
57
58
  /*
59
   * Watchdog-Timer hier nochmals bedienen
60
   */
61
  WDTsrv();
62
63
 /* CAN steht zur Verfuegung */
64
 C167.CAN_rdy = TRUE;
65
66
  /*
67
   * Port 3.0 schaltet Flashlights
68
   * (Output, Push/Pull, passiv)
69
   */
70
  _putbit(1,DP3,0);
71
  _putbit(0,ODP3,0);
72
  _putbit(0,P3,0);
73
74
  /*
75
   * Port 3.1 schaltet Starkhorn
76
   * (Output, Push/Pull, passiv)
77
   */
78
  _putbit(1,DP3,1);
79
  _putbit(0,ODP3,1);
80
  _putbit(0,P3,1);
81
82
  /*
83
   * Port 3.2 schaltet LED-Matrix Bild 1
84
   * (Output, Push/Pull, passiv)
85
   */
86
  _putbit(1,DP3,2);
87
  _putbit(0,ODP3,2);
88
  _putbit(0,P3,2);
89
90
  /*
91
   * Port 3.3 schaltet LED-Matrix Bild 2
92
   * (Output, Push/Pull, passiv)
93
   */
94
  _putbit(1,DP3,3);
95
  _putbit(0,ODP3,3);
96
  _putbit(0,P3,3);
97
98
  /* Interrupts zulassen */
99
  IEN = 1;
100
101
 /* Hauptschleife */
102
 while (1)
103
 {
104
 ;
105
 }
106
}
Die Interrupt-Routine, welche ausgeführt werden soll sieht so aus.
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <reg167cs.h>
4
#include "can_ext.h"
5
#include "global.h"
6
7
interrupt 0x26
8
void TAKT(void) {
9
10
  unsigned int t6ic_alt = 0;
11
  //static int counter = 1;
12
13
  /* waehrend der Abarbeitung keinen neuen Interrupt zulassen */
14
  t6ic_alt = T6IC;
15
  T6IC = 0;
16
17
18
/*  if (counter < 100)
19
    counter++;
20
  else
21
    counter = 1;
22
*/
23
24
  //if(counter%2==0) { // alle 20 ms; Taktung: 10 ms (Timer 6)
25
26
    vRel = vEigen - vZielUebergabe;  // Relativgeschwindigkeit berechenen
27
    vZiel = vEigen + vRel;      // Tatsächtiche Zielgeschwindigkeit
28
29
    aEigen = (vEigen - vEigenVortakt) * (1000 / taktzeit); //Eigenbeschleunigung
30
    aZiel = (vZiel - vZielVortakt) * (1000 / taktzeit);    // Zielbeschleunigung
31
32
    aRel = aZiel - aEigen;    // Relativbeschleunigung
33
    aRelMax = -800 - aEigen;  // Maximale Relativbeschleunigung
34
35
    dReferenz1 = vEigen * vEigen * 7 / 12500;  // Referenzabstand für die 1. Warnstufe [cm/s]
36
    dReferenz2 = vEigen * vEigen / 2500;      // Referenzabstand für die 2. Warnstufe [cm/s]
37
38
    radikand = vRel * vRel + aRel * abstand * 2;    // Wurzelberechnung
39
    wurzel = isqrt_heron(radikand);            // Wurzelberechnung
40
    tBrems1 = ((vRel * 1000 / - aRelMax) / 2) + 1600 + 2000;  // Bremszeit1; Vergleichszeit Stufe 1
41
    tBrems2 = ((vRel * 1000 / - aRelMax) / 2) + 1600;       // Bremszeit2; Vergleichszeit Stufe 2
42
    ttcBesch = (wurzel - vRel) * 1000 / aRel;
43
    ttcConst = (abstand / vRel) * 1000;
44
45
    switch (sensorAus)  {
46
47
      case 1:  fehlerIDIS(); break;  // IDIS hat sich abgeschaltet
48
49
      default :
50
51
               if (aRelMax >= 0) {    // Das Egofahrzeug führt eine Notbremsung durch
52
53
                  notbremsung();
54
55
               }// else if (vRel < -100 && aRelMax < 0) {}      // Ziel entfernt sich
56
57
                 else if (vRel >= -100 && vRel <= 100 && aRelMax < 0) {  // Ziel folgt
58
59
                 if (abstand <= dReferenz2) stufe2();
60
61
                 if (abstand <= dReferenz1 && abstand > dReferenz2) stufe1();
62
63
                 //if (abstand > dReferenz1) allesOk();
64
65
               } else {    // Ziel fährt auf
66
67
                 if (vRel * vRel >= - aRel * abstand * 2 && aRel != 0 && aRelMax < 0) {    // TTC mit beschleunigten Fahrzeugen
68
69
                   if (ttcBesch <= tBrems2 && ttcBesch > 0) stufe2();
70
71
                   if (ttcBesch > tBrems2 && ttcBesch <= tBrems1) stufe1();
72
73
                   //if (ttcBesch > tBrems1 || ttc < 0) allesOk();
74
75
                 } else if (aRel == 0 && aRelMax < 0) {    // Keine Relativbeschleunigung --> Formel für unbeschleunigte Bewegung
76
77
                   if (ttcConst <= tBrems2) stufe2();
78
79
                   if (ttcConst > tBrems2 && ttcConst <= tBrems1) stufe1();
80
81
                   //if (ttcConst > tBrems1) allesOk();
82
83
                 }
84
    }
85
86
    vEigenUebergabe = vEigen * 36 / 100;  // Umrechnung der Einheiten und Auflösung für IDIS
87
88
    daten[0] = (gierrate&0x00FF);
89
    daten[1] = ((gierrate&0xFF00)>>8);
90
    daten[2] = (vEigenUebergabe&0x00FF);
91
    daten[3] = ((vEigenUebergabe&0xFF00)>>8);
92
    daten[4] = (lenkwinkel&0x00FF);
93
    daten[5] = ((lenkwinkel&0xFF00)>>8);
94
    daten[6] = (bremslicht);
95
    daten[7] = 0;
96
97
    def_mo_16x(0,14, 0, 0x333, 1, 8, 0, 0);
98
    ld_modata_16x(0,14, (unsigned char*)&daten);
99
    send_mo_16x(0,14);
100
101
    }
102
  //counter++;
103
  vZielVortakt = vZiel;
104
  vEigenVortakt = vEigen;
105
106
  //}
107
108
  T6IC = t6ic_alt; // Interrupt wieder zulassen
109
110
}

Grüße,
Andreas

von sdfgq5zg (Gast)


Lesenswert?

Also. Ich bin mir 99% sicher, dass Du das Interrupt-Flag nicht sichern 
und
rücksetzen musst. Das erledigt für dich entweder der µC oder der 
Compiler.

Lösungsvorschlag zu Deinem Problem: Hast Du die Interrupts (sinnvoll) 
priorisiert (habe die Konfig oben nicht näher untersucht)?
Sind die Timer soweit hardwareseitig aktiviert (schau mal in Deine
Startup-Konfiguration) und rennt Timer6 überhaupt?

Ansonsten baue Dir ein kleines Test-Projekt, in dem Du ohne viel
Beeinflussung den Fehler finden kannst (mit Timer6 z.B. eine LED
im Sekundenrhythmus toggeln, o.ä.).

von Guido (Gast)


Lesenswert?

In der while-Schleife wird der Watchdog doch nicht bedient.
Macht der die Probleme?

von Andreas H. (andreas_h32)


Lesenswert?

sdfgq5zg schrieb:
> Also. Ich bin mir 99% sicher, dass Du das Interrupt-Flag nicht sichern
> und
> rücksetzen musst. Das erledigt für dich entweder der µC oder der
> Compiler.
>
> Lösungsvorschlag zu Deinem Problem: Hast Du die Interrupts (sinnvoll)
> priorisiert (habe die Konfig oben nicht näher untersucht)?
> Sind die Timer soweit hardwareseitig aktiviert (schau mal in Deine
> Startup-Konfiguration) und rennt Timer6 überhaupt?
>
> Ansonsten baue Dir ein kleines Test-Projekt, in dem Du ohne viel
> Beeinflussung den Fehler finden kannst (mit Timer6 z.B. eine LED
> im Sekundenrhythmus toggeln, o.ä.).

Danke für die schnellen Antworten!

Hab jetzt mit der Prüfung einzelner Segmente angefangen. Kenntnisstand 
bis jetzt: Timer laufen, und zwar richtig. Überhaupt, habe ich 
hardwareseitig schon alles doppelt und dreifach geprüft. Ich glaub, dass 
was übersehe...

Guido schrieb:
> In der while-Schleife wird der Watchdog doch nicht bedient.
> Macht der die Probleme?

Watchdog ist es nicht. Habe ihn schon mal stillgelegt, ohne Ergebnis. 
Außerdem ist er auf 419 ms eingestellt, deshalb denke ich nicht, dass er 
hier Probleme macht. Aber danke für den Tipp!

Grüße,
Andreas

von sdfgq5zg (Gast)


Lesenswert?

Ist das beim Tasking-Compiler wirklich so:

interrupt 0x26
void TAKT(void)
{
}

und nicht so wie beim Keil µVision:

void TAKT(void) interrupt 0x26
{
}

?

von Steel (Gast)


Lesenswert?

Das IC Register zu sichern und nachher wieder zu schreiben macht genau 0 
Sinn. Du solltest das IR Flag zurücksetzen in der Interruptroutine, 
sonst nichts.

von Pipeline (Gast)


Lesenswert?

Andreas schrieb:
> T6IC   = 0x39;                          // Einstellen des Interruptlevels fuer 
Takt-Interrupt : enable, Level 14, Gruppenlevel 1 */39
>  T6IE   = 1;                             /* Interrupt enablen */

ersetze die beiden Anweisungen gegen
1
T6IC = 0x79;

ach ja, in der ISR kannst du den Interrupt mit dem T6IE ein- und 
ausplanen.

von Andreas H. (andreas_h32)


Lesenswert?

sdfgq5zg schrieb:
> Ist das beim Tasking-Compiler wirklich so:

Ja, es ist so. Anders spuckt der Compiler einen Fehler aus.

Steel schrieb:
> Das IC Register zu sichern und nachher wieder zu schreiben macht genau 0
> Sinn. Du solltest das IR Flag zurücksetzen in der Interruptroutine,
> sonst nichts.

Ok, mach ich. Obwohl ich vermute, dass das nicht der Grund für mein 
Leiden ist...

Pipeline schrieb:
> ersetze die beiden Anweisungen gegenT6IC = 0x79;

Das habe ich der Übersichtlichkeitshalber gemacht. So kann ich den Timer 
stilllegen, ohne jedes mal binär in hex umzurechnen.

Pipeline schrieb:
> ach ja, in der ISR kannst du den Interrupt mit dem T6IE ein- und
> ausplanen.

Wie oben angemerkt, werde ich es gleich mal versuchen...

von B. J. (bjue)


Lesenswert?

> Das IC Register zu sichern und nachher wieder zu schreiben macht genau 0
> Sinn.
Richtig! Der Interrupt unterbricht sich nicht selbst! Alle Interrupts 
mit gleichem oder niedrigerem Level unterbrechen diesen Interrupt nicht.
Das IR Bit wird automatisch vom Prozessor zurückgesetzt.

In Deinem hier gezeigtem Code wird der Watchdog tatsächlich nicht 
bedient, allerdings gehört ja noch weiterer Code dazu, in dem der 
Watchdog wahrscheinlich bedient wird? Zum Testen würde ich den Watchdog 
definitiv erst mal ausschalten.

Wo werden denn die Port 3 Pins geschaltet und wie sieht der Code dazu 
aus?

von Andreas H. (andreas_h32)


Lesenswert?

So, anscheinend habe ich (zumindest) eine Stelle lokalisieren können. 
Anscheinend geht der Interrupt. Da ich die Bedungungen durch Variablen 
festlegen kann, habe ich eine speziellen Fall erzeugt, und zwar: Ziel 
folgt mit abstand <= dReferenz2. Bei der Berechnung von dReferenz2 
stockt er. Das Problem liegt bei "vEigen * vEigen". Das kriegt er 
irgendwie nicht gebacken. Ersetze ich vEigen durch den Wert, z.B. 2400 - 
läuft es. Es funktioniert auch, wenn ich eine Zwischenvariable 
deklariere und mit der weiter rechne. Also nochmal zusammengefasst:
1
vEigen = 2400;
2
dReferenz1 = vEigen*vEigen/2500; // geht NICHT!
3
4
dReferenz1 = 2400*2400/2500; // geht!
5
6
vEigen = 2400;
7
bla = vEigen * vEigen;
8
dReferenz1 = bla/2500; // geht!

Ich verstehe überhaupt nicht, wie das kommt! In meinen Augen ist das 
unlogisch!

von B. J. (bjue)


Lesenswert?

Als was sind die Variablen deklariert? Integer?
Passt das Ergebnis nicht in ein Integer gibt es Probleme...

von Andreas H. (andreas_h32)


Lesenswert?

B. Jue schrieb:
> Als was sind die Variablen deklariert? Integer?
> Passt das Ergebnis nicht in ein Integer gibt es Probleme...

Ja, sind alle Integer. Für die Berechnung sollte das ja reichen. Was 
mich wundert, ist das es mit einer Zwischenvariablen funktioniert...

von Andreas H. (andreas_h32)


Lesenswert?

B. Jue schrieb:
> Als was sind die Variablen deklariert? Integer?
> Passt das Ergebnis nicht in ein Integer gibt es Probleme...

War doch die Deklaration! Einige Variablen sind überlaufen. Vielen Dank 
für den Hinweis. Ich hoffe, das jetzt Ruhe ist! =)

von Pipeline (Gast)


Lesenswert?

Andreas H. schrieb:
> Ja, sind alle Integer. Für die Berechnung sollte das ja reichen.

Andreas H. schrieb:
> vEigen = 2400;
> dReferenz1 = vEigen*vEigen/2500;

Frage: Wieviel sind 2400*2400?
Antwort: ;-)

Andreas H. schrieb:
> Anscheinend geht der Interrupt.

Wie debugst du eigentlich?

von Andreas H. (andreas_h32)


Lesenswert?

Pipeline schrieb:
> Frage: Wieviel sind 2400*2400?
> Antwort: ;-)

Jaja=), unter Windows/Linux ist int meist ausreichend. Natürlich ist es 
bei einem 16-Bit uC anders... Hab ja schon vermutet, dass ich irgendwo 
gut auf dem Schlauch gestanden habe.

Pipeline schrieb:
> Wie debugst du eigentlich?

Das Debuggen ist recht abenteuerlich. Entweder spreche ich Ports an, 
oder schick mir über CAN was. Richtiges Debuggen geht nicht, weil ich 
den Tasking nur im Rahmen des Minimodul-Pakets nutzen kann. Das bedeutet 
compiliren --> flashen --> gucken.

von sdfgq5zg (Gast)


Lesenswert?

Wenn ich zwei 16-Bit-Integers multipliziere und in eine 
16-Bit-Integervariable ablege, dürfte ich gar keine Probleme mit dem 
Überlauf haben. Das Resultat mag nicht das sein, was man erwartet (obere 
16Bit abgeschnitten), das wird aber keinen Interrupt verhindern.

von falsche Fährte (Gast)


Lesenswert?

sdfgq5zg schrieb:
> das wird aber keinen Interrupt verhindern.

Hat es auch nicht. Der OT hat es nur nicht gemerkt.

von Andreas H. (andreas_h32)


Lesenswert?

Habe gerade festgestellt, dass temporären Variablen auch alle int sind. 
Wie Caste ich die denn richtig?
1
tBrems1 = ((vRel * 1000 / - aRelMax) / 2) + 1600 + 2000;
Hier liegt das Problem in "vRel*1000", wobei vRel auch 1000 gesetzt ist. 
Als Antwort bekomme ich da ungefähr 16000 raus. Casten mit 
(long)(vRel*1000) funktioniert nicht... Weiß jemand Rat?

von casting show (Gast)


Lesenswert?

Andreas H. schrieb:
> Casten mit
> (long)(vRel*1000) funktioniert nicht...

kann auch nicht, da du mit 16Bit rechnest und das übergelaufende Ergbnis 
auf 32Bit erweiterst. Du möchtest aber mit 32Bit rechnen.

Andreas H. schrieb:
> tBrems1 = ((vRel * 1000 / - aRelMax) / 2) + 1600 + 2000;

mal ungeprüft aus der hohlen Hand:
1
tBrems1 = (((long)vRel * (long)1000 / - aRelMax) / 2) + 1600 + 2000;
wobei ein cast genügen würde.

von casting show (Gast)


Lesenswert?


von Edgar F. (edgarfalke)


Lesenswert?

Ich möchte mit dieses Modul mit dem 167Cr zu legen.
Kannst Du mich mal anmailen.
Edgar

von Edgar F. (edgarfalke)


Lesenswert?

Hallo Andreas,
Ich bin Modellbahner mit einer mittelgroßen µC gesteurten Anlage.
Der µC SAB88C166 ist verreckt und nicht mehr erhältlich.
Als Ersatzoption sehe ich das Phytec Minimodul 167, das ich aus einen 
Restposten günstig erwerben kann.
Ich bin Grufti und mit µCs nicht vertraut.
ICh hätte jetzt 2 Fragen
1. Hast Du einen Schltplan vom Minimodul 167, den Du mir als PDF 
zumailen kannst? e,falke@web.de
2. Was für Geräte braucht man für das Programmiern des Moduls und seiner 
Flash Eproms und würdest Du mir dabei ggffls. helfen ?

von Andreas (Gast)


Lesenswert?

Hallo Edgar. Ich bin zur Zeit nicht in DE. Ich schaue in meiner 
Dokumentation, wenn ich wieder zurück bin. Meine Erfahrungen mit dem 
C167 habe ich im Rahmen meiner Diplomarbeit gemacht. Die liegt aber 
schon was zurück. :)

Grüße
Andreas

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.