Millisecond resolution laser clock -- now 10us resolution

For having visible timestamps in high framerate recordings I was interested in having a clock at millisecond reolution. Most clocks on even expensive smartphones cheat in having jumps of 8ms in display (tested that on an iphone 6 of a colleague).

First I did direct display framebuffer manipulations in top left corner of 7" Raspberry display, with 5000 updates per second (the 6 horizontal bars are 100s, 10s, 1s, space, 0.1s, 0.01s and 1ms:

Yesterday I did same on normal RHEL Linux ascii console framebuffer:
https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=228145&p=1401287#p1401287

Both methods suffer from low display refresh rate. My monitor does 60Hz only, and even the best do "only" 240Hz which is not good enough for millisecond precision.

I read that leds can be toggled off->on->off in nanosecond range. Then I remembered my experiment with eight 5mW 3.3V red laser diodes directly connected to Raspberry Pi Zero:
https://www.raspberrypi.org/forums/viewtopic.php?t=155133

In that thread I asked whether direct connection to GPIO pins is safe -- luckily it was because the laser diodes have SMD transistor built in:

So today I wanted to build a laser led clock at millisecond resolution from that, and started with Arduino Due because I was able to directly put the led cables into the Due headers.

I wanted to build the millisecond resolution bottom bar today only. In order to represent 10 numbers 4 bit are necessary, I used 5 leds to get better viewable clock by having a "snake of length 5" move through the five laser sensors.

I did connect the 5 sensors to D9-D13 and had to cheat because Due has only 4 GND pins in putting two cables into one GND.

I did superglue the 5 laser sensor on 6x2 Lego piece and expected to have laser dots in line. Unfortunately that is not true, but the "display" is good enough as clock for now.

OK, first the code that I used:

void setup() {
  pinMode( 9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);

  Serial.begin(115200);
  
  int i,m,t1,t0=millis();
  
//  for(i=0; i<1000000; ++i) {
  for(;;) {
    delay(0);
    t1=millis();
    m = t1 % 10;
    digitalWrite( 9 + m%5, m/5 );
  }
  Serial.println(t1-t0);
}

void loop() {
}

It turned out that a call to delay() is necessary in order to make everything work. It was a total surprise to me that "delay(0)" is allowed and does what is needed (similar to yield() call).

I tested 1,000,000 loops and measured 31678ms in total. That means 1000000/31.678=31567 updates/second, resulting in more than 30 updates between two consecutive millisecond values.

So what do you get with above code?

In order to "see" that I did high framerate 1007fps(!) 640x150_s videos with Raspberry v2 camera. For being able to record with 1000fps scene has to be very bright. I moved a 1000lm Ikea lamp very near to scene (you can see its round bottom at top of video). Here you can see animated .gif played at 25fps, 40 times slower than real:

Although this video is played 40 times slowed down, not much details can be seen. Here is animated .gif played at 1fps so that you can see each and every frame (recorded at 1007fps):

I am happy with the result of now having millisecond resolution clock when needed (the code can be easily modified for 0.1ms resolution because of >10000 updates/second) -- and that it is so easy code with Arduino. I have the same 5mW laser leds for 5V, those could be connected to Arduino Uno and others. The 3.3V leds used here with Aruino Due can be directly used with Raspberries that have 3.3V GPIO as well.

I have to correct the timing analysis, there was a typo in last line of sketch I corrected yesterday already.
Old: Serial.println(10*t1-t0);
Correct: Serial.println(t1-t0);

I just did rerun the 1 million loops, and as expected the reported time drops by factor 10, now 3238ms.

Therefore 1,000,000/3.238 = 308,832 updates per second are done by Due (I love the 84MHz CPU).
That means that above code can easily be modified for laser clock with 10µs precision!!

I currently have no means to verify that 10µs resolution laser clock works, I can "only" record 1007fps videos right now :wink:

This is the whole setup:

  • in front you see Arduino Due
  • on topopf Lego brick bridge you see the 5 superglued 5mW 3V laser diodes
  • on the wooden wall you see the 5 laser dots generated
  • in top left you see Raspberry v2 camera in "third hand" for recording the scene
    (connected by 2m cable, not the short 15cm ones)

I found a (simple) way to verify function of a laser clock with 10µs resolution and went ahead.
Instead of a very high framerate camera I made use of a Laser sensor module.
And a cheap 5$ 8CH 24Msps logic analyzer.

I used the same program from last posting, but did connect a single laser only.
Not a clean setup, but worked fine:

I did first measurements with old 1ms resolution program:

It takes less than 1µs for the laser sensor to detect laser turned on, and 10µs to detect laser off.
The reported frequency is 99.96Hz, which is (nearly) correct:
While every 1ms one laser LED gets switched, because of the 5-snake moving through the laser LEDS a single laser is on for 5ms and off for 5ms.

Next I simplified the program for laser clock 10µs, here it is:

void setup() {
  int i;
  
  for(i=9; i<=13; ++i) { pinMode( i, OUTPUT); }

  for(;;) {
    delay(0);
    i=(micros()/10)%10;
    digitalWrite( 9 + i%5, i/5 );
  }
}

void loop() {
}

On (84MHz) Arduino Due micros() function resolution is really 1µs. Integer divided by 10 gives 10µs resolution, and modulo 10 is for this clock. A real full blown laser clock at 10µs resolution would need 25 laser leds to represent 1 second.

This is the logic analyzer capturing:

The 10µs delay of laser sensor on falling edge is no problem here since laser is on/off for 5*10µs as discussed before. Its not a perfect clock because the measured frequency is 9.975 kHz while for a perfect 10µs resolution it would be 10 kHz. But I would say for most applications -0.25% precision is acceptable.

This will be the last posting for now. It will show that even a 100us resolution clock can make sense.
I modified the 10µs resolution sketch, from

 i=(micros()/10)%10;

to

 i=(micros()/100)%10;

resulting in a 100µs resolution clock.

Of course the raspiraw tool 640x150_s I used sofar would always display all dots because its shutter time is nearly 1ms for 1007fps and that catches all 10 states of the clock. In order to get a "real" photo the camera shutter time needs to be reduced to 100µs (which is challenging scene lighting wise, I kept the 1000lm lamp, perhaps its time to use my 50W 5000lm light chips).

Currently I have problem with adding 100µs shutter time to 1007fps 640x150_s tool, so I switched to 1007fps 640x75 tool. This is the diff, just adding --expus 100:

$ diff 640x75 640x75_100 
10c10
< raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 75 --voinc 01 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null
---
> raspiraw -md 7 -t $1 -ts tstamps.csv -hd0 hd0.32k --height 75 --voinc 01 --expus 100 --fps $fps -sr 1 -o /dev/shm/out.%04d.raw 2>/dev/null >/dev/null
$

Because now only 75 lines get captured, only the bottom 3 laser dots are in view. What you see here are 280 consecutive frames without a single frame skip in between from a 2s recording, captured at 1007fps and played at 25fps, 40 times slower than real:

There are 4 patterns:

  • no dot
  • 2 dots on left
  • 3 dots
  • 2 dots on top

The last one (two dots on top) is "wrong" in that the sketch would never produce this pattern. It exists because Raspberry v2 camera rolling shutter effect. Positioning all 5 laser dots in one horizontal line will eliminate this kind of issue.

Summary:
Even with 1007fps maximal framerate camera a 100µs resolution clock can make sense.
The timestamps are like water marks for the scenes of interest that are really recorded.
100µs resolution clock needs 4*5=20 laser leds to represent 1 second.

Minor followup, I used the last sketch with updates every 100µs. As discussed, because of every laser being 5 ticks on, 5 ticks off, the frequency of a laser on/off is 1 kHz.

Today I remembered a cheap 8$ digital laser tachometer I bought recently to verify propeller speed of RC airplane that I determined visually via 1007fps video as 20,140rpm before:
https://www.raspberrypi.org/forums/viewtopic.php?f=43&t=190407&p=1396192#p1396192

The tachometer works by adding some reflective material to the object the rotational speed should be determined and directing tachometer's laser light onto that. I just tried whether a single 5mW laser dot is bright enough to be detected by the laser tachometer (no rotation, but the laser led toggles on/off with 1kHz). And it works, as you can see tachometer reports 60*1,000=60,000 (rpm):

The measured exact 60,000 says us that Arduino Due did deliver 1kHz laser frequency exactly, and that the -0.25% measured via the logic analyzer are either caused by the logic analyzer or the laser sensor. So Arduino Due is good.

Thanks for sharing.
I wander if I can replicate your results using a cheap STM32F103 Blue Pill board.

You can, and I after having received ST-LINK programmer:

Mmmm.. I will test it. Maybe with direct port manipulation. I ordered the same tachometer but I have to wait one or two months.
Thanks again.