Da das die Standard-UART jedes PCs ist (ganz alte verwendeten noch den
Fifo-losen Vorgänger 16450 bzw. 8250), dürfte sie in PC-Hardware-Büchern
wie "Data Becker - PC Intern" beschrieben sein.
Was willst Du erreichen?
Hallo, ja und zwar möchte ich das ganze Vorgehen für die ISR bzw COM
Interrupt Handler beschreiben.
1
void__cdeclCommIntHandler(ETSINTREGS*pRegs);
2
3
voidCOM(void)
4
{
5
...
6
UartIntVecNum=EtsPicGetIRQIntNumber(UartIRQNum);
7
// UartIntVecNum = 0x0C
8
SaveFlags=EtsSetInterruptFlag(ETS_DISABLEINTS);
9
EtsSaveInterruptHandler(UartIntVecNum,&CommDesc);
10
EtsSetInterruptHandler(UartIntVecNum,CommIntHandler);// set handler
11
...
12
}
//
// Saved register block passed to interrupt handlers registered
// with EtsSetInterruptHandler() and EtsSetExceptionHandler().
// These fields contain the register contents at the time of the
// interrupt. The interrupt service routine can modify the
// values in the passed structure in order to change the user
// registers on return from the interrupt.
//
// Note: The FS and GS registers are neither saved nor restored
// by the interrupt handler framework. If a user interrupt handler
// wants to use either of these registers, it must preserve them itself!
//
typedef struct tagETSINTREGS
{
DWORD Ebp; // [00]
DWORD Eax; // [04]
DWORD Ebx; // [08]
DWORD Ecx; // [12]
DWORD Edx; // [16]
DWORD Esi; // [20]
DWORD Edi; // [24]
DWORD Gs; // [28]
DWORD Ds; // [32]
DWORD Es; // [36]
DWORD IntNum; // [40]
DWORD Ecode; // [44]
(Zero if int w/o error code)
DWORD Eip; // [48]
DWORD Cs; // [52]
DWORD Eflags; // [56]
} ETSINTREGS, *PETSINTREGS;
//----------------------------------------------------------------------
-------
// EtsSetInterruptHandler - Install a C function as an interrupt handler
//
// This API installs a C function as an interrupt handler
// for the specified interrupt. The handler is entered as a normal
// C function (__cdecl calling sequence) with interrupts disabled
// and receives a pointer to the saved register set on the stack
// as its argument. The saved register set includes all general
// purpose registers, DS, ES, and EFLAGS. The FS and GS registers
// are neither saved nor restored; if the handler alters them, it
// must restore them itself before returning. The handler
// is expected to process the interrupt and may modify the
// saved register set on the stack if wishes to
// alter the context of the interrupted code. When the handler
function
// returns, the saved registers are popped off the stack and
// control returns to the interrupted code.
//
// The return value from the function is TRUE if successful or
FALSE
// if an error occurs.
//
//----------------------------------------------------------------------
-------
BOOL __cdecl EtsSetInterruptHandler(unsigned IntNumber,
PETSINTHANDLER pHandler);
Ich verstehe da das genau Vorgehen nicht.
Was geschieht bei diesem Funktionsaufruf genau:
>>EtsSetInterruptHandler( UartIntVecNum, CommIntHandler);
Ist der CommIntHandler ein Zeiger auf einen bestimmten STACK?
Diese Definitionen und Funktionen haben nichts mit der UART zu tun,
sondern scheinen von irgendeinem Betriebssystem zu sein - versuchst Du
Dich da gerade mit dem Win32 DDK?
Was auch immer das da sein soll, das hat nach wie vor nichts mit der
UART zu tun.
Warum im Interrupthandler der Interruptcontroller befummelt wird,
entzieht sich meinem Verständnis; die übliche Vorgehensweise in einem
PC-Interrupthandler (unter DOS, also praktisch ohne Betriebssystem)
sieht so aus:
[int]
Schnittstellenstatus aus UART auslesen
(Warum hat die UART den Interrupt ausgelöst?)
Je nach Schnittstellenstatus zu erledigende Dinge tun
(Zeichen abholen und speichern oder Zeichen aus Sendepuffer lesen und an
UART übertragen oder ...)
Interruptcontroller die Beendigung der Interruptroutine mitteilen
[reti]
Es ist nicht erforderlich, in der Interruptroutine irgendwelche
Interruptvektoren zu bestimmen, denn das geschieht schon implizit durch
Aufruf der richtigen Interruptroutine.
Dann darf das aber nicht mit dem Namen der Interruptroutine beschriftet
sein.
Im übrigen wird auf PC-Hardware (unter DOS, also ohne Betriebssystem)
ein Interrupthandler dadurch installiert, daß seine Startadresse in die
Interrupttabelle im Arbeitsspeicher eingetragen wird. Danach muss nur
noch dem Interruptcontroller mitgeteilt werden, daß es den
Interrupthandler gibt (setzen/löschen des erforderlichen Bits) und
fertig.
Hier mal etwas Pascal-Quelltext:
Interrupthandler
1
procedure v24_irq;
2
{ interruptroutine. Wird fr jedes auf 8250 ankommendes Zeichen aufgerufen }
und ist natürlich vor dem Setzen und Initialisieren des
Interrupthandlers durchzuführen.
Auch wenn das Turbo-Pascal-Code ist, lässt sich das recht leicht auch in
C ausdrücken.
Was Du da gepostet hast, hat mit irgendeinem Betriebssystem oder
irgendeiner betriebssystemartigen Umgebung zu tun.
Danke für die Hilfe!!!
Ich habe es jetzt mal so in Sätzen zusammengefasst:
Das Senden und Empfangen von der seriellen Schnittstelle funktioniert
hier Interruptgesteuert. Dazu wurde ein Interrupt Handler eingerichtet,
in diesem wird das Interrupt Identifikations Register ausgelesen. Über
das Interrupt Identifikations Register, erfährt der Interrupt
Controller, wegen welchem Ereignis der Interrupt ausgelöst wurde. Der
Interrupt Handler wird dadurch installiert, dass seine Startadresse in
die Interrupttabelle im Arbeitsspeicher eingetragen wird. Danach wird
noch dem Interrupt Controller mitgeteilt, dass der Interrupt Handler
existiert.
Sobald der UART ein Datum empfängt bzw. ein Datum an die UART übergibt,
wird ein Interrupt ausgelöst, dieser veranlasst, dass der Interrupt
Handler gestartet wird.
(Auf dem Board läuft ein 32Bit Echtzeitbetriebssystem, dort kann man auf
die Win API zugreifen)
> Über das Interrupt Identifikations Register, erfährt der Interrupt> Controller, wegen welchem Ereignis der Interrupt ausgelöst wurde.
Nein. Der Interrupt-Controller hat damit nichts zu tun, durch das
Auslesen des IIR erfährt der Interrupt-Handler (also Deine Software),
welches Ereignis den Interrupt ausgelöst hat.
Wann der/die UART Interrupts auslöst, wird durch die Initialisierung
festgelegt, dort lassen sich Interrupts bei Datenempfang, leerem
Senderegister, Änderungen der Handshakeleitungen etc. konfigurieren.
Da Du aber ein Betriebssystem verwendest, werden etliche Details anders
gehandhabt werden; das Betriebssystem selbst verwaltet die Behandlung
des Interruptcontrollers und auch das Einrichten eines Interrupthandlers
durch entsprechende Funktionsaufrufe.
Daher sind die in den von mir geposteten Pascal-Sourcen getätigten Dinge
nur mit äußerster Vorsicht zu genießen.
Ist das 32-Bit-Echtzeitsystem zufälligerweise OnTime RTOS-32?
>Ich habe es jetzt mal so in Sätzen zusammengefasst:
Schön aber was soll das?
>Das Senden und Empfangen von der seriellen Schnittstelle funktioniert>hier Interruptgesteuert...
Brauchst du das für einen Vortrag oder willst du irgendwas
programmieren?
Wie das mit den Interrupts funktioniert wissen zumindest die die dir
helfen könnten. Es ist nur unklar was du eigentlich willst.
>Sobald der UART ein Datum empfängt bzw. ein Datum an die UART übergibt,>wird ein Interrupt ausgelöst, dieser veranlasst, dass der Interrupt>Handler gestartet wird.
nicht ganz der 16c550 kann auch erst bei einem bestimmten Füllstand
Interrupts auslösen. Also wenn mehrere Daten vorhanden sind.
>(Auf dem Board läuft ein 32Bit Echtzeitbetriebssystem, dort kann man auf>die Win API zugreifen)
Die erste richtige Info, wie heißt das Betriebssystem und was willst du
eigentlich machen?
Als Betriebssoftware wird die ETS - TNT Embedded ToolSuite von PharLap
eingesetzt. Diese ist ein 32 bit Real-Time Operating System (RTOS), das
sich durch Unterstützung eines Teils der WIN32 API leicht in Windows
Systeme integrieren lässt.
Ich möchte eigentlich den ganzen Vorgang von der seriellen Kommunikation
(UART) dokumentieren. Mein Programm benutzt ein Interrupt Handler für
die serielle Schnittstelle.
1. Beschreibung UART
2. Initialiserung UART
3. Aktivierung Interrupt für COM
4. Erstellung eines Interrupt Handlers für COM
5. Funktionsweise des Interrupt Handlers
> Ja das ist ein 32-Bit-Echtzeitsystem (OnTime RTOS-32).> Als Betriebssoftware wird die ETS - TNT Embedded ToolSuite> von PharLap eingesetzt.
Was denn nun? Das sind zwei vollkommen unterschiedliche Paar Schuhe.
Ich hab nochmals meinen Text einwenig verändert:
Das Senden und Empfangen von der seriellen Schnittstelle funktioniert
hier Interruptgesteuert. Dazu wurde ein Interrupt Handler eingerichtet,
in diesem wird das Interrupt Identifikations Register ausgelesen. Über
das Auslesen des Interrupt Identifikations Registers, erfährt der
Interrupt Handler, welches Ereignis den Interrupt ausgelöst hat. Der
Interrupt Handler wird dadurch installiert, indem seine Startadresse in
die Interrupttabelle im Arbeitsspeicher eingetragen wird. Danach wird
dem Interrupt Controller mitgeteilt, dass der Interrupt Handler
existiert.
Sobald der UART ein Datum empfängt bzw. ein Datum an die UART übergibt,
wird ein Interrupt ausgelöst, dieser veranlasst, dass der Interrupt
Handler gestartet wird.
(Dies soll eigentlich einfach gehalten werden)
> Fakt ist, das ist ein ein 32 bit Real-Time Operating System (RTOS).> Dieses Programmiere ich mit Visual Studio 6.0 (C++).
Du wirst unglaubwürdig, da Du zwei unterschiedliche Produkte aufgeführt
hast. Würdest Du tatsächlich mit einem davon arbeiten, wüsstest Du, wie
es heißt.
Trotzreaktionen sind hier wenig hilfreich.
> > Ich programmiere unter Linux.>> > Ich programmiere unter Windows.>> Was denn nun?>> > Fakt ist, das ist ein 32-Bit Betriebssystem.
Erkennst Du Deine "Argumentation" wieder?
Sei's drum.
> Sobald der UART ein Datum empfängt bzw. ein Datum an die UART übergibt,
Den Sendeinterrupt (TXEMPT) solltest Du besser anders beschreiben.
Sobald der UART ein in sein Senderegister geschriebenes Zeichen (trenne
Dich vom unglücklichen "Datum"!) versendet hat, wird der "transmit
register empty"-Interrupt ausgelöst, um zu signalisieren, daß ein neues
Zeichen versendet werden kann.
Ich habe bereits dargelegt, daß es einen ganz erheblichen Unterschied
macht, worunter/wofür man einen Interrupthandler schreibt - es ist was
anderes, ob man einen Interrupthandler für RTOS-32 (das ist ein Produkt!
Keine generische Bezeichnung) oder für Pharlap TNT ETS schreibt.
Der Windows-/Linux-Vergleich ist eine Metapher für Deine Reaktion auf
die Frage, wofür Du da was zu schreiben glaubst.
Das Handling des ganzen Geraffels ist eben unterschiedlich und
deswegen kommt es darauf an, die Rahmenbedingungen zu kennen und auch zu
nennen.
Dir aber scheint es wohl nur um einen Aufsatz oder dergleichen zu gehen
...
Ich habs jetzt so geschrieben:
Sobald der UART ein in seinem Senderegister geschriebenes Zeichen
versendet hat, wird „transmit holding register empty“- Interrupt
ausgelöst, um zu signalisieren, dass ein neues Zeichen versendet werden
kann. Im umgekehrten Fall, wenn ein Zeichen im Empfangsregister
vorliegt, dann wird „receive data is available“- Interrupt ausgelöst,
damit wird signalisiert dass ein neues Zeichen empfangen werden kann.
Ich habe eher das Gefühl, du machst einen Teil einer Belegarbeit an der
Uni,
die anderen haben es programmiert und da du Probleme dabei hattest, hast
du dir den Dokumentationsteil rausgesucht.
Wenns wirklich so sein sollte: Schlechte Wahl, das setzt nämlich erst
recht voraus, daß du alles verstehst.
Deine Bezeichnungen lassen erkennen, daß du in Hardwarenaher
Programmierung nicht firm bist.
>Ich habs jetzt so geschrieben:>...
ist etwas besser, aber deutlicher wird es mit einem Statediagram und
Text
>dann wird „receive data is available“- Interrupt ausgelöst,>damit wird signalisiert dass ein neues Zeichen empfangen werden kann.
das ist Müll, wenn du ein Zeichen bekommst solltest du es abholen
Ich hoffe das stimmt was ich hier geschrieben habe:
Das Senden und Empfangen von der seriellen Schnittstelle funktioniert
hier Interruptgesteuert. Dazu wurde ein Interrupt Handler eingerichtet,
in diesem wird das Interrupt Status Register ausgelesen. Über das
Auslesen des Interrupt Status Registers, erfährt der Interrupt Handler,
welches Ereignis den Interrupt ausgelöst hat.
Der Interrupt Handler wird dadurch installiert, indem seine Startadresse
in die Interrupttabelle im Arbeitsspeicher eingetragen wird. Danach wird
dem Interrupt Controller mitgeteilt, dass der Interrupt Handler
existiert.
Sobald der UART ein in seinem Senderegister geschriebenes Zeichen
versendet hat, wird „transmit holding register empty“- Interrupt
ausgelöst, um zu signalisieren, dass ein neues Zeichen versendet werden
kann. Im umgekehrten Fall, wenn ein Zeichen im Empfangsregister
vorliegt, wird „receive data is available“- Interrupt ausgelöst, damit
kann nun das Zeichen vom Empfangsregister abgeholt werden.
> Danach wird dem Interrupt Controller mitgeteilt, dass der Interrupt> Handler existiert.
Ich weiß ja nicht was da für ein Interruptcontroller drauf ist aber
normalerweise wird der betreffende Interrupt nur freigeschaltet.
Es ist ein 8259 Controller. Der kann doch 15 Geräte verwllten oder?
void __cdecl CommIntHandler(ETSINTREGS *pRegs);
void COM(void)
{
...
UartIntVecNum = EtsPicGetIRQIntNumber(UartIRQNum);
// --> UartIntVecNum = 0x0C
....
EtsSetInterruptHandler( UartIntVecNum, CommIntHandler); // set handler
...
}
Ich hab da noch immer Probleme damit. Ich beschreibe es mal mit meinen
eigenen Worten.
1. UartIntVecNum = EtsPicGetIRQIntNumber(UartIRQNum);
--> Nr. von der Vectortabelle auslesen, ist hier 0x0C
(Warum Vectortabelle?)
2.EtsSetInterruptHandler( UartIntVecNum, CommIntHandler); // set handler
--> Interrupt Handler einrichten: 0x0C und Adresse vom Interrupt Handler
der Funktion übergeben. Dann passiert irgendwas im Stack.
Weiss nicht so ganz obn dies hier stimmt.
Ich verstehe das genau Zusammenspiel UART, Interrupt Controller,
Interrupt Handler noch nicht ganz.
Kann mir einer erklären wie es im Prinzip funktioniert?
Ein 8259 kann 8 Interrupts verwalten - man kann ihn aber auch
kaskadieren und bekommt dann Weitere.
Wie ein Interrupt abläuft:
Byte wurde empfangen -> UART akiviert die IRQ-Leitung -> IRQController
prüft, ob aktiviert -> IRQController aktiviert die INT-Leitung zum
Prozessor -> wenn Interrupts dort freigeschaltet sind: Prozessor macht
seinen aktuellen Befehl noch fertig, schreibt die aktuelle CS:IP Adresse
auf den Stack und setzt die INTA-Leitung zum IRQController ->
IRQController überträgt den Vector (Vectortabelle ist ein Array mit den
Anfangsaddressen der Interrupthandler-Funktionen, Vector der Index eines
Eintrages in dieser Tabelle) -> CPU springt die zum Vector passende
Interrupthandler-Funktion an -> Interrupthandler fragt die Hardware ab
-> UART deaktiviert seine IRQ-Leitung -> Interrupthandler macht ein IRET
(oder wars RETI?) -> CPU macht da weiter wo sie unterbrochen wurde.
Guten Abend, ich habe doch noch Probleme mit dem Interrupt Handler.
Und zwar es wird doch zuerst die Vectornummer von der Schnittstelle COM1
(0x3F8) ausgelesen. Dies ist hier 0x0C. Dann wirdn doch der eigentliche
Interrupt Handler installiert bzw. eingerichtet. Die Funktion
EtsSetInterrupt Handler erhält zwei Parameter. 1. Parameter =
Vectornummer 0x0C, 2. Parameter die Adresse vom Interrupt Handler. Ist
das jetzt richtig so?
Ich möchte nur diesen Vorgang beschreiben. Mir ist nun nicht ganz klar
ob meine Aussage so stimmt.
1
void__cdeclCommIntHandler(ETSINTREGS*pRegs);
2
3
voidCOM(void)
4
{
5
...
6
UartIntVecNum=EtsPicGetIRQIntNumber(UartIRQNum);
7
...
8
EtsSetInterruptHandler(UartIntVecNum,CommIntHandler);// set handler
2F8 und 3F8 sind IO adressen, wo das UART montiert ist. Was soll das
Ganze ? Weder unter Linux, noch unter Windows schreibt jemand einen
Interrupthandler. Dort ist die Thematik eine ganz andere. Wie
manoevriert man in den Tiefen des verbockten Windows, ohne das alles
abschmiert. Sogar kundige Spzialisten verbraten da schnell mal 2 Monate.
Vergiss es.
Intel hat einen schoenen Interruptcontroller gemacht, der kann
Prioritaeten zuweisen und rotieren. Trotzdem wollte Microsoft was
anderes und hat oben eine Software draufgesetzt die alles vermurkst.
Als Einsteigelektuere sei das iAPX86 Manual von Intel empfohlen, Dort
wird auch der 8259 beschrieben, und ein paar Interrupthandler sind da
auch drin. Als naechstes waere das 386 Manual mit dem Protected mode
empfohlen. Dort wurden die Interrupts virtualisiert und muessen durch
trap gates. Seither hat sich interruptmaessig nicht mehr sehr viel fuer
den Benutzer geaendert.
Das ist ein Webserverboard von PharLap. Es nutzt ETS ein 32 bit Echtzeit
Betriebssystem und kann ein Teil der WIN32 API-Funktionen. Der Prozessor
ist ein AMD-ELAN Prozessor mit 66 MHZ. Programmieren tue ich das ganze
unter Visual Studio 6.0 mit C++.
Und, hast Du mittlerweile mal in der Dokumentation nachgesehen? Die
beschreibt, was die von Dir verwendete Funktion macht bzw. machen
sollte.
Hättest Du Deinen Aufsatz nicht eigentlich schon längst abgeben sollen?
Ich habe die Beschreibungen zu dem entsprechenden Funktionen gefunden.
Ich hab da Probleme das ganze hier zu verstehen.
//
// Return the interrupt vector number which corresponds to the
// specified hardware IRQ. Assumes PC/AT mapping of 08h for IRQs 0-7
// and 70h for IRQs 8-15. Source is provided in
PHAREMB/EMBCUST/PCPIC.ASM.
//
// hardwareIRQNum is the desired IRQ number
//
// Returns the interrupt vector number which corresponds to the
// specified IRQ, or -1 if the specified IRQ is out of range.
//
int __cdecl EtsPicGetIRQIntNumber(int hardwareIRQNum);
//----------------------------------------------------------------------
-------
// EtsSetInterruptHandler - Install a C function as an interrupt handler
//
// This API installs a C function as an interrupt handler
// for the specified interrupt. The handler is entered as a normal
// C function (__cdecl calling sequence) with interrupts disabled
// and receives a pointer to the saved register set on the stack
// as its argument. The saved register set includes all general
// purpose registers, DS, ES, and EFLAGS. The FS and GS registers
// are neither saved nor restored; if the handler alters them, it
// must restore them itself before returning. The handler
// is expected to process the interrupt and may modify the
// saved register set on the stack if wishes to
// alter the context of the interrupted code. When the handler
// function
// returns, the saved registers are popped off the stack and
// control returns to the interrupted code.
//
// The return value from the function is TRUE if successful or
FALSE
// if an error occurs.
//
//----------------------------------------------------------------------
-------
BOOL __cdecl EtsSetInterruptHandler(unsigned IntNumber,
PETSINTHANDLER pHandler);
//
// Saved register block passed to interrupt handlers registered
// with EtsSetInterruptHandler() and EtsSetExceptionHandler().
// These fields contain the register contents at the time of the
// interrupt. The interrupt service routine can modify the
// values in the passed structure in order to change the user
// registers on return from the interrupt.
//
// Note: The FS and GS registers are neither saved nor restored
// by the interrupt handler framework. If a user interrupt handler
// wants to use either of these registers, it must preserve them itself!
//
typedef struct tagETSINTREGS
{
DWORD Ebp; // [00]
DWORD Eax; // [04]
DWORD Ebx; // [08]
DWORD Ecx; // [12]
DWORD Edx; // [16]
DWORD Esi; // [20]
DWORD Edi; // [24]
DWORD Gs; // [28]
DWORD Ds; // [32]
DWORD Es; // [36]
DWORD IntNum; // [40]
DWORD Ecode; // [44] (Zero if int w/o error code)
DWORD Eip; // [48]
DWORD Cs; // [52]
DWORD Eflags; // [56]
} ETSINTREGS, *PETSINTREGS;
void __cdecl CommIntHandler(ETSINTREGS *pRegs);