Arducam OV5642 SPI camera returns inconsistent byte array sizes in Python on Raspberry Pi 4

Hi everyone, I’m trying to get my Arducam OV5642 (5MP Plus SPI cam) working on a Raspberry Pi 4 using Python. I’ve got numpy, busio, board, and serial installed, and I’m importing the Arducam library via from Arducam import * and from board import *.

The only Python access documentation I could find was this: SPI Camera for Raspberry Pi Pico - Arducam Wiki

I modified the example ArduCAM_Mini_5MP_Plus_VideoStreaming.py. Here’s my code:

import time as utime, numpy as np
import busio
import board
import serial
# import usb_cdc
from Arducam import *
from board import *


mode = 0
start_capture = 0
stop_flag=0
once_number=128
value_command=0
flag_command=0
buffer=bytearray(once_number)

mycam = ArducamClass(OV5642)
mycam.Camera_Detection()
mycam.Spi_Test()
mycam.Camera_Init()
mycam.Spi_write(ARDUCHIP_TIM,VSYNC_LEVEL_MASK)
utime.sleep(1)
mycam.clear_fifo_flag()
mycam.Spi_write(ARDUCHIP_FRAMES,0x00)
mycam.OV5642_set_JPEG_size(1)

def read_fifo_burst():
    count=0
    length=mycam.read_fifo_length()
    mycam.SPI_CS_LOW()
    mycam.set_fifo_burst()
    print('{}/{}'.format(count, length), end='')
    buffer = bytearray()
    while True:
        b = bytearray(once_number)
        mycam.spi.readinto(b,start=0,end=once_number)
        buffer.extend(b)
        utime.sleep(0.00015)
        count+=once_number
        print('\r{}/{}'.format(count, length), end='')
        if count+once_number>length:
            count=length-count
            mycam.spi.readinto(b,start=0,end=count)
            buffer.extend(b)
            mycam.SPI_CS_HIGH()
            mycam.clear_fifo_flag()
            break
    data = np.frombuffer(buffer, dtype=np.int)
    print('end_read: {}'.format(data.shape))

mycam.flush_fifo()
mycam.clear_fifo_flag()
mycam.start_capture()
utime.sleep(1)
while mycam.get_bit(ARDUCHIP_TRIG,CAP_DONE_MASK)!=0:
    read_fifo_burst()
 
print('end')

The script runs, but when I read the FIFO burst and convert the buffer to a NumPy array with np.frombuffer(buffer, dtype=np.int), the data shape keeps changing between runs:

  • 53256
  • 48888
  • 48504

None of these are anywhere near 640*480. Am I doing something wrong with the FIFO read? It seems like the data length should match the resolution.

Those variable sizes actually look normal for this camera. The OV5642 in JPEG mode is outputting compressed JPEG frames, not raw pixel data. So the frame size varies depending on the compression, and it won’t match 640 * 480 = 307200 bytes.

In other words, the JPEG data is not the original image data, it’s the compressed stream, so there’s no guarantee the length equals the raw resolution.

Instead of expecting a fixed resolution-based byte length, treat the FIFO output as a JPEG stream and validate the frame boundaries using the JPEG markers:

  • Check that the data header is FFD8.
  • Check that the data tail is FFD9.

So the inconsistent counts you’re seeing (53256, 48888, 48504) are just the compressed frame sizes. Try validating with those markers instead of relying on 640*480.

Thanks, that makes sense now. I reworked the read to treat the data as a JPEG stream and it does produce valid frames. But honestly the Python path is way too slow for what I need, so I moved over to the C code from the GitHub repo:

https://github.com/ArduCAM/RaspberryPi/SPI_Camera

I ran sudo make, but the build is failing. The errors show gcc compiling a .c file while it’s including what looks like C+±style header content. Should I paste the full output here?

Yes, please paste the full compiler output. That will help confirm whether it’s a file naming issue or something else in the header that’s tripping up the build.

Here’s the full output from sudo make:

gcc -c -o obj/ArducamDemo.o src/ArducamDemo.c -Wall -pthread
In file included from src/ArducamDemo.c:3:
src/ArduCAM.h:345:27: error: expected ‘:’, ‘,’, ‘;’, ‘}’ or ‘__attribute__’ before ‘=’ token
  345 |     unsigned int errCount = 0;
      |                           ^
src/ArduCAM.h:351:1: error: unknown type name ‘class’
  351 | class ArduCAM{
      | ^~~~~
src/ArduCAM.h:351:14: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token
  351 | class ArduCAM{
      |              ^
src/ArducamDemo.c: In function ‘main’:
src/ArducamDemo.c:42:3: warning: implicit declaration of function ‘ArduCAM_CS_init’ [-Wimplicit-function-declaration]
   42 |   ArduCAM_CS_init( CAM_CS1, -1, -1, -1 );   // init the cs
      |   ^~~~~~~~~~~~~~~
src/ArducamDemo.c:48:3: warning: implicit declaration of function ‘Arducam_bus_detect’ [-Wimplicit-function-declaration]
   48 |   Arducam_bus_detect( CAM_CS1, -1, -1, -1 );
      |   ^~~~~~~~~~~~~~~~~~
src/ArducamDemo.c:50:3: warning: implicit declaration of function ‘resetFirmware’ [-Wimplicit-function-declaration]
   50 |   resetFirmware( CAM_CS1, -1, -1, -1 );  //reset the firmware
      |   ^~~~~~~~~~~~~
src/ArducamDemo.c:52:3: warning: implicit declaration of function ‘ArduCAM_Init’ [-Wimplicit-function-declaration]
   52 |   ArduCAM_Init(sensor_model);
      |   ^~~~~~~~~~~~
src/ArducamDemo.c:52:16: error: ‘sensor_model’ undeclared (first use in this function); did you mean ‘sensor_reg’?
   52 |   ArduCAM_Init(sensor_model);
      |                ^~~~~~~~~~~~
      |                sensor_reg
src/ArducamDemo.c:52:16: note: each undeclared identifier is reported only once for each function it appears in
src/ArducamDemo.c:102:12: error: ‘revCmdData’ undeclared (first use in this function)
  102 |     bzero(&revCmdData, CMD_BUF_SIZE);  // Clear the revCmdData buffer
      |            ^~~~~~~~~~
src/ArducamDemo.c: In function ‘readDataThread’:
src/ArducamDemo.c:129:7: warning: implicit declaration of function ‘singleCapture’ [-Wimplicit-function-declaration]
  129 |       singleCapture(CAM_CS1);
      |       ^~~~~~~~~~~~~
src/ArducamDemo.c:131:7: error: ‘sendbuf_cam1’ undeclared (first use in this function)
  131 |       sendbuf_cam1 = readbuf;
      |       ^~~~~~~~~~~~
src/ArducamDemo.c:131:22: error: ‘readbuf’ undeclared (first use in this function); did you mean ‘read’?
  131 |       sendbuf_cam1 = readbuf;
      |                     ^~~~~~~
      |                     read
src/ArducamDemo.c: In function ‘dataParse’:
src/ArducamDemo.c:223:9: error: ‘sensor_model’ undeclared (first use in this function); did you mean ‘sensor_reg’?
  223 |     if (sensor_model == OV2640) {
      |         ^~~~~~~~~~~~
      |         sensor_reg
src/ArducamDemo.c:224:7: warning: implicit declaration of function ‘OV2640_set_JPEG_size’ [-Wimplicit-function-declaration]
  224 |       OV2640_set_JPEG_size(OV2640_160x120);
      |       ^~~~~~~~~~~~~~~~~~~~
src/ArducamDemo.c:228:7: warning: implicit declaration of function ‘OV5640_set_JPEG_size’ [-Wimplicit-function-declaration]
  228 |       OV5640_set_JPEG_size(OV5640_320x240);
      |       ^~~~~~~~~~~~~~~~~~~~
src/ArducamDemo.c:232:7: warning: implicit declaration of function ‘OV5642_set_JPEG_size’ [-Wimplicit-function-declaration]
  232 |       OV5642_set_JPEG_size(OV5642_320x240);
      |       ^~~~~~~~~~~~~~~~~~~~
make: *** [makefile:15: obj/ArducamDemo.o] Error 1

It stops with make: *** [makefile:15: obj/ArducamDemo.o] Error 1.

The root cause here is that src/ArduCAM.h contains C++ constructs, but the build is compiling src/ArducamDemo.c as plain C with gcc.

The first fatal header errors are:

  • src/ArduCAM.h:345:27: error: expected ':', ',', ';', '}' or '__attribute__' before '=' token
  • src/ArduCAM.h:351:1: error: unknown type name 'class'
  • src/ArduCAM.h:351:14: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token

That’s because line 345 has unsigned int errCount = 0; (in-class initializer) and line 351 has class ArduCAM{. C doesn’t support classes, so gcc chokes on the header. Most of the later errors (sensor_model, revCmdData, sendbuf_cam1, readbuf undeclared) are knock-on effects because the header never got parsed correctly.

The easiest fixes to try:

  • Rename src/ArducamDemo.c to src/ArducamDemo.cpp (and update the makefile to match), then rebuild, or
  • Compile with g++ instead of gcc.

That should let the C++ header compile properly. If the makefile still points at the .c name after renaming, you’ll need to adjust that too.