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

Inspecting Pi camera registers over I2C without need for logic analyzer

Fri Jan 25, 2019 3:55 pm

More than a year ago I got great help from 6by9 to capture I2C traffic from Pi to camera board.
That allowed later to make raspiraw do really high framerate recordings up to 750fps/1007fps for v1/v2 camera.

The schematics pointers In this posting only show PP39+PP40 (the intresting ones for Pi camera) for Pi 2B:
https://www.raspberrypi.org/forums/view ... 0#p1236942

After I soldered tin-solder balls onto PP39 and PP40 on Pi 2B capturing worked:
Image


Now if you don't have a Pi 2B, or don't have a logic analyzer, you can still inspect Pi camera registers!
And the advantage of this method is that you get all register values (you ask for), whereas capturing I2C traffic only gets those sent/updated.

In order to inspect v2 camera registers I used my i2cread tool, attached to this posting:
https://www.raspberrypi.org/forums/view ... 4#p1420790

All "intreresting" registers for v2 camera seem to be in 0x0000-0x3ff range, per the imx219 data sheet:
https://github.com/rellimmot/Sony-IMX21 ... Pi-V2-CMOS

This is how I did the capture, raspivid needs to run in background in order for the capturing to succeed:

Code: Select all

[email protected]:~ $ raspivid -md 7 -w 640 -h 480 -pts tstv.pts -t 10000 -fps 100 -o tstv.h264 &
[1] 1144
[email protected]:~ $ ./i2cread /dev/i2c-0 0000 0400 | for b in `cat` ; do echo $b; done > 1
[email protected]:~ $ ./i2cread /dev/i2c-0 0000 0400 | for b in `cat` ; do echo $b; done > 2
[email protected]:~ $ ./i2cread /dev/i2c-0 0000 0400 | for b in `cat` ; do echo $b; done > 3
[email protected]:~ $ ./i2cread /dev/i2c-0 0000 0400 | for b in `cat` ; do echo $b; done > 4
i2cread: i2cread.c:31: main: Assertion `WRITE_I2C(i2c_fd, msg)==0' failed.
[1]+  Done                    raspivid -md 7 -w 640 -h 480 -pts tstv.pts -t 10000 -fps 100 -o tstv.h264
[email protected]:~ $ 
The generated files contain 1024 2-digit hex values, one per line.
The registers are not identical:

Code: Select all

[email protected]:~ $ diff 1 2
25c25
< 08
---
> e2
323,324c323,324
< 36
< 70
---
> ff
> f0
[email protected]:~ $ diff 2 3
25c25
< e2
---
> c0
[email protected]:~ $ 
The line numbers reported by diff are 1 more than the register number (those are 0-based).
The first diff is for register "0018 [7:0] FRM_CNT[7:0]" (Frame Count).
The other diff is for registers 0x014[23]:
Image


The first two registers are MODEL_ID:

Code: Select all

$ head -2 1
02
19
$
Since that is a constant (for imx219 sensor), the better capturing is probably this one where reported diff line number corresponds to register number:

Code: Select all

/i2cread /dev/i2c-0 0001 0400 | for b in `cat` ; do echo $b; done
bookmark list: https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://github.com/Hermann-SW/fork-raspiraw
https://github.com/Hermann-SW/userland
https://twitter.com/HermannSW

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 6899
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: Inspecting Pi camera registers over I2C without need for logic analyzer

Fri Jan 25, 2019 4:51 pm

You remember those warnings I gave about collisions between ARM and VPU accessing the I2C peripheral?

Code: Select all

i2cread: i2cread.c:31: main: Assertion `WRITE_I2C(i2c_fd, msg)==0' failed.
If you select "-ex off" then I'd expect there to be fewer writes from the VPU as it shouldn't be updating exposure time or gain.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

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

Re: Inspecting Pi camera registers over I2C without need for logic analyzer

Fri Jan 25, 2019 7:12 pm

6by9 wrote:
Fri Jan 25, 2019 4:51 pm
You remember those warnings I gave about collisions between ARM and VPU accessing the I2C peripheral?
I do ;-)

These messages only happen AFTER raspivid has completed.
I should have written that that error message was expected -- I should not have tried the 4th capture command in 10 second range.
bookmark list: https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://github.com/Hermann-SW/fork-raspiraw
https://github.com/Hermann-SW/userland
https://twitter.com/HermannSW

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

Re: Inspecting Pi camera registers over I2C without need for logic analyzer

Sat Jan 26, 2019 9:50 am

6by9 wrote:
Fri Jan 25, 2019 4:51 pm
You remember those warnings I gave about collisions between ARM and VPU accessing the I2C peripheral?
OK, I made a stress test and just do continuous horizontal view changes.
250*2 of these register changes are done in 6.1s in tototal during the 10s raspivid recording.
As you can see below there is no single register write problem:

Code: Select all

$ raspivid -md 7 -w 640 -h 480 -pts tstv.pts -t 10000 -fps 100 -o tstv.h264 &[2] 7879
[1]   Done                    raspivid -md 7 -w 640 -h 480 -pts tstv.pts -t 10000 -fps 100 -o tstv.h264
$ time for((i=1; i<=250; ++i)); do ./i2cwrite /dev/i2c-0 0164 04 e8 09 e7; ./i2cwrite /dev/i2c-0 0164 03 e8 08 e7; done

real	0m6.157s
user	0m3.654s
sys	0m2.243s
$ 

What is interesting is that horizontal view changes happens every 1.2ms, while taking a frame at 100fps takes 10ms. So there are more than 8 register view changes per frame in the video. It seems that the register settings are taken at begin of capturing a frame (otherwise there woul be frames with 8 different sections of horizontal view, but there are none). In fact there seem to be a few frames that "do not look right". This is a sample frame:
Image
It seems that the previous frame was with left coordinates ( 03 e8 08 e7), and then the i2cwrite of "04 e8 09 e7" seems to be successful for the first two registers only, while 0x016[67] registers are still on old value (08 e7) when the frame started to be captured. That is the reason why the frame missed 256 pixels/128 columns on the right. This happens five times in the video, but as I said I have not found the other GPU/ARM clash issues you mentioned.

This is the I2C injection stress test video uploaded to yutube (10s recorded at 100fps, played at 25fps result in 40s video):
https://www.youtube.com/watch?v=UiFSyKR ... e=youtu.be
bookmark list: https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://github.com/Hermann-SW/fork-raspiraw
https://github.com/Hermann-SW/userland
https://twitter.com/HermannSW

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

Re: Inspecting Pi camera registers over I2C without need for logic analyzer

Sat Jan 26, 2019 4:16 pm

The timing calculation in previous posting was wrong -- 6.1s per 2*250 horizontal view changes is 12ms per change, and not 1.2ms. 12ms is bigger than the 10ms frame time at 100fps, that is the reason not more than one change happened really per recorded frame.

I did a second corrected stress test, 2000 horizontal view changes, and at maximal speed through loop unrolling via "#define"s. Exactly 6 I2C bus clashes happened in the 8.4 seconds it took to send the 2000 6-byte messages (2 bytes address, 4 register values) to i2c bus (each emits a ".", they happened at similar time interval between each pair):

Code: Select all

$ raspivid -md 7 -w 640 -h 480 -pts tstv.pts -t 10000 -fps 100 -o tstv.h264 &
[1] 3659
$ ./lftT.2000 /dev/i2c-0
......8.411251s
$ 
The video shows phases of very rapid horizontal view changes, and after a I2C bus clash a longer phase of constant horizontal view until the next very rapid horizontal view change pahase starts:
https://www.youtube.com/watch?v=zlJNr79 ... e=youtu.be

[For single frame inspection stop youtube video, then press "."/"," keys for single-frame fore/back stepping]

Next I did send only 200 horizontal view changes, resulting in zero I2C bus clashes:

Code: Select all

$ raspivid -md 7 -w 640 -h 480 -pts tstv.pts -t 10000 -fps 100 -o tstv.h264 &
[1] 3749
$ ./lftT.200 /dev/i2c-0
0.215551s
$ 
Because 200 changes take 0.21s,2000 without clashes should take 2.1s. That means that the additional 6.3s time between the 6 changing phases of the first video is time where I2C bus is blocked for lftT.200.c; this is the recorded video (again 40s youtube video because 10s recorded at 100fps get played at 25fps):
https://www.youtube.com/watch?v=hw7jnyy ... e=youtu.be

In the changing phase of the second video 17 horizontal view changes can be seen. I would have expected 21 in 0.216s at 100fps ...

Summary:
I2C bus clashes even with hammering I2C bus maximally are rare events, because the GPU sends raspivid setting updates rarely (1 per 1.4s).
If they happen, the bus I2C bus is blocked for some time.
Asserting correct I2C bus write (as previously done) instead of just emitting "." in case of clash is best, because successful program completion proves no clashes.

Code: Select all

$ diff lftT.2000.c lftT.200.c 
35c35
<         L1000; 
---
>         L100;
$ 
$ cat lftT.2000.c 
#include <stdlib.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <time.h>

#define I2C_SLAVE_FORCE 0x0706
#define WRITE_I2C(fd, arr)  (write(fd, arr, sizeof(arr)) != sizeof(arr))
#define W(fd, arr) if WRITE_I2C(fd, arr) fprintf(stderr,".")
int main(int argc, char *argv[])
{
    int  i2c_fd = 0;
    char *i2c_device_name;
    struct timespec t0, t1;

    assert(argc==2);
    i2c_device_name = argv[1];

    assert( 0 == clock_gettime(CLOCK_REALTIME, &t0) );

    i2c_fd = open(i2c_device_name, O_RDWR);
    assert(i2c_fd);
    assert(ioctl(i2c_fd, I2C_SLAVE_FORCE, 0x10) >= 0);

        unsigned char msg1[] = {0x01, 0x64, 0x03, 0xe8, 0x08, 0xe7};
        unsigned char msg2[] = {0x01, 0x64, 0x04, 0xe8, 0x09, 0xe7};

#define L1  W(i2c_fd, msg1); W(i2c_fd, msg2)
#define L10 L1; L1; L1; L1; L1; L1; L1; L1; L1; L1
#define L100 L10; L10; L10; L10; L10; L10; L10; L10; L10; L10
#define L1000 L100; L100; L100; L100; L100; L100; L100; L100; L100; L100

        L1000; 

    if (i2c_fd) 
        close(i2c_fd);

    assert( 0 == clock_gettime(CLOCK_REALTIME, &t1) );

    printf("%lfs\n", (t1.tv_sec*1.0 - t0.tv_sec) + (t1.tv_nsec*1.0 - t0.tv_nsec)*0.000000001);

    return 0;
}
$ 
bookmark list: https://stamm-wilbrandt.de/en/Raspberry_camera.html

https://github.com/Hermann-SW/Raspberry_v1_camera_global_external_shutter
https://github.com/Hermann-SW/fork-raspiraw
https://github.com/Hermann-SW/userland
https://twitter.com/HermannSW

rcasiodu
Posts: 8
Joined: Tue May 28, 2019 2:28 am

Re: Inspecting Pi camera registers over I2C without need for logic analyzer

Tue May 28, 2019 3:15 am

Hi HermannSW, I try to use your i2cread code to read the register of OV5647 sensor. I didnot run raspistill/raspivid before i2cread(i just try to read the default reg value in this way). I have test with "raspistill -o test.jpg" to make sure the hardware is working.(I add the dt-blob.bin from https://www.raspberrypi.org/documentati ... ualcam.dts) And add "dtparam=i2c_vc=on" to /boot/config.txt

I use this cmd: raspi-gpio set 3 dh to power up the sensor. But if i didnot run the camera_i2c script from raspiraw, i2cread will give this warning:

Code: Select all

Assertion `WRITE_I2C(i2c_fd, msg)==0' failed
And the i2cdetect -y 0 can find the 0x36 (slave address of OV5647) only after i run the camera_i2c script.

I think the i2c config has been done by dt-blob.bin. So what i have missed? Why the i2c cannot work only after camera_i2c runs?

Code: Select all

# i2c can be on pins 28 and 29, so make sure they are not set to alt0
gpio -g mode 28 in
gpio -g mode 29 in
# i2c on these pins
gpio -g mode 0 in
gpio -g mode 0 alt0
gpio -g mode 1 in
gpio -g mode 1 alt0
# shutdown
gpio -g mode 3 out
gpio -g write 3 1
# LED
gpio -g mode 2 out
gpio -g write 2 1
;;

Return to “Camera board”