ArduCAM-M-2MP not working on Raspberry Pi Pico W (using Micropython)

  1. Where did you get the camera module(s)?
    KSY Shop (https://raspberry-pi.ksyic.com/)
  2. Model number of the product(s)?
    ArduCAM-M-2MP OV2640
  3. What hardware/platform were you working on?
    Raspberry Pi Pico W
  4. Instructions you have followed. (link/manual/etc.)
    I am trying to run the code ChatGPT 4o is suggesting.
    Here is the wiring.
ArduCAM Pin Pico W Pin Name Pico W Pin Number
VCC 5V (VBUS) Pin 40
GND GND Any GND Pin (e.g., Pin 38)
CS GP5 Pin 7
SCK GP10 Pin 14
MOSI GP11 Pin 15
MISO GP12 Pin 16
SDA GP14 Pin 19
SCL GP15 Pin 20

There are two Micropython files.

#arducam.py
import machine
import time

class ArduCAM:
    def __init__(self, spi, cs):
        self.spi = spi
        self.cs = cs
        self.cs.init(machine.Pin.OUT, value=1)
        self.init_camera()

    def init_camera(self):
        """ Initialize the ArduCAM-M-2MP module (OV2640) """
        self.write_reg(0x07, 0x80)  # Software reset
        time.sleep(0.1)
        self.write_reg(0x07, 0x00)  # Exit reset
        time.sleep(0.1)

        # βœ… Enable system clock and configure FIFO
        self.write_reg(0x03, 0x01)  
        self.write_reg(0x45, 0x40)
        self.write_reg(0x10, 0x00)  

        # βœ… Force OV2640 into JPEG Mode
        self.write_reg(0xFF, 0x01)  # Select register bank 1
        self.write_reg(0x12, 0x80)  # Reset sensor
        time.sleep(0.1)
        self.write_reg(0x12, 0x04)  # Set JPEG output mode
        self.write_reg(0xFF, 0x00)  # Select default bank

        # βœ… Enable FIFO Capture (Fixes issue where FIFO doesn't store data)
        self.write_reg(0x04, 0x00)  # Clear FIFO flag
        self.write_reg(0x04, 0x02)  # Start capture

        print("πŸ“· ArduCAM Initialized with 5V Power & Stabilized FIFO!")

    def write_reg(self, addr, value):
        """ Write to a register over SPI with proper CS handling """
        self.cs.value(0)  
        time.sleep_us(10)  
        self.spi.write(bytearray([0x80 | addr, value]))  # Write command
        time.sleep_us(10)
        self.cs.value(1)  
        time.sleep_us(10)

    def read_reg(self, addr):
        """ Read a register value over SPI with proper CS handling """
        self.cs.value(0)  
        time.sleep_us(10)  
        self.spi.write(bytearray([addr & 0x7F]))  
        result = self.spi.read(1)[0]  
        time.sleep_us(10)
        self.cs.value(1)  
        return result

    def flush_fifo(self):
        """ Clear FIFO buffer """
        self.write_reg(0x04, 0x01)

    def start_capture(self):
        """ Start capturing an image """
        self.write_reg(0x04, 0x02)

    def is_capture_done(self):
        """ Check if image capture is complete """
        return self.read_reg(0x41) & 0x08

    def read_fifo(self):
        """ Read image data from FIFO buffer """
        self.cs.value(0)
        self.spi.write(bytearray([0x3C]))  # FIFO read command
        img_data = bytearray()
        while True:
            byte = self.spi.read(1)[0]
            img_data.append(byte)
            if len(img_data) > 50000:  # Avoid infinite loop in case of error
                break
        self.cs.value(1)
        return img_data

Here is the contents of the second Micropython file.

#arducam_test.py
import machine
import time
import arducam

# βœ… **SPI1 Configuration (Optimized for Pico W)**
spi = machine.SPI(1, baudrate=1000000, polarity=0, phase=0,
                  sck=machine.Pin(10), mosi=machine.Pin(11), miso=machine.Pin(12))
cs = machine.Pin(5, machine.Pin.OUT)

#  βœ… **I2C1 Configuration (Optimized for Camera Sensor)**
i2c = machine.I2C(1, scl=machine.Pin(15), sda=machine.Pin(14))

#  βœ… Initialize ArduCAM with 5V Power
camera = arducam.ArduCAM(spi, cs)

def capture_image():
    print("πŸ”„ Flushing FIFO before capture...")
    camera.flush_fifo()
    time.sleep(0.1)
    camera.flush_fifo()  # Flush twice to ensure it's cleared

    print("πŸ“Έ Starting Image Capture...")
    camera.start_capture()
    time.sleep(2)  # Wait for image capture

    # πŸ” Check FIFO Status
    fifo_status = camera.read_reg(0x41)
    print(f"πŸ›  Capture Status Register (0x41): {fifo_status:#02x}")

    if fifo_status & 0x08:
        print("βœ… Image Captured Successfully!")

        # πŸ” Read FIFO Size
        fifo_size_high = camera.read_reg(0x42)
        fifo_size_low = camera.read_reg(0x43)
        fifo_size = (fifo_size_high << 8) | fifo_size_low
        print(f"πŸ“Š FIFO Data Size: {fifo_size} bytes")

        if fifo_size == 0:
            print("❌ Error: FIFO buffer is empty.")
            return

        img_data = camera.read_fifo()
        with open("image.jpg", "wb") as f:
            f.write(img_data)
        print(f"πŸ“· Image Saved! File size: {len(img_data)} bytes")
    else:
        print("❌ Error: Capture did not complete. Check power, SPI, and FIFO.")

# βœ… Run Image Capture Test
capture_image()
  1. Problems you were having?
    Camera doesn’t work. The result is something like this.
MPY: soft reboot
πŸ“· ArduCAM-M-2MP (OV2640) initialized!
πŸ”„ Flushing FIFO before capture...
πŸ“Έ Starting Image Capture...
πŸ›  Capture Status Register (0x41): 0x1
❌ Error: Capture did not complete. Check power, SPI, and FIFO.
  1. The dmesg log from your hardware?
    None.
  2. Troubleshooting attempts you’ve made?
    Tried both 3.3V and 5V, different wiring. None worked.
  3. What help do you need?
    Any suggestions to identify the root cause.