Interrupt in C

Zur Verwendung und Behandlung von Interrupts in C-Quellen ist das Einbinden von vorgefertigtem Assemblercode nötig. Seine Aufgabe besteht in der Maskierung und Verteilung ausgelöster Interrupts.

Interrupts im GCC behandeln


Weiter Informationen stehen im Wiki unter Assemblerbefehle zur Interrupt Steuerung.

Sekunden Interrupt in C mit Ausgabe eines Wertes auf LED


Beim SpartanMC ist auch die Programmierung von ISR Programmen in C möglich. Dazu muss zusammen mit dem startup Kode in der Firmware make Datei "config-build.mk" ein Assembler Programm geladen werden. Der Systembuilder jConfig erstellt für alle im System installierten Geräte zwei Dateien, die immer als Include in einem C-Programm eingebunden werden müssen. Im #include "moduleParameters.h" werden für jedes Gerät die im jConfig getroffenen Einstellungen übergeben. Alle Einstellungen können also im C-Programm abgefragt werden. Die zweite Datei #include "peripherals.h" legt für alle Geräte den Namen der Geräteregister-Struktur fest. Wurde im jConfig der zu verwendende Timer Modul auf seiner Seite mit "timer_1" bezeichnet, dann bekommt die Registerstruktur des Timers in dem #include "peripherals.h" die Bezeichnung "TIMER_1". In dieser Datei werden auch automatisch alle *.h Dateien für alle implementierten Geräte geladen. Der Programmierer muss also nur noch die Register der verwendete Geräte initialisieren um sie zu verwenden. Soll also das Register für den maximalen Zählerwert vom Timer geladen werden, dann erfolgt das in der Form:

TIMER_1.limit = 24415;

Die Namen aller Geräteregister des Timers und aller vorbereiteten Konstanten findet man in der "timer.h" Datei auf der Wiki-Seite zum Timer.

Zur Erzeugung eines Sekundeninterrupt wird eine Konfiguration mit einem TIMER Modul, dessen Eingang mit dem System Takt von 25 MHz verbunden ist eingesetzt. Das Bit 14 des TIMER Zählerregisters soll dann mit dem Eingang eines RTI Moduls verbunden werden, der dann den Interrupt auslösen soll. Mit den Vorteilern vom RTI von 2⁰ bis 2¹⁵, dem Vorteiler vom TIMER von 2¹ bis 2⁸ und dem einstellbaren maximalen Wert vom Zähler des Timer von 2^14 < wert < 2^15 -1 muss der Sekunden Interrupt eingestellt werden. Beim Test hat sich eine Einstellung auf (2^14 + 24415) * 2^10 = 40799 * 1024 = 41778176 als günstigste Variante herausgestellt, bei der die Sekunde sehr genau eingehalten wird. Die 2^10 wurde mit 2^7 im Vorteiler des TIMER und 2^3 im RTI eingestellt.

#include "peripherals.h"	// I/O-Adessen und Registerstrukturen aller installierten Interfaces
#include "moduleParameters.h"	// in der Hardwere eingestellte Parameter aller installierten Interfaces
#include <interrupt.h>

/**
 * Zuordnung der Interrupts
 */
#define	isr_rti0	ISR(0)	// Interrupt von RTI0 in jeder Sekunde

/**
 * Werte fuer RTI0 Interrupt in jeder Sekunde
 */
/**
 * Impuls mit einer Periodendauer von 1s aus 25MHz erzeugen. Fuer den Sekundenimpuls
 * an RTI0 bringen die Vorteiler vom TIMER = 2^7 und RTI0 = 2^3 den Wert 128 * 8 = 1024.
 * Der Rest muss vom Haupteiler des Timers kommen und muss bei Verwendung von Bit 14 die Bedingung
 * 2^14 < Wert < (2^15 -1) erfuellen.
 * 2^14	                  = 16384 = 0x4000
 * int(25000000 / 1024)+1 = 24415 = 0x5F5F erfuellt die Bedingung
 * 2^15 – 1               = 32767 = 0x7fff
 * Die Periodendauer des Impuls am TIMER RTI Ausgang ergibt sich damit zu:
 * (1 / 25000000 Hz)*(int(25000000 / 1024)+1) * 1024 = 0,00000004s * 24415 * 1024 = 1,0000384s
 */
#define	LI_TIMER1	((25000000 / 1024)+1) // limit fuer Timer 1
#define	VT_TIMER1	7                     // TIMER_PRE_VAL = 2^7
#define	VT_RTI0		3                     // RTI_PRE_VAL   = 2^3


// Variablen der ISR-Fuktionen
   unsigned int	i;                    // Wert zur Ausgabe auf die LEDs

/**
 * Timer und LED Testprogramm
 */
void main(void) {

	// Initialisierung der Geraete
	interrupt_disable();
	PORT_OUT_2_LED.data	= 0;	// alle Ausgaenge auf 0 (LEDs aus)
	PORT_OUT_2_LED.oe	= 0x7f;	// alle Ausgaenge aktiv

	RTI_0.ctrl	= RTI_EN|RTI_EN_INT|(RTI_PRE_VAL*VT_RTI0);		// RTI_PRE_VAL = 2^3 (Fuer VSIM 2^1)
	TIMER_1.limit	= LI_TIMER1;						// getesteter Wert fuer eine Sekunde
	TIMER_1.control	= TIMER_EN|TIMER_PRE_EN|(TIMER_PRE_VAL*(VT_TIMER1-1));	// TIMER_PRE_VAL = 2^4  (Fuer VSIM 2^1)

	// Initialisierung beendet
	interrupt_enable();

	while (1);
}

/* Funktionen zur Interrupt Behandlung */
// Sekunden Interupt von RTI0
isr_rti0() {
	volatile int	rtictrl;
	rtictrl	= RTI_0.ctrl;		// Interrupt ruecksetzen
	i++;
	if (i>=128) i=0;
	PORT_OUT_2_LED.data	= i;	// Wert auf LEDs ausgeben
}

Vollständige C-Quellen für die Konfiguration der Förderband5 Version:






SpartanMC