ov2640 (Red board without MCLK) on Raspberry Pi Pico/CircuitPython (7 & 8 Beta)

Run on Raspberry Pi Pico/CircuitPython 7.3.3, capture images from ov2640 cam module (without MCLK), display on ST7789 TFT. Develop on Raspberry Pi OS.

Prepare Libraries:

Visit https://circuitpython.org/libraries, download and extract library bundle match with your CircuitPython version.

Libraries need: adafruit_st7789 and adafruit_ov2640, copy to CircuitPython device's /lib folder.

Connection:
	      ST7789 SPI
	     +--------------
	3V3  | BLK
	GP1  | CS
	GP0  | DC
	GP4  | RES
	GP3  | SDA
	GP2  | SCL
	3V3  | VCC
	GND  | GND
	     +--------------

	      ov2640 (Red board without MCLK)
	     +-------------+
	3V3  | 3V3    GND  | GND
	GP5  | VSYNC  SCL  | GP17 *
	GP6  | HREF   SDA  | GP16 *
	GP7  | RST    D0   | GP8
	GP9  | D1     D2   | GP10
	GP11 | D3     D4   | GP12
	GP13 | D5     D6   | GP14
	GP15 | D7     DCLK | GP18
	N/C  | NC     PWDN | N/C
	     +-------------+
			
*SCL/SDA are I2C-like interface,
 pull-up resistors are needed to connect to 3V3. 
 What I use here are 10KOhm resistors.


Note that the ov2640 module used in this exercise have built-in X'tal, so no MCLK pin. 

Example code:

cpy_Pico_ov2640_displayio_pico_st7789_2in.py
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense

"""
Capture an image from the camera and display it on a supported LCD.
"""

import time
from displayio import (
    Bitmap,
    Group,
    TileGrid,
    FourWire,
    release_displays,
    ColorConverter,
    Colorspace,
    FourWire,
)

from adafruit_st7789 import ST7789
import board
import busio
import digitalio
import adafruit_ov2640

release_displays()
# Set up the display (You must customize this block for your display!)
"""
spi = busio.SPI(clock=board.GP2, MOSI=board.GP3)
display_bus = FourWire(spi, command=board.GP0, chip_select=board.GP1, reset=None)
display = ST7789(display_bus, width=320, height=240, rotation=270)
"""

# --- Setup st7789 display---
# Define GPIOs for ST7789
tft_SCL = board.GP2
tft_SDA = board.GP3
tft_RES = board.GP4
tft_DC = board.GP0
tft_CS = board.GP1

# On CircuitPython for Raspberry Pi Pico
# 'module' object has no attribute 'SPI'
#spi = board.SPI()
tft_spi = busio.SPI(clock=tft_SCL, MOSI=tft_SDA)
display_bus = FourWire(tft_spi, command=tft_DC, chip_select=tft_CS, reset=tft_RES)
display = ST7789(display_bus, width=320, height=240, rotation=270)
# -------------


display.auto_refresh = False

# Ensure the camera is shut down, so that it releases the SDA/SCL lines,
# then create the configuration I2C bus
"""
with digitalio.DigitalInOut(board.GP10) as reset:
    reset.switch_to_output(False)
    time.sleep(0.001)
    bus = busio.I2C(board.GP9, board.GP8)

# Set up the camera (you must customize this for your board!)
cam = adafruit_ov2640.OV2640(
    bus,
    data_pins=[
        board.GP12,
        board.GP13,
        board.GP14,
        board.GP15,
        board.GP16,
        board.GP17,
        board.GP18,
        board.GP19,
    ],  # [16]     [org] etc
    clock=board.GP11,  # [15]     [blk]
    vsync=board.GP7,  # [10]     [brn]
    href=board.GP21,  # [27/o14] [red]
    mclk=board.GP20,  # [16/o15]
    shutdown=None,
    reset=board.GP10,
)  # [14]
"""

ov_SCL   = board.GP17
ov_SDA   = board.GP16
ov_RST   = board.GP7
ov_VSYNC = board.GP5
ov_HREF  = board.GP6
ov_DCLK  = board.GP18

# Pins must be sequential
ov_D0    = board.GP8
ov_D1    = board.GP9
ov_D2    = board.GP10
ov_D3    = board.GP11
ov_D4    = board.GP12
ov_D5    = board.GP13
ov_D6    = board.GP14
ov_D7    = board.GP15

with digitalio.DigitalInOut(ov_RST) as reset:
    reset.switch_to_output(False)
    time.sleep(0.001)
    bus = busio.I2C(ov_SCL, ov_SDA)

# Set up the camera (you must customize this for your board!)
cam = adafruit_ov2640.OV2640(
    bus,
    data_pins=[
        ov_D0,
        ov_D1,
        ov_D2,
        ov_D3,
        ov_D4,
        ov_D5,
        ov_D6,
        ov_D7,
    ],
    clock=ov_DCLK,
    vsync=ov_VSYNC,
    href=ov_HREF,
    mclk=None,  # for ov2640 module without MCLK
    shutdown=None,
    reset=ov_RST,
)

width = display.width
height = display.height

cam.size = adafruit_ov2640.OV2640_SIZE_QQVGA
# cam.test_pattern = True
bitmap = Bitmap(cam.width, cam.height, 65536)

print(width, height, cam.width, cam.height)
if bitmap is None:
    raise SystemExit("Could not allocate a bitmap")

g = Group(scale=1, x=(width - cam.width) // 2, y=(height - cam.height) // 2)
tg = TileGrid(
    bitmap, pixel_shader=ColorConverter(input_colorspace=Colorspace.BGR565_SWAPPED)
)
g.append(tg)
display.show(g)

display.auto_refresh = False
while True:
    cam.capture(bitmap)
    bitmap.dirty()
    display.refresh(minimum_frames_per_second=0)

ref:
~ CircuitPython Library doc: adafruit_ov2640



Run on Raspberry Pi Pico/CircuitPython 8.0.0 Beta 5, develop on Linux Mint 21/Thonny 4.0.1.


Remember to install the libraries (adafruit_st7789 and adafruit_ov2640) from Bundle for Version 8.x to match with CircuitPython run on your board.

cpy_Pico_ov2640_displayio_pico_st7789_verB.py
further modify to select the biggest size base on memory and display.
# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense

"""
Capture an image from the camera and display it on a supported LCD.
"""

import time
from displayio import (
    Bitmap,
    Group,
    TileGrid,
    FourWire,
    release_displays,
    ColorConverter,
    Colorspace,
    FourWire,
)

from adafruit_st7789 import ST7789
import board
import busio
import digitalio
import adafruit_ov2640

release_displays()
# Set up the display (You must customize this block for your display!)
"""
spi = busio.SPI(clock=board.GP2, MOSI=board.GP3)
display_bus = FourWire(spi, command=board.GP0, chip_select=board.GP1, reset=None)
display = ST7789(display_bus, width=320, height=240, rotation=270)
"""

# --- Setup st7789 display---
# Define GPIOs for ST7789
tft_SCL = board.GP2
tft_SDA = board.GP3
tft_RES = board.GP4
tft_DC = board.GP0
tft_CS = board.GP1

# On CircuitPython for Raspberry Pi Pico
# 'module' object has no attribute 'SPI'
#spi = board.SPI()
tft_spi = busio.SPI(clock=tft_SCL, MOSI=tft_SDA)
display_bus = FourWire(tft_spi, command=tft_DC, chip_select=tft_CS, reset=tft_RES)
display = ST7789(display_bus, width=320, height=240, rotation=270)
# -------------


display.auto_refresh = False

# Ensure the camera is shut down, so that it releases the SDA/SCL lines,
# then create the configuration I2C bus
"""
with digitalio.DigitalInOut(board.GP10) as reset:
    reset.switch_to_output(False)
    time.sleep(0.001)
    bus = busio.I2C(board.GP9, board.GP8)

# Set up the camera (you must customize this for your board!)
cam = adafruit_ov2640.OV2640(
    bus,
    data_pins=[
        board.GP12,
        board.GP13,
        board.GP14,
        board.GP15,
        board.GP16,
        board.GP17,
        board.GP18,
        board.GP19,
    ],  # [16]     [org] etc
    clock=board.GP11,  # [15]     [blk]
    vsync=board.GP7,  # [10]     [brn]
    href=board.GP21,  # [27/o14] [red]
    mclk=board.GP20,  # [16/o15]
    shutdown=None,
    reset=board.GP10,
)  # [14]
"""

ov_SCL   = board.GP17
ov_SDA   = board.GP16
ov_RST   = board.GP7
ov_VSYNC = board.GP5
ov_HREF  = board.GP6
ov_DCLK  = board.GP18

# Pins must be sequential
ov_D0    = board.GP8
ov_D1    = board.GP9
ov_D2    = board.GP10
ov_D3    = board.GP11
ov_D4    = board.GP12
ov_D5    = board.GP13
ov_D6    = board.GP14
ov_D7    = board.GP15

with digitalio.DigitalInOut(ov_RST) as reset:
    reset.switch_to_output(False)
    time.sleep(0.001)
    bus = busio.I2C(ov_SCL, ov_SDA)

# Set up the camera (you must customize this for your board!)
cam = adafruit_ov2640.OV2640(
    bus,
    data_pins=[
        ov_D0,
        ov_D1,
        ov_D2,
        ov_D3,
        ov_D4,
        ov_D5,
        ov_D6,
        ov_D7,
    ],
    clock=ov_DCLK,
    vsync=ov_VSYNC,
    href=ov_HREF,
    mclk=None,  # for ov2640 module without MCLK
    shutdown=None,
    reset=ov_RST,
)

width = display.width
height = display.height
"""
cam.size = adafruit_ov2640.OV2640_SIZE_QQVGA
# cam.test_pattern = True
bitmap = Bitmap(cam.width, cam.height, 65536)

print(width, height, cam.width, cam.height)
if bitmap is None:
    raise SystemExit("Could not allocate a bitmap")
"""

bitmap = None
# Select the biggest size for which we can allocate a bitmap successfully, and
# which is not bigger than the display
# * borrow from example ov7670_displayio_pico_st7789_2in.py
for size in range(adafruit_ov2640.OV2640_SIZE_UXGA, adafruit_ov2640.OV2640_SIZE_96X96 + 1, -1):
    cam.size = size
    print(size, ":\t", cam.width, "x", cam.height)
    if cam.width > width:
        continue
    if cam.height > height:
        continue
    try:
        bitmap = Bitmap(cam.width, cam.height, 65536)
        break
    except MemoryError:
        continue

print("Selected size: ", width, height, cam.width, cam.height)
if bitmap is None:
    print("bitmap error: Could not allocate a bitmap")
    raise SystemExit("Could not allocate a bitmap")
# ----------------------------


g = Group(scale=1, x=(width - cam.width) // 2, y=(height - cam.height) // 2)
tg = TileGrid(
    bitmap, pixel_shader=ColorConverter(input_colorspace=Colorspace.BGR565_SWAPPED)
)
g.append(tg)
display.show(g)

display.auto_refresh = False
while True:
    cam.capture(bitmap)
    bitmap.dirty()
    display.refresh(minimum_frames_per_second=0)



Comments

Popular posts from this blog

MicroPython/ESP32-C3 + 1.8" 128x160 TFT ST7735 SPI, using boochow/MicroPython-ST7735 library.

CameraWebServe: ESP32-S3 (arduino-esp32) + OV5640 camera module