Timer Raspberry Pi

We kunnen in Raspbian Linux door middel van gettimeofday(&gettime_now, NULL);start_time = gettime_now.tv_nsec; wel een redelijk nauwkeurige timer maken maar deze timer zal niet altijd nauwkeurig zijn. Alleen de aanroepen van deze functies kost al 100 nanoseconden en kan onderbroken worden door een task switch van de kernel of een kernel proces. Dit gaat ook op voor de functie usleep() die alleen de garantie geeft dat er “minimaal” de slaaptijd gewacht zal worden, maar waar de slaaptijd best wel het tienvoudige kan zijn. Linux is helaas geen realtime besturingssysteem en elke embedded ontwikkelaar wil graag een realtime besturingssysteem om nog enige controle te hebben. Desondanks wordt de Rasberry Pi veel gebruikt in bijvoorbeeld robots waar de enorme voorraad aan programmacode en bibliotheken wel weer een enorm voordeel is.

Een stabiele en nauwkeurige timer is geen standaard onderdeel van de ARM specificatie maar de meeste ARM gebaseerde SoC's hebben ergens wel een timer. De Raspberry Pi is geen uitzondering, het uitlezen van deze timer in Linux vergt wel enig hackwerk. Volgens de officiële Broadcom 2835 documentatie zit er een 'free-running 1MHz timer' op ARM adres 0x20003004 die als we het goed bekijken op I/O base 0x20000000 zit met een offset van 0x3000 en de vrij lopende 1MHz teller op offset 0x0004. Dit klinkt goed maar hoe kunnen we deze teller gebruiken? In het ontwerp van Unix zit een methode om rechtstreeks het fysieke geheugen te lezen, via de device driver “/dev/mem”. Maar hoe kunt u dit gebruiken om de teller te lezen? Volgens de man pagina's geeft dit device de geheugen adressen identiek aan het fysieke geheugen. Wanneer we een klein stuk geheugen rechtstreeks willen benaderen dan kunnen we dit doen met de functie mmap(). Er zit een kleine adder onder het gras en dat is dat de geheugenadressen van de timer alleen leesbaar zijn, er naar toe proberen te schrijven (vanuit user space) zal fatale gevolgen hebben. Omdat dergelijke "raw" toegang tot het geheugen beveiligingsinformatie kan vrijgeven en het systeem wagenwijd open kan zetten is het gebruik van /dev/mem beperkt tot root gebruiker. Hier staat een eenvoudige demonstratie programma dat timing informatie van een lus in microseconden afgedrukt.

Voorbeeld code

#include 
#include  
#include  
#include  
#include  
#include   

#define ST_BASE (0x20003000) 
#define TIMER_OFFSET (4)  

int main(int argc, char *argv[]) {    
long long int t, prev, *timer; // 64 bit timer 
int fd;     
void *st_base;
 
  if (-1 == (fd = open("/dev/mem", O_RDONLY))) {
      fprintf(stderr, "open() failed.\n");
      return -1;     
  }
  if (MAP_FAILED == (st_base = mmap(NULL, 4096,
       PROT_READ, MAP_SHARED, fd, ST_BASE))) {
     fprintf(stderr, "mmap() failed.\n");
     return -2;
   }
   timer = (long long int *)((char *)st_base + TIMER_OFFSET); 
   prev = *timer;
   sleep(1);
   while (1==1) { 
       t = *timer;
       printf("Timer diff = %lld    \r", t – prev);
       prev = t;
       sleep(1);
   } // zal hier nooit komen
   return 0; 
} 

Uitleg code

De eerste stap om toegang te krijgen tot de timer is de open () functie, de mmap() en het instellen van de timer pointer. Wanneer we de TIMER_OFFSET toevoegen aan st_base en deze casten naar een pointer naar "long long int" (64 bits), dan wordt dit een pointer naar de 1 MHz free running timer. Door deze waarde te lezen kunt u eenvoudig lezen hoeveel microseconden verstreken zijn zonder dat dit door aanroepen van functies of kernel processen verstoord kan worden. Het bovenstaande programma is een proof-of-concept voor het lezen van de timer. Het begint met het voor de eerste keer lezen van de timer waarde, 1 seconde slapen en dan de timer weer lezen om te zien hoeveel microseconden nu werkelijk verstreken zijn. slapen voor 1 seconde, dan is het lezen van een andere timer waarde en het afdrukken van het verschil. Op een 600 Mhz Raspbeery Pi is de typische afwijking slechts 1.000.225 microseconden. Al met al een zeer nauwkeurig timer waarmee u bijvoorbeeld afstand bepaling kunt doen door middel van ultrasone sensoren. In elk realtime programma zoals bijvoorbeeld code voor een robot is zeer nauwkeurige timing soms erg belangrijk.

Last update: 02-03-2015

Disclaimer: Hoewel de heer Pragt de informatie beschikbaar op deze site met grote zorg samenstelt, sluit hij alle aansprakelijkheid uit met betrekking tot de informatie die via deze site wordt aangeboden. Op de artikelen van de heer Pragt rust auteursrecht, overname van tekst en afbeeldingen is uitsluitend toegestaan na voorafgaande schriftelijke toestemming. Voor vragen hierover kunt u contact opnemen met: (email: mail@heinpragt.com). Heinpragt.com is ingeschreven bij de KvK onder nummer: 73839426.  Lees hier de privacyverklaring van deze site. Voor informatie over adverteren op deze site kunt u contact opnemen met: (email: mail@heinpragt.com).