Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Portenta H7: Trying to add the Camera/GC2145 support #78

Open
KurtE opened this issue Feb 25, 2025 · 25 comments
Open

Portenta H7: Trying to add the Camera/GC2145 support #78

KurtE opened this issue Feb 25, 2025 · 25 comments
Assignees

Comments

@KurtE
Copy link

KurtE commented Feb 25, 2025

For the fun of it, I thought I would try to add the Camera support that was added to the GIGA to the Portenta H7.

I now have it building and the camera makes it through the begin call, but the camera soon errors out:

In case anyone wishes to play along:

Here are my overlay and config file.

arduino_portenta_h7_m7.zip

I also needed to edit the fixups.c to allow the Portenta to work.
Changed the line that had GIGA and added portenta:

#if (defined(CONFIG_BOARD_ARDUINO_GIGA_R1) || defined(CONFIG_BOARD_ARDUINO_PORTENTA_H7)) && defined(CONFIG_VIDEO)

The error code shown in monitor window:
[00:00:14.808,000] <wrn> video_stm32_dcmi: HAL_DCMI_ErrorCallback(41)
Note: I edited the file to add the error code, which is error DMA overrun I believe.

Now back to playing

@KurtE
Copy link
Author

KurtE commented Feb 25, 2025

Quick update:
Looking at where this message is generated: [00:00:14.808,000] video_stm32_dcmi: HAL_DCMI_ErrorCallback(41)
It is in the zephyr/drivers/video/vides_stm32_dcmi.c

void HAL_DCMI_ErrorCallback(DCMI_HandleTypeDef *hdcmi)
{
	LOG_WRN("%s(%x)", __func__, hdcmi->ErrorCode);
}

Which is called from: the modules\hal\stm32\stm32cure\stm32h7xx\drivers\src\stm32h7xx_hal_dma.c
from the function:
HAL_StatusTypeDef HAL_DMA_Abort_IT(DMA_HandleTypeDef *hdma)
which was called by the (same directory) stm32h7xx_hal_dcmi.c
from: void HAL_DCMI_IRQHandler(DCMI_HandleTypeDef *hdcmi)
Where it sets the error callback to the HAL_DCMI_ErrorCallback.

So my read of this is, that in this case we receive that one message, and the DMA stream is stopped, we probably
need to call something to restart it?

Something like: HAL_DCMI_Start_DMA ?

@pillo79 and/or @facchinm - Does this make sense?

@KurtE
Copy link
Author

KurtE commented Mar 3, 2025

For the fun (or pain) of it, I thought it might be interesting to try adapting to a different camera that zephyr supports, such as the
OV2640 and OV5640. So today I (actually both of us) have tried to setup for the OV5640. I have a couple of them that the two of us
a while ago, were experimenting with, in adapting and extending the camera library to work on the Teensy 4.x boards.

So far it is not working yet. Some of the issues we have run into include:

a) Reset/power down pins - The name of the power down pin is different: powerdown-gpios versus pwdn-gpios
Also the Adafruit OV5640 and maybe others, the camera is powered down when the pin has a high signal, not low.

b) the port { area - looks like they use remote-endpoint-label instead of remote-endpoint and they have different
data associated with them.

c) the current OV5640 object does not currently support the size 320x240 size of image.
Actually, only support (1280x720) and 640x480). The camera reference shows that they support several other resolutions as well,
like 2592x1944, 1920x1080, 1280x960. And can support several others by setting up windows within...

So far I have not gotten past the camera initializing, but will try some more tomorrow. Will also try the OV2640 as well.

@mjs513
Copy link

mjs513 commented Mar 3, 2025

Theres a lot more that @KurtE didn't mentioned that we noticed. As mentioned for the OV5640 camera failed to start until we releasized about reset and powerdown pin states via a LA trace that Kurte did.

  1. DCMI DMA ERRORS:
    Once started noticed a error messages on Serial1:
[00:00:10.008,000] <err> video_stm32_dcmi: Failed to start DCMI DMA
[00:00:15.017,000] <err> video_stm32_dcmi: Failed to start DCMI DMA
[00:00:20.026,000] <err> video_stm32_dcmi: Failed to dequeue a DCMI buffer.
[00:00:25.036,000] <err> video_stm32_dcmi: Failed to dequeue a DCMI buffer.

Digging a bit deeper noticed in driver that we are currently using in the core it is starting the stream with IO as mipi vs dvp? Think we are using DVP for the GC2145. The above errors are coming from video_stm32_dcmi.c

static int ov5640_stream_start(const struct device *dev)
{
	const struct ov5640_config *cfg = dev->config;
	/* Power up MIPI PHY HS Tx & LP Rx in 2 data lanes mode */
	int ret = ov5640_write_reg(&cfg->i2c, IO_MIPI_CTRL00_REG, 0x45);

	if (ret) {
		LOG_ERR("Unable to power up MIPI PHY");
		return ret;
	}
	return ov5640_write_reg(&cfg->i2c, SYS_CTRL0_REG, SYS_CTRL0_SW_PWUP);
}

Though I am not seeing an error for unable to power up MIPI. The latest driver for the OV5640 actually provides support for both: https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/video/ov5640.c

  1. @KurtE mention about available resolutions. There is an open issue on zephyr about that: video: ov5640 support for vga , qvga and qqvga not there zephyrproject-rtos/zephyr#86519, that @KurtE found yesterday. Kurt mentioned that we played with this camera on the Teensy 4 so I modified the ov5640_reg low_res_params to support the lower resoutions but hard to test.

  2. While @KurtE was testing the OV2640 I tried the OV7670 and again managed to get camera started but received the same DCMI errors:

[00:00:10.008,000] <err> video_stm32_dcmi: Failed to start DCMI DMA
[00:00:15.017,000] <err> video_stm32_dcmi: Failed to start DCMI DMA
[00:00:20.026,000] <err> video_stm32_dcmi: Failed to dequeue a DCMI buffer.
[00:00:25.036,000] <err> video_stm32_dcmi: Failed to dequeue a DCMI buffer.

@KurtE
Copy link
Author

KurtE commented Mar 3, 2025

Thanks @mjs513 for filling in a lot of the gaps, Will try 2640 next as it looks like there may be more complete information in the driver.

One thing that I keep wondering about, is once more of Arduino integration with zephyr is completed. How do you expect it
will work. That is the MBED version I believe supported 4 cameras. It was reasonably easy to switch between them.
With this current version on Zephyr, there may be Several more cameras. How can different sketches choose which one to use?
Will the Overlay(s) allow multiple cameras to be included. How then to choose?

The chosen{zephyr,camera = &dcmi; Sort of maybe allows you choose to use the hardware camera subsystem, but currently
not necessarily which actual camera, the DCMI should be configured for.

I am assuming that once the real basics of the camera are working, that a lot more of the functionality of the MBED camera library will be added.

But now back to trying some of the basics.

@KurtE
Copy link
Author

KurtE commented Mar 3, 2025

Quick update: currently the OV2640 shows more promise than the OV5640.

Note: I changed all of the 5640 to 2640 in overlay and config file. Also noted that it has a different I2C address of 0x30, so
changed that in two places.

Build first failed as POWERDOWN pin is not defined in their yaml file... so commented out that line.

Images are not good yet, Sort of like I am seeing from GC2145.

Image
Note: the ceiling in my office does not look like that ;)

The images of the GC2145 are similar. I am not getting the same error on the OV2640...
And runs for long time. I do get the: could not get buffer a few times, but...

@mjs513
Copy link

mjs513 commented Mar 4, 2025

@KurtE
I hacked up the existing ov5640.c file to take the initialization arrays and a couple of things from the 5640.c that looks like will be in release 4.1 as a quick and dirty test and did get a totally out of synch image and lot of errors on serial1 about dma buffers.

Image

So don;t think I am going to do anything else on the 5640 until I see if the incoporarte the driver changes. Otherwise I will rewriting it completely

@KurtE
Copy link
Author

KurtE commented Mar 4, 2025

Quick update: OV2640.
I added debug code to the ov2640.c to printk all of the registers that are set by the code. Plus when I know them their name.
Code extracted/modified from our Teensy code. Note: the processing image still looks like the one I posted yesterday:

*** Booting Zephyr OS build v3.7.0-8126-g33bc8a018ecc ***
Camera::begin(320 240 0 0)
        Choosen: 0x808080c
        Requested caps: w:320 h:240 fmt:50424752
        0: w:160 h:120 fmt:50424752
        1: w:176 h:144 fmt:50424752
        2: w:240 h:160 fmt:50424752
        3: w:240 h:240 fmt:50424752
        4: w:320 h:240 fmt:50424752
[00:00:02.038,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (ff, 0)
[00:00:02.047,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (da, 8)-  IMAGE_MODE
[00:00:02.087,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (ff, 0)
[00:00:02.096,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (5, 1)-  R_BYPASS
[00:00:02.105,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (5a, 50)-  ZMOW
[00:00:02.115,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (5b, 3c)-  ZMOH
[00:00:02.125,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (5c, 0)-  ZMHH
[00:00:02.134,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (ff, 1)
[00:00:02.143,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (11, 87)-  CLKRC
[00:00:02.153,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (ff, 1)
[00:00:02.161,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (12, 0)-  COM7
[00:00:02.171,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (3, f)-  COM1
[00:00:02.180,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (32, 36)-  REG32
[00:00:02.190,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (17, 11)-  HREFST
[00:00:02.200,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (18, 75)-  HREFEND
[00:00:02.210,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (19, 1)-  VSTRT
[00:00:02.219,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (1a, 97)-  VEND
[00:00:02.229,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (3d, 34)
[00:00:02.238,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (35, 88)
[00:00:02.247,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (22, a)
[00:00:02.255,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (37, 40)
[00:00:02.264,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (34, a0)-  ARCOM2
[00:00:02.274,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (6, 2)
[00:00:02.283,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (d, b7)-  COM4
[00:00:02.292,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (e, 1)
[00:00:02.301,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (42, 83)
[00:00:02.310,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (ff, 0)
[00:00:02.319,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (5, 1)-  R_BYPASS
[00:00:02.329,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (e0, 4)-  RESET
[00:00:02.338,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (c0, c8)-  HSIZE8
[00:00:02.348,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (c1, 96)-  VSIZE8
[00:00:02.358,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (8c, 0)-  SIZEL
[00:00:02.367,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (53, 0)-  XOFFL
[00:00:02.377,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (54, 0)-  YOFFL
[00:00:02.387,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (51, 90)-  HSIZE
[00:00:02.396,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (52, 2c)-  VSIZE
[00:00:02.406,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (55, 88)-  VHYX
[00:00:02.415,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (57, 0)-  TEST
[00:00:02.425,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (86, 3d)-  CTRL2
[00:00:02.435,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (50, 80)-  CTRLI
[00:00:02.444,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (d3, 84)-  R_DVP_SP
[00:00:02.454,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (5, 0)-  R_BYPASS
[00:00:02.464,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (e0, 0)-  RESET
[00:00:02.473,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (0, 0)-  R_BYPASS_DSP_EN
[00:00:02.484,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (ff, 0)
[00:00:02.493,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (5, 0)-  R_BYPASS
[00:00:02.532,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (ff, 1)
[00:00:02.542,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (4, 28)-  REG04
[00:00:02.551,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (ff, 1)
[00:00:02.560,000] <dbg> video_ov2640: DBG_OV2640WriteReg: (4, 28)-  REG04
uart:~$

As a comparison, here is the debug output I just ran on a Teensy Micromod using OV2640 and displayed on an ILI9341 display:
Note: in this output, the code shows each of them as they are set, and then later prints a summary of the current setting for
each of the registers we touched:

Start Display CS:5 DC:4 RST:2
hm0360 Camera Test
FLEXIO_CUSTOM_LIKE_8_BIT
------------------
Using Micromod ATP Adapter
  VS=33, HR=32, PC=10 XC=29
  RST=31(-2), PWDN=30(-1)
  _dpins(0)=40
  _dpins(1)=41
  _dpins(2)=42
  _dpins(3)=43
  _dpins(4)=44
  _dpins(5)=45
  _dpins(6)=6
  _dpins(7)=9
MAP Pin 29(0x401f8090)
Warning pin: 29 is not a known CSI pin
** beginXCLK PWM **
getModelID: return: 2642
getModelID: return: 2642
Calling ov7670_configure
Cam Name: 3, Format: 2, Resolution: 2, Clock: 12
Frame rate: 8
hardware_configure - try CSI
MAP Pin 33(0x401f8030)
Warning pin: 33 is not a known CSI pin
	failed try FLEXIO
Custom - Flexio is 8 bit mode

@@@ SetVSYNC ISR priority: 102 camera Input:1
cameraWriteRegister(ff, 0)
cameraWriteRegister(2c, ff)
cameraWriteRegister(2e, df)
cameraWriteRegister(ff, 1)
cameraWriteRegister(3c, 32)
cameraWriteRegister(11, 82) -  CLKRC
cameraWriteRegister(9, 2) -  COM2
cameraWriteRegister(4, f8) -  REG04
cameraWriteRegister(13, e5) -  COM8
cameraWriteRegister(14, 48) -  COM9
cameraWriteRegister(2c, c)
cameraWriteRegister(33, 78)
cameraWriteRegister(3a, 33)
cameraWriteRegister(3b, fb)
cameraWriteRegister(3e, 0)
cameraWriteRegister(43, 11)
cameraWriteRegister(16, 10)
cameraWriteRegister(39, 2)
cameraWriteRegister(35, 88)
cameraWriteRegister(22, a)
cameraWriteRegister(37, 40)
cameraWriteRegister(23, 0)
cameraWriteRegister(34, a0) -  ARCOM2
cameraWriteRegister(6, 2)
cameraWriteRegister(6, 88)
cameraWriteRegister(7, c0)
cameraWriteRegister(d, b7) -  COM4
cameraWriteRegister(e, 1)
cameraWriteRegister(4c, 0)
cameraWriteRegister(4a, 81)
cameraWriteRegister(21, 99)
cameraWriteRegister(24, 40) -  AEW
cameraWriteRegister(25, 38) -  AEB
cameraWriteRegister(26, 82) -  VV
cameraWriteRegister(5c, 0)
cameraWriteRegister(63, 0)
cameraWriteRegister(46, 22) -  FLL
cameraWriteRegister(c, 3a) -  COM3
cameraWriteRegister(5d, 55) -  REG5D
cameraWriteRegister(5e, 7d) -  REG5E
cameraWriteRegister(5f, 7d) -  REG5F
cameraWriteRegister(60, 55) -  REG60
cameraWriteRegister(61, 70) -  HISTO_LOW
cameraWriteRegister(62, 80) -  HISTO_HIGH
cameraWriteRegister(7c, 5)
cameraWriteRegister(20, 80) -  COM8_BNDF_EN
cameraWriteRegister(28, 30)
cameraWriteRegister(6c, 0)
cameraWriteRegister(6d, 80)
cameraWriteRegister(6e, 0)
cameraWriteRegister(70, 2)
cameraWriteRegister(71, 94)
cameraWriteRegister(73, c1)
cameraWriteRegister(3d, 34)
cameraWriteRegister(12, 4) -  COM7
cameraWriteRegister(5a, 57)
cameraWriteRegister(4e, 0) -  COM25
cameraWriteRegister(4f, bb) -  BD50
cameraWriteRegister(50, 9c) -  BD60
cameraWriteRegister(ff, 0)
cameraWriteRegister(e5, 7f)
cameraWriteRegister(f9, c0) -  MC_BIST
cameraWriteRegister(41, 24)
cameraWriteRegister(e0, 14) -  RESET
cameraWriteRegister(76, ff)
cameraWriteRegister(33, a0)
cameraWriteRegister(42, 20)
cameraWriteRegister(43, 18)
cameraWriteRegister(4c, 0)
cameraWriteRegister(87, d0) -  CTRL3
cameraWriteRegister(88, 3f)
cameraWriteRegister(d7, 3)
cameraWriteRegister(d9, 10)
cameraWriteRegister(d3, 82) -  R_DVP_SP
cameraWriteRegister(c8, 8)
cameraWriteRegister(c9, 80)
cameraWriteRegister(7c, 0) -  BPADDR
cameraWriteRegister(7d, 0) -  BPDATA
cameraWriteRegister(7c, 3) -  BPADDR
cameraWriteRegister(7d, 48) -  BPDATA
cameraWriteRegister(7d, 48) -  BPDATA
cameraWriteRegister(7c, 8) -  BPADDR
cameraWriteRegister(7d, 20) -  BPDATA
cameraWriteRegister(7d, 10) -  BPDATA
cameraWriteRegister(7d, e) -  BPDATA
cameraWriteRegister(90, 0)
cameraWriteRegister(91, e)
cameraWriteRegister(91, 1a)
cameraWriteRegister(91, 31)
cameraWriteRegister(91, 5a)
cameraWriteRegister(91, 69)
cameraWriteRegister(91, 75)
cameraWriteRegister(91, 7e)
cameraWriteRegister(91, 88)
cameraWriteRegister(91, 8f)
cameraWriteRegister(91, 96)
cameraWriteRegister(91, a3)
cameraWriteRegister(91, af)
cameraWriteRegister(91, c4)
cameraWriteRegister(91, d7)
cameraWriteRegister(91, e8)
cameraWriteRegister(91, 20)
cameraWriteRegister(92, 0)
cameraWriteRegister(93, 6)
cameraWriteRegister(93, e3)
cameraWriteRegister(93, 3)
cameraWriteRegister(93, 3)
cameraWriteRegister(93, 0)
cameraWriteRegister(93, 2)
cameraWriteRegister(93, 0)
cameraWriteRegister(93, 0)
cameraWriteRegister(93, 0)
cameraWriteRegister(93, 0)
cameraWriteRegister(93, 0)
cameraWriteRegister(93, 0)
cameraWriteRegister(93, 0)
cameraWriteRegister(96, 0)
cameraWriteRegister(97, 8)
cameraWriteRegister(97, 19)
cameraWriteRegister(97, 2)
cameraWriteRegister(97, c)
cameraWriteRegister(97, 24)
cameraWriteRegister(97, 30)
cameraWriteRegister(97, 28)
cameraWriteRegister(97, 26)
cameraWriteRegister(97, 2)
cameraWriteRegister(97, 98)
cameraWriteRegister(97, 80)
cameraWriteRegister(97, 0)
cameraWriteRegister(97, 0)
cameraWriteRegister(a4, 0)
cameraWriteRegister(a8, 0)
cameraWriteRegister(c5, 11)
cameraWriteRegister(c6, 51)
cameraWriteRegister(bf, 80)
cameraWriteRegister(c7, 10)
cameraWriteRegister(b6, 66)
cameraWriteRegister(b8, a5)
cameraWriteRegister(b7, 64)
cameraWriteRegister(b9, 7c)
cameraWriteRegister(b3, af)
cameraWriteRegister(b4, 97)
cameraWriteRegister(b5, ff)
cameraWriteRegister(b0, c5)
cameraWriteRegister(b1, 94)
cameraWriteRegister(b2, f)
cameraWriteRegister(c4, 5c)
cameraWriteRegister(a6, 0)
cameraWriteRegister(a7, 20)
cameraWriteRegister(a7, d8)
cameraWriteRegister(a7, 1b)
cameraWriteRegister(a7, 31)
cameraWriteRegister(a7, 0)
cameraWriteRegister(a7, 18)
cameraWriteRegister(a7, 20)
cameraWriteRegister(a7, d8)
cameraWriteRegister(a7, 19)
cameraWriteRegister(a7, 31)
cameraWriteRegister(a7, 0)
cameraWriteRegister(a7, 18)
cameraWriteRegister(a7, 20)
cameraWriteRegister(a7, d8)
cameraWriteRegister(a7, 19)
cameraWriteRegister(a7, 31)
cameraWriteRegister(a7, 0)
cameraWriteRegister(a7, 18)
cameraWriteRegister(7f, 0)
cameraWriteRegister(e5, 1f)
cameraWriteRegister(e1, 77)
cameraWriteRegister(dd, 7f)
cameraWriteRegister(c2, e) -  CTRL0
cameraWriteRegister(ff, 1)
cameraWriteRegister(f, 4b)
cameraWriteRegister(3, 8f) -  COM1
cameraWriteRegister(ff, 0)
cameraWriteRegister(5, 0) -  R_BYPASS
cameraWriteRegister(da, 9) -  IMAGE_MODE
cameraWriteRegister(d7, 3)
cameraWriteRegister(e0, 0) -  RESET
cameraWriteRegister(5, 0) -  R_BYPASS
UXGA Width: 1600, Height: 1200
Width: 320, Height: 240
cameraWriteRegister(ff, 1)
cameraWriteRegister(12, 40) -  COM7
cameraWriteRegister(3, 8a) -  COM1
cameraWriteRegister(17, 11) -  HREFST
cameraWriteRegister(18, 43) -  HREFEND
cameraWriteRegister(19, 1) -  VSTRT
cameraWriteRegister(1a, 97) -  VEND
cameraWriteRegister(32, 9) -  REG32
cameraWriteRegister(ff, 0)
cameraWriteRegister(e0, 4) -  RESET
cameraWriteRegister(8c, 0) -  SIZEL
cameraWriteRegister(c0, 64) -  HSIZE8
cameraWriteRegister(c1, 4b) -  VSIZE8
cameraWriteRegister(86, 3d) -  CTRL2
Sensor w,h: 800 - 600
sensor_w / w: 2, sensor_h / h: 2
temp_div: 2, log_div: 0, div: 1
w_mul: 640, h_mul: 480
x_off: 80, y_off: 60
cameraWriteRegister(50, 89) -  CTRLI
cameraWriteRegister(51, a0) -  HSIZE
cameraWriteRegister(52, 78) -  VSIZE
cameraWriteRegister(53, 50) -  XOFFL
cameraWriteRegister(54, 3c) -  YOFFL
cameraWriteRegister(55, 0) -  VHYX
cameraWriteRegister(57, 0) -  TEST
cameraWriteRegister(5a, 50) -  ZMOW
cameraWriteRegister(5b, 3c) -  ZMOH
cameraWriteRegister(5c, 0) -  ZMHH
cameraWriteRegister(d3, 2) -  R_DVP_SP
cameraWriteRegister(e0, 0) -  RESET
Set PLL: clk_2x: 1, clk_div: 3, pclk_auto: 1, pclk_div: 8
c.clk value: 131
c.pclk value: 136
cameraWriteRegister(ff, 1)
cameraWriteRegister(11, 83) -  CLKRC
cameraWriteRegister(ff, 0)
cameraWriteRegister(d3, 88) -  R_DVP_SP
cameraWriteRegister(ff, 0)
cameraWriteRegister(5, 0) -  R_BYPASS
Begin status: 1
cameraWriteRegister(ff, 1)
cameraWriteRegister(4, 78) -  REG04
cameraWriteRegister(ff, 1)
cameraWriteRegister(4, 28) -  REG04
cameraWriteRegister(ff, 0)
cameraWriteRegister(c7, 40)
Camera settings:
	width = 320
	height = 240

TFT Width = 320 Height = 240

ImageSize (w,h): 320, 240
cameraWriteRegister(ff, 1)
cameraWriteRegister(12, 40) -  COM7

*** Camera Registers ***
cameraWriteRegister(ff, 0)
(0)  QS(44): 12(c)
(0)  HSIZE(51): 160(a0)
(0)  VSIZE(52): 120(78)
(0)  XOFFL(53): 80(50)
(0)  YOFFL(54): 60(3c)
(0)  VHYX(55): 0(0)
(0)  DPRP(56): 0(0)
(0)  TEST(57): 0(0)
(0)  ZMOW(5a): 80(50)
(0)  ZMOH(5b): 60(3c)
(0)  ZMHH(5c): 0(0)
(0)  BPADDR(7c): 11(b)
(0)  BPDATA(7d): 0(0)
(0)  SIZEL(8c): 0(0)
(0)  HSIZE8(c0): 100(64)
(0)  VSIZE8(c1): 75(4b)
(0)  CTRL1(c3): 255(ff)
(0)  MS_SP(f0): 4(4)
(0)  SS_ID(f7): 96(60)
(0)  SS_CTRL(f7): 96(60)
(0)  MC_AL(fa): 0(0)
(0)  MC_AH(fb): 0(0)
(0)  MC_D(fc): 0(0)
(0)  P_CMD(fd): 0(0)
(0)  P_STATUS(fe): 60(3c)
(0)  CTRLI(50): 137(89)
(0)  CTRLI_LP_DP(80): 0(0)
(0)  CTRLI_ROUND(40): 51(33)
(0)  CTRL0(c2): 14(e)
(0)  CTRL2(86): 61(3d)
(0)  CTRL3(87): 208(d0)
(0)  R_DVP_SP(d3): 136(88)
(0)  R_DVP_SP_AUTO_MODE(80): 0(0)
(0)  R_BYPASS(5): 0(0)
(0)  R_BYPASS_DSP_EN(0): 0(0)
(0)  R_BYPASS_DSP_BYPAS(1): 0(0)
(0)  IMAGE_MODE(da): 9(9)
(0)  RESET(e0): 0(0)
(0)  MC_BIST(f9): 192(c0)
(0)  BANK_SEL(ff): 0(0)
(0)  BANK_SEL_DSP(0): 0(0)
(0)  BANK_SEL_SENSOR(1): 0(0)
cameraWriteRegister(ff, 1)
(1)  GAIN(0): 0(0)
(1)  COM1(3): 138(8a)
(1)  REG_PID(a): 38(26)
(1)  REG_VER(b): 66(42)
(1)  COM4(d): 183(b7)
(1)  AEC(10): 178(b2)
(1)  CLKRC(11): 131(83)
(1)  CLKRC_DOUBLE(82): 0(0)
(1)  CLKRC_DIVIDER_MASK(3f): 1(1)
(1)  COM10(15): 0(0)
(1)  HREFST(17): 17(11)
(1)  HREFEND(18): 67(43)
(1)  VSTRT(19): 1(1)
(1)  VEND(1a): 151(97)
(1)  MIDH(1c): 127(7f)
(1)  MIDL(1d): 162(a2)
(1)  AEW(24): 64(40)
(1)  AEB(25): 56(38)
(1)  REG2A(2a): 0(0)
(1)  FRARL(2b): 0(0)
(1)  ADDVSL(2d): 0(0)
(1)  ADDVSH(2e): 0(0)
(1)  YAVG(2f): 79(4f)
(1)  HSDY(30): 8(8)
(1)  HEDY(31): 48(30)
(1)  REG32(32): 9(9)
(1)  ARCOM2(34): 160(a0)
(1)  REG45(45): 1(1)
(1)  FLL(46): 34(22)
(1)  FLH(47): 0(0)
(1)  COM19(48): 0(0)
(1)  ZOOMS(49): 0(0)
(1)  COM22(4b): 32(20)
(1)  COM25(4e): 0(0)
(1)  BD50(4f): 187(bb)
(1)  BD60(50): 156(9c)
(1)  REG5D(5d): 85(55)
(1)  REG5E(5e): 125(7d)
(1)  REG5F(5f): 125(7d)
(1)  REG60(60): 85(55)
(1)  HISTO_LOW(61): 112(70)
(1)  HISTO_HIGH(62): 128(80)
(1)  REG04(4): 43(2b)
(1)  REG08(8): 64(40)
(1)  COM2(9): 2(2)
(1)  COM2_STDBY(10): 55(37)
(1)  COM3(c): 58(3a)
(1)  COM7(12): 64(40)
(1)  COM8(13): 229(e5)
(1)  COM8_DEFAULT(c0): 0(0)
(1)  COM8_BNDF_EN(20): 128(80)
(1)  COM8_AGC_EN(4): 43(2b)
(1)  COM8_AEC_EN(1): 0(0)
(1)  COM9(14): 72(48)
(1)  CTRL1_AWB(8): 64(40)
(1)  VV(26): 130(82)
(1)  REG32(32): 9(9)
Window Hor: (137 - 537) = 400 * 2 = 800 Vert: (6 - 606) = 600 * 2 = 1200
cameraWriteRegister(ff, 0)
device	Size H: 160 * 4 = 640 V: 120 * 4 = 480
	 offset H: 80 V: 60 

Image of setup:

Image

@mjs513
Copy link

mjs513 commented Mar 5, 2025

Did manage to get an image out of the ov7670

Image

Still dies after a while with the errors you see with DCMI failed callback.

to get it working to this point

  1. Changed pixel clock to 12 mhz (not sure if 10 may work better).
  2. changed hsynch and vsynch to active high in ov7670.c
	/* configure the output timing */
	/* Free running PCLK, default VSYNC, HSYNC and PCLK */
	{OV7670_COM10, 0x03}, /* COM10 */
	{OV7670_COM12, 0x00}, /* COM12,No HREF when VSYNC is low */

after reading this:
zephyrproject-rtos/zephyr#84229

however doesn't look like that change made it into 4.1-rc2

@mjs513
Copy link

mjs513 commented Mar 5, 2025

Just as a quick update I switched to using portenta mid-carrier with the ov7670 and image quality improved drastically but still hit the error message when it stops noted in previous posts:

Image

Do have to hit reset a couple of times to get more that a single image to display. Then I will get may 10-12 then it errors out.

Did verify that you have to update to {OV7670_COM10, 0x03}, /* COM10 */ otherwise will get no images.

@KurtE
Copy link
Author

KurtE commented Mar 5, 2025

Will have to try it in the morning. Looks a lot better

@mjs513
Copy link

mjs513 commented Mar 8, 2025

See this issue as well: #81

@iabdalkader
Copy link

I've sent a fix for the pixel format array: zephyrproject-rtos/zephyr#86810

Only the GC2145 has been tested and known to work well enough with the Giga. The rest of the sensors all have issues, bad regs, bad config, buggy drivers etc... I don't know the state of the H7 support and whether it can use the cameras or not.

Note if the colors look wrong, try passing True in the last argument: cam.begin(DISPLAY_W, DISPLAY_H, CAMERA_RGB565, true)

@mjs513
Copy link

mjs513 commented Mar 8, 2025

@iabdalkader

I have been having issues with the GC2145 on the GIGA and H7 but going to try and sort it out. Basically on Giga looks like its running if I watch the Serial1 spew and on the H7 will see 1 frame in the visualizer. In both cases get this message and then it halts:

 **_<wrn> video_stm32_dcmi: HAL_DCMI_ErrorCallback_**

Again using the H7:

  1. The 5640 looks like the driver has major issues with reg settings etc. Did try and hack it to use settings from other sources including openmv. DId get that messed up image in Portenta H7: Trying to add the Camera/GC2145 support #78 (comment) then said forget since it looks like they redid the driver in a later release.

  2. On the other hand had alot better luck with the OV7670 by making one change in the driver:

	/* configure the output timing */
	/* Free running PCLK, default VSYNC, HSYNC and PCLK */
	{OV7670_COM10, 0x03}, /* COM10 */
	{OV7670_COM12, 0x00}, /* COM12,No HREF when VSYNC is low */

also set clock to 12Mhz and using FIFO_FULL then will run for a couple of minutes but will eventually get the:

[00:00:24.443,000] <dbg> video_stm32_dcmi: HAL_DCMI_FrameEventCallback: Failed to get buffer from fifo
[00:00:24.571,000] <dbg> video_stm32_dcmi: HAL_DCMI_FrameEventCallback: Failed to get buffer from fifo
[00:01:40.769,000] <wrn> video_stm32_dcmi: HAL_DCMI_ErrorCallback

Image

@mjs513
Copy link

mjs513 commented Mar 9, 2025

@iabdalkader - @KurtE - @facchinm

Did some more experimenting this morning with the GC2145 on the GIGA. First I incorporated the pr (zephyrproject-rtos/zephyr#86810) then went back to the original 2145 settings (12Mhz, 1/4 FIFO). Now for the interesting stuff

  1. Running the camera sketch and the visualizer I was not seeing any images being displayed but did the see what looked like 1 frame of spew and then it stopped sending data to visualizer unless I stopped the visualizer and restarted???? Weird.
  2. Found that if I modified the camera sketch to add in a print before releasing the frame:
  FrameBuffer fb;
  if (cam.grabFrame(fb)) {
    if (Serial.read() == 1) {
      Serial.write(fb.getBuffer(), fb.getBufferSize());
    }
    Serial.println(fb.getBufferSize());
    cam.releaseFrame(fb);
  }

I would get some images but seems to be a synch issue going on as well
a. On starting the visualizer it seems to delay a few seconds and then I will get an image that looks like:

Image

b. If I then close the visualizer and reopen the visualizer window;

Image

it is slightly out of synch and will keep streaming with the synch changing.

@KurtE
Copy link
Author

KurtE commented Mar 9, 2025

Will have to try it again. Been a bit since I tried it on the GIGA. On H7, I am not getting good images. Will have to try it again
with the GC2145, currently trying with OV7670, Curious to see if any of the changes with the update Zephyr will improve things.

@iabdalkader
Copy link

iabdalkader commented Mar 9, 2025

Failed to get buffer from fifo

This is not an error, it just means you're not reading the frames fast enough so the video buffers FIFO is full. The streaming will not stop as the video driver always holds one video buffer. You could try increasing CONFIG_VIDEO_BUFFER_POOL_NUM_MAX to 4.

HAL_DCMI_ErrorCallback

This is an error, most likely DCMI FIFO overrun. It's possible to recover from this by just restarting the DMA stream, but the Zephyr driver doesn't do that. Try lowering the clock to 10MHz, if it works better we can make this the default.

Found that if I modified the camera sketch to add in a print before releasing the frame:

You can't print anything because the frame is sent over serial, so you'll corrupt the frame if you do and break the sync. This serial frame visualizer has always been unreliable, so you may have to stop/start it a few times, and make sure the board runs first.

Also, have you tried this branch arduino_core_merge_4.1.0-rc2? It should have the latest fixes. Doesn't build.

I just tested this with and I had no problems with streaming. The colors are wrong, but I already fixed that upstream.

Image

@KurtE
Copy link
Author

KurtE commented Mar 9, 2025

Thanks @iabdalkader
Will try more of this again. I am also trying to output the image to a TFT display over SPI, which is maybe slower than output over USB... Which is showing similar issues.

The Arduino_core_merge... build issue, - A few days ago on the other machine I was able to build some of the variants.
But there was/is an issue where you could not compile sketches due to devicetree stuff with embeded comments.
I believe @facchinm has a fix on his fork/branch:
facchinm/zephyr@b7940c6
Which I am going to try on my other machine that I installed the merge...

Personally wish there were easier ways to switch between cameras... Than having to edit the overlay and the config file, rebuild zephyr...

On the different cameras, has someone gone through and tried to fix the configurations and maybe add in the missing pieces? For example the OV7670 camera, I don't believe they have anything in it to support the OV7675 camera that Arduino sells. I definitely notice differences of trying it versus some of the older OV7670 cameras I purchased from Amazon or elsewhere.

Will try again on GIGA, but need to grab another USB to serial adapter, as GIGA is always now in debug mode...

Thanks again

@mjs513
Copy link

mjs513 commented Mar 9, 2025

Thanks @iabdalkader for getting back so fast.

SOrry it took so long in getting back to you but wanted to try with a few changes based on your feedback.
 

This is not an error, it just means you're not reading the frames fast enough so the video buffers FIFO is full. The streaming will not stop as the video driver always holds one video buffer. You could try increasing CONFIG_VIDEO_BUFFER_POOL_NUM_MAX to 4.

Yep - I remember that you mentioned that to facchinm in your original PR. Didn;t mean to say that was an error sorry.

HAL_DCMI_ErrorCallback
This is an error, most likely DCMI FIFO overrun. It's possible to recover from this by just restarting the DMA stream, but the Zephyr driver doesn't do that. Try lowering the clock to 10MHz, if it works better we can make this the default.

@KurtE discussed that in the first post so we are on own on that one.

You can't print anything because the frame is sent over serial, so you'll corrupt the frame if you do and break the sync. This serial frame visualizer has always been unreliable, so you may have to stop/start it a few times, and make sure the board runs first.

Yep thats why I mentioned it since I thought it was kind of funny. And yeah have to start and stop it several times to get to work. Glad you confirmed it.

If I wait for continuous spew (even with vido buffers = 4)

Image

This is at 10 mhz by the way

PS. First if I was going to do anything serious with the camera I would be using OpenMV!!!!

Second is there an alternate way to view the images with openmv ide or the arducam windows app?

@mjs513
Copy link

mjs513 commented Mar 9, 2025

well made a couple of minor changes and the visualizer seems to be working better.

In the sketch change loop to

void loop() {
  FrameBuffer fb;
  if (cam.grabFrame(fb)) {
    if (Serial.read() == 1) {
      Serial.write('\n');
      Serial.write(fb.getBuffer(), fb.getBufferSize());
    }
    cam.releaseFrame(fb);
  }
}

and in the processing sketch in setup

  // Let the Arduino sketch know we're ready to receive data
  myPort.write(1);
  myPort.bufferUntil('\n');

kind of a handshake

@iabdalkader
Copy link

It could be a serial issue on Windows, maybe it's buffering the data, as it works fine on Linux. Could you try the mbed core? If you get similar results then it's definitely a Windows issue.

Second is there an alternate way to view the images with openmv ide or the arducam windows app?

I don't know anything about arducam app, but OpenMV uses a debugging protocol over serial, and the IDE is more fault-tolerant, but it will never work with this. There's a websockets viewer in mbed core. The sketch will need to be update to support work with it though (see CameraCaptureWebSerial example).

@mjs513
Copy link

mjs513 commented Mar 10, 2025

@iabdalkader - @KurtE

Sorry I didn't get back to you all yesterday - kind of ran out of steam

As for the GC2145 on the GIGA and the Visualizer sketch I never had much luck with it working with mbed on the GIGA thats why I just loaded up OpenMv on it and it worked like a charm.

With that said I hack up the camera api to add:

bool Camera::startCamera(bool enable) {
  if(enable == true) {
    if (video_stream_start(this->vdev)) {
          Serial.println("Failed to start capture");
      return false;
    }
  } else {
    if (video_stream_stop(this->vdev)) {
          Serial.println("Failed to end capture");
      return false;
    }
  }
  
  return true;
}

wanted to see if I could send a BMP to the arducam windows app (supports jpeg and bmp images) and it kind of worked but not well. So reverted back to the H7 and used a modified sketch that @KurtE generated

#include <elapsedMillis.h>
#include "camera.h"
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/video.h>
#include <zephyr/drivers/video-controls.h>

Camera cam;

elapsedMicros emFrame;
#define FRAME_RESTART_TIMEOUT_US 200000ul
uint8_t restart_count = 0;

void fatal_error(const char *msg) {
  Serial.println(msg);
  pinMode(LED_BUILTIN, OUTPUT);
  while(1) {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(100);
    digitalWrite(LED_BUILTIN, LOW);
    delay(100);
  }
}

const struct device *vdev;

void setup(void) {
  Serial.begin(115200);
  while (!Serial && millis() < 5000) {}
  if (!cam.begin(320, 240, CAMERA_RGB565)) {
    fatal_error("Camera begin failed");
  }
  Serial.println("Camera Started....");
  cam.setVerticalFlip(false);
  cam.setHorizontalMirror(false);
  vdev = DEVICE_DT_GET(DT_CHOSEN(zephyr_camera));
/***************************************/
	struct video_format fmt;
	struct video_caps caps;
	struct video_frmival frmival;
	struct video_frmival_enum fie;
  int i = 0;
  
  printf("Video device: %s", vdev->name);
  
	/* Get capabilities */
	if (video_get_caps(vdev, VIDEO_EP_OUT, &caps)) {
		printf("Unable to retrieve video capabilities\n");
		while(1){}
	}

	printf("\n- Capabilities:\n");
	while (caps.format_caps[i].pixelformat) {
		const struct video_format_cap *fcap = &caps.format_caps[i];
		/* fourcc to string */
		printf("  %c%c%c%c width [%u; %u; %u] height [%u; %u; %u]\n",
		       (char)fcap->pixelformat, (char)(fcap->pixelformat >> 8),
		       (char)(fcap->pixelformat >> 16), (char)(fcap->pixelformat >> 24),
		       fcap->width_min, fcap->width_max, fcap->width_step, fcap->height_min,
		       fcap->height_max, fcap->height_step);
		i++;
	}

	/* Get default/native format */
	if (video_get_format(vdev, VIDEO_EP_OUT, &fmt)) {
		printf("Unable to retrieve video format\n");
		while(1){}
	}

	printf("\n- Current Video format: %c%c%c%c %ux%u", (char)fmt.pixelformat,
	       (char)(fmt.pixelformat >> 8), (char)(fmt.pixelformat >> 16),
	       (char)(fmt.pixelformat >> 24), fmt.width, fmt.height);

	if (!video_get_frmival(vdev, VIDEO_EP_OUT, &frmival)) {
		printf("\n- Default frame rate : %f fps\n",
		       1.0 * frmival.denominator / frmival.numerator);
	}

	printf("\n- Supported frame intervals for the default format:\n");
	memset(&fie, 0, sizeof(fie));
	fie.format = &fmt;
	while (video_enum_frmival(vdev, VIDEO_EP_OUT, &fie) == 0) {
		if (fie.type == VIDEO_FRMIVAL_TYPE_DISCRETE) {
			printf("   %u/%u ", fie.discrete.numerator, fie.discrete.denominator);
		} else {
			printf("   [min = %u/%u; max = %u/%u; step = %u/%u]",
			       fie.stepwise.min.numerator, fie.stepwise.min.denominator,
			       fie.stepwise.max.numerator, fie.stepwise.max.denominator,
			       fie.stepwise.step.numerator, fie.stepwise.step.denominator);
		}
    printf("\n");
		fie.index++;
	}
  printf("\n");

  emFrame = 0;
}

void loop() {
  FrameBuffer fb;
  if (cam.grabFrame(fb)) {
    //Serial.println((uint32_t)emFrame);
    if (Serial.read() == 1) {
      Serial.write(fb.getBuffer(), fb.getBufferSize());
    }
    //Serial.println(fb.getBufferSize());
    cam.releaseFrame(fb);
    emFrame = 0;
  } else if (emFrame > FRAME_RESTART_TIMEOUT_US) {
    Serial.println("Timeout try restart");
    if (!cam.startCamera(true)) {
    //if (!cam.begin(320, 240, CAMERA_RGB565)) {
      fatal_error("Camera begin failed");
    }
    emFrame = 0;
  }
}

and seems I am able to get past the HAL_DCMI_ErrorCallback warning message with H7 and the OV7670. And using the visualizer (and processing 4.3):

Image

now when I get that warning I will see in the visualizer
Image
but if I open and close the image window I recover back to what I showed in the original image.

However with that said I am now getting an error message:

<err> video_stm32_dcmi: Failed to dequeue a DCMI buffer.

that I am not sure how to handle.

As for restarting DMA I did notice in video_stm32_dcmi.c a command they use when they start stream:

HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS,
			(uint32_t)data->vbuf->buffer, data->vbuf->bytesused / 4);

not sure we can use that to restart DMA?

@KurtE
Copy link
Author

KurtE commented Mar 10, 2025

I think I tried to recover by using things like:

HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS,
			(uint32_t)data->vbuf->buffer, data->vbuf->bytesused / 4);

But I believe it gave me a lot of errors. And/or they were not in the export table... forgot what I ran into.

Will try more later. Now I trying to figure out how to force a pin into Analog mode.

@mjs513
Copy link

mjs513 commented Mar 11, 2025

Got energetic and ran the GC2145 on the H7 and guess what its working as well as the ov7670, same behavior as described in my last post. No issues with Visualizer.

Image

@iabdalkader
Copy link

iabdalkader commented Mar 11, 2025

When I was testing the camera to display, I had to restart the DMA stream in the Zephyr driver (drivers/video/video_stm32_dcmi.c), not in the sketch/library. More specially in video_stm32_dcmi_dequeue when an overrun is detected. I didn't not commit that change as it seemed pointless to keep restarting it if it can't keep up, so I ended up reducing the frequency to 10MHz. It might be useful to send this fix upstream at some point, for occasional frame drops, but the issue seems to be in IRQ priorities, SDRAM speed or maybe CPU clock, as the H7 can normally maintain way more bandwidth than this (as you've already noticed, by comparing this to the OpenMV firmware for example).

I see above that it seems to be working fine. Note the colors issue has been fixed upstream.

@mjs513
Copy link

mjs513 commented Mar 11, 2025

I see above that it seems to be working fine. Note the colors issue has been fixed upstream.

I did try to reduce the clock to 10mhz and it helped with the dropped frames but still eventually stopped just before seeing <err> video_stm32_dcmi: Failed to dequeue a DCMI buffer.

Now on the Giga I did manage to visualizer working by adding an extra myPort.write(1) in setup. Now seeing corrupt images at 10mhz and fifo_1_4

Image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants