Various AE related bugs in Argus

Hello,
because there is source code to fix this, here I report two serious bugs withing the Argus / SCF subsystem on TX2 R28.1

Bug #1

  • heavy oscillating exposure when autoexposure is enabled, under the condition when the digital ISP gain is limited to range of 1.000 to 1.000 (that setting in our intention is to disable application of any digital gain).

Bug #2

  • Allowing a digital ISP gain range of 1.0 to 4.0 will lower the oscillation, but the analog gain will stay at magic number of 999 instead of maxing out the control to 1958. Because we do not have SCF sources, we expect different behavior (apply digital ISP gain after the analog gain on the sensor is fully maxed out).

Bug #3

  • the AE which modifies the gain (older style controls with integer value, not the new int64/fixedpoint) is not operating at all when the control has a range starting with 0 (to MAX). Shifting the range of 1 to MAX+1 will enable auto exposure. Truly wonderful “feature” to waste a week of our precious time.

@danieel

Did you reproduce the bug #1, #2 with argus_camera sample APP. Any specific environment to observe this issue?

@ShaneCCC:

The bug 1 and 2 appears on both the LI IMX377 driver and our IMX377 driver. While LI choose to use gain range of 1-1957 in driver and 0-1957 in device tree, we have shifted the range to 1-1958 in both locations (since the sensor has a range of usable values 0-1957).

The easiest way to test is indeed through the argus_camera sample APP, as one can easily change the used ranges in its GUI.

There is also:

Bug #4
argus_daemon will SEGFAULT when there is none of /dev/videoX nodes (e.g. sensor driver not probed due missing I2C bus)

Bug #5
argus_daemon will SEGFAULT when there are mixed old and new style controls. Luckily, it will print a warning message to not mix these controls.

And one open question which would be otherwise clear from SCF sources:

Q: How does SCF determine that the frame_length has to be set to 3200 for 30 fps? From which pixel rate / line length does it calculate the value?

@danieel

  1. You have to make sure the gain range is linear.
  2. For the bug #4 that’s the error handle not doing well. BUg #5 I think the sensor programing guide should have NOTE for this.

@ShaneCCC: What is the advisory for implementing a non-linear gain transfer curve? At the bottom of the curve, the gain is pretty detailed, while on the top of the range, the steps are very big:

Value  Gain[dB] Gain(ratio)
  0	 0.0000	 1.000
  1	 0.0042	 1.000
  2	 0.0085	 1.001
  3	 0.0127	 1.001
  4	 0.0170	 1.002
  5	 0.0212	 1.002
  6	 0.0255	 1.003
  7	 0.0297	 1.003
  8	 0.0340	 1.004
  9	 0.0383	 1.004
  10	 0.0425	 1.005
  11	 0.0468	 1.005
  12	 0.0510	 1.006
  13	 0.0553	 1.006
  14	 0.0596	 1.007
  15	 0.0639	 1.007
  16	 0.0681	 1.008
  17	 0.0724	 1.008
  18	 0.0767	 1.009
  19	 0.0810	 1.009
  20	 0.0852	 1.010
   :
   :
   :
1946	26.0546	20.078
1947	26.1402	20.277
1948	26.2266	20.480
1949	26.3139	20.687
1950	26.4021	20.898
1951	26.4912	21.113
1952	26.5812	21.333
1953	26.6721	21.558
1954	26.7640	21.787
1955	26.8569	22.022
1956	26.9508	22.261
1957	27.0458	22.505

It would be great, if Argus could use a volatile control which will read back the actual floating point gain (either Linear, or in dB scale). The idea is that at startup it shall scan the range defined by the gain control (the legacy, integer version), and when using the gain, it will stick to this table, to pick the best setting.

Or if we use the new INT64 control for gain, with fixed point - can we somehow round the control to the nearest value so that we let Argus know what is the actual gain?

If the actual gain vs. expected gain will differ, then we are always facing a trouble of getting Argus into an unstable state.

With my experience with several brands of image sensors, the feature of linear gain without missing codes is very scarce.
What is the solution for this within SCF ?

Looking to the reference driver which is the IMX185 (judging by other posts, and also that it came with L4T and bears an NVidia copyright):

static int imx185_set_gain(struct imx185 *priv, s64 val)
:
        /* translate value */
        gain64 = (s64)(val / FIXED_POINT_SCALING_FACTOR);
        gain = (u8)(gain64 * 160 / 48);

This does rounds the fixed point number to the integer part, leaving 49 options in range of 0 to 48 and then translates this number into a register setting where the mapping is 48dB = 0xA0 (160d).

So the question is: does the Argus/SCF expects the gain to be “linear” on the dB scale? Or rather linear in the gain ratio scale?

Whoever wrote that IMX185 driver, did a lousy job, ignoring the fractional bits of the fixed point number. Or if it was intentional, can Argus handle such rounding? Or does not even use the fractional bits when trying to set the gain with INT64 control in dB?

Soo many questions and so little documentation. Or source code :)

I think the 28.2 sensor programing guide have explain it.

This only explains that you mis-use the controls and enforce a variable fixed point encoding mapping. If the min value determines the position of the decimal point, then really the 0 value can not be used. This would imply, that the gain is LINEAR, starting with 1.000 ratio as the minimal gain, but also mean that you can not set less than 1.00 gain (e.g. 0.5, as some sensor support that as well). But the IMX185 driver does not use LINEAR gain, it uses LOG gain, in units of dB. And discards the fractional part anyway, due to poor coding.

The documentation (screenshot you posted) is unclear in what units the gain really should be - whether LINEAR (ratio) or LOG (dB), and does not specify how to handle missing codes, when the sensor can not be set to an exact gain.

Every sensor we have worked with, being that with integrated ADC or external one, the PGC stage has a finite amount of gain settings, ranging from as low as few steps to few thousands and the values are rarely continuous in linear or log space, sometimes even multiple values map to the same gain. This shall be handled by a LUT, with gain ID and gain Value and not by an imaginary fixed point number of an unknown unit, that was designed by someone who never worked with an image sensor.

I have implemented the gain control as a INTEGER64 type - similar as it is in the reference imx185.c code. Note that, the min/max/default are no longer valid for int64 controls and your programmers are not aware of that.

So now I have this control:

gain (int64)  : min=0 max=0 step=0 default=0 value=4194304 flags=slider

NOTE: the version of v4l2-ctl in Ubuntu is too old, and for int64 controls only the value shall be printed.

But it does not work.

Reading through the Sensor programming guide, I have found out that the camera framework can work either in dB scale or in linear ratio scale. This is controlled by the DTB settings:

dB

imx377_a@1a {
          use_decibel_gain = "true";
          mode0 {
            min_gain_val = "0"; /* dB */
            max_gain_val = "27.046"; /* dB */
          };

LINEAR

imx377_a@1a {
          use_decibel_gain = "false";
          mode0 { 
            min_gain_val = "1"; /* :1 */
            max_gain_val = "22.505"; /* :1 */
          };

In dB scale: the argus_camera will not change the gain at all. Probably the bug when the range starts with 0? But we really need a +0.0 dB unity gain!

In LINEAR: when running the argus_camera tool always the the maximal gain is applied (value found in DT), no matter what limits do we set with:

argus_camera --ispdigitalgainrange=1,1 --gainrange=1,5

The user interface show the proper range, but the call in kernel shows only the initial and then the maximal one:

[   79.118028] [imx377:2] control[10100747:Gain] = 4194722 ~ 1.000099
[   79.124224] [imx377:2] gain req:4194722 -> out:4194304 err:-418 idx:0 -> +0.000 dB ~ 1.000
[   79.132564] [imx377:2] control[10100753:A gain] new VALUE is 0
[   79.138410] [imx377:2] control[10100753:A gain] = 0

[   79.380495] [imx377:2] control[10100747:Gain] = 94394885 ~ 22.505494
[   79.386963] [imx377:2] gain req:94394885 -> out:94394885 err:0 idx:1957 -> +27.045 dB ~ 22.505
[   79.395765] [imx377:2] control[10100753:A gain] new VALUE is 1957
[   79.401996] [imx377:2] control[10100753:A gain] = 1957

This uses a helper function that translates the linear or dB gain request value into the sensor register setting (made through the ‘A gain’ custom control). I had to list all the 1958 settings in a lookup table which is searched for the minimal difference.

AE of course does not work at all now. With the old style INTEGER control, some functionality could be observed, but the system get into flickering by the gain being not the same scale as expected.

Any ideas?

  1. For the start from 0, IMX185 reference driver start from 0 too, but it working well.
  2. To enable logs to know the setting from user space.
sudo su
kill the process of argus_daemon or nvcamera-daemon
export enableCamPclLogs=5
export enableCamScfLogs=5
/usr/sbin/argus_daemon      option for argus
/usr/sbin/nvcamera-daemon   option for gst-launch
 
launch camera from another console

@ShaneCCC - in our case, starting with 0 does not do anything, we are in dB mode.

Having the lens on a fully open aperture we see one GAIN setting call when we run argus_camera:

argus_daemon log:

INPUT: Width 4104 Height 3046 pixelformat RG12
writeFrameRate: INPUT frameLength:3200, frameRate:30.000000
writeGain:      INPUT gainCtrl:47 analogGain:0.004000
writeExposure:  INPUT coarseTime:3188, expTime:0.033208
updateOutputSettings:   OUTPUT frameLength:3200, frameRate:30.000000
updateOutputSettings:   OUTPUT analogGain:1.000460
updateOutputSettings:   OUTPUT coarseTime:3188, expTime:0.033208

dmesg log:

[   82.327520] [imx377:2] control[10100739:Group Hold] = 1
[   82.332821] [imx377:2] control[10100736:Frame Length] = 3200
[   82.338667] [imx377:2] control[10100752:VS period] new VALUE is 3200
[   82.345133] [imx377:2] control[10100752:VS period] = 3200
[   82.350567] [imx377:2] WR reg 0x30F9 = 0x00
[   82.355454] [imx377:2] WR reg 0x30F8 = 0x0C
[   82.359983] [imx377:2] WR reg 0x30F7 = 0x80
[   82.364541] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=655 VMAX=3200 HT=9.097us VT=29.111ms HS=109.926kHz VS=34.351Hz FPS=34.351 SHR=8 SVR=0 EC=2090907 ET=29040.375us 1/=34.434
[   82.381294] [imx377:2] control[10100759:SHR] new RANGE is <8,3196> step=1 def=8
[   82.388651] [imx377:2] control[10100758:SVR] new RANGE is <0,65535> step=1 def=0
[   82.396079] [imx377:2] control[10100751:HS period] new RANGE is <655,65535> step=1 def=655
[   82.404353] [imx377:2] control[10100757:Exposure time] new RANGE is <2767,2090907> step=655 def=2090907
[   82.413822] [imx377:2] control[10100736:Frame Length] new RANGE is <3100,8000> step=1 def=3200
[   82.422449] [imx377:2] control[10100736:Frame Length] = 3200
[   82.428202] [imx377:2] control[10100752:VS period] new VALUE is 3200
[   82.434583] [imx377:2] control[10100752:VS period] = 3200
[   82.440022] [imx377:2] control[10100737:Coarse Time] new RANGE is <0,3188> step=1 def=3188
[   82.448359] [imx377:2] control[10100737:Coarse Time] = 3188
[   82.453969] [imx377:2] WR reg 0x300C = 0x00
[   82.458515] [imx377:2] WR reg 0x300B = 0x08
[   82.463124] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=655 VMAX=3200 HT=9.097us VT=29.111ms HS=109.926kHz VS=34.351Hz FPS=34.351 SHR=8 SVR=0 EC=2090907 ET=29040.375us 1/=34.434
[   82.479974] [imx377:2] control[10100747:Gain] = 113438186 ~ 27.045771
[   82.486442] [imx377:2] gain req:113438186 -> out:113438186 err:0 idx:1956 out:1957 -> +27.045 dB ~ 22.505x
[   82.496181] [imx377:2] control[10100753:A gain] new VALUE is 1957
[   82.502346] [imx377:2] control[10100753:A gain] = 1957
[   82.507588] [imx377:2] WR reg 0x300A = 0x07
[   82.512206] [imx377:2] WR reg 0x3009 = 0xA5
[   82.516824] [imx377:2] control[10100739:Group Hold] = 0

The value intended to set is the minimal gain (had to start with something other than 0 to get this work):

// GAIN LUT
imx377_gain_type imx377_gain_data[] = {
  {   67141648,     284689 }, //    1:   1.000489x =   0.004242 dB
  {   67174464,     569517 }, //    2:   1.000978x =   0.008486 dB
:
:

There is also a visible misinterpretation of the line timing, which I have modified to be variable, and the currently used minimal value of 651 makes the line time and exposure time calculations different for Argus and my kernel driver. Argus still thinks it is set to the 750, probably an entry in DT has to be modified. Hard to tell if we can use this control at all, since you expect things to be fixed values.

But the gain issue - my interpretation of the above is, that Argus tries to correctly set the gain to 0.004 dB (INPUT analogGain:0.004000), but it did not recognise the sensor as being in dB mode, thus it executes a write of 1.00046x linear gain (OUTPUT analogGain:1.000460). The write of this 64bit control is incorrectly handled in SCF and the V4L2 subsystem caps the value to the control’s max. Since we do not have the source-code, we are unable to check how the V4L2 IOCTL was really called in the user-space.

With a LINEAR gain mode, we get:

calls intended by Argus:

updateOutputSettings:	OUTPUT analogGain:1.000000
updateOutputSettings:	OUTPUT analogGain:1.000100
updateOutputSettings:	OUTPUT analogGain:1.000000

and as received in driver:

[  355.943492] [imx377:2] control[10100747:Gain] = 94394885 ~ 22.505494
[  355.950155] [imx377:2] gain req:94394885 -> out:94394885 err:0 idx:1957 out:1957 -> +27.045 dB ~ 22.505x
--
[  356.908905] [imx377:2] control[10100747:Gain] = 4194722 ~ 1.000099
[  356.915124] [imx377:2] gain req:4194722 -> out:4194304 err:-418 idx:0 out:0 -> +0.000 dB ~ 1.000x
--
[  357.210709] [imx377:2] control[10100747:Gain] = 94394885 ~ 22.505494
[  357.217202] [imx377:2] gain req:94394885 -> out:94394885 err:0 idx:1957 out:1957 -> +27.045 dB ~ 22.505x

The middle call went through okay, but the first/last are wrong. Hard to tell the IOCTL parameters without sources.

Changing HMAX to the expected 750 value, to match the request of 30.000 fps by using VMAX of 3200, we still see minor discrepancy of exposure time setting:

Argus:

updateOutputSettings:	OUTPUT coarseTime:3188, expTime:0.033208
updateOutputSettings:	OUTPUT coarseTime:2962, expTime:0.030854
updateOutputSettings:	OUTPUT coarseTime:2851, expTime:0.029698
updateOutputSettings:	OUTPUT coarseTime:2797, expTime:0.029135
updateOutputSettings:	OUTPUT coarseTime:2771, expTime:0.028865
updateOutputSettings:	OUTPUT coarseTime:2767, expTime:0.028823
updateOutputSettings:	OUTPUT coarseTime:1956, expTime:0.020375
updateOutputSettings:	OUTPUT coarseTime:1383, expTime:0.014406
updateOutputSettings:	OUTPUT coarseTime:978, expTime:0.010188
updateOutputSettings:	OUTPUT coarseTime:733, expTime:0.007635
updateOutputSettings:	OUTPUT coarseTime:634, expTime:0.006604
updateOutputSettings:	OUTPUT coarseTime:506, expTime:0.005271
updateOutputSettings:	OUTPUT coarseTime:391, expTime:0.004073
updateOutputSettings:	OUTPUT coarseTime:302, expTime:0.003146
updateOutputSettings:	OUTPUT coarseTime:230, expTime:0.002396
updateOutputSettings:	OUTPUT coarseTime:204, expTime:0.002125
updateOutputSettings:	OUTPUT coarseTime:183, expTime:0.001906
updateOutputSettings:	OUTPUT coarseTime:152, expTime:0.001583
updateOutputSettings:	OUTPUT coarseTime:145, expTime:0.001510
updateOutputSettings:	OUTPUT coarseTime:137, expTime:0.001427
updateOutputSettings:	OUTPUT coarseTime:126, expTime:0.001312
updateOutputSettings:	OUTPUT coarseTime:125, expTime:0.001302
updateOutputSettings:	OUTPUT coarseTime:122, expTime:0.001271
updateOutputSettings:	OUTPUT coarseTime:120, expTime:0.001250
updateOutputSettings:	OUTPUT coarseTime:116, expTime:0.001208
updateOutputSettings:	OUTPUT coarseTime:115, expTime:0.001198
updateOutputSettings:	OUTPUT coarseTime:114, expTime:0.001187
updateOutputSettings:	OUTPUT coarseTime:113, expTime:0.001177
updateOutputSettings:	OUTPUT coarseTime:112, expTime:0.001167

Our driver:

[  356.882895] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=8 SVR=0 EC=2394147 ET=33252.041us 1/=30.073
[  357.262357] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=234 SVR=0 EC=2224647 ET=30897.875us 1/=32.364
[  357.309085] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=345 SVR=0 EC=2141397 ET=29741.625us 1/=33.622
[  357.352445] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=399 SVR=0 EC=2100897 ET=29179.125us 1/=34.271
[  357.396445] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=425 SVR=0 EC=2081397 ET=28908.291us 1/=34.592
[  357.439183] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=429 SVR=0 EC=2078397 ET=28866.625us 1/=34.642
[  357.481906] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=1240 SVR=0 EC=1470147 ET=20418.708us 1/=48.974
[  357.525823] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=1813 SVR=0 EC=1040397 ET=14449.958us 1/=69.204
[  357.569244] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=2218 SVR=0 EC=736647 ET=10231.208us 1/=97.740
[  357.612226] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=2463 SVR=0 EC=552897 ET=7679.125us 1/=130.223
[  357.655644] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=2562 SVR=0 EC=478647 ET=6647.875us 1/=150.424
[  357.698527] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=2690 SVR=0 EC=382647 ET=5314.541us 1/=188.163
[  357.741061] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=2805 SVR=0 EC=296397 ET=4116.625us 1/=242.917
[  357.786534] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=2894 SVR=0 EC=229647 ET=3189.541us 1/=313.524
[  357.829348] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=2966 SVR=0 EC=175647 ET=2439.541us 1/=409.913
[  357.872459] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=2992 SVR=0 EC=156147 ET=2168.708us 1/=461.104
[  357.915937] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3013 SVR=0 EC=140397 ET=1949.958us 1/=512.831
[  357.959693] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3044 SVR=0 EC=117147 ET=1627.041us 1/=614.612
[  358.003032] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3051 SVR=0 EC=111897 ET=1554.125us 1/=643.448
[  358.046408] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3059 SVR=0 EC=105897 ET=1470.791us 1/=679.906
[  358.089522] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3070 SVR=0 EC=97647 ET=1356.208us 1/=737.350
[  358.132099] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3071 SVR=0 EC=96897 ET=1345.791us 1/=743.057
[  358.174862] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3074 SVR=0 EC=94647 ET=1314.541us 1/=760.721
[  358.217385] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3076 SVR=0 EC=93147 ET=1293.708us 1/=772.971
[  358.260390] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3080 SVR=0 EC=90147 ET=1252.041us 1/=798.695
[  358.303091] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3081 SVR=0 EC=89397 ET=1241.625us 1/=805.396
[  358.346756] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3082 SVR=0 EC=88647 ET=1231.208us 1/=812.210
[  358.389841] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3083 SVR=0 EC=87897 ET=1220.791us 1/=819.141
[  358.457195] [imx377:2] timing: INCK=24.000MHz TGEN=72.000MHz HMAX=750 VMAX=3200 HT=10.416us VT=33.333ms HS=96.000kHz VS=30.000Hz FPS=30.000 SHR=3084 SVR=0 EC=87147 ET=1210.375us 1/=826.190

Please share the formulas how does SCF expect the time is calculated, because I see that we are both assuming something different.

I have fixed the exposure time (it was offset by 4 lines). The change was in the coarse_time range of not being 0…3188, but rather as 4…3192. Because the SHR register has a valid range of 8 to VMAX-4 (assuming SVR being 0).

But the Argus library still assumes that the exposure time is a multiple of the LINE time. That is not true, for example this IMX377 sony sensor has a difference of about 117 cycles of static offset. On a 750 HMAX line, that moves the integration time by 15% of the line time off. The SCF framework is so complex yet it misses some of the basic image sensor principles to work correctly and reliably :(

So… how do we work out the GAIN issue now? It really does not work as we expect.