Beitrag
von Ralf » 19 Mär 2004 - 09:41
Hi Ansgar!
Das ist garnicht so kompliziert, wie es für dich zu sein scheint.
Allerdings bin ich mir nicht ganz sicher, was du da eigentlich für ein
Interupt zusammenbastelst:
> #pragma INTCALL 25 c_func()
Damit deklarierst du eine Funktion, die du als Software(!)-Interrupt
(#25) nutzen willst. Das kann nützlich sein, wenn du aus deiner SW(!)
heraus Interrupts generieren willst, anstatt es die M16C-Peripherie
(z.B. Uart) oder externe Komponenten (z.b. INT-Leitung) erledigen zu
lassen. War das wirklich deine Absicht?
> #pragma INTCALL 29 WheelSensor_ISR();
Dies ist Code aus dem SIxO: Interrupt 29 ist eigentlich der HW-Int0 Eingang des M16C, an dem der Radsensor hängt. Der Interrupt wird also eigentlich durch HW ausgelöst. In meiner 'Vehicle-Simulation' tue ich aber einfach so, als ob das Rad sich dreht, in dem ich (mehr oder weniger) regelmäßig genau diese Int0-ISR aus meiner SW(!) heraus aufrufe. Um dies tun zu können, muss ich o.a. Pragma nutzen, sonst setzt der Compiler nicht die für eine ISR nötige Call-Prozedur auf (Register retten, etc.)
Allgemein zu Interrupts im M16C/NC30:
Wenn du gewöhnliche ISR aufsetzen willst, sind diese Schritte zu erledigen:
0. HW-Interrupt enablen
Die entsprechenden M16C-Register, die den HW-Interrupt lösen können, müssen entsprechend konfiguriert werden. Aber das hast du ja wohl schon herausgesucht?
1. Korrekten Interrupt heraussuchen
Nr.+Funktion des Interrupts heraussuchen, am besten aus sect30.inc, dort sind sowohl Nr. als auch Bedeutung aufgeführt. Wenn es um den Uart1 geht, ist dies z.B. Interrupt Vector 19(Uart1-TX) und 20(Uart1-RX). Dort ist z.Zt nur ein 'dummy_int' abgelegt, die nichts tut und z.Zt. auch nicht aufgerufen wird.
2. InterruptServiceRoutine definieren
Irgendwo im C-Code (oder bei dir Assembler?) muss deine ISR ja implementiert sein. Die nötige Syntax/Einschränkungen findest du NC30 Manual. Sie muss neben der normalen C-Definition auf jeden Fall mit dem 'INTERRUPT'-Pragma (nicht zu verwechseln mit 'INTCALL') versehen werden. Hier als Beispiel die Radsensor-ISR:
> #pragma INTERRUPT WheelSensor_ISR
> void WheelSensor_ISR(void) {...}
3. ISR in InterruptVectorTable (IVT) ablegen
Die ISR selbst ist ja nun deklariert. Im Prinzip kannst du sie jetzt jedem beliebigen HW-Interrupt unterschieben. Wenn du aber den Uart1-RX/TX Interrupt bedienen willst, musst du sie in der IVT anstelle(!) der 'dummy_int' einsetzen, also die Zeilen mit den Vektoren 19+20 in der 'sect30.inc'. Und damit der Assembler (AS30) nicht rummmeckert, weil er das Symbol (ISR-Namen) nicht kennt, muss sie zusätzlich in 'sect30.inc' weiter oben angemeldet werden:
> .glb _WheelSensor_ISR ; as int0 isr vector
Der führende UnderScore vor dem Fkt-Namen ist nur in diesem Assemblerfile nötig, weil nach dem Compilieren alle Funktionsnamen den Underscore verpasst bekommen. ACHTUNG: In der IVT-Definition (sect30.inc) vorsichtig editieren! Man kann eine Menge eigenartiger Efekte generieren, wenn mann aus Versehen eine Zeile zuviel/zuwenig in der IVT stehen hat, alle ISRs verrutschen um eine Stelle...
Das ist alles. Etwas ausführlich beschrieben, ich gebe es zu. Aber lieber zuviel, als zuwenig. Ich hoffe, es hilft dir.
Ralf