Skip to content

Commit d774678

Browse files
authored
Merge pull request #3369 from kamtom480/camera
Add camera module
2 parents 1fc7971 + 61687c8 commit d774678

File tree

18 files changed

+634
-9
lines changed

18 files changed

+634
-9
lines changed

locale/circuitpython.pot

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ msgid ""
88
msgstr ""
99
"Project-Id-Version: PACKAGE VERSION\n"
1010
"Report-Msgid-Bugs-To: \n"
11-
"POT-Creation-Date: 2020-09-13 14:21-0500\n"
11+
"POT-Creation-Date: 2020-09-11 13:30+0200\n"
1212
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1313
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1414
"Language-Team: LANGUAGE <[email protected]>\n"
@@ -430,7 +430,7 @@ msgstr ""
430430
msgid "Buffer is not a bytearray."
431431
msgstr ""
432432

433-
#: shared-bindings/displayio/Display.c
433+
#: ports/cxd56/common-hal/camera/Camera.c shared-bindings/displayio/Display.c
434434
#: shared-bindings/framebufferio/FramebufferDisplay.c
435435
msgid "Buffer is too small"
436436
msgstr ""
@@ -615,6 +615,10 @@ msgstr ""
615615
msgid "Corrupt raw code"
616616
msgstr ""
617617

618+
#: ports/cxd56/common-hal/camera/Camera.c
619+
msgid "Could not initialize Camera"
620+
msgstr ""
621+
618622
#: ports/cxd56/common-hal/gnss/GNSS.c
619623
msgid "Could not initialize GNSS"
620624
msgstr ""
@@ -841,6 +845,10 @@ msgstr ""
841845
msgid "File exists"
842846
msgstr ""
843847

848+
#: ports/cxd56/common-hal/camera/Camera.c
849+
msgid "Format not supported"
850+
msgstr ""
851+
844852
#: shared-module/framebufferio/FramebufferDisplay.c
845853
#, c-format
846854
msgid "Framebuffer requires %d bytes"
@@ -1503,6 +1511,10 @@ msgstr ""
15031511
msgid "Server side context cannot have hostname"
15041512
msgstr ""
15051513

1514+
#: ports/cxd56/common-hal/camera/Camera.c
1515+
msgid "Size not supported"
1516+
msgstr ""
1517+
15061518
#: shared-bindings/nvm/ByteArray.c
15071519
msgid "Slice and value different lengths."
15081520
msgstr ""

ports/cxd56/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ all: $(BUILD)/firmware.spk
201201
$(FIRMWARE):
202202
$(ECHO) ""
203203
$(ECHO) "Download the spresense binaries zip archive from:"
204-
$(ECHO) "https://developer.sony.com/file/download/download-spresense-firmware-v1-4-000"
204+
$(ECHO) "https://developer.sony.com/file/download/download-spresense-firmware-v2-0-000"
205205
$(ECHO) "Extract spresense binaries to $(FIRMWARE)"
206206
$(ECHO) ""
207207
$(ECHO) "run make flash-bootloader again to flash bootloader."
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright 2020 Sony Semiconductor Solutions Corporation
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include <string.h>
28+
#include <fcntl.h>
29+
30+
#include <arch/board/board.h>
31+
#include <nuttx/video/video.h>
32+
#include <nuttx/arch.h>
33+
34+
#include "py/runtime.h"
35+
36+
#include "shared-bindings/camera/Camera.h"
37+
38+
typedef struct {
39+
const char* devpath;
40+
int fd;
41+
} camera_dev_t;
42+
43+
STATIC camera_dev_t camera_dev = {"/dev/video", -1};
44+
45+
typedef struct {
46+
uint16_t width;
47+
uint16_t height;
48+
} image_size_t;
49+
50+
STATIC const image_size_t image_size_table[] = {
51+
{ VIDEO_HSIZE_QVGA, VIDEO_VSIZE_QVGA },
52+
{ VIDEO_HSIZE_VGA, VIDEO_VSIZE_VGA },
53+
{ VIDEO_HSIZE_HD, VIDEO_VSIZE_HD },
54+
{ VIDEO_HSIZE_QUADVGA, VIDEO_VSIZE_QUADVGA },
55+
{ VIDEO_HSIZE_FULLHD, VIDEO_VSIZE_FULLHD },
56+
{ VIDEO_HSIZE_3M, VIDEO_VSIZE_3M },
57+
{ VIDEO_HSIZE_5M, VIDEO_VSIZE_5M },
58+
};
59+
60+
static bool camera_check_width_and_height(uint16_t width, uint16_t height) {
61+
for (int i = 0; i < MP_ARRAY_SIZE(image_size_table); i++) {
62+
if (image_size_table[i].width == width && image_size_table[i].height == height) {
63+
return true;
64+
}
65+
}
66+
return false;
67+
}
68+
69+
static bool camera_check_buffer_length(uint16_t width, uint16_t height, camera_imageformat_t format, size_t length) {
70+
if (format == IMAGEFORMAT_JPG) {
71+
// In SPRESENSE SDK, JPEG compression quality=80 by default.
72+
// In such setting, the maximum actual measured size of JPEG image
73+
// is about width * height * 2 / 9.
74+
return length >= (size_t)(width * height * 2 / 9);
75+
} else {
76+
return false;
77+
}
78+
}
79+
80+
static bool camera_check_format(camera_imageformat_t format) {
81+
return format == IMAGEFORMAT_JPG;
82+
}
83+
84+
static void camera_set_format(enum v4l2_buf_type type, uint32_t pixformat, uint16_t width, uint16_t height) {
85+
v4l2_requestbuffers_t req = {0};
86+
87+
// Set Buffer Mode.
88+
req.type = type;
89+
req.memory = V4L2_MEMORY_USERPTR;
90+
req.count = 1;
91+
req.mode = V4L2_BUF_MODE_RING;
92+
ioctl(camera_dev.fd, VIDIOC_REQBUFS, (unsigned long)&req);
93+
v4l2_format_t fmt = {0};
94+
95+
// Set Format.
96+
fmt.type = type;
97+
fmt.fmt.pix.width = width;
98+
fmt.fmt.pix.height = height;
99+
fmt.fmt.pix.field = V4L2_FIELD_ANY;
100+
fmt.fmt.pix.pixelformat = pixformat;
101+
ioctl(camera_dev.fd, VIDIOC_S_FMT, (unsigned long)&fmt);
102+
}
103+
104+
static void camera_start_streaming(enum v4l2_buf_type type) {
105+
ioctl(camera_dev.fd, VIDIOC_STREAMON, (unsigned long)&type);
106+
}
107+
108+
static void camera_start_preview() {
109+
camera_set_format(V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_PIX_FMT_UYVY, VIDEO_HSIZE_QVGA, VIDEO_VSIZE_QVGA);
110+
111+
v4l2_buffer_t buf;
112+
113+
memset(&buf, 0, sizeof(v4l2_buffer_t));
114+
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
115+
buf.memory = V4L2_MEMORY_USERPTR;
116+
ioctl(camera_dev.fd, VIDIOC_QBUF, (unsigned long)&buf);
117+
118+
camera_start_streaming(V4L2_BUF_TYPE_VIDEO_CAPTURE);
119+
}
120+
121+
void common_hal_camera_construct(camera_obj_t *self) {
122+
if (camera_dev.fd < 0) {
123+
if (video_initialize(camera_dev.devpath) < 0) {
124+
mp_raise_ValueError(translate("Could not initialize Camera"));
125+
}
126+
camera_dev.fd = open(camera_dev.devpath, 0);
127+
if (camera_dev.fd < 0) {
128+
mp_raise_ValueError(translate("Could not initialize Camera"));
129+
}
130+
}
131+
132+
camera_start_preview();
133+
134+
camera_start_streaming(V4L2_BUF_TYPE_STILL_CAPTURE);
135+
136+
sleep(1);
137+
}
138+
139+
void common_hal_camera_deinit(camera_obj_t *self) {
140+
if (common_hal_camera_deinited(self)) {
141+
return;
142+
}
143+
144+
video_uninitialize();
145+
146+
close(camera_dev.fd);
147+
camera_dev.fd = -1;
148+
}
149+
150+
bool common_hal_camera_deinited(camera_obj_t *self) {
151+
return camera_dev.fd < 0;
152+
}
153+
154+
size_t common_hal_camera_take_picture(camera_obj_t *self, uint8_t *buffer, size_t len, uint16_t width, uint16_t height, camera_imageformat_t format) {
155+
if (!camera_check_width_and_height(width, height)) {
156+
mp_raise_ValueError(translate("Size not supported"));
157+
}
158+
if (!camera_check_buffer_length(width, height, format, len)) {
159+
mp_raise_ValueError(translate("Buffer is too small"));
160+
}
161+
if (!camera_check_format(format)) {
162+
mp_raise_ValueError(translate("Format not supported"));
163+
}
164+
165+
camera_set_format(V4L2_BUF_TYPE_STILL_CAPTURE, V4L2_PIX_FMT_JPEG, width, height);
166+
167+
v4l2_buffer_t buf;
168+
169+
memset(&buf, 0, sizeof(v4l2_buffer_t));
170+
buf.type = V4L2_BUF_TYPE_STILL_CAPTURE;
171+
buf.memory = V4L2_MEMORY_USERPTR;
172+
buf.m.userptr = (unsigned long)buffer;
173+
buf.length = len;
174+
ioctl(camera_dev.fd, VIDIOC_QBUF, (unsigned long)&buf);
175+
176+
ioctl(camera_dev.fd, VIDIOC_TAKEPICT_START, 0);
177+
178+
ioctl(camera_dev.fd, VIDIOC_DQBUF, (unsigned long)&buf);
179+
180+
ioctl(camera_dev.fd, VIDIOC_TAKEPICT_STOP, false);
181+
182+
return (size_t)buf.bytesused;
183+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright 2020 Sony Semiconductor Solutions Corporation
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#ifndef MICROPY_INCLUDED_CXD56_COMMON_HAL_CAMERA_CAMERA_H
28+
#define MICROPY_INCLUDED_CXD56_COMMON_HAL_CAMERA_CAMERA_H
29+
30+
#include "py/obj.h"
31+
32+
typedef struct {
33+
mp_obj_base_t base;
34+
} camera_obj_t;
35+
36+
#endif // MICROPY_INCLUDED_CXD56_COMMON_HAL_CAMERA_CAMERA_H
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// No camera module functions.

ports/cxd56/configs/circuitpython/defconfig

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@ CONFIG_USBDEV=y
165165
CONFIG_USBDEV_DMA=y
166166
CONFIG_USBDEV_DUALSPEED=y
167167
CONFIG_USEC_PER_TICK=1000
168-
CONFIG_USERMAIN_STACKSIZE=1064960
169168
CONFIG_USER_ENTRYPOINT="spresense_main"
170169
CONFIG_VIDEO_ISX012=y
171170
CONFIG_VIDEO_STREAM=y

ports/cxd56/mpconfigport.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,15 @@
2727
#ifndef __INCLUDED_MPCONFIGPORT_H
2828
#define __INCLUDED_MPCONFIGPORT_H
2929

30-
#define MICROPY_PY_SYS_PLATFORM "CXD56"
30+
#define MICROPY_PY_SYS_PLATFORM "CXD56"
3131

3232
// 64kiB stack
33-
#define CIRCUITPY_DEFAULT_STACK_SIZE 0x10000
33+
#define CIRCUITPY_DEFAULT_STACK_SIZE (0x10000)
3434

3535
#include "py/circuitpy_mpconfig.h"
3636

37+
#define MICROPY_BYTES_PER_GC_BLOCK (32)
38+
3739
#define MICROPY_PORT_ROOT_POINTERS \
3840
CIRCUITPY_COMMON_ROOT_POINTERS \
3941

ports/cxd56/mpconfigport.mk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ MPY_TOOL_LONGINT_IMPL = -mlongint-impl=mpz
1111

1212
CIRCUITPY_AUDIOBUSIO = 0
1313
CIRCUITPY_AUDIOIO = 0
14+
CIRCUITPY_CAMERA = 1
1415
CIRCUITPY_COUNTIO = 0
1516
CIRCUITPY_DISPLAYIO = 0
1617
CIRCUITPY_FREQUENCYIO = 0

ports/cxd56/supervisor/port.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,22 @@
4646
#include "common-hal/pwmio/PWMOut.h"
4747
#include "common-hal/busio/UART.h"
4848

49+
#define SPRESENSE_MEM_ALIGN (32)
50+
51+
uint32_t* heap;
52+
uint32_t heap_size;
53+
4954
safe_mode_t port_init(void) {
5055
boardctl(BOARDIOC_INIT, 0);
5156

5257
// Wait until RTC is available
5358
while (g_rtc_enabled == false);
5459

60+
heap = memalign(SPRESENSE_MEM_ALIGN, 128 * 1024);
61+
uint32_t size = CONFIG_RAM_START + CONFIG_RAM_SIZE - (uint32_t)heap - 2 * SPRESENSE_MEM_ALIGN;
62+
heap = realloc(heap, size);
63+
heap_size = size / sizeof(uint32_t);
64+
5565
if (board_requests_safe_mode()) {
5666
return USER_SAFE_MODE;
5767
}
@@ -100,11 +110,11 @@ uint32_t *port_stack_get_top(void) {
100110
}
101111

102112
uint32_t *port_heap_get_bottom(void) {
103-
return port_stack_get_limit();
113+
return heap;
104114
}
105115

106116
uint32_t *port_heap_get_top(void) {
107-
return port_stack_get_top();
117+
return heap + heap_size;
108118
}
109119

110120
extern uint32_t _ebss;

py/circuitpy_defns.mk

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,9 @@ endif
139139
ifeq ($(CIRCUITPY_BUSIO),1)
140140
SRC_PATTERNS += busio/% bitbangio/OneWire.%
141141
endif
142+
ifeq ($(CIRCUITPY_CAMERA),1)
143+
SRC_PATTERNS += camera/%
144+
endif
142145
ifeq ($(CIRCUITPY_COUNTIO),1)
143146
SRC_PATTERNS += countio/%
144147
endif
@@ -310,6 +313,8 @@ SRC_COMMON_HAL_ALL = \
310313
busio/SPI.c \
311314
busio/UART.c \
312315
busio/__init__.c \
316+
camera/__init__.c \
317+
camera/Camera.c \
313318
countio/Counter.c \
314319
countio/__init__.c \
315320
digitalio/DigitalInOut.c \
@@ -380,6 +385,7 @@ $(filter $(SRC_PATTERNS), \
380385
_bleio/Attribute.c \
381386
_bleio/ScanEntry.c \
382387
_eve/__init__.c \
388+
camera/ImageFormat.c \
383389
digitalio/Direction.c \
384390
digitalio/DriveMode.c \
385391
digitalio/Pull.c \

0 commit comments

Comments
 (0)