Die wichtigste Funktion im Gerätetreiber ist die Bedienfunktion für den Hardwareinterrupt. In ihr wird der Hauptteil der Hardware- und Prozeßsteuerung ausgeführt. Aus diesem Grund wird hier die ganze Interruptbearbeitungsfunktion erläutert:
void pendel_interrupt()
{
Mit dieser Funktion wird die Priorität des Steuerprozesses
auf das Maximum gesetzt, was bewirkt, daß
er beim nächsten Prozeßwechsel sofort ausgeführt wird. Da hier auf
interne Kernelstrukturen zugegriffen wird, hängt die Funktion
stark von der Kernelversion ab!
Das Feld process->policy gibt hierbei die Art des Prozesses an, wobei SCHED_RR die Kennung für einen Echtzeitprozeß ist. In process->current wird die augenblickliche Laufpriorität - nicht zu verwechseln mit der Priorität process->priority - gespeichert. Der Wert von 2000 sollte der maximalen Priorität entsprechen, was einem nice Wert von <-20 ergibt.
/* this changes the process scheduling to real-time */
/* and manipulates the task queue */
/* the calculation process will be started by the */
/* next schedule event */
/* WARNING: this is very dependant on kernel version!*/
void high_priority()
{
if (process) {
if (process_pid != process->pid) {
printk(KERN_ALERT "Fatal: Control
process %d was lost\n", process_pid);
kill_proc(process->pid, SIGSEGV, 1);
kill_proc(process_pid, SIGSEGV, 1);
process = NULL;
return;
}
#ifdef SCHED_RR
process->policy = SCHED_RR;
#endif
process->counter = process->priority = 2000;
need_resched = 1;
}
}
Hier wird überprüft, ob der Rechenaufwand des Steuerungsprozesses zu hoch
ist. Dies ist z.B. dann der Fall, wenn die Rechenzeit für einen
Steuerimpuls höher ist als der Takt des Interrupts /* check for overload */
if (process && process->pid == current->pid) overload++;
if (irq_counter % freq == 0) {
if ( process && freq == overload) {
printk(KERN_ALERT "Fatal: CPU overload! Processor to
slow! Process %d killed!\n", current->pid);
kill_proc(process->pid, SIGSEGV,1);
process = NULL;
}
overload = 0;
}
Hier wird die aktuelle Position des Pendel- und Antriebsarms ausgelesen.
/* save pendulum position */
_motw = get_arm_pos();
_penw = get_pen_pos();
_status = get_input();
Falls die Steuerung eingeschaltet ist und ein Steuerimpuls vom Prozeß
übergeben wurde, wird dieser an die Hardware weitergeleitet und damit
der Motor geregelt.
/* control motor of pendulum */
if (force_flag) {
if (new_force) {
skipped+= force_flag - 1;
if (force_flag > max_skipped)
max_skipped = force_flag - 1;
force_flag= 1;
new_force = 0;
/* control statement */
set_arm_pos(force);
} else {
high_priority();
force_flag++;
}
}
Da die Geschwindigkeit des Pendel- und Antriebsarms für die Regelung
benötigt wird, aber nicht direkt von der Hardware gemessen werden
kann, wird sie hier berechnet. Dazu werden die Positionen des Pendels
und Antriebsarms über VCOUNTER Interrupttakte gespeichert und
über die Positionsänderungen
durch die Zeit die Geschwindigkeit berechnet.
/* calculate pendulum speed */
memcpy(&pen_speed[0], &pen_speed[1], sizeof(int)
* (VCOUNTER - 1 ));
memcpy(&mot_speed[0], &mot_speed[1], sizeof(int)
* (VCOUNTER - 1 ));
pen_speed[VCOUNTER-1] = _penw;
mot_speed[VCOUNTER-1] = _motw;
_penv = (_penw - pen_speed[0]) * freq / VCOUNTER;
_motv = (_motw - mot_speed[0]) * freq / VCOUNTER;
irq_counter++;
Falls der Steuerprozeß gerade schläft und auf neue Parameter von der
Hardware wartet, wird er hiermit aufgeweckt, damit er einen
Steuerimpuls für den nächsten Interrupt berechnen kann.
/* wakeup process if sleeping */
if (wakeup) {
sleeping--;
if (sleeping < 0) {
high_priority();
wake_up_interruptible(&pendel_waitq);
}
}
}