User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

pigpio C sub µs single pulse generation

Wed May 22, 2019 8:31 pm

I did need a single pulse of duration from few microseconds to sub microsecond.

After I realized that using wiringPi these commands produce a >50µs length pulse, wiringPi was no option.

Code: Select all

...
    digitalWrite (13, LOW) ;
    digitalWrite (13, HIGH) ;
    digitalWrite (13,  LOW) ;
...

I found many postings wrt pigpio and (nanosecond) pulse generation.

Solution was simple, turn on 10Hz hardware PWM on GPIO13, wait 0.8ms and then turn off PWM on GPIO13:

Code: Select all

$ cat pulse.c 
/*
gcc -o pulse pulse.c -lpigpio -lrt
sudo ./pulse d   (0.1µs steps)
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pigpio.h>

int main(int argc, char *argv[])
{
   int d = (argc<2) ? 25 : atoi(argv[1]);

   if (gpioInitialise() < 0) return 1;

   gpioHardwarePWM(13, 10, d);
   usleep(800);
   gpioHardwarePWM(13, 0, 0);

   gpioTerminate();
}
$

Resolution of pulse length is 0.1µs, I did a short test after starting 100Msps logic analyzer:

Code: Select all

$ for((d=1; d<=20; ++d)); do sudo ./pulse $d; done

Then I exported the measured data, imported .csv into Libre office calc, did some work and finally got these pulse lengths in µs:

Code: Select all

0.17
0.31
0.43
0.54
0.64
0.75
0.84
0.93
1.05
1.13
1.23
1.33
1.43
1.53
1.64
1.73
1.83
1.93
2.04

As you can see there is no measured pulse for "1" argument (0.1µs), but for 0.2µs-2µs there are.
Not totally perfect, but I can live with sub 0.1µs imprecision.
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Wed May 22, 2019 8:55 pm

Oops, just realized that no C code is needed, this bash script using pigs does the same:

Code: Select all

$ cat pulse
#!/bin/bash
if [ -a /var/run/pigpio.pid ];
then
  echo "pigpiod running"
else
  sudo pigpiod
  echo "pigpiod started"
  sleep 0.5
fi

pigs hp 13 10 $1
sleep 0.0008
pigs hp 13 0 0
$
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

dl324
Posts: 122
Joined: Mon May 06, 2019 7:33 pm
Location: Pacific Northwest, USA

Re: pigpio C sub µs single pulse generation

Wed May 22, 2019 8:59 pm

HermannSW wrote:
Wed May 22, 2019 8:31 pm

Code: Select all

$ for((d=1; d<=20; ++d)); do sudo ./pulse $d; done
I question the validity of your experiment. You're adding process creation overhead that wouldn't be incurred in an actual application.

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Wed May 22, 2019 10:27 pm

dl324 wrote:
Wed May 22, 2019 8:59 pm
HermannSW wrote:
Wed May 22, 2019 8:31 pm

Code: Select all

$ for((d=1; d<=20; ++d)); do sudo ./pulse $d; done
I question the validity of your experiment. You're adding process creation overhead that wouldn't be incurred in an actual application.
While you might be right in general, in this case the process overhead does not count, since GPIO13 goes from low to high to low inside pulse. And only the pulse high duration is important and got measured. Since the measured durations are 2µs or below process startup cannot play any role as that takes far more time.
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
joan
Posts: 14260
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: pigpio C sub µs single pulse generation

Thu May 23, 2019 12:24 am

Not sure what pulses you want. Another way for countable pulses is a fast SPI clock and then transfer one byte on MOSI. 0x01 for one fast pulse, 0x05 for two etc.

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Thu May 23, 2019 7:14 am

joan wrote:
Thu May 23, 2019 12:24 am
Not sure what pulses you want.
I need to emit a single pulse in low single digit microsecond range to trigger a diy strobe light for making v1 camera do global shutter images. In this thread I was able to take global shutter images and videos with Arducam ov5647 camera (a v1 type camera with FREX and STROBE pins exposed):
viewtopic.php?t=235523

Now I want to do the same with "normal" v1 camera (7$ clone), so I need to trigger the strobe via GPIO from the Pi. In that thread I successfully took frames with 11µs strobe pulse length (see animated .gif below, propeller rotates with 26000rpm or 46m/s(!) at blade tip) , and with 4µs strobe pulse length. I have to get more lux out of 5000lm led with reflector for that case. When I will have done that, the final target is to capture flying rifle bullet at 375m/s, which moves 0.375mm/µs. For getting sharp image (<1mm movement) I need to have strobe pulse length <3µs.
Another way for countable pulses is a fast SPI clock and then transfer one byte on MOSI. 0x01 for one fast pulse, 0x05 for two etc.
I will test whether I can get configurable single digit microsecond length pulse durations with that method later, for now the "turn hardware PWM on, wait a little and turn it off then" gives me what I need.

Image
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
joan
Posts: 14260
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: pigpio C sub µs single pulse generation

Thu May 23, 2019 8:55 am

Ah, I thought you were after sub-microsecond times.

For an integral number of microseconds I would use a pigpio wave.

The following is a command line example.

Code: Select all

T=18 # trigger GPIO (Broadcom numbering)
L=3 # trigger length in microseconds

pigs m $T w # set GPIO into OUTPUT mode

pigs wvag $((1<<T)) 0 $L 0 $((1<<T)) 0 # pulse triplets
pigs wvcre # create wave from pulses (first should be number 0)

pigs wvtx 0 # transmit wave 0
pigs wvtx 0 # transmit wave 0
pigs wvtx 0 # transmit wave 0

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Fri May 24, 2019 11:41 pm

That sounds very interesting.

With 100Msps logic analyzer I saw that the falling edge of 11µs pwn signal is not clean:
Image
I don't know whether that is principal problem of Pi hardware PWM, or caused by SIG channel of IRF520 mosfet controlling the 5000lm led. I will try later whether pigs wafefoms can do better (the dirt at the falling edge is no problem for the strobe itsself, but if I capture the PWM pulses of taking a global shutter video with v1 camera, doing a measurement does not show the correct value for "average framerate" because of the dirt).


Today I had quite some problem to recreate the v1 camera (global shutter = global reset + very short flash duration) capturing from yesterday at all:
viewtopic.php?f=43&t=240442&p=1471612#p1471612
Most time I got completely black videos despite working 5000lm flash. Finally I got propeller images again, but with still incorrect timing. This results in broken images on the one hand, but generated my first triple (11µs strobe duration) exposure video frame today (of propeller moving radially with more than 35m/s at blade tips, that is 0.035mm/µs*11µs=0.385mm blade movement only per exposure -- the propeller has only two blades as shown in previous posting animated .gif):
Image
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Sat May 25, 2019 9:57 pm

joan wrote:
Thu May 23, 2019 8:55 am
For an integral number of microseconds I would use a pigpio wave.
Thank you so much for that advice, and the sample!

I used a modification of your example to generate ⁹₂₄₁⁹₂₄₁⁹₂₄₁⁹₂₄₁⁹ waveform (9µs high, 241µs low, ...).
The propeller rotating at 20000rpm takes 1000/(20000/60)=3ms for a full rotation.
The shown waveform is 1/3rd of full rotation, and shows each of the two propeller blades 5 times over a 1/3rd rotation.
Below you can see that it really works!

This is the script I used to emit that waveform:

Code: Select all

#!/bin/bash
if [ ! -f /var/run/pigpio.pid ]; then sudo pigpiod; sleep 0.5; fi

T=13 # trigger GPIO (Broadcom numbering)
S=9  # trigger length in microseconds
O=241

pigs wvclr    # clear all wavefoms
pigs m $T w   # set GPIO into OUTPUT mode

pigs wvag $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) 0

pigs wvcre # create wave from pulses (first should be number 0)

pigs wvtx 0 # transmit wave 0

This is the 2MP frame generated by the five 9µs duration strobe flashes:
Image


I did record with raspivid with "-fps 1". Finally I executed above script repeatedly fast. This is a frame where script was executed two times, so generated by ten 9µs duration strobe flashes:
Image


P.S:
Comparison of capturing with 5, 10 and 15 flashes of 9µs strobe pulse length (>22000rpm):
Image
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Sun May 26, 2019 11:50 am

This is the small diff to capture 9 flashes of 9µs strobe pulse length (propeller runs slightly faster at 22000rpm):

Code: Select all

$ diff shot3 shot3a
6c6
< O=241
---
> O=116
11c11
< pigs wvag $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) 0
---
> pigs wvag $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) $O $((1<<T)) 0 $S 0 $((1<<T)) 0
$
Image


As the frame comparison in "P.S" of previous posting shows it is not a good idea to have white wall short after the propeller as in Motor Test Station, because the white accumulates with each flash. Better have dark background, or just distant background so that it does not affect the frames. This becomes more important when capturing flying rifle bullet, at eg. 375m/s. The bullet moves 0.375mm/µs. If Bullet should be captured every 3cm, a flash needs to be done every 30/0.375=80µs. In that case it is easier to capture 12.5kHz PWM signal with duty cycle 10% for 8µs duration flashes. The best of this approach is that after turning on the PWM signal, the shot can be done anytime and will be captured, no need to know when it goes off the rifle.

Image


P.S:
I did tape the bright parts of motor and the white cable to motor with black tape in order to reduce bright spots from behind the propeller blades. Works fine mostly, only on top left the tape reflects the flash. When I will have received received my Black 3.0 (the blackest black) this kind of "make something non-reflective" will become trivial.
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
joan
Posts: 14260
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: pigpio C sub µs single pulse generation

Sun May 26, 2019 3:59 pm

There is a way to chain the waves together which may be simpler for some uses.

Code: Select all

T=13  # trigger GPIO (Broadcom numbering)
S=9   # on micros (trigger)
O=241 # off micros
R=15  # repeats

pigs m $T w   # set GPIO into OUTPUT mode
pigs wvag $((1<<T)) 0 $S 0 $((1<<T)) $O
W=$(pigs wvcre) # create wave from pulses and get Id

# Now repeat trigger on/off R times
pigs wvcha 255 0 $W 255 1 $R 0
Then, for instance, to send 50 triggers you could do

Code: Select all

pigs wvcha 255 0 $W 255 1 50 0

User avatar
Gavinmc42
Posts: 3732
Joined: Wed Aug 28, 2013 3:31 am

Re: pigpio C sub µs single pulse generation

Mon May 27, 2019 3:35 am

Could you have a sensor that triggers the strobe after a programmable time?
I'm thinking milk drops etc's
Been some time since I used Joan's code.

Nice link to Black3.0, got some gadgets with lasers that need black inside them.
I was annoyed that only one guy could use that other black.
I'm dancing on Rainbows.
Raspberries are not Apples or Oranges

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Mon May 27, 2019 6:28 am

Gavinmc42 wrote:
Mon May 27, 2019 3:35 am
Could you have a sensor that triggers the strobe after a programmable time?
I'm thinking milk drops etc's
Vela Pop (38£) sound trigger allows to configure delays between 0 and 1000 microseconds:
http://www.vela.io/vela-pop-high-speed-sound-trigger

That is cheap compared to 1 million lumen Vela One flash (0.5µs-5µs).
I built my own single digit µs flash based on a single 5000lm led with reflector, passive heat sink, mosfet and 50W led driver for less than 15$. Even that allows for 2.5 million lux (the relevant physical unit) just above the reflector.

I agree that you need the kind of delay if you want to capture eg. a bullet hitting an apple. But for capturing flying bullet (at eg. 375m/s) or milk drops this is not necessary. Just yesterday I captured a flying 6mm diameter airsoft pistol bullet (only 28m/s for now) with multiple exposure (that allowed to determine speed from the frame!) with PWM instead of pigs wafeforms (pigs hp 13 3000 25000; sleep 2; pigs hp 13 0 0). The only reason the bullet is not sharp is that lens was not adjusted well, was my first ever captured bullet in flight. For capturing 375m/s bullet (0.375mm/µs) every 3cm in flight PWM frequency has to be 1000000/(30/0.375)=12.5kHz. Duty cycle 1.25% will result in 1µs strobe duration. See thread "Raspberry v1 camera global shutter videos" started yesterday:
viewtopic.php?f=43&t=241418
Image
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
Gavinmc42
Posts: 3732
Joined: Wed Aug 28, 2013 3:31 am

Re: pigpio C sub µs single pulse generation

Mon May 27, 2019 8:39 am

Picture tells a thousands words, even if it is fuzzy ;)
Multi-exposures can determine speed, brilliant.

Need one of those black and white distance ruler background like on Mythbusters?
Perhaps black and grey to avoid saturation?
I'm dancing on Rainbows.
Raspberries are not Apples or Oranges

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Mon May 27, 2019 8:51 am

Gavinmc42 wrote:
Mon May 27, 2019 8:39 am
Need one of those black and white distance ruler background like on Mythbusters?
Perhaps black and grey to avoid saturation?
I thought about that, but it is no good idea for my kind of PWM multiple exposure (each frame gets 3000 exposures of single digit µs strobe pulse length per 1fps frame, and each exposure accumulates the ruler). In the image I know the diameter of airsoft bullet (ball) as 6mm, so no ruler needed there.

A ruler is no problem for a (low) fixed number of multiple exposures from a waveform though, but in that case you need to synchronize milk drops and tiggering strobe pulses somehow.
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
Gavinmc42
Posts: 3732
Joined: Wed Aug 28, 2013 3:31 am

Re: pigpio C sub µs single pulse generation

Mon May 27, 2019 9:08 am

in that case you need to synchronize milk drops and triggering strobe pulses somehow.
Time to google milk drop setups.

If you use a NOIR camera, IR LEDS and only green/luminance can you go faster, ignoring the other colours?

I going to have to try this now, you are having too much fun.
Hmm perhaps a propeller first, I can see milk getting messy real quick.
I'm dancing on Rainbows.
Raspberries are not Apples or Oranges

User avatar
[email protected]
Posts: 2020
Joined: Tue Feb 07, 2012 2:14 pm
Location: Devon, UK
Contact: Website

Re: pigpio C sub µs single pulse generation

Mon May 27, 2019 1:08 pm

HermannSW wrote:
Wed May 22, 2019 8:31 pm
I did need a single pulse of duration from few microseconds to sub microsecond.

After I realized that using wiringPi these commands produce a >50µs length pulse, wiringPi was no option.

Code: Select all

...
    digitalWrite (13, LOW) ;
    digitalWrite (13, HIGH) ;
    digitalWrite (13,  LOW) ;
...
With wiringPiSetup() or wiringPiSetupGpio() or wiringPiSetupPhys() those calls ought to produce a pulse well under one microsecond, so I've no idea what you're actually doing.

Of-course Linux scheduling/DRAM refresh will get in the way at some point, but really - I can wiggle a GPIO pin at just under 20Mhz using digitalWrite() in wiringPi.

You've no timing control whatsoever though, but pulse widths of well under one microsecond are very possible.

-Gordon
--
Gordons projects: https://projects.drogon.net/

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Wed May 29, 2019 12:54 am

[email protected] wrote:
Mon May 27, 2019 1:08 pm
With wiringPiSetup() or wiringPiSetupGpio() or wiringPiSetupPhys() those calls ought to produce a pulse well under one microsecond, so I've no idea what you're actually doing.
Perhaps I forgot to compile with "-O6" option, I don't know.
Of-course Linux scheduling/DRAM refresh will get in the way at some point, ...
I completely based new tool "raspivid_ges" on pigpio because of that, pigpio waveforms are what is needed for playing with µs resolution waves:
viewtopic.php?f=43&t=241418&p=1473724#p1473724
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Wed May 29, 2019 1:01 am

joan wrote:
Sun May 26, 2019 3:59 pm
There is a way to chain the waves together which may be simpler for some uses.

Code: Select all

T=13  # trigger GPIO (Broadcom numbering)
S=9   # on micros (trigger)
O=241 # off micros
R=15  # repeats

pigs m $T w   # set GPIO into OUTPUT mode
pigs wvag $((1<<T)) 0 $S 0 $((1<<T)) $O
W=$(pigs wvcre) # create wave from pulses and get Id

# Now repeat trigger on/off R times
pigs wvcha 255 0 $W 255 1 $R 0
Then, for instance, to send 50 triggers you could do

Code: Select all

pigs wvcha 255 0 $W 255 1 50 0

Thanks Joan, I built tool "shots" based on your code:

Code: Select all

#!/bin/bash
#             based on joan's code:
# https://www.raspberrypi.org/forums/viewtopic.php?f=33&t=241151#p1473730
#
T=13  # trigger GPIO (Broadcom numbering), GPIO13 has hardware PWM
O=241 # off micros
S=9   # on micros (trigger)
R=5   # repeats
if [ "$4" != "" ]; then T=$4; fi
if [ "$3" != "" ]; then O=$3; fi
if [ "$2" != "" ]; then S=$2; fi
if [ "$1" != "" ]; then R=$1; fi

if [ ! -f /var/run/pigpio.pid ]; then sudo pigpiod; sleep 0.5; fi

N=/dev/null

pigs wvclr                                          # clear all wavefoms
pigs m $T w                                         # set GPIO into OUTPUT mode
pigs wvag $((1<<T)) 0 $S 0 $((1<<T)) $O >$N         # add pulse to waveform
pigs wvcre   >$N                                    # wave from pulses (1st 0)
pigs wvcha  255 0 0  255 1 $(($R%256)) $(($R/256))  # repeat trigger on/off R×

Just execution "./shots" with default settings results in this frame captured (of propeller rotating with 20000rpm):
Image


I did copy and modify that script to capture with 1/3/5/7/9µs strobe duration as experiment, discussion here:
viewtopic.php?f=43&t=241418&p=1473724#p1473724
Image
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Tue Jun 04, 2019 6:34 am

While the initial postings in this thread were on pigpio C, the latter ones were just on shell scripts/pigs.

Yesterday I had to go back to pigpio C library. "shots" tool generates multiple strobe pulses, but there is no synchronization between strobe pulse generation and camera frame taking. If the total length of the waveform is less than 0.5s getting all pulses recorded onto a single "-fps 1" raspivid frame is not really a problem. But I had to try 15 times to get two 9µs strobe pulses 0.9s apart onto the same frame.

I remembered that since 2017 firmware the camera led GPIO can be misused to signal camera frame transmission start and end. I used the frame end signal to start the waveform just in time for the new frame to be recorded. The passed argument N states how many frames with (this time 0.925s apart) double exposures should be taken. I tried with 20 and each and every frame got its double exposure correctly. I learned about gpioSetAlertFunc() function, and with that function the code is simple.

More details in "Hardware camera sync pulses" section on "Raspberry v1 camera global external shutter" github repo:
https://github.com/Hermann-SW/Raspberry ... ync-pulses

https://github.com/Hermann-SW/Raspberry ... io_alert.c

Code: Select all

/*
   $ gcc -O6 -o gpio_alert gpio_alert.c -lpigpio -lrt -lpthread
   $
   
   After start of raspivid_ges:
   $ sudo killall pigpiod
   $ sudo ./gpio_alert N
   $
   will sync to frame end and do two 9µs strobe pulses, 925000µs apart.
   The two flashes will show up on a single frame with raspivid_ges "-fps 1".
   There will be N consecutive camera synced double exposure frames.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

#include <pigpio.h>

#define gpioStrobe 13
#define gpioHWsync 18

int wave_id, N=1;

gpioPulse_t pulse[5]={
   {0,1<<gpioStrobe,2},      {1<<gpioStrobe,0,9},
   {0,1<<gpioStrobe,925000}, {1<<gpioStrobe,0,9},
   {0,1<<gpioStrobe,0}
};

void alert(int gpio, int level, uint32_t tick)
{
   if (level!=0)  return;

   if (--N == 0)  gpioSetAlertFunc(gpioHWsync, NULL);

   gpioWaveTxSend(wave_id, PI_WAVE_MODE_ONE_SHOT);
}

int main(int argc, char *argv[])
{
   assert(argc > 1);
   assert(0 < (N = atoi(argv[1])));
       
   assert(gpioInitialise()>=0);

   gpioSetMode(gpioStrobe, PI_OUTPUT);

   gpioWaveAddNew();

   gpioWaveAddGeneric(sizeof(pulse)/sizeof(pulse[0]), pulse);

   wave_id = gpioWaveCreate();

   assert((wave_id >= 0) | !"wave create failed\n");

   gpioSetAlertFunc(gpioHWsync, alert);

   sleep(3+N);

   gpioTerminate();
}
Image
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Thu Jun 27, 2019 6:40 pm

I am working on getting global external shutter done with ESP32-CAM ov2640 sensor (a predecessor of Raspberry v1 ov5647 sensor which does global external shutter captures nicely). After I learned how to solder a cable to one of 24 pins of ESP32-CAM module flat ribbon cable connector (0.5mm spaced!)
https://www.esp32.com/viewtopic.php?f=1 ... 445#p45445

I did need the ESP32 equivalent of Raspbian pigpio waveforms.
It turned out that ESP32 component RMT (The Remote Peripheral) can do exactly that.

This is the ESP32 Arduino sketch that does similar to gpio_alert.c in previous posting (send two 9µs high pulses, this time 32000µs apart instead of 925000µs in previous posting).
Image
The duration length has to be a 15bit number. Anyway, porting pigpio waveform code to ESP32 (as I need for the global external shutter tools) can be easily done like this (rmtInit is done for GPIO4, connected to builtin flash of ESP32-CAM module):

Code: Select all

#include "esp32-hal-rmt.h"

#define assert(expr) if (!(expr)) {                   \
  Serial.begin(115200); Serial.println(#expr);        \
  Serial.println(__FILE__); Serial.println(__LINE__); \
  for(;;) {}                                          \
}

rmt_data_t data[]={
  {      2, 0, 9, 1 },
  {  32000, 0, 9, 1 },
  {      2, 0, 0, 0 }
};

rmt_obj_t* rmt_send = NULL;

void setup() 
{
  assert((rmt_send = rmtInit(4, true, RMT_MEM_64)) != NULL)

  assert(1000 == rmtSetTick(rmt_send, 1000)) // 1µs resolution
}

void loop() 
{
  assert(rmtWrite(rmt_send, data, sizeof(data)/sizeof(data[0])))

  delay(1000);
  // assert(4==5);
}
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Mon Sep 02, 2019 11:35 pm

HermannSW wrote:
Mon May 27, 2019 6:28 am
Gavinmc42 wrote:
Mon May 27, 2019 3:35 am
Could you have a sensor that triggers the strobe after a programmable time?
I'm thinking milk drops etc's
Vela Pop (38£) sound trigger allows to configure delays between 0 and 1000 microseconds:
http://www.vela.io/vela-pop-high-speed-sound-trigger
...
No need for that, I just used <1$ microphone sensor to trigger global external shutter capturing after a provided offset in µs.
And using pigpio library it was so easy to do!
Initial commit of audio_shots.c is here (1 waveform doing it all seemed easier than stopping PWM):
https://github.com/Hermann-SW/Raspberry ... 5aede4f054

More details in camera forum thread posting:
https://www.raspberrypi.org/forums/view ... 7#p1529967

Captured 10µs offset after mirophone sensor trigger, 100 flashes of length 9µs at frequency 3000Hz (36m/s pellet, 6mm diameter):

Code: Select all

$ sudo ./audio_shots 100 9 3000 10
Image
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Tue Sep 03, 2019 5:27 pm

Just a short update, audio_shots.c just works, no changes needed; and it enables to find the correct offset needed:
(five 9µs long flashes at 6KHz, 2000µs after microphone sensor trigger, 36m/s airsoft pistol 6mm diameter pellet)

Code: Select all

$ sudo ./audio_shots 5 9 6000 2000
Image
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
HermannSW
Posts: 1493
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany
Contact: Website Twitter YouTube

Re: pigpio C sub µs single pulse generation

Thu Sep 05, 2019 6:38 pm

@joan:

The initial commit of audio_shots.c had severe stability issues.
When I did 9 shots in a row then the Pi froze completely, power cycling was needed.
Sometimes after 2 shots, sometimes after 8.

I think I found the reason for this and fixed it with this commit:
https://github.com/Hermann-SW/Raspberry ... 67705ebc04

Can you confirm that calling gpioWaveTxSend() inside an alert function might freeze the Pi completely?


My application is really time sensitive, the pellet flies through camera view in 13/6000Hz=2.166ms (at speed of 36m/s).
While debugging the freeze issue I read function documentation completely:
http://abyz.me.uk/rpi/pigpio/cif.html#gpioSetAlertFunc
The GPIO are sampled at a rate set when the library is started.
If a value isn't specifically set the default of 5 us is used.
5µs would be OK, because the pellet flies only 5µs*36m/s = 5µs*0.036mm/µs = 0.18mm in that time.

But this is a problem for my application:
The thread which calls the alert functions is triggered nominally 1000 times per second.
The possible delay between sound from shot and call of alert function is in range 0..1ms.
During that time pellet might fly up to 1ms*36mm/ms=36mm, which is nearly half of the 7.8cm horizontal FoV.

This seems to indicate that alert function is not the right way to use pigpio library when searching for µs precision, right?


Is Interrupt Service Routine be the right way to go?
http://abyz.me.uk/rpi/pigpio/cif.html#gpioSetISRFunc
The tick is that read at the time the process was informed of the interrupt. This will be a variable number of microseconds after the interrupt occurred. Typically the latency will be of the order of 50 microseconds. The latency is not guaranteed and will vary with system load.
I understand that this is the latency of the tick value which will be passed to ISR function.
I know that no long stuff should be done inside an ISR, so not calling gpioWaveTxSend() to avoid freeze as before.
What could be the latency with using ISR between sound trigger and sending wave using ISR?


Perhaps I was thinking in the wrong direction.
With latest commit I do an active wait already (done gets set in alert function, or perhaps in ISR):

Code: Select all

   while (! done) { }
   gpioWaveTxSend(wave_id, PI_WAVE_MODE_ONE_SHOT);
Would it be better for my µs precision requirements to not use alert/ISR at all and just do active waiting?
The Pi has 4 cores, one core runs raspivid, and a 2nd runs audio_shots during capturing an airsoft/airgun shot, no other CPU load.
⇨https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://gitlab.freedesktop.org/HermannSW/gst-template
https://github.com/Hermann-SW/fork-raspiraw
https://twitter.com/HermannSW

User avatar
joan
Posts: 14260
Joined: Thu Jul 05, 2012 5:09 pm
Location: UK

Re: pigpio C sub µs single pulse generation

Thu Sep 05, 2019 8:30 pm

There shouldn't be a problem starting a wave from an alert function.

There may be a problem starting a new wave before the previous one has completed. It's best to check that the previous wave has finished with gpioWaveTxBusy(). For the time being I'd assume this is what is causing the crash.

Alerts are not the best trigger for your purpose.

Statistically a busy spin will likely give the least latency, followed by interrupts (ISR), followed by alerts. I say statistically as you don't know what Linux may be doing in the background.

Return to “C/C++”