next up previous contents
Next: Linux Gerätetreiber Up: Hardware Previous: Motorsteuerung

Interruptservicefunktion

  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 tex2html_wrap_inline3494 . Dann läuft wegen der Prioritätsanpassung im Interrupt nur noch der Steuerprozeß. Alle anderen Prozesse des Rechners stehen in diesem Fall und damit scheinbar auch das System selbst. Um dies zu verhindern, wird der Steuerprozeß mit kill(SIGSEGV) beendet, wenn das System länger als eine Sekunde nur den Steuerprozeß ausführt.
        /* 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);
                }
        }
}


next up previous contents
Next: Linux Gerätetreiber Up: Hardware Previous: Motorsteuerung

Marius Heuler
Tue Jan 7 12:11:50 MET 1997