* * *

Author Topic: Working with Microseconds  (Read 806 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.                                                                
  32.         while(!(digitalRead(Echo) == 1));
  33.         gettimeofday(&tv1, NULL);           //获取当前时间
  34.  
  35.         while(!(digitalRead(Echo) == 0));
  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

Thaddy

  • Hero Member
  • *****
  • Posts: 4617
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 »
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

enko

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

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.  

On compiling I have Error: Identifier not found "GetTickCount64"
Simply a Italian Programmer

Thaddy

  • Hero Member
  • *****
  • Posts: 4617
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.  

On compiling I have Error: Identifier not found "GetTickCount64"

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.pas
Free Pascal Compiler version 3.1.1-r36940 [2017/08/18] for arm
Copyright (c) 1993-2017 by Florian Klaempfl and others
Target OS: Linux for ARMHF
Compiling counter.pas
Linking counter
7 lines compiled, 0.9 sec
pi@raspberrypi:~/fpcdemos $ ./counter
20724027

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 »
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

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: 506
    • My "almost daily" development blog
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 »
Thaddy
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

Thaddy

  • Hero Member
  • *****
  • Posts: 4617
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
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

Thaddy

  • Hero Member
  • *****
  • Posts: 4617
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 »
"Logically, no number of positive outcomes at the level of experimental testing can confirm a scientific theory, but a single counterexample is logically decisive."

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus