The Kaluga board v1.2's reset button will not work when the camera is attached. Instead, the board must be power cycled. This hardware bug was corrected for v1.3 of the board.
On the Kaluga, the camera connector shares pins with the JTAG debugging facility. It is not possible to use a JTAG debugger together with the camera on this board.

The Kaluga development kit from Espressif includes almost everything you need: The microcontroller, a camera, and an LCD.

Take the assembled Kaluga board stack (all three boards) and attach the camera at the dedicated header, making sure the pins are inserted properly.

You do not need to add any pull-up resistors; they are already provided on the Kaluga's audio daughterboard.

There are at least 3 variants of the LCD board that ship with the Kaluga:

  • st7789
  • ili9341
  • ili9341 with rotation=90

There are no markings to distinguish the three, so you will need to try each variant until you find the one that works.

First, make sure you can see the Kaluga's CIRCUITPY drive and connect to the REPL. Open the REPL and double check that import imagecapture works without showing an error. (note: if it does, the most likely reason is that you are using CircuitPython 8 or newer, which is incompatible with the code in this guide)

Then, copy the correct bundle to your device. It will automatically reload and start displaying the image from the camera on the built-in LCD.

Kaluga 1.3 with OV2640 and ili9341 display (CircuitPython 7)

This code is for CircuitPython 7. Revised code will be required for CircuitPython 8.

Click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the entire lib folder and the code.py file to your CIRCUITPY drive.

Espressif Kaluga ESP32-S2 with OV2640 display showing the test pattern. The test pattern's color bars appear heavily distorted due to the viewing angle.

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

"""
The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
tested on v1.3.  It probably won't work on v1.2 without modification.

The v1.3 development kit's LCD can have one of two chips, the ili9341 or
st7789.  Furthermore, there are at least 2 ILI9341 variants, one of which needs
rotation=90!  This demo is for the ili9341.  If the display is garbled, try adding
rotation=90, or try modifying it to use ST7799.

The audio board must be mounted between the Kaluga and the LCD, it provides the
I2C pull-ups(!)
"""

import board
import busio
import displayio
from adafruit_ili9341 import ILI9341
import adafruit_ov2640

# Pylint is unable to see that the "size" property of OV2640_GrandCentral exists
# pylint: disable=attribute-defined-outside-init

# Release any resources currently in use for the displays
displayio.release_displays()

spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK)
display_bus = displayio.FourWire(
    spi, command=board.LCD_D_C, chip_select=board.LCD_CS, reset=board.LCD_RST
)
display = ILI9341(display_bus, width=320, height=240, rotation=90)

bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
cam = adafruit_ov2640.OV2640(
    bus,
    data_pins=board.CAMERA_DATA,
    clock=board.CAMERA_PCLK,
    vsync=board.CAMERA_VSYNC,
    href=board.CAMERA_HREF,
    mclk=board.CAMERA_XCLK,
    mclk_frequency=20_000_000,
    size=adafruit_ov2640.OV2640_SIZE_QVGA,
)

cam.flip_x = False
cam.flip_y = True
pid = cam.product_id
ver = cam.product_version
print(f"Detected pid={pid:x} ver={ver:x}")
# cam.test_pattern = True

g = displayio.Group(scale=1)
bitmap = displayio.Bitmap(320, 240, 65536)
tg = displayio.TileGrid(
    bitmap,
    pixel_shader=displayio.ColorConverter(
        input_colorspace=displayio.Colorspace.BGR565_SWAPPED
    ),
)
g.append(tg)
display.root_group = g

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

cam.deinit()

Your CIRCUITPY drive should resemble the screenshot below

You should have in / of the CIRCUITPY drive:

  • code.py

And in the lib folder on your CIRCUITPY drive:

  • adafruit_bus_device
  • adafruit_ov2640.mpy
  • adafruit_ili9341.mpy

CircuitPython will automatically reload and begin showing the image from the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.4 or newer.

If the image does not fill the whole display, try removing rotation=90 from the line beginning display = ILI9341. If it does not appear at all or is in reverse video, try the example for the st7789 display.

Folder

Kaluga 1.3 with OV2640 and st7789 display (CircuitPython 7)

This code is for CircuitPython 7. Revised code will be required for CircuitPython 8.

If you have a Kaluga 1.3 board with an ili9341 LCD display, use the project below.

Click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the entire lib folder and the code.py file to your CIRCUITPY drive.

Your CIRCUITPY drive should resemble the image.

You should have in / of the CIRCUITPY drive:

  • code.py

And in the lib folder on your CIRCUITPY drive:

  • adafruit_bus_device
  • adafruit_ov2640.mpy
  • adafruit_st7789.mpy

CircuitPython will automatically reload and begin showing the image from the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.4 or newer.

If the image does not appear at all or is in reverse video, try the example for the ili9341. display.

The author did not have a Kaluga with an st7789 display, so this example is untested.

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

"""
The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
tested on v1.3.

The v1.3 development kit's LCD can have one of two chips, the ili9341 or
st7789.  This demo is for the ili9341.  There is no marking to distinguish the
two chips.  If the visible portion of the display's flexible cable has a bunch
of straight lines, it may be an ili9341.  If it has a bunch of wiggly traces,
it may be an st7789.  If in doubt, try both demos.

The audio board must be mounted between the Kaluga and the LCD, it provides the
I2C pull-ups(!)
"""

import board
import busio
import displayio
from adafruit_st7789 import ST7789
import adafruit_ov2640

# Pylint is unable to see that the "size" property of OV2640_GrandCentral exists
# pylint: disable=attribute-defined-outside-init

# Release any resources currently in use for the displays
displayio.release_displays()

spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK)
display_bus = displayio.FourWire(
    spi, command=board.LCD_D_C, chip_select=board.LCD_CS, reset=board.LCD_RST
)
display = ST7789(
    display_bus, width=320, height=240, rotation=90, reverse_bytes_in_word=True
)

bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
cam = adafruit_ov2640.OV2640(
    bus,
    data_pins=board.CAMERA_DATA,
    clock=board.CAMERA_PCLK,
    vsync=board.CAMERA_VSYNC,
    href=board.CAMERA_HREF,
    mclk=board.CAMERA_XCLK,
    mclk_frequency=20_000_000,
    size=adafruit_ov2640.OV2640_SIZE_QVGA,
)

# cam.flip_x = False
# cam.flip_y = True
pid = cam.product_id
ver = cam.product_version
print(f"Detected pid={pid:x} ver={ver:x}")
# cam.test_pattern = True

g = displayio.Group(scale=1)
bitmap = displayio.Bitmap(320, 240, 65536)
tg = displayio.TileGrid(
    bitmap,
    pixel_shader=displayio.ColorConverter(
        input_colorspace=displayio.Colorspace.BGR565_SWAPPED
    ),
)
g.append(tg)
display.root_group = g

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

cam.deinit()

Kaluga 1.3 with OV7670 and ili9341 display

This code is for CircuitPython 7. Revised code will be required for CircuitPython 8.

Take the assembled Kaluga board stack (all three boards) and attach the camera at the dedicated header, making sure the pins are inserted properly.

Click the Download Project Bundle button below to download the necessary libraries and the code.py file in a zip file. Extract the contents of the zip file, and copy the entire lib folder and the code.py file to your CIRCUITPY drive.

Your CIRCUITPY drive should resemble the image.

You should have in / of the CIRCUITPY drive:

  • code.py

And in the lib folder on your CIRCUITPY drive:

  • adafruit_bus_device
  • adafruit_ov7670.mpy
  • adafruit_ili9341.mpy

CircuitPython will automatically reload and begin showing the image from the camera on the LCD. If it doesn't, you can open up the REPL to diagnose what went wrong. Double check that you copied all the files from the bundle, and that you have a compatible build of CircuitPython installed, 7.0.0-beta.4 or newer.

If the image does not fill the whole display, try removing rotation=90 from the line beginning display = ILI9341. If it does not appear at all or is in reverse video, try the example for the st7789 display.

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

"""
The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
tested on v1.3.  It probably won't work on v1.2 without modification.

The v1.3 development kit's LCD can have one of two chips, the ili9341 or
st7789.  Furthermore, there are at least 2 ILI9341 variants, one of which needs
rotation=90!  This demo is for the ili9341.  If the display is garbled, try adding
rotation=90, or try modifying it to use ST7799.

The camera included with the Kaluga development kit is the incompatible OV2640,
it won't work.

The audio board must be mounted between the Kaluga and the LCD, it provides the
I2C pull-ups(!)
"""

import time
import board
import busio
import displayio
from adafruit_ili9341 import ILI9341
from adafruit_ov7670 import (  # pylint: disable=unused-import
    OV7670,
    OV7670_TEST_PATTERN_COLOR_BAR,
    OV7670_SIZE_DIV2,
    OV7670_NIGHT_MODE_2,
)

# Pylint is unable to see that the "size" property of OV7670_GrandCentral exists
# pylint: disable=attribute-defined-outside-init

# Release any resources currently in use for the displays
displayio.release_displays()

spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK)
display_bus = displayio.FourWire(
    spi, command=board.LCD_D_C, chip_select=board.LCD_CS, reset=board.LCD_RST
)
display = ILI9341(display_bus, width=320, height=240)

bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
cam = OV7670(
    bus,
    data_pins=board.CAMERA_DATA,
    clock=board.CAMERA_PCLK,
    vsync=board.CAMERA_VSYNC,
    href=board.CAMERA_HREF,
    mclk=board.CAMERA_XCLK,
    mclk_frequency=20_000_000,
)

cam.size = OV7670_SIZE_DIV2
cam.flip_x = False
cam.flip_y = True
pid = cam.product_id
ver = cam.product_version
print(f"Detected pid={pid:x} ver={ver:x}")
# cam.test_pattern = OV7670_TEST_PATTERN_COLOR_BAR

g = displayio.Group(scale=1)
bitmap = displayio.Bitmap(320, 240, 65536)
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

cam.deinit()

Adapting to other ESP32-S2 boards

By selecting appropriate pins, you can adapt the example to work on other RP2040 boards:

  • mclk, pclk, vsync, href: Free choice of any pin
  • reset, shutdown: Free choice of any pin. Can omit one or both, but the initialization sequence is less reliable.
  • d0d7: Free choice of any pin
USB Type A Plug Breakout Cable with Premium Female Jumpers
If you'd like to connect a USB-capable chip to your USB host, this cable will make the task very simple. There is no converter chip in this cable! Its basically a...
$1.95
In Stock
USB Type A Extension Cable
This handy USB extension cable will make it easy for you to extend your USB cable when it won't reach. The connectors are gold plated for years of reliability. We use these handy...
Out of Stock

This guide was first published on Jun 29, 2021. It was last updated on Mar 29, 2024.

This page (Espressif Kaluga Setup) was last updated on Mar 29, 2024.

Text editor powered by tinymce.