Merge pull request #5540 from jepler/continuous-capture

ParallelImageCapture: Add continuous capture on espressif
This commit is contained in:
Scott Shawcroft 2021-11-04 13:33:32 -07:00 committed by GitHub
commit a08412420e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 205 additions and 31 deletions

View File

@ -347,6 +347,7 @@ msgstr ""
msgid "64 bit types"
msgstr ""
#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
#: ports/atmel-samd/common-hal/countio/Counter.c
#: ports/atmel-samd/common-hal/rotaryio/IncrementalEncoder.c
msgid "A hardware interrupt channel is already in use"
@ -625,6 +626,10 @@ msgstr ""
msgid "Buffer too short by %d bytes"
msgstr ""
#: ports/espressif/common-hal/imagecapture/ParallelImageCapture.c
msgid "Buffers must be same size"
msgstr ""
#: ports/atmel-samd/common-hal/paralleldisplay/ParallelBus.c
#: ports/espressif/common-hal/paralleldisplay/ParallelBus.c
#: ports/nrf/common-hal/paralleldisplay/ParallelBus.c
@ -1587,6 +1592,10 @@ msgstr ""
msgid "No available clocks"
msgstr ""
#: ports/espressif/common-hal/imagecapture/ParallelImageCapture.c
msgid "No capture in progress"
msgstr ""
#: shared-bindings/_bleio/PacketBuffer.c
msgid "No connection: length cannot be determined"
msgstr ""
@ -1607,6 +1616,7 @@ msgstr ""
msgid "No hardware support on clk pin"
msgstr ""
#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
#: ports/atmel-samd/common-hal/frequencyio/FrequencyIn.c
#: ports/atmel-samd/common-hal/pulseio/PulseIn.c
msgid "No hardware support on pin"
@ -1727,7 +1737,6 @@ msgstr ""
msgid "Only connectable advertisements can be directed"
msgstr ""
#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
#: ports/stm/common-hal/alarm/pin/PinAlarm.c
msgid "Only edge detection is available on this hardware"
msgstr ""
@ -1822,6 +1831,7 @@ msgstr ""
msgid "Permission denied"
msgstr ""
#: ports/atmel-samd/common-hal/alarm/pin/PinAlarm.c
#: ports/stm/common-hal/alarm/pin/PinAlarm.c
msgid "Pin cannot wake from Deep Sleep"
msgstr ""
@ -2175,6 +2185,10 @@ msgstr ""
msgid "The sample's signedness does not match the mixer's"
msgstr ""
#: shared-module/imagecapture/ParallelImageCapture.c
msgid "This microcontroller does not support continuous capture."
msgstr ""
#: shared-module/paralleldisplay/ParallelBus.c
msgid ""
"This microcontroller only supports data0=, not data_pins=, because it "
@ -3880,6 +3894,7 @@ msgstr ""
msgid "pow() with 3 arguments requires integers"
msgstr ""
#: ports/espressif/boards/adafruit_feather_esp32s2/mpconfigboard.h
#: ports/espressif/boards/adafruit_feather_esp32s2_nopsram/mpconfigboard.h
#: ports/espressif/boards/adafruit_feather_esp32s2_tftback_nopsram/mpconfigboard.h
#: ports/espressif/boards/adafruit_funhouse/mpconfigboard.h

View File

@ -151,14 +151,14 @@ static void setup_dma(DmacDescriptor *descriptor, size_t count, uint32_t *buffer
descriptor->DESCADDR.reg = 0;
}
#include <string.h>
void common_hal_imagecapture_parallelimagecapture_capture(imagecapture_parallelimagecapture_obj_t *self, void *buffer, size_t bufsize) {
void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecapture_parallelimagecapture_obj_t *self, mp_obj_t buffer) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_RW);
uint8_t dma_channel = dma_allocate_channel();
uint32_t *dest = buffer;
size_t count = bufsize / 4; // PCC receives 4 bytes (2 pixels) at a time
uint32_t *dest = bufinfo.buf;
size_t count = bufinfo.len / 4; // PCC receives 4 bytes (2 pixels) at a time
turn_on_event_system();

View File

@ -79,6 +79,11 @@ void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_paralle
}
void common_hal_imagecapture_parallelimagecapture_deinit(imagecapture_parallelimagecapture_obj_t *self) {
cam_deinit();
self->buffer1 = NULL;
self->buffer2 = NULL;
reset_pin_number(self->data_clock);
self->data_clock = NO_PIN;
@ -102,28 +107,73 @@ bool common_hal_imagecapture_parallelimagecapture_deinited(imagecapture_parallel
return self->data_clock == NO_PIN;
}
void common_hal_imagecapture_parallelimagecapture_capture(imagecapture_parallelimagecapture_obj_t *self, void *buffer, size_t bufsize) {
size_t size = bufsize / 2; // count is in pixels
if (size != self->config.size || buffer != self->config.frame1_buffer) {
cam_deinit();
self->config.size = bufsize / 2; // count is in pixels(?)
self->config.frame1_buffer = buffer;
cam_init(&self->config);
cam_start();
} else {
cam_give(buffer);
void common_hal_imagecapture_parallelimagecapture_continuous_capture_start(imagecapture_parallelimagecapture_obj_t *self, mp_obj_t buffer1, mp_obj_t buffer2) {
if (buffer1 == self->buffer1 && buffer2 == self->buffer2) {
return;
}
mp_buffer_info_t bufinfo1, bufinfo2 = {};
mp_get_buffer_raise(buffer1, &bufinfo1, MP_BUFFER_RW);
if (buffer2 != mp_const_none) {
mp_get_buffer_raise(buffer2, &bufinfo2, MP_BUFFER_RW);
if (bufinfo1.len != bufinfo2.len) {
mp_raise_ValueError(translate("Buffers must be same size"));
}
}
self->buffer1 = buffer1;
self->buffer2 = buffer2;
cam_deinit();
self->config.size = bufinfo1.len / 2; // count is in pixels
self->config.frame1_buffer = bufinfo1.buf;
self->config.frame2_buffer = bufinfo2.buf;
self->buffer_to_give = NULL;
cam_init(&self->config);
cam_start();
}
void common_hal_imagecapture_parallelimagecapture_continuous_capture_stop(imagecapture_parallelimagecapture_obj_t *self) {
cam_deinit();
self->buffer1 = self->buffer2 = NULL;
self->buffer_to_give = NULL;
}
STATIC void common_hal_imagecapture_parallelimagecapture_continuous_capture_give_frame(imagecapture_parallelimagecapture_obj_t *self) {
if (self->buffer_to_give) {
cam_give(self->buffer_to_give);
self->buffer_to_give = NULL;
}
}
mp_obj_t common_hal_imagecapture_parallelimagecapture_continuous_capture_get_frame(imagecapture_parallelimagecapture_obj_t *self) {
if (self->buffer1 == NULL) {
mp_raise_RuntimeError(translate("No capture in progress"));
}
common_hal_imagecapture_parallelimagecapture_continuous_capture_give_frame(self);
while (!cam_ready()) {
RUN_BACKGROUND_TASKS;
if (mp_hal_is_interrupted()) {
self->config.size = 0; // force re-init next time
cam_stop();
return;
return mp_const_none;
}
}
uint8_t *unused;
cam_take(&unused); // this just "returns" buffer
cam_take(&self->buffer_to_give);
if (self->buffer_to_give == self->config.frame1_buffer) {
return self->buffer1;
}
if (self->buffer_to_give == self->config.frame2_buffer) {
return self->buffer2;
}
return mp_const_none; // should be unreachable
}
void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecapture_parallelimagecapture_obj_t *self, mp_obj_t buffer) {
common_hal_imagecapture_parallelimagecapture_continuous_capture_start(self, buffer, mp_const_none);
common_hal_imagecapture_parallelimagecapture_continuous_capture_get_frame(self);
}

View File

@ -26,6 +26,7 @@
#pragma once
#include "py/obj.h"
#include "shared-bindings/imagecapture/ParallelImageCapture.h"
#include "cam.h"
@ -36,4 +37,6 @@ struct imagecapture_parallelimagecapture_obj {
gpio_num_t vertical_sync;
gpio_num_t horizontal_reference;
uint8_t data_count;
mp_obj_t buffer1, buffer2;
uint8_t *buffer_to_give;
};

View File

@ -137,7 +137,10 @@ bool common_hal_imagecapture_parallelimagecapture_deinited(imagecapture_parallel
return common_hal_rp2pio_statemachine_deinited(&self->state_machine);
}
void common_hal_imagecapture_parallelimagecapture_capture(imagecapture_parallelimagecapture_obj_t *self, void *buffer, size_t bufsize) {
void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecapture_parallelimagecapture_obj_t *self, mp_obj_t buffer) {
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_RW);
PIO pio = self->state_machine.pio;
uint sm = self->state_machine.state_machine;
uint8_t offset = rp2pio_statemachine_program_offset(&self->state_machine);
@ -149,7 +152,7 @@ void common_hal_imagecapture_parallelimagecapture_capture(imagecapture_paralleli
pio_sm_exec(pio, sm, pio_encode_jmp(offset));
pio_sm_set_enabled(pio, sm, true);
common_hal_rp2pio_statemachine_readinto(&self->state_machine, buffer, bufsize, 4);
common_hal_rp2pio_statemachine_readinto(&self->state_machine, bufinfo.buf, bufinfo.len, 4);
pio_sm_set_enabled(pio, sm, false);
}

View File

@ -466,6 +466,7 @@ $(filter $(SRC_PATTERNS), \
digitalio/DriveMode.c \
digitalio/Pull.c \
fontio/Glyph.c \
imagecapture/ParallelImageCapture.c \
math/__init__.c \
microcontroller/ResetReason.c \
microcontroller/RunMode.c \
@ -535,6 +536,7 @@ SRC_SHARED_MODULE_ALL = \
gamepadshift/GamePadShift.c \
gamepadshift/__init__.c \
getpass/__init__.c \
imagecapture/ParallelImageCapture.c \
ipaddress/IPv4Address.c \
ipaddress/__init__.c \
keypad/__init__.c \

View File

@ -25,6 +25,7 @@
*/
#include "py/obj.h"
#include "py/objproperty.h"
#include "py/runtime.h"
#include "shared/runtime/context_manager_helpers.h"
@ -82,19 +83,69 @@ STATIC mp_obj_t imagecapture_parallelimagecapture_make_new(const mp_obj_type_t *
return self;
}
//| def capture(self, buffer: WriteableBuffer, width: int, height: int, bpp: int=16) -> None:
//| """Capture a single frame into the given buffer"""
//| def capture(self, buffer: WriteableBuffer) -> WriteableBuffer:
//| """Capture a single frame into the given buffer.
//|
//| This will stop a continuous-mode capture, if one is in progress."""
//| ...
//|
STATIC mp_obj_t imagecapture_parallelimagecapture_capture(mp_obj_t self_in, mp_obj_t buffer) {
imagecapture_parallelimagecapture_obj_t *self = (imagecapture_parallelimagecapture_obj_t *)self_in;
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_RW);
common_hal_imagecapture_parallelimagecapture_capture(self, bufinfo.buf, bufinfo.len);
common_hal_imagecapture_parallelimagecapture_singleshot_capture(self, buffer);
return buffer;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(imagecapture_parallelimagecapture_capture_obj, imagecapture_parallelimagecapture_capture);
//| def continuous_capture_start(self, buffer1: WriteableBuffer, buffer2: WriteableBuffer, /) -> None:
//| """Begin capturing into the given buffers in the background.
//|
//| Call `continuous_capture_get_frame` to get the next available
//| frame, and `continuous_capture_stop` to stop capturing.
//|
//| Until `continuous_capture_stop` (or `deinit`) is called, the
//| `ParallelImageCapture` object keeps references to ``buffer1`` and
//| ``buffer2``, so the objects will not be garbage collected."""
//| ...
//|
STATIC mp_obj_t imagecapture_parallelimagecapture_continuous_capture_start(mp_obj_t self_in, mp_obj_t buffer1, mp_obj_t buffer2) {
imagecapture_parallelimagecapture_obj_t *self = (imagecapture_parallelimagecapture_obj_t *)self_in;
common_hal_imagecapture_parallelimagecapture_continuous_capture_start(self, buffer1, buffer2);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_2(imagecapture_parallelimagecapture_capture_obj, imagecapture_parallelimagecapture_capture);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(imagecapture_parallelimagecapture_continuous_capture_start_obj, imagecapture_parallelimagecapture_continuous_capture_start);
//| def continuous_capture_get_frame(self) -> WriteableBuffer:
//| """Return the next available frame, one of the two buffers passed to `continuous_capture_start`"""
//| ...
//|
STATIC mp_obj_t imagecapture_parallelimagecapture_continuous_capture_get_frame(mp_obj_t self_in) {
imagecapture_parallelimagecapture_obj_t *self = (imagecapture_parallelimagecapture_obj_t *)self_in;
return common_hal_imagecapture_parallelimagecapture_continuous_capture_get_frame(self);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(imagecapture_parallelimagecapture_continuous_capture_get_frame_obj, imagecapture_parallelimagecapture_continuous_capture_get_frame);
//| def continuous_capture_stop(self) -> None:
//| """Stop continuous capture.
//|
//| Calling this method also causes the object to release its
//| references to the buffers passed to `continuous_capture_start`,
//| potentially allowing the objects to be garbage collected."""
//| ...
//|
STATIC mp_obj_t imagecapture_parallelimagecapture_continuous_capture_stop(mp_obj_t self_in) {
imagecapture_parallelimagecapture_obj_t *self = (imagecapture_parallelimagecapture_obj_t *)self_in;
common_hal_imagecapture_parallelimagecapture_continuous_capture_stop(self);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(imagecapture_parallelimagecapture_continuous_capture_stop_obj, imagecapture_parallelimagecapture_continuous_capture_stop);
//| def deinit(self) -> None:
//| """Deinitialize this instance"""
@ -134,6 +185,9 @@ STATIC const mp_rom_map_elem_t imagecapture_parallelimagecapture_locals_dict_tab
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&imagecapture_parallelimagecapture___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_capture), MP_ROM_PTR(&imagecapture_parallelimagecapture_capture_obj) },
{ MP_ROM_QSTR(MP_QSTR_continuous_capture_start), MP_ROM_PTR(&imagecapture_parallelimagecapture_continuous_capture_start_obj) },
{ MP_ROM_QSTR(MP_QSTR_continuous_capture_stop), MP_ROM_PTR(&imagecapture_parallelimagecapture_continuous_capture_stop_obj) },
{ MP_ROM_QSTR(MP_QSTR_continuous_capture_get_frame), MP_ROM_PTR(&imagecapture_parallelimagecapture_continuous_capture_get_frame_obj) },
};
STATIC MP_DEFINE_CONST_DICT(imagecapture_parallelimagecapture_locals_dict, imagecapture_parallelimagecapture_locals_dict_table);

View File

@ -40,4 +40,7 @@ void common_hal_imagecapture_parallelimagecapture_construct(imagecapture_paralle
const mcu_pin_obj_t *horizontal_sync);
void common_hal_imagecapture_parallelimagecapture_deinit(imagecapture_parallelimagecapture_obj_t *self);
bool common_hal_imagecapture_parallelimagecapture_deinited(imagecapture_parallelimagecapture_obj_t *self);
void common_hal_imagecapture_parallelimagecapture_capture(imagecapture_parallelimagecapture_obj_t *self, void *buffer, size_t bufsize);
void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecapture_parallelimagecapture_obj_t *self, mp_obj_t buffer);
void common_hal_imagecapture_parallelimagecapture_continuous_capture_start(imagecapture_parallelimagecapture_obj_t *self, mp_obj_t buffer1, mp_obj_t buffer2);
void common_hal_imagecapture_parallelimagecapture_continuous_capture_stop(imagecapture_parallelimagecapture_obj_t *self);
mp_obj_t common_hal_imagecapture_parallelimagecapture_continuous_capture_get_frame(imagecapture_parallelimagecapture_obj_t *self);

View File

@ -0,0 +1,44 @@
/*
* This file is part of the Micro Python project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2019 Scott Shawcroft for Adafruit Industries
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "shared-bindings/imagecapture/ParallelImageCapture.h"
#include "py/runtime.h"
// If the continuous-capture mode isn't supported, then this default (weak) implementation will raise exceptions for you
__attribute__((weak))
void common_hal_imagecapture_parallelimagecapture_continuous_capture_start(imagecapture_parallelimagecapture_obj_t *self, mp_obj_t buffer1, mp_obj_t buffer2) {
mp_raise_NotImplementedError(translate("This microcontroller does not support continuous capture."));
}
__attribute__((weak))
void common_hal_imagecapture_parallelimagecapture_continuous_capture_stop(imagecapture_parallelimagecapture_obj_t *self) {
mp_raise_NotImplementedError(translate("This microcontroller does not support continuous capture."));
}
__attribute__((weak))
mp_obj_t common_hal_imagecapture_parallelimagecapture_continuous_capture_get_frame(imagecapture_parallelimagecapture_obj_t *self) {
mp_raise_NotImplementedError(translate("This microcontroller does not support continuous capture."));
}