It's just my exercise running on Arduino Nano RP2040 Connect/CircuitPython 7.2.3, to work with ov7670 cam module and display on ST7789 SPI display.
For the connection between Nano RP2040 Connect and ov7670/st7789, refer to the code listed below.
In my practice, pre-defined SPI MOSI/SCK are assigned to SDA/SCL for ST7789. I2C SCL/SDA are assigned to SCL/SDA for ov7670.
*ov7670 SCL/SDA are I2C-like control pins, pull-up resistors are needed. 2K ohm resistors are used in my exercise.
For the st7789 part, it's very straightforward - just install libraries and run the exercise code.
Libraries adafruit_st7789 and adafruit_display_text are needed.
For ov7670 part, libraries adafruit_st7789 and adafruit_ov7670 are needed. adafruit_ov7670 is a CircuitPython driver for OV7670 cameras.
The problem is in adafruit_ov7670, data_pins is a list of 8 data pins in sequential order. But I can't find 8 continuous sequence GPIO on Nano RP2040 Connect. As an exercise, GPIO14~21 are assigned to ov7670 d0~d7, GPIO14 is internal connceted to SCK of the onboard ESP32 (U-blox Nina W102), so it's actually no use. So there are only 7 bits in parallel data bus, and ESP32 SCK is mis-used (you should cannot use ESP32 at the same time). That's why I call it "incomplete".
It seem functionally work, as shown in the video. But I don't know any side-effect. It's just my exercise and not suggested, or follow at your own risk.
To list pins name of all GPIOs (include internal), read last post.
cpyNrp2040_spiST7789_320.py
"""
Example of Arduino Nano RP2040 Connect/CircuitPython 7.2.3
to display on 2.0" IPS 240x320 (RGB) screen
with SPI ST7789 driver.
Connection between Nano RP2040 Connect and
the SPI ST7789 IPS screen.
BLK - 3V3 (backlight, always on)
CS - A0
DC - A1
RES - A2
SDA - D11 (=MOSI)
SCL - D13 (=SCK)
VCC - 3V3
GND - GND
"""
import os
import sys
import board
import microcontroller
import time
import terminalio
import displayio
import busio
from adafruit_display_text import label
#from adafruit_st7789 import ST7789
import adafruit_st7789
print("=====================================")
info = sys.implementation[0] + ' ' + \
os.uname()[3] + '\n' + \
'run on ' + os.uname()[4]
print(info)
print("board_id:", board.board_id)
print("with number of cpu: " +
str(len(microcontroller.cpus)))
print("=====================================")
print(adafruit_st7789.__name__ + " version: "
+ adafruit_st7789.__version__)
print()
# Release any resources currently in use for the displays
displayio.release_displays()
tft_cs = board.A0
tft_dc = board.A1
tft_res = board.A2
spi_mosi = board.D11
spi_clk = board.D13
"""
classbusio.SPI(clock: microcontroller.Pin,
MOSI: Optional[microcontroller.Pin] = None,
MISO: Optional[microcontroller.Pin] = None)
"""
spi = busio.SPI(clock=spi_clk, MOSI=spi_mosi)
display_bus = displayio.FourWire(
spi, command=tft_dc, chip_select=tft_cs, reset=tft_res
)
display = adafruit_st7789.ST7789(display_bus,
width=240, height=320)
# Make the display context
splash = displayio.Group()
display.show(splash)
color_bitmap = displayio.Bitmap(135, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x00FF00
bg_sprite = displayio.TileGrid(color_bitmap,
pixel_shader=color_palette,
x=0, y=0)
splash.append(bg_sprite)
# Draw a smaller inner rectangle
inner_bitmap = displayio.Bitmap(133, 238, 1)
inner_palette = displayio.Palette(1)
inner_palette[0] = 0x0000FF
inner_sprite = displayio.TileGrid(inner_bitmap,
pixel_shader=inner_palette,
x=1, y=1)
splash.append(inner_sprite)
# Draw a label
text_group1 = displayio.Group(scale=1, x=20, y=40)
text1 = os.uname()[4]
text_area1 = label.Label(terminalio.FONT, text=text1, color=0xFF0000)
text_group1.append(text_area1) # Subgroup for text scaling
# Draw a label
text_group2 = displayio.Group(scale=1, x=20, y=60)
text2 = sys.implementation[0] + " " + os.uname()[3]
text_area2 = label.Label(terminalio.FONT, text=text2, color=0x00FF00)
text_group2.append(text_area2) # Subgroup for text scaling
# Draw a label
text_group3 = displayio.Group(scale=2, x=20, y=100)
text3 = adafruit_st7789.__name__
text_area3 = label.Label(terminalio.FONT, text=text3, color=0xFFFFFF)
text_group3.append(text_area3) # Subgroup for text scaling
# Draw a label
text_group4 = displayio.Group(scale=2, x=20, y=120)
text4 = adafruit_st7789.__version__
text_area4 = label.Label(terminalio.FONT, text=text4, color=0xFFFFFF)
text_group4.append(text_area4) # Subgroup for text scaling
splash.append(text_group1)
splash.append(text_group2)
splash.append(text_group3)
splash.append(text_group4)
time.sleep(3.0)
rot = 0
while True:
time.sleep(5.0)
rot = rot + 90
if (rot>=360):
rot =0
display.rotation = rot
cpyNrp2040_ov7670_displayio_pico_st7789.py
"""
Run on Arduino NANO RP2040 Connect/CircuitPython 7.2.3
+ ov7670 cam + st7789 LCD.
Capture images from the camera and display it on LCD.
Modified from ov7670_displayio_pico_st7789_2in.py example
ref:
Adafruit CircuitPython ov7670 Library
https://docs.circuitpython.org/projects/ov7670/
"""
import time
from displayio import (
Bitmap,
Group,
TileGrid,
FourWire,
release_displays,
ColorConverter,
Colorspace,
)
import board
import microcontroller
import busio
import digitalio
import displayio
import adafruit_st7789
import adafruit_ov7670
"""
Connection between Nano RP2040 Connect and
the SPI ST7789 IPS screen.
==========================================
BLK - 3V3 (backlight, always on)
CS - A0
DC - A1
RES - A2
SDA - D11 (MOSI)
SCL - D13 (SCK)
VCC - 3V3
GND - GND
"""
tft_cs = board.A0
tft_dc = board.A1
tft_res = board.A2
spi_mosi = board.D11
spi_clk = board.D13
"""
Connection between Arduino Nano RP2040 Connect and
the ov7670 camera module.
==========================================
ov7670
+-----------+
3V3 |3V3 GND | GND
A5 (SCL) |SCL SDA | A4 (SDA)
TX |VS HS | RX
D12 |PLK XLK | D10
D9 |D7 D6 | D8
D7 |D5 D4 | D6
D5 |D3 D2 | D4
D3 |D1 D0 | XXX
A3 |RET PWDN| -
+-----------+
*ov7670 SCL/SDA are I2C-like control pins, pull-up resistors are needed.
I use 2K ohm resistor for it.
"""
cam_scl = board.A5
cam_sda = board.A4
cam_vs = board.TX
cam_hs = board.RX
cam_plk = board.D12
cam_xlk = board.D10
cam_ret = board.A3
# cam data pins must be sequential
# I can't find 8 continuous sequence GPIO on Nano RP2040 Connect
# As a exercise, I assign GPIO14~21 to d0~d7,
# GPIO14 is internal connceted to onboard ESP32 SCK,
# so it's actually no use.
cam_d0 = board.SCK1 # GPIO14
cam_d1 = board.D3 # GPIO15
cam_d2 = board.D4 # GPIO16
cam_d3 = board.D5 # GPIO17
cam_d4 = board.D6 # GPIO18
cam_d5 = board.D7 # GPIO19
cam_d6 = board.D8 # GPIO20
cam_d7 = board.D9 # GPIO21
release_displays()
# Set up the display
spi = busio.SPI(clock=spi_clk, MOSI=spi_mosi)
display_bus = displayio.FourWire(
spi, command=tft_dc, chip_select=tft_cs, reset=tft_res)
display = adafruit_st7789.ST7789(display_bus,
width=240, height=320)
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(cam_ret) as reset:
reset.switch_to_output(False)
time.sleep(0.001)
bus = busio.I2C(cam_scl, cam_sda)
# Set up the camera
cam = adafruit_ov7670.OV7670(
bus,
data_pins=[
cam_d0,
cam_d1,
cam_d2,
cam_d3,
cam_d4,
cam_d5,
cam_d6,
cam_d7,
], #Pins must be sequential
clock=cam_plk,
vsync=cam_vs,
href=cam_hs,
mclk=cam_xlk,
shutdown=None,
reset=cam_ret,
)
#cam.test_pattern = adafruit_ov7670.OV7670_TEST_PATTERN_COLOR_BAR
print(adafruit_ov7670.__name__ + " version: "
+ adafruit_ov7670.__version__)
print(adafruit_st7789.__name__ + " version: "
+ adafruit_st7789.__version__)
pid = cam.product_id
ver = cam.product_version
print(f"Detected cam pid={pid:x} ver={ver:x}")
width = display.width
height = display.height
bitmap = None
# Select the biggest size for which we can allocate a bitmap successfully,
# and which is not bigger than the display
for size in range(adafruit_ov7670.OV7670_SIZE_DIV1,
adafruit_ov7670.OV7670_SIZE_DIV16 + 1):
cam.size = size
if cam.width > width:
continue
if cam.height > height:
continue
try:
bitmap = Bitmap(cam.width, cam.height, 65536)
break
except MemoryError:
continue
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.RGB565_SWAPPED)
)
g.append(tg)
display.show(g)
#t0 = time.monotonic_ns()
display.auto_refresh = False
while True:
cam.capture(bitmap)
bitmap.dirty()
display.refresh(minimum_frames_per_second=0)
#t1 = time.monotonic_ns()
#print("fps", 1e9 / (t1 - t0))
#t0 = t1
No comments:
Post a Comment