Overview
Ding dong! Hear that? It's the PiCowbell ringing, letting you know that the new Adafruit PiCowbell OV5640 Camera Breakout is in stock.
This is a quality OV5640 camera with a 5 Megapixel sensor element, a 120-degree wide-angle lens, plus all the support circuitry you need to start taking pictures with your Pico or Pico W. You can grab raw RGB images for image analysis, or use the built-in JPEG encoding to save images to an SD card.
The RP2040 chip has a fast PIO interface peripheral and enough memory to interface with 'DVP' (8-bit parallel digital) cameras. These camera sensors have 8 image data pins, Pixel Clock, H Sync and V Sync signals, plus an I2C configuration interface and a Reset plus power Down pin.
That does mean a lot of GPIO are used! But we still have 6 GPIO pin available even after adding a microSD card and shutter button.
Camera PiCowbell Features:
-
Interface for OV5640 Camera module
VSync: GPIO 0
Power Down: GPIO 1
HSync: GPIO 2
Pixel Clock: GPIO 3
SDA/SCL: GPIO 4 and GPIO 5
8-bit Digital: GPIO6 through GPIO 13
Reset: GPIO 14
VMotor connected to 3.3V for auto-focus modules -
Micro SD Card:
SPI on GPIO 16, GPIO 18 and GPIO 19
Chip select on GPIO 17
Optional SD Detect on GPIO 15 - Shutter button on GPIO 22
- Reset button
- 16 MHz 'XClock' generated by onboard oscillator
- Stemma QT port for I2C on GPIO 4 / 5
There are multiple variants of this board. Each has a different camera module:
- Autofocus 72 Degree Lens
- Autofocus 120 Degree Lens
- Wide Angle 160 Degree Lens - No auto-focus, fixed 'infinite' focus module
- Wide Angle 120 Degree Lens - No auto-focus, fixed 'infinite' focus module
- 120 Degree Low Distortion - No auto-focus, fixed 'infinite' focus module
Note that to use the auto-focusing capability with the auto-focus modules, you need to load a new firmware binary over I2C. The autofocus system is controlled with I2C commands to begin an auto-focus procedure and determine that focus is complete. Otherwise, the camera looks just like any other OV5640 sensor.
Each order comes with an assembled PCB, camera sensor, and two pieces of 20-pin pin header. You will need to solder in the header yourself, but it's a quick task.
Since this board has the camera pointing 'up', it's best to use our PiCowbell 'doubler' to have the Pico on one side with the BOOT button accessible, and then the camera on the other side. Or you can 'stack' the camera 'bell on top, best when you don't need easy access to the BOOT loading button.
Or, for a compact package, you can...
- Use the Pico Stacking Headers if you want to be able to plug into a breadboard or other accessory with sockets. Solder these onto the Pico so that the camera is on top.
- Use the Pico Socket Headers if you want to plug directly in and have a nice solid connection that doesn't have any poking-out-bits. Ditto, solder these into the Pico and plug the camera on top.
Page last edited May 11, 2024
Text editor powered by tinymce.
Pinouts
Power
- VB (VBUS) - This is the micro-USB input voltage, connected to the micro-USB port on the Raspberry Pi Pico. It is nominally 5V.
- VS (VSYS) - This is the main system input voltage. It can range from 1.8V to 5.5V and is used to generate the 3.3V needed for the RP2040 and the GPIO pins.
- EN (3V3_EN) - This connects to the enable pin on the Raspberry Pi Pico, and is pulled high (to VSYS) via a 100kΩ resistor.
- 3V - This is the 3.3V output from the Raspberry Pi Pico.
- Vr (ADC_VREF) - This is the ADC power supply and reference voltage. It is generated on the Raspberry Pi Pico by filtering the 3.3V supply. It can be used with an external reference when ADC performance is required.
- G - This is the common ground for power and logic. All GND pins are highlighted in white on the PC board silkscreen.
- SCL - I2C clock pin on the PiCowbell. It is connected to your microcontroller I2C clock line, which is GPIO5 on the Pico. This connection is shared with the STEMMA QT port on the end of the board.
- SDA - I2C data pin on the PiCowbell. It is connected to your microcontroller I2C data line, which is GPIO4 on the Pico. This connection is shared with the STEMMA QT port on the end of the board.
- STEMMA QT - These connectors allow you to connect to dev boards with STEMMA QT connectors or to other things with various associated accessories. There's one port at the end of the PiCowbell.
In the center of the board is the OV5640 camera module. The camera utilizes the following pins:
- VSYNC - GP0
- HREF - GP2
- PCLK - GP3
- PWDN - GP1
- DATA2 - GP6
- DATA3 - GP7
- DATA4 - GP8
- DATA5 - GP9
- DATA6 - GP10
- DATA7 - GP11
- DATA8 - GP12
- DATA9 - GP13
- RESET - GP14
For more information on the OV5640 pins, check out the Adafruit Learn Guide for the module.
On the back center of the board is the XCLK jumper for the camera module. It is outlined in white and labeled XCLK on the board silk. This jumper connects the XCLK pin from the camera module (center pad of the jumper) to an onboard oscillator (left pad of the jumper labeled INT). This oscillator generates a 16 MHz clock. If you cut this jumper, this disconnects the XCLK pin from the oscillator. You can then solder the center pad of the jumper to the A0 pad to its right to connect XCLK to pin A0. The XCLK pin must be driven with a 16MHz square wave from the microcontroller or other source.
- Vmotor - On the back of the board, below the board label silk, is the Vmotor jumper. It is labeled Vmotor on the board silk. This jumper connects 3.3V to the motor for auto-focus camera modules. If you cut this jumper, it will disconnect 3.3V from the DATA1 pin on the camera module.
The microSD card slot is connected to the following pins for SPI:
- MISO (GP16) - This is the SPI MISO (Microcontroller In / Serial Out) pin. It's used for the SD card to send data to the microcontroller.
- SCK (GP18) - This is the SPI clock input pin.
- MO (MOSI/GP19) - This is the SPI MOSI (Microcontroller Out / Serial In) pin. It is used to send data from the microcontroller to the SD card.
- CS (Chip Select/GP17) - This is the chip select pin for the SD card.
- SD Det - On the back of the board, directly next to GP15, is the SD Detect jumper. The jumper is labeled SD Det on the silk. You can solder this jumper closed to connect the optional SD card detect line to GP15.
On the end of the board, next to the STEMMA QT connector, is the shutter button. It is connected to GP22. You can use this button in your code to take photos or as an additional input.
Page last edited May 11, 2024
Text editor powered by tinymce.
CircuitPython TFT Mirror Demo
It's easy to use the PiCowbell Camera Breakout with CircuitPython and the Adafruit_CircuitPython_OV5640 library. This library allows you to easily write Python code that lets you interface with the OV5640 camera modules.
The first example will use a 240x240 TFT display to show a preview from the camera.
Wiring
The Raspberry Pi Pico and the PiCowbell Camera will be plugged into a PiCowbell Doubler. You can use an EYESPI breakout to easily connect to the EYESPI TFT display.
- EYESPI Vin to Pico 3.3V (red wire)
- EYESPI Gnd to Pico GND (black wire)
- EYESPI SCK to Pico GP18 (green wire)
- EYESPI MOSI to Pico GP19 (blue wire)
- EYESPI DC to Pico GP21 (yellow wire)
- EYESPI TCS to Pico GP17 (white wire)
CircuitPython Usage
To use with CircuitPython, you need to first install the OV5640 library, and its dependencies, into the lib folder onto your CIRCUITPY drive. Then you need to update code.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file.
Connect your board to your computer via a known good data+power USB cable. The board should show up in your File Explorer/Finder (depending on your operating system) as a flash drive named CIRCUITPY.
Extract the contents of the zip file, and copy the entire lib folder and the code.py file to your CIRCUITPY drive.
Your CIRCUITPY/lib folder should contain the following folder and files:
- adafruit_bus_device/
- adafruit_ov5640.mpy
- adafruit_st7789.mpy
Example Code
Once everything is saved to the CIRCUITPY drive, connect to the serial console to see the data printed out!
# SPDX-FileCopyrightText: Copyright (c) 2023 Limor Fried for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
"""
This demo is designed for the Raspberry Pi Pico, Camera PiCowbell,
and ST7789 240x240 SPI TFT display
It shows the camera image on the LCD
"""
import time
import busio
import board
import digitalio
import adafruit_ov5640
import adafruit_st7789
import displayio
import fourwire
displayio.release_displays()
spi = busio.SPI(clock=board.GP18, MOSI=board.GP19)
display_bus = fourwire.FourWire(spi, command=board.GP21, chip_select=board.GP17, reset=None)
display = adafruit_st7789.ST7789(display_bus, width=240, height=240, rowstart=80, rotation=0)
print("construct bus")
i2c = busio.I2C(board.GP5, board.GP4)
print("construct camera")
reset = digitalio.DigitalInOut(board.GP14)
cam = adafruit_ov5640.OV5640(
i2c,
data_pins=(
board.GP6,
board.GP7,
board.GP8,
board.GP9,
board.GP10,
board.GP11,
board.GP12,
board.GP13,
),
clock=board.GP3,
vsync=board.GP0,
href=board.GP2,
mclk=None,
shutdown=None,
reset=reset,
size=adafruit_ov5640.OV5640_SIZE_240X240,
)
print("print chip id")
print(cam.chip_id)
cam.colorspace = adafruit_ov5640.OV5640_COLOR_RGB
cam.flip_y = False
cam.flip_x = False
cam.test_pattern = False
width = display.width
height = display.height
#cam.test_pattern = OV7670_TEST_PATTERN_COLOR_BAR_FADE
try:
bitmap = displayio.Bitmap(cam.width, cam.height, 65535)
except MemoryError:
print("Oops, 240x240 is a little too big, trying 240x176..")
cam.size = adafruit_ov5640.OV5640_SIZE_QCIF
bitmap = displayio.Bitmap(cam.width, cam.height, 65535)
print(width, height, cam.width, cam.height)
if bitmap is None:
raise SystemExit("Could not allocate a bitmap")
g = displayio.Group(scale=1, x=(width-cam.width)//2, y=(height-cam.height)//2)
tg = displayio.TileGrid(bitmap,
pixel_shader=displayio.ColorConverter(input_colorspace=displayio.Colorspace.RGB565_SWAPPED)
)
g.append(tg)
display.root_group = 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
In the code, the TFT display is instantiated over SPI. Then, the camera object is constructed. The camera frame is shown as a bitmap on the TFT display. In the serial monitor, you'll see the framerate of the camera printed.
Page last edited May 11, 2024
Text editor powered by tinymce.
CircuitPython JPEG Capture Demo
It's easy to use the PiCowbell Camera Breakout with CircuitPython and the Adafruit_CircuitPython_OV5640 library. This library allows you to easily write Python code that lets you interface with the OV5640 camera modules.
This example will use the shutter button on the PiCowbell Camera to take a photo with the camera module and save it to a microSD card.
Connect the PiCowbell to a Pico using a PiCowbell Doubler. Insert a microSD card into the microSD card slot on the PiCowbell.
CircuitPython Usage
To use with CircuitPython, you need to first install the OV5640 library, and its dependencies, into the lib folder onto your CIRCUITPY drive. Then you need to update code.py with the example script.
Thankfully, we can do this in one go. In the example below, click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file.
Connect your board to your computer via a known good data+power USB cable. The board should show up in your File Explorer/Finder (depending on your operating system) as a flash drive named CIRCUITPY.
Extract the contents of the zip file, and copy the entire lib folder and the code.py file to your CIRCUITPY drive.
Your CIRCUITPY/lib folder should contain the following folder and file:
- adafruit_bus_device/
- adafruit_ov5640.mpy
Example Code
Once everything is saved to the CIRCUITPY drive, connect to the serial console to see the data printed out!
# SPDX-FileCopyrightText: Copyright (c) 2023 Limor Fried for Adafruit Industries
#
# SPDX-License-Identifier: Unlicense
"""
This demo is designed for the Raspberry Pi Pico and Camera PiCowbell
It take an image when the shutter button is pressed and saves it to
the microSD card.
"""
import os
import time
import busio
import board
import digitalio
import adafruit_ov5640
import keypad
import sdcardio
import storage
print("Initializing SD card")
sd_spi = busio.SPI(clock=board.GP18, MOSI=board.GP19, MISO=board.GP16)
sd_cs = board.GP17
sdcard = sdcardio.SDCard(sd_spi, sd_cs)
vfs = storage.VfsFat(sdcard)
storage.mount(vfs, "/sd")
print("construct bus")
i2c = busio.I2C(board.GP5, board.GP4)
print("construct camera")
reset = digitalio.DigitalInOut(board.GP14)
cam = adafruit_ov5640.OV5640(
i2c,
data_pins=(
board.GP6,
board.GP7,
board.GP8,
board.GP9,
board.GP10,
board.GP11,
board.GP12,
board.GP13,
),
clock=board.GP3,
vsync=board.GP0,
href=board.GP2,
mclk=None,
shutdown=None,
reset=reset,
size=adafruit_ov5640.OV5640_SIZE_VGA,
)
print("print chip id")
print(cam.chip_id)
keys = keypad.Keys((board.GP22,), value_when_pressed=False, pull=True)
def exists(filename):
try:
os.stat(filename)
return True
except OSError as _:
return False
_image_counter = 0
def open_next_image():
global _image_counter # pylint: disable=global-statement
while True:
filename = f"/sd/img{_image_counter:04d}.jpg"
_image_counter += 1
if exists(filename):
continue
print("# writing to", filename)
return open(filename, "wb")
cam.colorspace = adafruit_ov5640.OV5640_COLOR_JPEG
# Different platforms have different amounts of memory available.
# Typically a Pico 2 can handle quality = 2 and a Pico can handle quality = 5.
# Rather than detect and select sizes, let's try to detect the best dynamically
# for broader platform support.
# Start with the highest quality setting and attempt to allocate a buffer
# of the necessary size. If it fails, try the next lowest.
b = None
for quality in range(2,55): #valid range is 2 to 54 inclusive
try:
cam.quality = quality
print(f"Attempting to use quality {quality}.")
b = bytearray(cam.capture_buffer_size)
print(f"Quality {quality} successfully selected.")
break
except MemoryError:
print(f"Quality {quality} was too big. Trying next lowest.")
if b is None:
print("There wasn't enough system memory to allocate the lowest quality buffer.")
jpeg = cam.capture(b)
while True:
shutter = keys.events.get()
# event will be None if nothing has happened.
if shutter:
if shutter.pressed:
time.sleep(0.01)
jpeg = cam.capture(b)
print(f"Captured {len(jpeg)} bytes of jpeg data")
print(f" (had allocated {cam.capture_buffer_size} bytes")
print(f"Resolution {cam.width}x{cam.height}")
try:
with open_next_image() as f:
f.write(jpeg)
print("# Wrote image")
except OSError as e:
print(e)
In the code, the microSD card is instantiated over SPI. Then, the camera object is constructed. The shutter button on GP22 is passed as a keypad object. In the loop, if the shutter button is pressed then the camera module takes a picture and it is saved to the microSD card. In the serial monitor, you'll see capture information and confirmation that the image was saved successfully.
Page last edited May 11, 2024
Text editor powered by tinymce.
Downloads
Page last edited May 11, 2024
Text editor powered by tinymce.