Skip to content

Commit 2cbdd18

Browse files
committed
esp32s2: Implement parallel image capture
1 parent 268717e commit 2cbdd18

File tree

6 files changed

+120
-6
lines changed

6 files changed

+120
-6
lines changed

locale/circuitpython.pot

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ msgstr ""
115115
msgid "%q must be a tuple of length 2"
116116
msgstr ""
117117

118+
#: ports/esp32s2/common-hal/imagecapture/ParallelImageCapture.c
119+
msgid "%q must be between %d and %d"
120+
msgstr ""
121+
118122
#: ports/raspberrypi/common-hal/rp2pio/StateMachine.c
119123
#: shared-bindings/canio/Match.c
120124
msgid "%q out of range"
@@ -3825,14 +3829,16 @@ msgstr ""
38253829
#: ports/esp32s2/boards/artisense_rd00/mpconfigboard.h
38263830
#: ports/esp32s2/boards/atmegazero_esp32s2/mpconfigboard.h
38273831
#: ports/esp32s2/boards/electroniccats_bastwifi/mpconfigboard.h
3832+
#: ports/esp32s2/boards/espressif_kaluga_1.3/mpconfigboard.h
38283833
#: ports/esp32s2/boards/espressif_kaluga_1/mpconfigboard.h
38293834
#: ports/esp32s2/boards/espressif_saola_1_wroom/mpconfigboard.h
38303835
#: ports/esp32s2/boards/espressif_saola_1_wrover/mpconfigboard.h
38313836
#: ports/esp32s2/boards/franzininho_wifi_wroom/mpconfigboard.h
38323837
#: ports/esp32s2/boards/franzininho_wifi_wrover/mpconfigboard.h
38333838
#: ports/esp32s2/boards/lilygo_ttgo_t8_s2_st7789/mpconfigboard.h
38343839
#: ports/esp32s2/boards/microdev_micro_s2/mpconfigboard.h
3835-
#: ports/esp32s2/boards/muselab_nanoesp32_s2/mpconfigboard.h
3840+
#: ports/esp32s2/boards/muselab_nanoesp32_s2_wroom/mpconfigboard.h
3841+
#: ports/esp32s2/boards/muselab_nanoesp32_s2_wrover/mpconfigboard.h
38363842
#: ports/esp32s2/boards/targett_module_clip_wroom/mpconfigboard.h
38373843
#: ports/esp32s2/boards/targett_module_clip_wrover/mpconfigboard.h
38383844
#: ports/esp32s2/boards/unexpectedmaker_feathers2/mpconfigboard.h

ports/esp32s2/common-hal/audiobusio/__init__.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ static i2s_t *i2s_instance[I2S_NUM_MAX];
4141
static QueueHandle_t i2s_queues[I2S_NUM_MAX];
4242
static TaskHandle_t i2s_tasks[I2S_NUM_MAX];
4343

44+
void port_i2s_allocate_i2s0(void) {
45+
if (!i2s_instance[0]) {
46+
i2s_instance[0] = (void *)~(intptr_t)0;
47+
return;
48+
}
49+
50+
mp_raise_RuntimeError(translate("Peripheral in use"));
51+
}
52+
4453
static int8_t port_i2s_allocate(void) {
4554
#if defined(I2S_NUM_1)
4655
if (!i2s_instance[1]) {

ports/esp32s2/common-hal/audiobusio/__init__.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,6 @@ bool port_i2s_playing(i2s_t *self);
5959
bool port_i2s_paused(i2s_t *self);
6060
void port_i2s_pause(i2s_t *self);
6161
void port_i2s_resume(i2s_t *self);
62+
63+
// some uses (imagecapture) can only operate on i2s0 and need their own init code
64+
void port_i2s_allocate_i2s0(void);

ports/esp32s2/common-hal/imagecapture/ParallelImageCapture.c

Lines changed: 87 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,26 +24,108 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include <string.h>
28+
2729
#include "py/obj.h"
2830
#include "py/runtime.h"
2931

32+
#include "common-hal/audiobusio/__init__.h"
3033
#include "common-hal/imagecapture/ParallelImageCapture.h"
34+
#include "cam.h"
3135

3236
void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_parallelimagecapture_obj_t *self,
33-
const mcu_pin_obj_t *data0,
37+
const uint8_t data_pins[],
38+
uint8_t data_count,
3439
const mcu_pin_obj_t *data_clock,
3540
const mcu_pin_obj_t *vertical_sync,
36-
const mcu_pin_obj_t *horizontal_reference,
37-
int data_count) {
38-
mp_raise_NotImplementedError(NULL);
41+
const mcu_pin_obj_t *horizontal_reference) {
42+
43+
// only 8 bits is supported at present
44+
if (data_count < 8 || data_count > 16) {
45+
mp_raise_ValueError_varg(translate("%q must be between %d and %d"), MP_QSTR_data_count, 8, 16);
46+
}
47+
48+
// This will throw if unsuccessful. Everything following is guaranteed to succeed.
49+
port_i2s_allocate_i2s0();
50+
51+
claim_pin(data_clock);
52+
claim_pin(vertical_sync);
53+
claim_pin(horizontal_reference);
54+
55+
self->data_count = data_count;
56+
self->data_clock = data_clock->number;
57+
self->vertical_sync = vertical_sync->number;
58+
self->horizontal_reference = horizontal_reference->number;
59+
60+
self->config = (cam_config_t) {
61+
.bit_width = data_count,
62+
.pin = {
63+
.pclk = data_clock->number,
64+
.vsync = vertical_sync->number,
65+
.hsync = horizontal_reference->number,
66+
},
67+
.vsync_invert = true,
68+
.hsync_invert = false,
69+
.size = 0,
70+
.max_buffer_size = 8 * 1024,
71+
.task_stack = 1024,
72+
.task_pri = configMAX_PRIORITIES
73+
};
74+
75+
for (int i = 0; i < data_count; i++) {
76+
claim_pin_number(data_pins[i]);
77+
self->config.pin_data[i] = data_pins[i];
78+
}
3979
}
4080

4181
void common_hal_imagecapture_parallelimagecapture_deinit(imagecapture_parallelimagecapture_obj_t *self) {
82+
reset_pin_number(self->data_clock);
83+
self->data_clock = NO_PIN;
84+
85+
reset_pin_number(self->vertical_sync);
86+
self->vertical_sync = NO_PIN;
87+
88+
reset_pin_number(self->horizontal_reference);
89+
self->horizontal_reference = NO_PIN;
90+
91+
for (int i = 0; i < self->data_count; i++) {
92+
if (self->config.pin_data[i] != NO_PIN) {
93+
reset_pin_number(self->config.pin_data[i]);
94+
self->config.pin_data[i] = NO_PIN;
95+
}
96+
}
97+
98+
port_i2s_reset_instance(0);
4299
}
43100

44101
bool common_hal_imagecapture_parallelimagecapture_deinited(imagecapture_parallelimagecapture_obj_t *self) {
45-
return true;
102+
return self->data_clock == NO_PIN;
46103
}
47104

48105
void common_hal_imagecapture_parallelimagecapture_capture(imagecapture_parallelimagecapture_obj_t *self, void *buffer, size_t bufsize) {
106+
size_t size = bufsize / 2; // count is in pixels
107+
if (size != self->config.size || buffer != self->config.frame1_buffer) {
108+
cam_deinit();
109+
self->config.size = bufsize / 2; // count is in pixels(?)
110+
self->config.frame1_buffer = buffer;
111+
112+
cam_init(&self->config);
113+
} else {
114+
cam_give(buffer);
115+
}
116+
cam_start();
117+
118+
while (!cam_ready()) {
119+
RUN_BACKGROUND_TASKS;
120+
if (mp_hal_is_interrupted()) {
121+
self->config.size = 0; // force re-init next time
122+
cam_stop();
123+
return;
124+
}
125+
}
126+
127+
uint8_t *unused;
128+
cam_take(&unused); // this just "returns" buffer
129+
130+
cam_stop();
49131
}

ports/esp32s2/common-hal/imagecapture/ParallelImageCapture.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,13 @@
2727
#pragma once
2828

2929
#include "shared-bindings/imagecapture/ParallelImageCapture.h"
30+
#include "cam.h"
3031

3132
struct imagecapture_parallelimagecapture_obj {
3233
mp_obj_base_t base;
34+
cam_config_t config;
35+
gpio_num_t data_clock;
36+
gpio_num_t vertical_sync;
37+
gpio_num_t horizontal_reference;
38+
uint8_t data_count;
3339
};

ports/esp32s2/supervisor/port.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@
6666
#include "common-hal/audiobusio/__init__.h"
6767
#endif
6868

69+
#if CIRCUITPY_IMAGECAPTURE
70+
#include "cam.h"
71+
#endif
72+
6973
#define HEAP_SIZE (48 * 1024)
7074

7175
uint32_t *heap;
@@ -155,6 +159,10 @@ safe_mode_t port_init(void) {
155159
}
156160

157161
void reset_port(void) {
162+
#if CIRCUITPY_IMAGECAPTURE
163+
cam_deinit();
164+
#endif
165+
158166
reset_all_pins();
159167

160168
// A larger delay so the idle task can run and do any IDF cleanup needed.

0 commit comments

Comments
 (0)