Trying to read the system timer

General programming chat and advice for beginners

9 posts
by blurp » Wed Jun 20, 2012 7:58 pm
Hello,

i was trying to the read the system timer, to do some calibration stuff for another piece.
Thats my code:

Code: Select all
#define BCM2708_PERI_BASE       0x20000000
#define SYST_BASE               (BCM2708_PERI_BASE + 0x3000)    /* SYST controller */
#define SYST_CS                 0x0
#define SYST_CLO                0x4
#define SYST_CHI                0x8


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int mem_fd;
char *syst_mem, *syst_map;
volatile unsigned *syst;

void setup_io();
void restore_io();
void prnt_syst();

int main(int argc, char **argv)
{
        setup_io();
        prnt_syst();
        restore_io();
}

void prnt_syst()
{
        int syst_cs, syst_clo, syst_chi;

        syst_cs = *(syst + SYST_CS);
        syst_clo = *(syst + SYST_CLO);
        syst_chi = *(syst + SYST_CHI);
        printf("syst: %08lx\n",(unsigned int)syst);
        printf("syst_cs  syst_clo syst_chi\n");
        printf("%08lx %08lx %08lx\n",syst_cs,syst_clo,syst_chi);
}


void setup_io()
{

        if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
                printf("can't open /dev/mem \n");
                exit (-1);
        }
        if ((syst_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
                printf("allocation error \n");
                exit (-1);
        }
        if ((unsigned long)syst_mem % PAGE_SIZE)
                syst_mem += PAGE_SIZE - ((unsigned long)syst_mem % PAGE_SIZE);
        syst_map = (unsigned char *)mmap(
                (caddr_t)syst_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE,
                MAP_SHARED|MAP_FIXED, mem_fd, SYST_BASE);
        if ((long)syst_map < 0) {
                printf("mmap error %d\n", (int)syst_map);
                exit (-1);
        }
        syst = (volatile unsigned *)syst_map;
}


void restore_io()
{
        munmap(syst_map,BLOCK_SIZE);
}


Thats the output of this short program:
Code: Select all
syst: 0152f000
syst_cs  syst_clo syst_chi
00000002 00000000 74696d65


The 74696d65 seems to be ASCII: "time", but not the system timer.
Whats wrong?
Any hints appreciated.

Best Regards
Posts: 11
Joined: Tue Jun 05, 2012 2:38 pm
by secretagent » Thu Jun 21, 2012 6:32 am
The problem is that this defaults to type int*:
Code: Select all
volatile unsigned *syst;

and when you do pointer arithmetic the address shifts by the specified amount times the size of the type. So, when you have SYST_CLO = 0x4 and syst + SYST_CLO, then the address is syst + 16 instead of syst + 4 and you end up with the wrong address. Same for CHI. To resolve this you need to either change the type to char* or divide the offsets by 4.
Posts: 36
Joined: Wed Mar 07, 2012 10:09 am
by blurp » Thu Jun 21, 2012 8:16 am
Thanks,

You are right.

The macros in the program where i have stolen the code :-) did the pointermath this way.


Best Regards
Posts: 11
Joined: Tue Jun 05, 2012 2:38 pm
by dom » Thu Jun 21, 2012 8:44 am
gettimeofday will do the same thing (reads system timer value with microsecond resolution).
viewtopic.php?f=68&t=8067&p=96770
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 4042
Joined: Wed Aug 17, 2011 7:41 pm
Location: Cambridge
by blurp » Thu Jun 21, 2012 11:20 am
Yes,

gettimeofday will give a portable solution.

But its heavy:
2012-06-21 13:12:47.033513
gettimeofday() took approx: 27 us

The direct access to the system timer is much faster.

Code: Select all
#define BCM2708_PERI_BASE       0x20000000
#define SYST_BASE               (BCM2708_PERI_BASE + 0x3000)    /* SYST controller */
#define SYST_CS                 0x0
#define SYST_CLO                0x4
#define SYST_CHI                0x8


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <sys/time.h>
#include <time.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

int mem_fd;
char *syst_mem, *syst_map;
volatile unsigned *syst;

void setup_io();
void restore_io();
void prnt_syst();

int main(int argc, char **argv)
{
struct timeval tv;
struct tm* ptm;
char time_string[40];

unsigned cnt1,cnt2;

        setup_io();

        cnt1 = *(syst + (SYST_CLO >> 2));

        /* Obtain the time of day, and convert it to a tm struct.  */
        gettimeofday (&tv, NULL);

        cnt2 = *(syst + (SYST_CLO >> 2));

        ptm = localtime (&tv.tv_sec);
        /* Format the date and time, down to a single second.  */
        strftime (time_string, sizeof (time_string), "%Y-%m-%d %H:%M:%S", ptm);
        printf ("%s.%06ld\n", time_string, tv.tv_usec);
        printf("gettimeofday() took approx: %d us\n",cnt2-cnt1);

        restore_io();
}

void prnt_syst()
{
        int syst_cs, syst_clo, syst_chi;

        printf("syst_cs  syst_chi syst_clo\n");
        syst_cs = *(syst + (SYST_CS >> 2));
        syst_clo = *(syst + (SYST_CLO >> 2));
        syst_chi = *(syst + (SYST_CHI >> 2));
        printf("%08x %08x %08 %d\n",syst_cs,syst_chi,syst_clo,syst_clo);
}


void setup_io()
{

        if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
                printf("can't open /dev/mem \n");
                exit (-1);
        }
        if ((syst_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
                printf("allocation error \n");
                exit (-1);
        }
        if ((unsigned long)syst_mem % PAGE_SIZE)
                syst_mem += PAGE_SIZE - ((unsigned long)syst_mem % PAGE_SIZE);
        syst_map = (unsigned char *)mmap(
                (caddr_t)syst_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE,
                MAP_SHARED|MAP_FIXED, mem_fd, SYST_BASE);
        if ((long)syst_map < 0) {
                printf("mmap error %d\n", (int)syst_map);
                exit (-1);
        }
        syst = (volatile unsigned *)syst_map;
}


void restore_io()
{
        munmap(syst_map,BLOCK_SIZE);
}


Thanks Dom, and

Best Regards
Posts: 11
Joined: Tue Jun 05, 2012 2:38 pm
by breadboard » Mon Nov 05, 2012 2:47 pm
I use Raspbian-wheezy version 2012-10-28 and have a program which uses gettimeofday (on an iMac) to provided formatted time. This does not work on the Pi because gettimeofday appears not to be in the standard C library.

Please would someone give advice on which library to explicitly link to pick up gettimeofday() and localtime() and asctime_r(). No doubt there might be workarounds so that I do this some other way. Hopefully these useful routines should be part of a standard C library.

Thanks....John
Posts: 3
Joined: Thu Jul 19, 2012 1:35 pm
by BlackJack » Mon Nov 05, 2012 3:56 pm
@breadboard: There is no need to explicitly link libraries for those functions. `gettimeofday()` is defines in `sys/time.h` the others in `time.h`.
Code: Select all
while not self.asleep():
    sheep += 1
Posts: 288
Joined: Sat Aug 04, 2012 8:28 am
by Narishma » Tue Nov 06, 2012 9:31 am
breadboard wrote:I use Raspbian-wheezy version 2012-10-28 and have a program which uses gettimeofday (on an iMac) to provided formatted time. This does not work on the Pi because gettimeofday appears not to be in the standard C library.

Please would someone give advice on which library to explicitly link to pick up gettimeofday() and localtime() and asctime_r(). No doubt there might be workarounds so that I do this some other way. Hopefully these useful routines should be part of a standard C library.

Thanks....John

gettimeofday() is part of the POSIX standard API's, which are implemented in most Unix-type systems like Linux. You don't have to link any library to use it, just include the right header file.

In any case, gettimeofday() has been deprecated for a few years now in favor of clock_gettime() and related functions in time.h. "man 2 clock_gettime" will give you more info.
Posts: 151
Joined: Wed Nov 23, 2011 1:29 pm
by panik » Tue Nov 06, 2012 3:25 pm
About the 'no need to link to any library', that is certainly true when compiling on the Pi itself. I found that when cross-compiling on an x86 Ubuntu machine and using clock_gettime(), I needed to explicitly link to librt.so (-lrt). Supposedly a 'bug in upstream ld'.

Topic: viewtopic.php?f=33&t=19756

I just put this here for completeness sake.
User avatar
Posts: 272
Joined: Fri Sep 23, 2011 12:29 pm
Location: Netherlands