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.
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
Post a Comment