Ethernut Home Hardware Firmware Tools Download Community
 
Ethernuts  /  Ethernut 5  /  Nut/OS  /  Timer
Suchen | Impressum | English

Ethernut 5 Timer/Counter

Achtung: Bis zur Version 4.10.2 verwendete Nut/OS den Timer/Counter 0 als Systemtimer. Dieser steht also erst ab Version 4.10.3 für Anwendungen zur Verfügung. Seitdem wird der Periodic Interval Timer als Systemtimer verwendet.

Anders als bei vielen anderen Peripheriebausteinen bietet Nut/OS keine API Schnittstelle für Timer/Counter. Die notwendingen Hardwarezugriffe müssen daher als Teil der Anwendung implementiert werden. Angeboten werden lediglich einige Grundfunktionen, die auf dem Systemtakt basieren. Siehe dazu Sleep and Delay im Nutwiki.

Die AT91SAM9XE CPU bietet insgesamt 6 Timer/Counter, die in zwei Gruppen unterteilt sind. Näheres findet man dazu im Datenblatt.

Diese Bausteine lassen sich sehr flexibel einsetzen, was den Umgang mit ihnen, besonders für Neulinge, sehr kompliziert aussehen lässt.

Registerzugriff

Zwar bietet Nut/OS keine portable API, aber wenigstens alle nötigen Definitionen für den Zugriff auf die Hardwareregister. Dies erlaubt es zumindest, den Anwendungscode innerhalb der AT91-Familie einigermaßen portabel zu halten. Andererseits gibt es selbst innerhalb dieser CPU-Familie einige Unterschiede, so dass in jedem Fall das Datenblatt des jeweiligen Chips genau beachtet werden muss.

Die Definition der Register befindet sich in der Header-Datei arch/arm/atmel/at91_tc.h. Diese muss in der Regel nicht selbst per include in den eigenen Quellcode eingefügt werden. Vielmehr erledigt das eine der anderen in Nut/OS verwendeten Headerdateien, die früher oder später die Datei compiler.h verwenden. Sollte dies nicht passieren, weil Sie sonst keine NutOS-spezifischen Headerdateien verwenden, dann setzten Sie eine der beiden includes an den Anfang Ihres Quellcodes.

#include <compiler.h>
...oder...
#include <arch/arm.h>

Traditionell wurde bei der Namensgebung wurde darauf geachtet, dass diese möglichst mit den im Datenblatt verwendeten Namen übereinstimmen.

Nut/OS verwendet die etwas altmodisch anmutenden Funktionen out() und in(), um Werte in Register zu schreiben bzw. von Registern zu lesen. Siehe dazu Low Level Port I/O im Nutwiki, insbesondere den Abschnitte "Nut/OS Port Access Macros" und "Using Digital I/O on AT91 ARM".

Ein Problem bei der Verwendung der Macros besteht darin, dass der Compiler nur bedingt die verwendeten Variablentypen überprüfen kann. Falls Sie für Nut/OS Version 5 programmieren, sollten Sie die neueren inline Funktionen mem_wr bzw. mem_rd in Erwägung ziehen, die ebenfalls von der Datei arch/arm.h angeboten werden.

Um Strom zu sparen, werden die Timer/Counter nach einem Reset nicht automatisch mit einer Clock versorgt. Dies ist aber unbedingt notwendig und muss von Anwendung selbst erledigt werden. Dazu setzt man das entsprechende Bit im Register PMC_PCER. Zum Beispiel für Timer 1:

outr(PMC_PCER, _BV(TC1_ID));

Dies wird leicht vergessen und sorgt dann bereits zu Anfang für entsprechend großen Frust, da "mal wieder nix funktioniert".

Den Timer selbst aktiviert man mit

outr(TC1_CCR, TC_CLKEN);

Nun braucht man nur noch das Register TC_CMR richtig setzen und gegebenfalls den Timer starten mit

outr(TC1_CCR, TC_SWTRG);

Nur noch war natürlich scherzhaft gemeint. Tasächlich ist die Konfiguration, wie bereits angedeutet, etwas kompliziert. Je nachdem, was man vorhat, sind auch die übrigen Register eines Timers von Interesse. Ein Hinweis noch: Möchte man digitale Ausgänge mit einem Timer steuern, muss man die entsprechende Peripheriefunktion des GPIO Ports aktivieren. Dazu empfiehlt es sich, die in arch/arm/atmel/at91sam9xe.h angebotenen Pin-Definitionen zu verwenden. So ist sichergestellt, dass diese Pins auch tatsächlich existieren. Wenn Sie den Code später für eine andere CPU übersetzten, wird der Compiler sofort meckern und Sie laufen nicht Gefahr, durch falsche Pinkonfiguration Ihre Hardware zu zerstören. Beispiel:

/* Enable TIOA peripheral function. */
outr(PIOA_ASR, _BV(PA27_TIOA1_A));
outr(PIOA_PDR, _BV(PA27_TIOA1_A));