User avatar
Posts: 6327
Joined: Fri Jul 22, 2016 9:09 pm
Location: Eberbach, Germany

nanoflash.c derived from pigpio examples

Fri Aug 28, 2020 12:30 pm

In 2017 6by9 added "hardware camera sync pulses" for Raspberry cameras (v1+v2 at that time) to firmware, allowing for frame synchronization:

This year Naushir added "HQ Camera external sync signals support " to firmware, where different signals are generated directly on exposed HQ camera sensor pins:

Recently I used VSYNC rising edge from HQ camera module to trigger 5000lm led flash after specified offset with specified duration, both specified in microseconds, leaving remainder of frame dark:

I wanted to investigate sub-microsecond length flashes and remembered pigpio library example nanopulse.c that worked with Pi4B after few line modification (of Pi1 code from 2016):

I knew from my v1 camera global external shutter work, that placing 5000lm led very near to pellet flying with 109m/s produced very bright pellet multiple exposures even for 9µs duration flashes, so less than 1µs duration flashes are likely to show useful (and sharper) exposures: ... nt-9000eps

So I merged nanopulse.c with my flash code fl.c, and finally added gpioRead() implementation from "Tiny" pigpio example:

Code: Select all

#define GPLEV0 13

#define PI_BANK (gpio>>5)
#define PI_BIT  (1<<(gpio&0x1F))
#define PI_INPUT  0

int gpioRead(unsigned gpio)
   if ((*(gpioReg + GPLEV0 + PI_BANK) & PI_BIT) != 0) return 1;
   else                                         return 0;
resulting in nanoflash.c: ... 61ebf6b0c2

I was able to capture green laser directly lighting into 35mm C mount lens of HQ camera with 800ns duration, and even with 500ns duration.

This is endless loop doing the work:

Code: Select all

     while ((*gpioReg2 & 0x10) == 0)  {}  // 0x10: 1<<gpioDin
     while (gpioRead(gpioDin))  {}
The last statement is important to avoid multiple triggering for single VSYNC signal.

As discussed in nanopulse thread pointed to, for Pi4B code results in 2/3rd of requested duration. This code accounts for that:

Code: Select all

   d = atoi(argv[2]);
   d = (d*3)/2;  // Pi4B correction
   assert((4 <= d) && (d <= 224000));

So on Pi4B possible durations range from 3ns to 149,333ns.

I want to measure the effect of

Code: Select all

     while ((*gpioReg2 & 0x10) == 0)  {}  // 0x10: 1<<gpioDin

Code: Select all

    while (!gpioRead(gpioDin))  {}
For that I want to run two versions concurrently, both listening on same gpioDin, but one pulsing on gpio18 (pwm0), and the other on gpio13 (pwm1). Then use 400Msps logic analyzer to determine difference.

@joan, what changes for nanopulse.c/nanoflash.c are needed for working on pwm1?

This former code results in 60+d microsecond duration pulse:

Code: Select all

     gpioWrite(gpioDout, 1);
     assert(0 == usleep(d));
     gpioWrite(gpioDout, 0);
So gpioWrite() does cost either 60µs or 30µs, quite expensive.

Is there a faster way than

Code: Select all

     while ((*gpioReg2 & 0x10) == 0)  {}  // 0x10: 1<<gpioDin
with memory mapped files to act with as low as possible delay on gpioDin rising edge? [304+402+536fps]

Return to “C/C++”