Der SystemTick in C

ARM Controller sind prädestiniert für den Einsatz spezieller Laufzeitumgebungen oder bestimmter Betriebssysteme. Solche basieren oft auf einer Timer-getriggerten Verteilung von Ressourcen, vor allem der Ressource Rechenzeit. Dafür steht beim ARM ein spezieller Timer zur Verfügung, der ausschließlich die Aufgabe hat, ein System-Trigger-Ereignis zu generieren. Auch ohne Echtzeitbetriebssystem ist dieser SystemTick für den Anwendungsentwickler sehr interessant. Die hier im Tutorial verwendeten Programmvorlagen, insbesondere das später verwendete myARM C++ Framework, sind bereits auf die Nutzung des SysTick vorbereitet bzw. basieren darauf.

Die Aufgabe

Diese Übung wird eine einfache Verwendung der SysTickFunction zur Generierung zyklischer Ausgaben demonstrieren. Wir lassen die LEDs auf dem Board abwechselnd blinken. Das folgende Blockbild verdeutlicht, welche Bausteine bei dieser Aufgabe eine Rolle spielen.

Die zwei LEDs auf dem XMC4500 Relax Kit sind immer noch fest mit den Pins 1.0 und 1.1 verbunden. Der SystemTick soll so konfiguriert werden, dass dieses Ereignis alle 10 Millisekunden eintritt. Fassen wir die Aufgaben zusammen:

  1. das SysTick-Ereignis auf 10 ms konfigurieren
  2. die Pins 1.0 und 1.1 als Ausgang konfigurieren
  3. wenn das SysTick-Ereignis eintritt, die LEDs unterschiedlich blinken lassen

Vorbereitung

Legen Sie bitte ein neues kleines Programm an und laden Sie das Grundgerüst für eine ARM C++ Anwendung. Beachten Sie die Einstellungen für die Zielplattform XMC4500 Relax Kit.

Erstellen Sie die Programmkopfdokumentation. Übersetzen und Übertragen Sie das noch leere Programm auf den Controller, um die Verbindung zu testen.

//----------------------------------------------------------------------
// Titel     : Beispiel einfache SysTick-Nutzung in SiSy XMC
//----------------------------------------------------------------------
// Funktion  : lässt die LEDs zyklisch blinken
// Schaltung : LEDs an Pin1.0 und Pin1.1
//----------------------------------------------------------------------
// Hardware  : XMC4500
// Takt      : 120 MHz
// Sprache   : ARM C++
// Datum     : 08.10.2012
// Version   : 1
// Autor     : ich
//----------------------------------------------------------------------

Grundlagen

Der XMC verfügt wie jeder ARM Cortex M über einen 24 Bit System Timer. Dieser ist explizit für Betriebssysteme vorgesehen, die einen Trigger für das Prozess-Scheduling benötigen. Da wir bei unseren Beispielen noch nicht auf ein Betriebssystem zurückgreifen, gehört der SysTick voll und ganz uns. Wir können damit im weiteren Verlauf schon ein bisschen einfache Nebenläufigkeit (Parallelverarbeitung) programmieren oder wie hier den SysTick als Trigger für zyklische Aufgaben nutzen, statt die Prozessorzeit mit Warteroutinen zu verbraten. Standardmäßig konfigurieren wir den SysTick auf 10 Millisekunden. Dieser Wert bewegt sich im Bereich der typischen Zeitscheibe von Betriebssystemen für eingebettete Systeme. Der SysTick-Timer löst einen entspechenden Interrupt aus. Die ISR (Interrupt Service Routine) oder auch Interupt-Handler genannt, wird beim Laden eines Grundgerüstes für den XMC bereits vorgefertigt angeboten.

extern "C" void SysTick_Handler(void)
{
	// Application SysTick
}

Die Deklaration als extern „C“ ist nötig, damit diese Funktion auch außerhalb von dem in SiSy verwendeten C++ Compiler, letztlich aus den Systemroutinen, die in der Regel in Assembler oder C geschrieben sind, aufgerufen werden kann.

Entwurf

Die 100Hz oder auch 10ms, mit der das SysTick-Ereignis ausgelöst wird, ist für das Blinken einer LED viel zu schnell. Das könnten wir mit unserem Auge nicht mehr wahrnehmen. Wir müssen uns etwas einfallen lassen, nur jeden 10ten oder 20ten SysTick für das Umschalten der LED zu nutzen.

Auch wenn es uns in den Fingern kribbelt sofort die nötigen Befehle einzugeben, kasteien wir uns mit dem folgenden Entwurf:

//----------------------------------------------------------------------
// Titel     : Beispiel einfache SysTick-Nutzung in SiSy XMC
//----------------------------------------------------------------------
// Funktion  : lässt die LEDs zyklisch blinken
// Schaltung : LEDs an Pin1.0 und Pin1.1
//----------------------------------------------------------------------
// Hardware  : XMC4500
// Takt      : 120 MHz
// Sprache   : ARM C++
// Datum     : heute
// Version   : 1
// Autor     : ich
//----------------------------------------------------------------------
#include <stddef.h>
#include <stdlib.h>
#include "hardware.h"
 
void initApplication()
{
	SysTick_Config(SystemCoreClock/100);
	// weitere Initialisierungen durchführen
 
	// Konfiguriere Pin1.0 und Pin1.1 als Ausgang
 
}
 
int main(void)
{
	SystemInit();
	initApplication();
	while(true)
	{
		//leer
	}
	return 0;
}
 
extern "C" void SysTickFunction(void)
{
	// Zähler anlegen
	// Zähler eins hochzählen
	// wenn Zähler = 10 dann Pin1.0 umschalten
	// wenn Zähler = 20 dann Pin1.1 umschalten
}

Realisierung

Nachdem wir den Entwurf bei einem kräftigen Schluck Kaffee auf uns wirken lassen, kann der Code erstellt werden.
Nicht kopieren! Selbstbewusst tippen!

//----------------------------------------------------------------------
// Titel     : Beispiel einfache SysTick-Nutzung in SiSy XMC
//----------------------------------------------------------------------
// Funktion  : lässt die LEDs zyklisch blinken
// Schaltung : LEDs an Pin1.0 und Pin1.1
//----------------------------------------------------------------------
// Hardware  : XMC4500
// Takt      : 120 MHz
// Sprache   : ARM C
// Datum     : heute
// Version   : 1
// Autor     : ich
//----------------------------------------------------------------------
#include <stddef.h>
#include <stdlib.h>
#include "hardware.h"
#include "xmc_gpio.h"
 
void initApplication()
{
	// u.a. nötig für waitMs(..) und waitUs(..)
	SysTick_Config(SystemCoreClock/100);
	// weitere Initialisierungen durchführen
 
	// Port 1 Input Output Control Register, Bit 0 = OUT
	PORT1->IOCR0 |= (XMC_GPIO_MODE_OUTPUT_PUSH_PULL<< 0*8);
 
	// Port 1 Input Output Control Register, Bit 1 = OUT
	PORT1->IOCR0 |= (XMC_GPIO_MODE_OUTPUT_PUSH_PULL<< 1*8);
 
}
 
int main(void)
{
	SystemInit();
	initApplication();
	do{
 
		// bleibt leer		
 
	} while (true);
	return 0;
}
 
extern "C" void SysTick_Handler(void)
{
	// Application SysTick
	static int counter=0;
	counter++;
	if (counter==10)
	{
		PORT1->OMR |= (BIT1<<16) + BIT1;
	}
 	if (counter>20)
 	{
  		PORT1->OMR |= (BIT0<<16) + BIT0;
 		counter=0;
 	}
}

Test

Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.

  1. Kompilieren
  2. Linken
  3. Brennen

Videozusammenfassung

Und hier diesen Abschnitt wiederum als Text- und Videozusammenfassung.

Die Infineons Low Level Treiber (XMC Lib) anwenden

Die Lösung mit der XMC Lib ist jetzt denkbar einfach zu erstellen. die dazu nötigen Funktionen kennen wir bereits:

//----------------------------------------------------------------------
// Titel     : Blinky 3, SysTick Nutzung mit XMC LIB und SiSy XMC
//----------------------------------------------------------------------
// Funktion  : LEDs blinken im SysTick Handler
// Schaltung : LED an Port 1, Bit 0
//----------------------------------------------------------------------
// Hardware  : XMC4500 Releax kit
// Takt      : 120 MHz
// Sprache   : ARM C++
// Autor     : Alexander Huwaldt
//----------------------------------------------------------------------
#include <stddef.h>
#include <stdlib.h>
#include "hardware.h"
#include "xmc_common.h"
#include "xmc_gpio.h"
 
void initApplication()
{
    // u.a. nötig für waitMs(..) und waitUs(..)
    SysTick_Config(SystemCoreClock/100);
    // weitere Initialisierungen durchführen
 
    // Port 1 Input Output Control Register, Bit 0 = OUT
    // PORT1->IOCR0 |= (XMC_GPIO_MODE_OUTPUT_PUSH_PULL<<0*8);
    XMC_GPIO_SetMode(XMC_GPIO_PORT1, 0, XMC_GPIO_MODE_OUTPUT_PUSH_PULL );
 
    // Port 1 Input Output Control Register, Bit 1 = OUT
    // PORT1->IOCR0 |= (XMC_GPIO_MODE_OUTPUT_PUSH_PULL<<1*8);
    XMC_GPIO_SetMode(XMC_GPIO_PORT1, 1, XMC_GPIO_MODE_OUTPUT_PUSH_PULL );
 
 }
 
int main(void)
{
    SystemInit();
    initApplication();
    do{
 
        // bleibt leer
 
    } while (true);
    return 0;
}
 
extern "C" void SysTick_Handler(void)
{
    // Application SysTick
    static int counter=0;
    counter++;
    if (counter==10)
    {
	// PORT1->OMR |= (BIT1<<16) + BIT1;
        XMC_GPIO_ToggleOutput(XMC_GPIO_PORT1,1);
    }
    if (counter>20)
    {
   	// PORT1->OMR |= (BIT0<<16) + BIT0;
        XMC_GPIO_ToggleOutput(XMC_GPIO_PORT1,0);
 	counter=0;
    }
}

Nächstes Thema