### Author Topic: Working with Microseconds  (Read 2156 times)

#### enko

• New member
• Posts: 21
##### Working with Microseconds
« on: August 18, 2017, 09:13:13 pm »
Im starting to work with Rasperry Pi3 devices and I'm study this C code :
Code: Pascal  [Select]
1. /*******************************
2. *    Ultra Sonic Raning module Pin VCC should
3. *  be connected to 5V power.
4. ******************************/
5. #include <wiringPi.h>
6. #include <stdio.h>
7. #include <sys/time.h>
8.
9. #define Trig    0
10. #define Echo    1
11.
12. void ultraInit(void)
13. {
14.         pinMode(Echo, INPUT);
15.         pinMode(Trig, OUTPUT);
16. }
17.
18. float disMeasure(void)
19. {
20.         struct timeval tv1;
21.         struct timeval tv2;
22.         long time1, time2;
23.     float dis;
24.
25.         digitalWrite(Trig, LOW);
26.         delayMicroseconds(2);
27.
28.         digitalWrite(Trig, HIGH);
29.         delayMicroseconds(10);      //发出超声波脉冲
30.         digitalWrite(Trig, LOW);
31.
33.         gettimeofday(&tv1, NULL);           //获取当前时间
34.
36.         gettimeofday(&tv2, NULL);           //获取当前时间
37.
38.         time1 = tv1.tv_sec * 1000000 + tv1.tv_usec;   //微秒级的时间
39.         time2  = tv2.tv_sec * 1000000 + tv2.tv_usec;
40.
41.         dis = (float)(time2 - time1) / 1000000 * 34000 / 2;  //求出距离
42.
43.         return dis;
44. }
45.
46. int main(void)
47. {
48.         float dis;
49.
50.         if(wiringPiSetup() == -1){ //when initialize wiring failed,print messageto screen
51.                 printf("setup wiringPi failed !");
52.                 return 1;
53.         }
54.
55.         ultraInit();
56.
57.         while(1){
58.                 dis = disMeasure();
59.                 printf("%0.2f cm\n\n",dis);
60.                 delay(300);
61.         }
62.
63.         return 0;
64. }
65.

to interact with gpio i'm using h2wiringpi.pas (digitalWrite, DigitalRead, delayMicroseconds), to calcolate time difference I'm using a function found in this forum :
Code: Pascal  [Select]
1. function GetTickCount: Cardinal;
2. var
3.   tv: ptimeval;
4. begin
5.   fpgettimeofday(tv, nil);
6.   Result := int64(tv.tv_sec) * 1000000 + tv.tv_usec;
7. end;
8.

when the programm execute GetTickCount I've an Access Violation
Can anyone help me ?
Simply a Italian Programmer

• Hero Member
• Posts: 6330
##### Re: Working with Microseconds
« Reply #1 on: August 18, 2017, 09:24:24 pm »
GetTickCount64 is standard in sysutils... example RPi3 code:
Code: Pascal  [Select]
1. uses sysutils;
2. begin
3. writeln(GetTickCount64);
4. end.

Your own code contains lots of mistakes, btw:
Code: Pascal  [Select]
1. //  use the above code instead because it faster, monotonic and cross-platform.. but this is your corrected code.
2. function GetTickCount:qword;  // it is twice the size of a cardinal!! And unsigned!
3. var
4.   tv: ptimeval;
5. begin
6.   fpgettimeofday(tv, nil); // sure about nil?......?? Also wrong anyway fpgettimeofday returns microsecond resolution NOT nanoseconds. This is also the acces violation...
7.   Result := tv.tv_sec * 1000000 + tv.tv_usec; // is enough. You cast to a signed int64 and return a 32 bit type cardinal.... Won't overflow for a couple of million years
8. end;

« Last Edit: August 18, 2017, 09:45:32 pm by Thaddy »
I am enjoining wine, not whine....

#### enko

• New member
• Posts: 21
##### Re: Working with Microseconds
« Reply #2 on: August 19, 2017, 12:38:34 pm »

Using your function GetTickCount revisited I continue to have Access Violation.

I copy and paste your function GetTickCount revisited in a new console program
Code: Pascal  [Select]
1. program Project1;
2. uses SysUtils, Unix, baseunix;
3.
4. function GetTickCount:qword;  // it is twice the size of a cardinal!! And unsigned!
5. var
6.   tv: PTimeVal;
7.   tz: PTimeZone;
8. begin
9.   tz := nil;
10.   fpgettimeofday(tv, tz); // sure about nil?......?? Also wrong anyway fpgettimeofday returns microsecond resolution NOT nanoseconds. This is also the acces violation...
11.   Result := tv.tv_sec * 1000000 + tv.tv_usec; // is enough. You cast to a signed int64 and return a 32 bit type cardinal.... Won't overflow for a couple of million years
12. end;
13.
14. begin
15.   writeln(GetTickCount);
16. end.
17.

I have some error and warning on compiling

project1.lpr(10,20) Warning: Local variable "tv" does not seem to be initialized
project1.lpr(11,16) Error: Illegal qualifier
project1.lpr(11,16) Hint: may be pointer dereference is missing
project1.lpr(11,15) Error: Incompatible types: got "ptimeval" expected "QWord"
project1.lpr(11,16) Fatal: Syntax error, ";" expected but "identifier TV_SEC" found

googling "free pascal  fpgettimeofday" ALL examples / code are passing to the fpgettimeofday function the PTimeZone = nil

Note i'm using lazarus version installed on a Raspberry Pi3

Have you any precious suggestion ?
Thanks
Simply a Italian Programmer

#### enko

• New member
• Posts: 21
##### Re: Working with Microseconds
« Reply #3 on: August 19, 2017, 12:44:18 pm »
Also
Code: Pascal  [Select]
1. uses sysutils;
2. begin
3. writeln(GetTickCount64);
4. end.
5.

Simply a Italian Programmer

• Hero Member
• Posts: 6330
##### Re: Working with Microseconds
« Reply #4 on: August 19, 2017, 01:12:20 pm »
Also
Code: Pascal  [Select]
1. uses sysutils;
2. begin
3. writeln(GetTickCount64);
4. end.
5.

That's very very strange because I wrote the example (and this reply!) from a Raspberry Pi 3. Are you sure you are not using an old version? Did you upgrade to Stretch already? (That has FPC 3.0.0)..
That should not be necessary, but at least 3 is still a supported version:
Code: [Select]
`pi@raspberrypi:~/fpcdemos \$ fpc -CX -XXs counter.pasFree Pascal Compiler version 3.1.1-r36940 [2017/08/18] for armCopyright (c) 1993-2017 by Florian Klaempfl and othersTarget OS: Linux for ARMHFCompiling counter.pasLinking counter7 lines compiled, 0.9 secpi@raspberrypi:~/fpcdemos \$ ./counter20724027`
Anyway, your homebrew gettickkount is wrong, I am not going to debug that any further.

The standard implementation in sysutils looks like this:
Code: Pascal  [Select]
1. function GetTickCount64: QWord;
2. var
3.   tp: TTimeVal;
4.   {\$IFDEF HAVECLOCKGETTIME}
5.   ts: TTimeSpec;
6.   {\$ENDIF}
7.
8. begin
9.  {\$IFDEF HAVECLOCKGETTIME}
10.    if clock_gettime(CLOCK_MONOTONIC, @ts)=0 then
11.      begin
12.      Result := (Int64(ts.tv_sec) * 1000) + (ts.tv_nsec div 1000000);
13.      exit;
14.      end;
15.  {\$ENDIF}
16.   fpgettimeofday(@tp, nil);
17.   Result := (Int64(tp.tv_sec) * 1000) + (tp.tv_usec div 1000);  // look here!
18. end;

Since RPi does have HAVECLOCKGETTIME that is the version that gets executed.
« Last Edit: August 19, 2017, 01:33:47 pm by Thaddy »
I am enjoining wine, not whine....

#### enko

• New member
• Posts: 21
##### Re: Working with Microseconds
« Reply #5 on: August 19, 2017, 01:35:45 pm »
It seems I have an old version ...

pi@raspberrypi:~ \$ fpc
Free Pascal Compiler version 2.6.4+dfsg-4+rpi1 [2014/10/21] for arm
Simply a Italian Programmer

#### Eugene Loza

• Hero Member
• Posts: 561
##### Re: Working with Microseconds
« Reply #6 on: August 19, 2017, 01:48:31 pm »
You may do it this way (don't mix records with pointers to records):
Code: Pascal  [Select]
1. function GetTickCount: Int64;
2. var
3.   tv: TTimeval;
4. begin
5.   FpGettimeofday(@tv, nil);
6.   Result := Int64(tv.tv_sec) * 1000000 + Int64(tv.tv_usec);
7. end;
or
Code: Pascal  [Select]
1. function GetTickCount: Int64;
2. var
3.   tv: PTimeval;
4. begin
5.   FpGettimeofday(tv, nil);
6.   Result := Int64(tv^.tv_sec) * 1000000 + Int64(tv^.tv_usec);
7. end;
Similar code works fine for me.
Lazarus 1.9 + FPC 3.1.1 Debian Jessie 64 bit.

My Free and Open Source games in Lazarus/FreePascal/CastleGameEngine:
https://decoherence.itch.io/
(and some ancient games in Turbo Pascal too)
Sources are here: https://github.com/eugeneloza?tab=repositories

#### enko

• New member
• Posts: 21
##### Re: Working with Microseconds
« Reply #7 on: August 19, 2017, 02:08:17 pm »
can you tell me what I must to do to upgrade FPC e Lazarus IDE to lastest release for RaspBerry ??
Thanks a lot for your patience.
Simply a Italian Programmer

• Hero Member
• Posts: 6330
##### Re: Working with Microseconds
« Reply #8 on: August 19, 2017, 04:03:37 pm »
See Raspberry.org
The new Raspbian Stretch comes with fpc 3.0.0 and Lazarus 1.6.2
From fpc 3.0 it is easy to build a new Lazarus from source and also a new FPC 3.0.4.

So first advice is to update to latest RaspBian stretch.
Then sudo apt-get purge fpc && apt-get  autoremove && sudo apt-get install fpc
I am enjoining wine, not whine....

• Hero Member
• Posts: 6330
##### Re: Working with Microseconds
« Reply #9 on: August 19, 2017, 04:09:24 pm »
You may do it this way (don't mix records with pointers to records):
Code: Pascal  [Select]
1. function GetTickCount: Int64;
2. var
3.   tv: TTimeval;
4. begin
5.   FpGettimeofday(@tv, nil);
6.   Result := Int64(tv.tv_sec) * 1000000 + Int64(tv.tv_usec);
7. end;
or
Code: Pascal  [Select]
1. function GetTickCount: Int64;
2. var
3.   tv: PTimeval;
4. begin
5.   FpGettimeofday(tv, nil);
6.   Result := Int64(tv^.tv_sec) * 1000000 + Int64(tv^.tv_usec);
7. end;
Similar code works fine for me.

Both are wrong. I already gave the correct calculation from the official sources (sysutils).
Yours are prone to range checks and overflow.! You should use the version from sysutils.
Code: [Select]
`// for if there is no CLOCK*  fpgettimeofday(@tp, nil);  Result := (Int64(tp.tv_sec) * 1000) + (tp.tv_usec div 1000);  // look here!`
« Last Edit: August 19, 2017, 04:11:09 pm by Thaddy »
I am enjoining wine, not whine....