Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 8023

Camera board • Re: Use bcm2835-unicam directly with userspace I2C driver?

$
0
0
There was a slightly hacked together plan with the dummy-sensor driver in the branch https://github.com/6by9/linux/tree/rpi- ... mmy-sensor, but seeing as that will require rebuilding the kernel you might as well look at fixing the ov9281 kernel driver.
You don't say in what way you believe it is broken, and note that Raspberry Pi OS has switched to using the upstream ov9282 driver instead.
Sooo... the new OV9282 driver (and/or the device tree overlay) changes a few things, the main result of which means we can no longer set the exposure at 120Hz in external trigger mode above 270us - which, with a 6.1 kernel and OV9281 driver, was fine up to 800us or something (NOTE: This assumes the scaling didn't change - the us values are just estimated from what we measured with the old drivers, I did not yet measure if what we see with the new drivers is ACTUALLY just 270us - will do that ASAP).
While there may be several reasons, one obvious is that it now respects V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK, and thus limits minimum HBLANK to 250 instead of 176 (HTS of 765 instead of 728).
Now seeing that the hardware clearly was fine with HTS of 728 before, I found two options:
a) Force the HTS register to 728 after streaming started (like I do with other registers for external trigger and strobe)
b) Disable noncontinous clock in the dtoverlay, which I was seemingly able to achieve with by adding clk-continuous=0:

Code:

dtoverlay=ov9281,media-controller=0,clk-continuous=0
Sadly, with both a) and b), the result is that NO frames are sent anymore (at least in my testing with external trigger mode and all other options like they were before).
So I carefully looked at ALL differences between the two drivers, the registers they set, and found it wrote 10 registers the previous driver did not - 9 of which are not documented at all. So I read their default value and reset them after the streaming started. Assuming I did no mistakes (so don't take these at face value), I arrived at this snippet to hopefully fully revert back to the behaviour of the old OV9281 driver:

Code:

// Revert changes from original OV9281 driver to new OV9282 driverunsigned char Analog_1[] = { 0x36, 0x20, 0x6f };// written 0x6e, completely undocumentedunsigned char GSReg2[] = { 0x38, 0xa8, 0x00 };// written 0x02, completely undocumentedunsigned char GSReg3[] = { 0x38, 0xa9, 0xF0 };// written 0x80, completely undocumentedunsigned char GSReg5[] = { 0x38, 0xc4, 0x01 };// written 0x00, completely undocumentedunsigned char GSReg6[] = { 0x38, 0xc5, 0x18 };// written 0xc0, completely undocumentedunsigned char GSReg7[] = { 0x38, 0xc6, 0x02 };// written 0x04, completely undocumentedunsigned char GSReg8[] = { 0x38, 0xc7, 0xA8 };// written 0x80, completely undocumented//unsigned char Unknown1[] = { 0x01, 0x01, 0x00 };// written 0x01, but always reads 0x00, completely undocumented//unsigned char Unknown2[] = { 0x10, 0x00, 0x00 };// written 0x03, but always reads 0x00, completely undocumentedunsigned char WINC_CTRL[] = { 0x5A, 0x08, 0x86 };// written 0x84, completely undocumentedconst int I2C_MSG_CNT = 8;struct i2c_msg I2C_MSG[I2C_MSG_CNT] = {{ 0x60, 0, sizeof(WINC_CTRL), WINC_CTRL },//{ 0x60, 0, sizeof(Unknown2), Unknown2 },//{ 0x60, 0, sizeof(Unknown1), Unknown1 },{ 0x60, 0, sizeof(GSReg8), GSReg8 },{ 0x60, 0, sizeof(GSReg7), GSReg7 },{ 0x60, 0, sizeof(GSReg6), GSReg6 },{ 0x60, 0, sizeof(GSReg5), GSReg5 },{ 0x60, 0, sizeof(GSReg3), GSReg3 },{ 0x60, 0, sizeof(GSReg2), GSReg2 },{ 0x60, 0, sizeof(Analog_1), Analog_1 },};for (int i = 0; i < I2C_MSG_CNT; i++){struct i2c_rdwr_ioctl_data I2C_DATA = { I2C_MSG+i, 1 };if (ioctl(i2c_fd, I2C_RDWR, &I2C_DATA) < 0)printf("Failed to write revert config register %d! %d: %s\n", i, errno, strerror(errno));}
Sadly, two of the registers are write-only (they always read 0x00), and since they are completely undocumented, I cannot properly revert whatever the new OV9282 driver did - the other values however were confirmed to be back to their default state.

While this worked without attempting to fix HTS with either options a) (force writing) or b) (clk-continuous=0), it did break with either of the options.
I also tried option b) but setting HBLANK to 250 (the minimum value if I didn't apply the clk-continuous=0 dtparam), still no frames.
(NOTE: I have no idea what that option actually does. But in case it is relevant, I have disabled the Power Saving in vblank (PSV) mode by setting PSV_CTRL to 0x08, which should prevent it from shutting off SCLK intermittently between frames - so I should have a continuous clock for all I know).

So none of my attempts to get HTS back down to 728 instead of 765 have failed.
And with the resulting loss in exposure time at 120Hz external trigger mode, this makes the new OV9282 driver unusable for us.
Have I missed something I can try?

The one remaining hope is that the old 6.1 ov9281-overlay.dts specifies an odd link-frequency of 456Mhz, while the new one in 6.12 specifies 400Mhz as would be expected. Now does that mean the timing was any different? Even if that was so, that should mean (ignoring other factors) that HTS should now be able to be set tighter, no? Anyway, all that is just badly-informed speculation.

As always, any help is greatly appreciated. As it stands, I'll have to stick with piCore 14 and the 6.1 kernel just to get the old OV9281 driver - or recompile it for the new kernel.
ov9281_driver_regression.zip

Statistics: Posted by Seneral — Tue Jun 17, 2025 1:37 am



Viewing all articles
Browse latest Browse all 8023

Trending Articles