Simple test
Ensure your device works with this simple test.
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5
6"""Capture an image from the camera and display it as ASCII art.
7
8This demo is designed to run on the Kaluga, but you can adapt it
9to other boards by changing the constructors for `bus` and `cam`
10appropriately.
11
12The camera is placed in YUV mode, so the top 8 bits of each color
13value can be treated as "greyscale".
14
15It's important that you use a terminal program that can interpret
16"ANSI" escape sequences. The demo uses them to "paint" each frame
17on top of the prevous one, rather than scrolling.
18
19Remember to take the lens cap off, or un-comment the line setting
20the test pattern!
21"""
22
23import sys
24import time
25
26import board
27import busio
28
29import adafruit_ov2640
30
31bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
32cam = adafruit_ov2640.OV2640(
33 bus,
34 data_pins=board.CAMERA_DATA,
35 clock=board.CAMERA_PCLK,
36 vsync=board.CAMERA_VSYNC,
37 href=board.CAMERA_HREF,
38 mclk=board.CAMERA_XCLK,
39 mclk_frequency=20_000_000,
40 size=adafruit_ov2640.OV2640_SIZE_QQVGA,
41)
42cam.colorspace = adafruit_ov2640.OV2640_COLOR_YUV
43cam.flip_y = True
44# cam.test_pattern = True
45
46buf = bytearray(2 * cam.width * cam.height)
47chars = b" .:-=+*#%@"
48remap = [chars[i * (len(chars) - 1) // 255] for i in range(256)]
49
50width = cam.width
51row = bytearray(2 * width)
52
53sys.stdout.write("\033[2J")
54while True:
55 cam.capture(buf)
56 for j in range(cam.height // 2):
57 sys.stdout.write(f"\033[{j}H")
58 for i in range(cam.width // 2):
59 row[i * 2] = row[i * 2 + 1] = remap[buf[4 * (width * j + i)]]
60 sys.stdout.write(row)
61 sys.stdout.write("\033[K")
62 sys.stdout.write("\033[J")
63 time.sleep(0.05)
LCD tests
Kaluga 1.3 with ili9341
Display an image from the camera on the Kaluga 1.3 board, if it is fitted with an ili9341 display.
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5
6"""
7The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
8tested on v1.3. It probably won't work on v1.2 without modification.
9
10The v1.3 development kit's LCD can have one of two chips, the ili9341 or
11st7789. Furthermore, there are at least 2 ILI9341 variants, one of which needs
12rotation=90! This demo is for the ili9341. If the display is garbled, try adding
13rotation=90, or try modifying it to use ST7799.
14
15The audio board must be mounted between the Kaluga and the LCD, it provides the
16I2C pull-ups(!)
17"""
18
19import board
20import busio
21import displayio
22import fourwire
23from adafruit_ili9341 import ILI9341
24
25import adafruit_ov2640
26
27# Pylint is unable to see that the "size" property of OV2640_GrandCentral exists
28
29# Release any resources currently in use for the displays
30displayio.release_displays()
31
32spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK)
33display_bus = fourwire.FourWire(
34 spi, command=board.LCD_D_C, chip_select=board.LCD_CS, reset=board.LCD_RST
35)
36display = ILI9341(display_bus, width=320, height=240, rotation=90)
37
38bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
39cam = adafruit_ov2640.OV2640(
40 bus,
41 data_pins=board.CAMERA_DATA,
42 clock=board.CAMERA_PCLK,
43 vsync=board.CAMERA_VSYNC,
44 href=board.CAMERA_HREF,
45 mclk=board.CAMERA_XCLK,
46 mclk_frequency=20_000_000,
47 size=adafruit_ov2640.OV2640_SIZE_QVGA,
48)
49
50cam.flip_x = False
51cam.flip_y = True
52pid = cam.product_id
53ver = cam.product_version
54print(f"Detected pid={pid:x} ver={ver:x}")
55# cam.test_pattern = True
56
57g = displayio.Group(scale=1)
58bitmap = displayio.Bitmap(320, 240, 65536)
59tg = displayio.TileGrid(
60 bitmap,
61 pixel_shader=displayio.ColorConverter(input_colorspace=displayio.Colorspace.BGR565_SWAPPED),
62)
63g.append(tg)
64display.root_group = g
65
66display.auto_refresh = False
67while True:
68 cam.capture(bitmap)
69 bitmap.dirty()
70 display.refresh(minimum_frames_per_second=0)
71
72cam.deinit()
Kaluga 1.3 with st7789
Display an image from the camera on the Kaluga 1.3 board, if it is fitted with an st7789 display.
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5
6"""
7The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
8tested on v1.3.
9
10The v1.3 development kit's LCD can have one of two chips, the ili9341 or
11st7789. This demo is for the ili9341. There is no marking to distinguish the
12two chips. If the visible portion of the display's flexible cable has a bunch
13of straight lines, it may be an ili9341. If it has a bunch of wiggly traces,
14it may be an st7789. If in doubt, try both demos.
15
16The audio board must be mounted between the Kaluga and the LCD, it provides the
17I2C pull-ups(!)
18"""
19
20import board
21import busio
22import displayio
23import fourwire
24from adafruit_st7789 import ST7789
25
26import adafruit_ov2640
27
28# Pylint is unable to see that the "size" property of OV2640_GrandCentral exists
29
30# Release any resources currently in use for the displays
31displayio.release_displays()
32
33spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK)
34display_bus = fourwire.FourWire(
35 spi, command=board.LCD_D_C, chip_select=board.LCD_CS, reset=board.LCD_RST
36)
37display = ST7789(display_bus, width=320, height=240, rotation=90, reverse_bytes_in_word=True)
38
39bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
40cam = adafruit_ov2640.OV2640(
41 bus,
42 data_pins=board.CAMERA_DATA,
43 clock=board.CAMERA_PCLK,
44 vsync=board.CAMERA_VSYNC,
45 href=board.CAMERA_HREF,
46 mclk=board.CAMERA_XCLK,
47 mclk_frequency=20_000_000,
48 size=adafruit_ov2640.OV2640_SIZE_QVGA,
49)
50
51# cam.flip_x = False
52# cam.flip_y = True
53pid = cam.product_id
54ver = cam.product_version
55print(f"Detected pid={pid:x} ver={ver:x}")
56# cam.test_pattern = True
57
58g = displayio.Group(scale=1)
59bitmap = displayio.Bitmap(320, 240, 65536)
60tg = displayio.TileGrid(
61 bitmap,
62 pixel_shader=displayio.ColorConverter(input_colorspace=displayio.Colorspace.BGR565_SWAPPED),
63)
64g.append(tg)
65display.root_group = g
66
67display.auto_refresh = False
68while True:
69 cam.capture(bitmap)
70 bitmap.dirty()
71 display.refresh(minimum_frames_per_second=0)
72 print(".")
73
74cam.deinit()
Raspberry Pi Pico with st7789
Display an image from the camera connected to a Raspberry Pi Pico with an st7789 2” display
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5
6"""
7Capture an image from the camera and display it on a supported LCD.
8"""
9
10import time
11
12import board
13import busio
14import digitalio
15from adafruit_st7789 import ST7789
16from displayio import (
17 Bitmap,
18 ColorConverter,
19 Colorspace,
20 FourWire,
21 Group,
22 TileGrid,
23 release_displays,
24)
25
26import adafruit_ov2640
27
28release_displays()
29# Set up the display (You must customize this block for your display!)
30spi = busio.SPI(clock=board.GP2, MOSI=board.GP3)
31display_bus = FourWire(spi, command=board.GP0, chip_select=board.GP1, reset=None)
32display = ST7789(display_bus, width=320, height=240, rotation=270)
33display.auto_refresh = False
34
35# Ensure the camera is shut down, so that it releases the SDA/SCL lines,
36# then create the configuration I2C bus
37
38with digitalio.DigitalInOut(board.GP10) as reset:
39 reset.switch_to_output(False)
40 time.sleep(0.001)
41 bus = busio.I2C(board.GP9, board.GP8)
42
43# Set up the camera (you must customize this for your board!)
44cam = adafruit_ov2640.OV2640(
45 bus,
46 data_pins=[
47 board.GP12,
48 board.GP13,
49 board.GP14,
50 board.GP15,
51 board.GP16,
52 board.GP17,
53 board.GP18,
54 board.GP19,
55 ], # [16] [org] etc
56 clock=board.GP11, # [15] [blk]
57 vsync=board.GP7, # [10] [brn]
58 href=board.GP21, # [27/o14] [red]
59 mclk=board.GP20, # [16/o15]
60 shutdown=None,
61 reset=board.GP10,
62) # [14]
63
64width = display.width
65height = display.height
66
67cam.size = adafruit_ov2640.OV2640_SIZE_QQVGA
68# cam.test_pattern = True
69bitmap = Bitmap(cam.width, cam.height, 65536)
70
71print(width, height, cam.width, cam.height)
72if bitmap is None:
73 raise SystemExit("Could not allocate a bitmap")
74
75g = Group(scale=1, x=(width - cam.width) // 2, y=(height - cam.height) // 2)
76tg = TileGrid(bitmap, pixel_shader=ColorConverter(input_colorspace=Colorspace.BGR565_SWAPPED))
77g.append(tg)
78display.root_group = g
79
80display.auto_refresh = False
81while True:
82 cam.capture(bitmap)
83 bitmap.dirty()
84 display.refresh(minimum_frames_per_second=0)
Kaluga 1.3 with ili9341, direct display
Preview images on LCD, bypassing displayio for slightly higher framerate
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5
6"""
7The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
8tested on v1.3.
9
10The audio board must be mounted between the Kaluga and the LCD, it provides the
11I2C pull-ups(!)
12
13The v1.3 development kit's LCD can have one of two chips, the ili9341 or
14st7789. Furthermore, there are at least 2 ILI9341 variants, which differ
15by rotation. This example is written for one if the ILI9341 variants,
16the one which usually uses rotation=90 to get a landscape display.
17
18This example also requires an SD card breakout wired as follows:
19 * IO18: SD Clock Input
20 * IO17: SD Serial Output (MISO)
21 * IO14: SD Serial Input (MOSI)
22 * IO12: SD Chip Select
23
24Insert a CircuitPython-compatible SD card before powering on the Kaluga.
25Press the "Record" button on the audio daughterboard to take a photo.
26"""
27
28import os
29import struct
30
31import analogio
32import board
33import busdisplay
34import busio
35import displayio
36import fourwire
37import sdcardio
38import storage
39
40import adafruit_ov2640
41
42V_MODE = 1.98
43V_RECORD = 2.41
44
45a = analogio.AnalogIn(board.IO6)
46
47# Release any resources currently in use for the displays
48displayio.release_displays()
49
50spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK)
51display_bus = fourwire.FourWire(
52 spi,
53 command=board.LCD_D_C,
54 chip_select=board.LCD_CS,
55 reset=board.LCD_RST,
56 baudrate=80_000_000,
57)
58_INIT_SEQUENCE = (
59 b"\x01\x80\x80" # Software reset then delay 0x80 (128ms)
60 b"\xef\x03\x03\x80\x02"
61 b"\xcf\x03\x00\xc1\x30"
62 b"\xed\x04\x64\x03\x12\x81"
63 b"\xe8\x03\x85\x00\x78"
64 b"\xcb\x05\x39\x2c\x00\x34\x02"
65 b"\xf7\x01\x20"
66 b"\xea\x02\x00\x00"
67 b"\xc0\x01\x23" # Power control VRH[5:0]
68 b"\xc1\x01\x10" # Power control SAP[2:0];BT[3:0]
69 b"\xc5\x02\x3e\x28" # VCM control
70 b"\xc7\x01\x86" # VCM control2
71 b"\x36\x01\x40" # Memory Access Control
72 b"\x37\x01\x00" # Vertical scroll zero
73 b"\x3a\x01\x55" # COLMOD: Pixel Format Set
74 b"\xb1\x02\x00\x18" # Frame Rate Control (In Normal Mode/Full Colors)
75 b"\xb6\x03\x08\x82\x27" # Display Function Control
76 b"\xf2\x01\x00" # 3Gamma Function Disable
77 b"\x26\x01\x01" # Gamma curve selected
78 b"\xe0\x0f\x0f\x31\x2b\x0c\x0e\x08\x4e\xf1\x37\x07\x10\x03\x0e\x09\x00" # Set Gamma
79 b"\xe1\x0f\x00\x0e\x14\x03\x11\x07\x31\xc1\x48\x08\x0f\x0c\x31\x36\x0f" # Set Gamma
80 b"\x11\x80\x78" # Exit Sleep then delay 0x78 (120ms)
81 b"\x29\x80\x78" # Display on then delay 0x78 (120ms)
82)
83
84display = busdisplay.BusDisplay(display_bus, _INIT_SEQUENCE, width=320, height=240)
85
86bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
87cam = adafruit_ov2640.OV2640(
88 bus,
89 data_pins=board.CAMERA_DATA,
90 clock=board.CAMERA_PCLK,
91 vsync=board.CAMERA_VSYNC,
92 href=board.CAMERA_HREF,
93 mclk=board.CAMERA_XCLK,
94 mclk_frequency=20_000_000,
95 size=adafruit_ov2640.OV2640_SIZE_QVGA,
96)
97
98cam.flip_x = False
99cam.flip_y = True
100pid = cam.product_id
101ver = cam.product_version
102print(f"Detected pid={pid:x} ver={ver:x}")
103# cam.test_pattern = True
104
105bitmap = displayio.Bitmap(320, 240, 65536)
106
107display.auto_refresh = False
108
109sd_spi = busio.SPI(clock=board.IO18, MOSI=board.IO14, MISO=board.IO17)
110sd_cs = board.IO12
111sdcard = sdcardio.SDCard(sd_spi, sd_cs)
112vfs = storage.VfsFat(sdcard)
113storage.mount(vfs, "/sd")
114
115
116def exists(filename):
117 try:
118 os.stat(filename)
119 return True
120 except OSError:
121 return False
122
123
124_image_counter = 0
125
126
127def open_next_image():
128 global _image_counter # noqa: PLW0603
129 while True:
130 filename = f"/sd/img{_image_counter:04d}.jpg"
131 _image_counter += 1
132 if exists(filename):
133 continue
134 print("#", filename)
135 return open(filename, "wb")
136
137
138def capture_image():
139 old_size = cam.size
140 old_colorspace = cam.colorspace
141 exposure = cam.exposure
142 try:
143 cam.size = adafruit_ov2640.OV2640_SIZE_UXGA
144 cam.colorspace = adafruit_ov2640.OV2640_COLOR_JPEG
145 cam.exposure = exposure
146 b = bytearray(cam.capture_buffer_size)
147 jpeg = cam.capture(b)
148
149 print(f"Captured {len(jpeg)} bytes of jpeg data")
150 with open_next_image() as f:
151 f.write(jpeg)
152 finally:
153 cam.size = old_size
154 cam.colorspace = old_colorspace
155 cam.exposure = exposure
156
157
158def main():
159 display.auto_refresh = False
160 display_bus.send(42, struct.pack(">hh", 0, 319))
161 display_bus.send(43, struct.pack(">hh", 0, 239))
162 while True:
163 a_voltage = a.value * a.reference_voltage / 65535
164 record_pressed = abs(a_voltage - V_RECORD) < 0.05
165 if record_pressed:
166 capture_image()
167 cam.capture(bitmap)
168 display_bus.send(44, bitmap)
169
170
171main()
Image-saving tests
Kaluga 1.3 with ili9341, internal flash, JPEG
Preview images on LCD t hen save JPEG images to internal flash on Kaluga 1.3. Requires the second snippet of
code to be saved as boot.py.
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5
6"""
7The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
8tested on v1.3.
9
10The audio board must be mounted between the Kaluga and the LCD, it provides the
11I2C pull-ups(!)
12
13You also need to place ov2640_jpeg_kaluga1_3_boot.py at CIRCUITPY/boot.py
14and reset the board to make the internal flash readable by CircuitPython.
15You can make CIRCUITPY readable from your PC by booting CircuitPython in
16safe mode or holding the "MODE" button on the audio daughterboard while
17powering on or resetting the board.
18"""
19
20import board
21import busio
22
23import adafruit_ov2640
24
25bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
26cam = adafruit_ov2640.OV2640(
27 bus,
28 data_pins=board.CAMERA_DATA,
29 clock=board.CAMERA_PCLK,
30 vsync=board.CAMERA_VSYNC,
31 href=board.CAMERA_HREF,
32 mclk=board.CAMERA_XCLK,
33 mclk_frequency=20_000_000,
34 size=adafruit_ov2640.OV2640_SIZE_QVGA,
35)
36
37pid = cam.product_id
38ver = cam.product_version
39print(f"Detected pid={pid:x} ver={ver:x}")
40# cam.test_pattern = True
41
42cam.colorspace = adafruit_ov2640.OV2640_COLOR_JPEG
43b = bytearray(cam.capture_buffer_size)
44jpeg = cam.capture(b)
45
46print(f"Captured {len(jpeg)} bytes of jpeg data")
47try:
48 with open("/jpeg.jpg", "wb") as f:
49 f.write(jpeg)
50except OSError as e:
51 print(e)
52 print(
53 "A 'read-only filesystem' error occurs if you did not correctly install"
54 "\nov2640_jpeg_kaluga1_3_boot.py as CIRCUITPY/boot.py and reset the board"
55 )
56print("Wrote to CIRCUITPY/jpeg.jpg")
boot.py for the above program
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5"""Use this file as CIRCUITPY/boot.py in conjunction with ov2640_jpeg_kaluga1_3.py
6
7It makes the CIRCUITPY filesystem writable to CircuitPython
8(and read-only to the PC) unless the "MODE" button on the audio
9daughterboard is held while the board is powered on or reset.
10"""
11
12import analogio
13import board
14import storage
15
16V_MODE = 1.98
17V_RECORD = 2.41
18
19a = analogio.AnalogIn(board.IO6)
20a_voltage = a.value * a.reference_voltage / 65535
21if abs(a_voltage - V_MODE) > 0.05: # If mode is NOT pressed...
22 print("storage writable by CircuitPython")
23 storage.remount("/", readonly=False)
Kaluga 1.3 with ili9341, external SD card, JPEG
Preview images on LCD then save JPEG images to SD on Kaluga 1.3 fitted with an ili9341 display.
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5
6"""
7Display an image on the LCD, then record an image when the REC button is pressed/held.
8
9The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
10tested on v1.3.
11
12The audio board must be mounted between the Kaluga and the LCD, it provides the
13I2C pull-ups(!)
14
15The v1.3 development kit's LCD can have one of two chips, the ili9341 or
16st7789. Furthermore, there are at least 2 ILI9341 variants, one of which needs
17rotation=90! This demo is for the ili9341. If the display is garbled, try adding
18rotation=90, or try modifying it to use ST7799.
19
20This example also requires an SD card breakout wired as follows:
21 * IO18: SD Clock Input
22 * IO17: SD Serial Output (MISO)
23 * IO14: SD Serial Input (MOSI)
24 * IO12: SD Chip Select
25
26Insert a CircuitPython-compatible SD card before powering on the Kaluga.
27Press the "Record" button on the audio daughterboard to take a photo.
28"""
29
30import os
31
32import analogio
33import board
34import busio
35import displayio
36import fourwire
37import sdcardio
38import storage
39from adafruit_ili9341 import ILI9341
40
41import adafruit_ov2640
42
43V_MODE = 1.98
44V_RECORD = 2.41
45
46a = analogio.AnalogIn(board.IO6)
47
48# Release any resources currently in use for the displays
49displayio.release_displays()
50
51spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK)
52display_bus = fourwire.FourWire(
53 spi, command=board.LCD_D_C, chip_select=board.LCD_CS, reset=board.LCD_RST
54)
55display = ILI9341(display_bus, width=320, height=240, rotation=90)
56
57bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
58cam = adafruit_ov2640.OV2640(
59 bus,
60 data_pins=board.CAMERA_DATA,
61 clock=board.CAMERA_PCLK,
62 vsync=board.CAMERA_VSYNC,
63 href=board.CAMERA_HREF,
64 mclk=board.CAMERA_XCLK,
65 mclk_frequency=20_000_000,
66 size=adafruit_ov2640.OV2640_SIZE_QVGA,
67)
68
69cam.flip_x = False
70cam.flip_y = True
71pid = cam.product_id
72ver = cam.product_version
73print(f"Detected pid={pid:x} ver={ver:x}")
74# cam.test_pattern = True
75
76g = displayio.Group(scale=1)
77bitmap = displayio.Bitmap(320, 240, 65536)
78tg = displayio.TileGrid(
79 bitmap,
80 pixel_shader=displayio.ColorConverter(input_colorspace=displayio.Colorspace.BGR565_SWAPPED),
81)
82g.append(tg)
83display.root_group = g
84
85display.auto_refresh = False
86
87sd_spi = busio.SPI(clock=board.IO18, MOSI=board.IO14, MISO=board.IO17)
88sd_cs = board.IO12
89sdcard = sdcardio.SDCard(sd_spi, sd_cs)
90vfs = storage.VfsFat(sdcard)
91storage.mount(vfs, "/sd")
92
93
94def exists(filename):
95 try:
96 os.stat(filename)
97 return True
98 except OSError:
99 return False
100
101
102_image_counter = 0
103
104
105def open_next_image():
106 global _image_counter # noqa: PLW0603
107 while True:
108 filename = f"/sd/img{_image_counter:04d}.jpg"
109 _image_counter += 1
110 if exists(filename):
111 continue
112 print("#", filename)
113 return open(filename, "wb")
114
115
116def capture_image():
117 old_size = cam.size
118 old_colorspace = cam.colorspace
119
120 try:
121 cam.size = adafruit_ov2640.OV2640_SIZE_UXGA
122 cam.colorspace = adafruit_ov2640.OV2640_COLOR_JPEG
123 b = bytearray(cam.capture_buffer_size)
124 jpeg = cam.capture(b)
125
126 print(f"Captured {len(jpeg)} bytes of jpeg data")
127 with open_next_image() as f:
128 f.write(jpeg)
129 finally:
130 cam.size = old_size
131 cam.colorspace = old_colorspace
132
133
134display.auto_refresh = False
135while True:
136 a_voltage = a.value * a.reference_voltage / 65535
137 record_pressed = abs(a_voltage - V_RECORD) < 0.05
138 if record_pressed:
139 capture_image()
140 cam.capture(bitmap)
141 bitmap.dirty()
142 display.refresh(minimum_frames_per_second=0)
Kaluga 1.3 with ili9341, external SD card, BMP
Preview images on LCD then save BMP images to SD on Kaluga 1.3 fitted with an ili9341 display.
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5
6"""
7The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
8tested on v1.3.
9
10The audio board must be mounted between the Kaluga and the LCD, it provides the
11I2C pull-ups(!)
12
13The v1.3 development kit's LCD can have one of two chips, the ili9341 or
14st7789. Furthermore, there are at least 2 ILI9341 variants, one of which needs
15rotation=90! This demo is for the ili9341. If the display is garbled, try adding
16rotation=90, or try modifying it to use ST7799.
17
18This example also requires an SD card breakout wired as follows:
19 * IO18: SD Clock Input
20 * IO17: SD Serial Output (MISO)
21 * IO14: SD Serial Input (MOSI)
22 * IO12: SD Chip Select
23
24Insert a CircuitPython-compatible SD card before powering on the Kaluga.
25Press the "Record" button on the audio daughterboard to take a photo in BMP format.
26"""
27
28import os
29import struct
30
31import analogio
32import board
33import busdisplay
34import busio
35import displayio
36import fourwire
37import sdcardio
38import storage
39import ulab.numpy as np
40
41import adafruit_ov2640
42
43# Nominal voltages of several of the buttons on the audio daughterboard
44V_MODE = 1.98
45V_RECORD = 2.41
46
47a = analogio.AnalogIn(board.IO6)
48
49# Release any resources currently in use for the displays
50displayio.release_displays()
51
52spi = busio.SPI(MOSI=board.LCD_MOSI, clock=board.LCD_CLK)
53display_bus = fourwire.FourWire(
54 spi,
55 command=board.LCD_D_C,
56 chip_select=board.LCD_CS,
57 reset=board.LCD_RST,
58 baudrate=80_000_000,
59)
60_INIT_SEQUENCE = (
61 b"\x01\x80\x80" # Software reset then delay 0x80 (128ms)
62 b"\xef\x03\x03\x80\x02"
63 b"\xcf\x03\x00\xc1\x30"
64 b"\xed\x04\x64\x03\x12\x81"
65 b"\xe8\x03\x85\x00\x78"
66 b"\xcb\x05\x39\x2c\x00\x34\x02"
67 b"\xf7\x01\x20"
68 b"\xea\x02\x00\x00"
69 b"\xc0\x01\x23" # Power control VRH[5:0]
70 b"\xc1\x01\x10" # Power control SAP[2:0];BT[3:0]
71 b"\xc5\x02\x3e\x28" # VCM control
72 b"\xc7\x01\x86" # VCM control2
73 b"\x36\x01\x90" # Memory Access Control
74 b"\x37\x01\x00" # Vertical scroll zero
75 b"\x3a\x01\x55" # COLMOD: Pixel Format Set
76 b"\xb1\x02\x00\x18" # Frame Rate Control (In Normal Mode/Full Colors)
77 b"\xb6\x03\x08\x82\x27" # Display Function Control
78 b"\xf2\x01\x00" # 3Gamma Function Disable
79 b"\x26\x01\x01" # Gamma curve selected
80 b"\xe0\x0f\x0f\x31\x2b\x0c\x0e\x08\x4e\xf1\x37\x07\x10\x03\x0e\x09\x00" # Set Gamma
81 b"\xe1\x0f\x00\x0e\x14\x03\x11\x07\x31\xc1\x48\x08\x0f\x0c\x31\x36\x0f" # Set Gamma
82 b"\x11\x80\x78" # Exit Sleep then delay 0x78 (120ms)
83 b"\x29\x80\x78" # Display on then delay 0x78 (120ms)
84)
85
86display = busdisplay.BusDisplay(
87 display_bus, _INIT_SEQUENCE, width=320, height=240, auto_refresh=False
88)
89
90bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
91cam = adafruit_ov2640.OV2640(
92 bus,
93 data_pins=board.CAMERA_DATA,
94 clock=board.CAMERA_PCLK,
95 vsync=board.CAMERA_VSYNC,
96 href=board.CAMERA_HREF,
97 mclk=board.CAMERA_XCLK,
98 mclk_frequency=20_000_000,
99 size=adafruit_ov2640.OV2640_SIZE_QVGA,
100)
101
102cam.flip_x = False
103cam.flip_y = False
104cam.test_pattern = False
105
106g = displayio.Group(scale=1)
107bitmap = displayio.Bitmap(320, 240, 65536)
108tg = displayio.TileGrid(
109 bitmap,
110 pixel_shader=displayio.ColorConverter(input_colorspace=displayio.Colorspace.RGB565_SWAPPED),
111)
112g.append(tg)
113display.root_group = g
114
115
116sd_spi = busio.SPI(clock=board.IO18, MOSI=board.IO14, MISO=board.IO17)
117sd_cs = board.IO12
118sdcard = sdcardio.SDCard(sd_spi, sd_cs)
119vfs = storage.VfsFat(sdcard)
120storage.mount(vfs, "/sd")
121
122
123def exists(filename):
124 try:
125 os.stat(filename)
126 return True
127 except OSError:
128 return False
129
130
131_image_counter = 0
132
133
134def open_next_image(extension="jpg"):
135 global _image_counter # noqa: PLW0603
136 while True:
137 filename = f"/sd/img{_image_counter:04d}.{extension}"
138 _image_counter += 1
139 if exists(filename):
140 continue
141 print("#", filename)
142 return open(filename, "wb")
143
144
145### These routines are for writing BMP files in the RGB565 or BGR565 formats.
146_BI_BITFIELDS = 3
147
148_bitmask_rgb565 = (0xF800, 0x7E0, 0x1F)
149_bitmask_bgr565 = (0x1F, 0x7E0, 0xF800)
150
151
152def write_header(output_file, width, height, masks):
153 def put_word(value):
154 output_file.write(struct.pack("<H", value))
155
156 def put_dword(value):
157 output_file.write(struct.pack("<I", value))
158
159 def put_long(value):
160 output_file.write(struct.pack("<i", value))
161
162 def put_padding(length):
163 output_file.write(b"\0" * length)
164
165 filesize = 14 + 108 + height * width * 2
166
167 # BMP header
168 output_file.write(b"BM")
169 put_dword(filesize)
170 put_word(0) # Creator 1
171 put_word(0) # Creator 2
172 put_dword(14 + 108) # Offset of bitmap data
173
174 # DIB header (BITMAPV4HEADER)
175 put_dword(108) # sizeof(BITMAPV4HEADER)
176 put_long(width)
177 put_long(-height)
178 put_word(1) # number of color planes (must be 1)
179 put_word(16) # number of bits per pixel
180 put_dword(_BI_BITFIELDS) # "compression"
181 put_dword(2 * width * height) # size of raw bitmap data
182 put_long(11811) # 72dpi -> pixels/meter
183 put_long(11811) # 72dpi -> pixels/meter
184 put_dword(0) # palette size
185 put_dword(0) # important color count
186 put_dword(masks[0]) # red mask
187 put_dword(masks[1]) # green mask
188 put_dword(masks[2]) # blue mask
189 put_dword(0) # alpha mask
190 put_dword(0) # CS Type
191 put_padding(3 * 3 * 4) # CIEXYZ infrmation
192 put_dword(144179) # 2.2 gamma red
193 put_dword(144179) # 2.2 gamma green
194 put_dword(144179) # 2.2 gamma blue
195
196
197def capture_image_bmp(the_bitmap):
198 with open_next_image("bmp") as f:
199 swapped = np.frombuffer(the_bitmap, dtype=np.uint16)
200 swapped.byteswap(inplace=True)
201 write_header(f, the_bitmap.width, the_bitmap.height, _bitmask_rgb565)
202 f.write(swapped)
203
204
205display.auto_refresh = False
206old_record_pressed = True
207
208while True:
209 a_voltage = a.value * a.reference_voltage / 65535
210 cam.capture(bitmap)
211 bitmap.dirty()
212
213 record_pressed = abs(a_voltage - V_RECORD) < 0.05
214 display.refresh(minimum_frames_per_second=0)
215 if record_pressed and not old_record_pressed:
216 capture_image_bmp(bitmap)
217 old_record_pressed = record_pressed
Kaluga 1.3 with Adafruit IO
Upload JPEG images to Adafruit IO. Requires that WIFI and Adafruit IO be configured in settings.toml.
1# SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries
2# SPDX-FileCopyrightText: Copyright (c) 2021 Jeff Epler for Adafruit Industries
3#
4# SPDX-License-Identifier: Unlicense
5
6"""
7The Kaluga development kit comes in two versions (v1.2 and v1.3); this demo is
8tested on v1.3.
9
10The audio board must be mounted between the Kaluga and the LCD, it provides the
11I2C pull-ups(!)
12
13This example requires that your WIFI and Adafruit IO credentials be configured
14in CIRCUITPY/settings.toml, and that you have created a feed called "image" with
15history disabled.
16
17The maximum image size is 100kB after base64 encoding, or about 65kB before
18base64 encoding. In practice, "SVGA" (800x600) images are typically around
1940kB even though the "capture_buffer_size" (theoretical maximum size) is
20(width*height/5) bytes or 96kB.
21"""
22
23import binascii
24import time
25from os import getenv
26
27import adafruit_connection_manager
28import adafruit_minimqtt.adafruit_minimqtt as MQTT
29import board
30import busio
31import wifi
32from adafruit_io.adafruit_io import IO_MQTT
33
34import adafruit_ov2640
35
36feed_name = "image"
37
38# Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml
39# (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.)
40ssid = getenv("CIRCUITPY_WIFI_SSID")
41password = getenv("CIRCUITPY_WIFI_PASSWORD")
42aio_username = getenv("ADAFRUIT_AIO_USERNAME")
43aio_key = getenv("ADAFRUIT_AIO_KEY")
44
45print("Connecting to WIFI")
46wifi.radio.connect(ssid, password)
47pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
48ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
49
50print("Connecting to Adafruit IO")
51mqtt_client = MQTT.MQTT(
52 broker="io.adafruit.com",
53 username=aio_username,
54 password=aio_key,
55 socket_pool=pool,
56 ssl_context=ssl_context,
57)
58mqtt_client.connect()
59io = IO_MQTT(mqtt_client)
60
61bus = busio.I2C(scl=board.CAMERA_SIOC, sda=board.CAMERA_SIOD)
62cam = adafruit_ov2640.OV2640(
63 bus,
64 data_pins=board.CAMERA_DATA,
65 clock=board.CAMERA_PCLK,
66 vsync=board.CAMERA_VSYNC,
67 href=board.CAMERA_HREF,
68 mclk=board.CAMERA_XCLK,
69 mclk_frequency=20_000_000,
70 size=adafruit_ov2640.OV2640_SIZE_QVGA,
71)
72
73cam.flip_x = False
74cam.flip_y = False
75cam.test_pattern = False
76
77cam.size = adafruit_ov2640.OV2640_SIZE_SVGA
78cam.colorspace = adafruit_ov2640.OV2640_COLOR_JPEG
79jpeg_buffer = bytearray(cam.capture_buffer_size)
80while True:
81 jpeg = cam.capture(jpeg_buffer)
82 print(f"Captured {len(jpeg)} bytes of jpeg data")
83
84 # b2a_base64() appends a trailing newline, which IO does not like
85 encoded_data = binascii.b2a_base64(jpeg).strip()
86 print(f"Expanded to {len(encoded_data)} for IO upload")
87
88 io.publish("image", encoded_data)
89
90 print("Waiting 3s")
91 time.sleep(3)