Forum: Mikrocontroller und Digitale Elektronik Hardware-Interrupt R8C/13


von Peter (Gast)


Lesenswert?

Hallo,

ich hab ein kleines Problem an den ich nicht weiterkomme.

Ich habe für mein µC R8C/13 ein Programm geschrieben das ein 
X_Timer-Interrupt und ein UART0_RX-Interrupt verwendet.

Der X_Timer hat ein Prioritätslevel von 1.
Der UART0_RX hat ein Prioritätslevel von 6.
1
txic  = 0x02;    //Timer interrupt priority level = 2
2
s0ric   = 0x06;    //UART0 interrupt priority level = 6

Das heißt das der UART0_RX-Interrupt "bevorzugt" wird. Ich habe nun das 
Problem, dass ich den UART0_RX-Interrupt zwischenzeitlich auf ein 
anderes Level ändern muss.
1
s0ric   = 0x01;    //UART0 interrupt priority level = 1

Wenn ich den interrupt jetzt wieder auf Level 6 zurück ändern will, 
funktioniert das ganze aber nicht.
1
s0ric   = 0x06;    //UART0 interrupt priority level = 6


Hat jemand eine Idee ???

Gruß

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Hast du vor der Zuweisung des neuen IPL das IR Bit getestet, ob noch ein 
IRQ ansteht (requested ist)? Wenn das der Fall wäre, würde die Zuweisung 
nicht funktionieren. (Hardwaremanual 19.2.6)

Mit dem Holzhammer könntest du diesen IRQ disablen, das IR Bit löschen 
und dann die Zuweisung machen und dann den IRQ wieder enablen.

Damit keine Zeichen verloren gehen, könnte man auch anders arbeiten: In 
der UART Interruptroutine ein globales Flag aus dem Userprogramm 
abfragen, ob die IPL Maske geändert werden soll und entsprechend 
reagieren. Zu diesem Zeitpunkt sollte die UART ja mit hoher 
Wahrscheinlichkeit leer sein bzw. das IR Bit auf 0 stehen.

von Peter (Gast)


Lesenswert?

Hallo Stefan,

Stefan B. schrieb:
> (Hardwaremanual 19.2.6)

Das hatte ich übersehen, ich werde das damit mal probieren.

Danke für den Tipp


Gruß
Peter

von Peter (Gast)


Lesenswert?

Hallo,

ich mach das genauso, wie es im Handbuch steht, nur es funktioniert 
nicht. Was mache ich falsch ?

Gruss

von Peter (Gast)


Lesenswert?

Kann mir keiner weiterhelfen ?

Gruss

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Ich kann dir nicht weiterhelfen, weil du keinen Quellcode zeigst.

von Peter (Gast)


Lesenswert?

Hallo,

hier der Code:
1
asm("FCLR I");    //Interrupt ausschalten
2
s0ric   = 0x00;   //Interrupt disable
3
ir_s0ric = 0;
4
asm("nop");    
5
asm("nop");
6
asm("FSET I");    //Interrupt einschalten
7
8
      
9
Warten_ms(3000);  //Dauer bis zum wegdrücken
10
Senden(Befehl[2]);  //wegdrücken
11
Warten_ms(3000);  //warten    
12
Senden(Befehl[1]);  //anrufen
13
Warten_ms(15000);  //Dauer des Anrufs
14
Senden(Befehl[0]);  //auflegen
15
      
16
asm("FCLR I");    //Interrupt ausschalten
17
s0ric   = 0x06;   //Interrupt Level 6
18
ir_s0ric = 0;
19
asm("nop");    
20
asm("nop");
21
asm("FSET I");    //Interrupt einschalten

Wenn ich Ihn einmal ausschalte, lässt er leider nicht wider einschalten, 
ich hoffe Du kannst helfen.

Gruss

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Tja was soll ich sagen. Unter debugbarem Code verstehe ich was anderes.

Der Codefetzen eingebettet in ein provisorisches main() konnte 
fehlerfrei simuliert werden. s0ric konnte auf 0 bzw. 6 gesetzt werden. 
ir_s0ric konnte gelöscht werden.

Interruptinitialisierung und Interruptroutinen fehlen ja, daher war 
diese Simulation schnell erledigt :-)

Hast du irgendwo im Programm IPL im FLG Register geändert? Es darf nicht 
6 oder 7 sein!

von P. F. (pfuhsy)


Lesenswert?

Hallo,

sorry. Ich schicke Dir am besten den kompletten Code sobald ich zuhause 
bin. Du hast recht wenn Du sagst, dass man mit so ein paar Codefetzen 
nichts anfangen kann.

Gruss

von P. F. (pfuhsy)


Angehängte Dateien:

Lesenswert?

Also, hier de komplette Code.

von P. F. (pfuhsy)


Lesenswert?

Hallo,

also das alles hat folgenden Hintergrund, vielleicht hast Du ja einen 
besseren Lösungsansatz.

Zur Hardwareverschaltung:
Ich hab den R8C/13 über UART an das Bluetoothmodul BTM-222 verbunden. 
Der BTM-222 ist über Bluetooth an ein Handy verbunden.

Zur Idee und Programmierung:
Ich habe im Code 2 Interrupts. Ein Time-Interrupt mit Level 2 und den 
besagten UART0-Interrupt mit Level 6.
Der Time-Interrupt soll nichts anderes machen als alle 20ms (50 Hz) eine 
Variable mit +1 zu Inkrementieren. Damit will ich Zeiten haben, die das 
Programm "abbummeln" kann, der Code soll also z.B. 5000 ms warten bis er 
den nächsten Schritt ausführt.
Der UART0-Interrupt soll dafür gut sein, dass er eine Funktion ausführt 
(Empfangene Daten im Array ablegen), sobald er Daten von den verbundenen 
Handy bekommt. Da ich nicht immer weiß wann die Daten kommen, hab ich 
mir gedacht dies einfach mit einem Interrupt zu machen. Dieser ist 
natürlich "höher gestellt" als der Time-Interrupt, damit mir Daten die 
während des Time-Interrupts gesendet werden, nicht verloren gehen. Nun 
hatte ich aber, in der Funktion Ueberwachung, folgendes Problem. In der 
If-Schleife "Testanruf", habe ich eine Abfrage, nach dem Inhalt im Array 
des UART0-Interrupts, und Warteschleifen. Das blöde ist jetzt, das das 
Program an der Stelle nicht weitergeht und hängen bleibt. Ich hab 
einfach mal den UART0-interrupt ausgeschaltet und es hat ohne Probleme 
funktioniert. Ich kann jetzt nicht genau nachvollziehen warum sich das 
so verhält, da sich im Array (empfangene Daten) nichts befindet, es 
funktioniert aber so.

Daher kommt die Idee den "störenden" Interrupt kurzzeitig abzuschalten. 
hast Du vielleicht eine andere Idee wie man das Problem lösen könnte.

Gruss

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Mit dem letztens geposteten Codestück konnte ich dein Problem (UART RX 
wird nach dem Ändern seines IPLs nicht mehr angesprungen) reproduzieren 
aber noch nicht lösen. Das Problem interessiert mich und ich schaue 
heute abend weiter danach. Gestern hat das HEW Einrichten und Projekt 
aufsetzen die meiste Zeit verschlungen.

Jeder Interrupt hat sein eigenes Interrupt Request Flag, d.h. selbst bei 
gleichem Interrupt Prioritätslevel gehen keine Interrupts verloren 
wenn keine zwei Interrupts für den gleichen Vektor eintreffen. Wenn A 
und B Interrupts bekommen und wenn A vorrangig zu B ist, wird B nach dem 
RETI von A aufgerufen. Aber zwei Interrupts für B können eintreffen, 
wenn ein (mehrere) vorrangige(r) Interrupt A zu lange abgearbeitet wird.

Bei einem default vorrangigen Timer X alle 20ms der bloß einen Zähler 
erhöht gegen eine default nachrangige UART RX mit 19200 BAUD, sehe ich 
da keine Gefahr. Das könnte man mal berechnen oder testen.

Dein Code hat auch noch ein Problem mit dem nicht-interruptfesten 
Zugriff/Reset des Index i des RX-Datenpuffers wenn der RX-Puffer 
entleert wird.

von P. F. (pfuhsy)


Lesenswert?

Ok, vielen dank für die Infos. Ich hab schon mehrere Probleme des Codes 
gelöst und damit immerwieder neue Probleme ans Tageslicht gebracht. Ich 
hba gemerkt, dass man dafür einen langen Atem braucht.

Stefan B. schrieb:
> Das Problem interessiert mich und ich schaue
> heute abend weiter danach.

Vielen Dank, ich bin mal gespannt. Ich versuche auch noch ein parr 
Sachen vielleicht finde ich ja noch was.

Stefan B. schrieb:
> wenn ein (mehrere) vorrangige(r) Interrupt A zu lange abgearbeitet wird.

Was heißt den "zu lange" ?

Stefan B. schrieb:
> Bei einem default vorrangigen Timer X alle 20ms der bloß einen Zähler
> erhöht gegen eine default nachrangige UART RX mit 19200 BAUD, sehe ich
> da keine Gefahr. Das könnte man mal berechnen oder testen.

Wie berechnet man den sowas ?



Hast du vielleicht noch eine Idee warum im Eingangpuffer manchmal ein 
paar empfange Daten verloren gehen. Wenn ich z.B. "atd0123456" sende, 
bekomme ich manchmal nur"atd01" wieder, beim nächsten senden dann "atd" 
und vielleicht beim 3. mal bekomme ich komplett auch das wieder was ich 
sende. Deswegen habe ich dort eine Schleife eingebaut, die das Senden 
sollange wiederholt, bis ich ein "OK" sehe. Damit umgehe ich das Problem 
aber nur, vorhanden ist es trotzdem.

Gruss

von gk (Gast)


Lesenswert?

Peter F. schrieb:
> Wie berechnet man den sowas ?

Berechne die minimale Zeit zwischen zwei Zeichen bei 19200. Deine 
Timerroutine muss entsprechend schnell abgearbeitet sein, damit kein 
Zeichen verloren geht.
gk

von Stefan B. (stefan) Benutzerseite


Angehängte Dateien:

Lesenswert?

So könnte ich mit dem Programm leben. Das zeitweilige Ausschalten des 
UART0 RX beim Testanruf funktioniert jetzt IMHO. Eingaben über UART0 RX 
während des Anrufes und in den Wartezeiten werden ersatzlos verworfen. 
Nach dem Anruf wird der IRQ auch wieder eingeschaltet und weitere 
Testanrufe sind über Eingaben über UART0 RX möglich. Ich habe nirgends 
echt angerufen sondern mit einem Terminalprogramm simuliert.

von P. F. (pfuhsy)


Lesenswert?

Ui...da hast Du Dir ja richtig Mühe gegeben. Das werde ich natürlich 
austesten und Dir Rückmeldung geben. Danke für die Hilfe erstmal.

von Olaf (Gast)


Lesenswert?

Das ist ja schon eine weile her das ich mit dem r8c13 rumgespielt habe.
Aber warum machst du das in deiner Interruptroutine?

//Daten am Empfang (RX) abholen
while (!ri_u0c1);//Warten bis Empfangspuffer voll

Wenn der Interrupt aufgerufen wird dann solle es sichergestellt sein das 
du ein Byte aus von deiner Schnittstelle abholen kannst. Dein while ist 
also mindestens mal unnoetig. Und eine eventuelle Endlosschleife ist 
sowieso schlecht und im Interrupt ist sie doppelt schlecht.

Kann es vielleicht sein das der Interrupt bereits dein Bit zuruecksetzt 
und dein while auf das naechste Byte wartet?

Olaf

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Peter F. schrieb

> Ui...da hast Du Dir ja richtig Mühe gegeben. Das werde ich natürlich
> austesten und Dir Rückmeldung geben. Danke für die Hilfe erstmal.

Jo, ein paar Namen sind aussagekräftiger geworden und manche 
auskommentierte Abschnitte aus deinem Original sind rausgeflogen. nicht 
wundern bzw. aus dem Backup einpflegen, wenn es gebraucht wird.

Olaf schrieb

> //Daten am Empfang (RX) abholen
> while (!ri_u0c1);//Warten bis Empfangspuffer voll
>
> Wenn der Interrupt aufgerufen wird dann solle es sichergestellt sein das
> du ein Byte aus von deiner Schnittstelle abholen kannst. Dein while ist
> also mindestens mal unnoetig. Und eine eventuelle Endlosschleife ist
> sowieso schlecht und im Interrupt ist sie doppelt schlecht.

U.a. hatte ich mich über das Gleiche gewundert und auch in Olafs Sinn 
geändert.

von P. F. (pfuhsy)


Lesenswert?

Hallo,

also ich hab das ganze mall ausgetest leider funktioniert der testanruf 
nicht. Bzw. nach dem resetn funktioniert das ganze 1x dannach nicht 
mehr.

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Schade war ein Versuch. Aber bei so einem komplexen Projekt ist es 
wahrscheinlich, dass man nicht 100% der Bugs mit dem ersten und einzigen 
Schuß erledigt.

Ferndiagnostisch gesehen stehe ich mit 
Beitrag "Re: Hardware-Interrupt R8C/13" im unbeleuchteten 
Tunnel, Hände auf dem Rücken.

Vielleicht magst du ja die eingebauten Debug- und Simulationshinweise 
verwenden, um herauszufinden, ob der R8C das Problemkind ist oder das 
von mir nicht berücksichtigte BTM oder das von mir nicht berücksichtigte 
Telefon.

Die nächste Maßnahme von mir an deiner Stelle wäre einen UART/RS232 
Sniffer anzuklemmen und wenistens die Kommunikation zwischen R8C und BTM 
abzuhören und zu loggen.

von P. F. (pfuhsy)


Lesenswert?

Hmm, Schade. Ein paar Sachen habe ich übernommen, da ich diese für 
ziemlich gut und übersichtlich finde.

Hast Du denn eine Idee warum beim Empfang, der vom BTM gesendeten 
Signale, hin und wieder mal etwas verschluckt wird ? Kann es mit den 
Time-Interrupt zusammen hängen, so nach dem Motto: Wenn der 
Time-Interrupt anspringt und wieder "zurückkommt" hat er in der Zeit ein 
Zeichen übersehen. Aber das darf doch eigentlich nicht sein oder, der 
Interrupt vom UART0 unterbricht doch eigentlich den Time-Interrupt.


Gruss

von P. F. (pfuhsy)


Lesenswert?

Stefan B. schrieb:
> Vielleicht magst du ja die eingebauten Debug- und Simulationshinweise
> verwenden, um herauszufinden, ob der R8C das Problemkind ist oder das
> von mir nicht berücksichtigte BTM oder das von mir nicht berücksichtigte
> Telefon.

Das werde ich sowieso mal machen, kann aber ein bisschen dauern.

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.