Requested changes for Ibrahim

This commit is contained in:
Kwabena W. Agyeman 2020-06-01 20:16:38 -07:00
parent 8d09c6630a
commit 2f5216f448
2 changed files with 51 additions and 41 deletions

View File

@ -75,9 +75,11 @@ static mp_obj_t py_sensor_snapshot(uint n_args, const mp_obj_t *args, mp_map_t *
#endif // MICROPY_PY_IMU #endif // MICROPY_PY_IMU
mp_obj_t image = py_image(0, 0, 0, 0); mp_obj_t image = py_image(0, 0, 0, 0);
// Note: OV2640 JPEG mode can __fatal_error().
int ret = sensor.snapshot(&sensor, (image_t *) py_image_cobj(image), NULL);
if (sensor.snapshot(&sensor, (image_t *) py_image_cobj(image), NULL) == -1) { if (ret < 0) {
nlr_raise(mp_obj_new_exception_msg(&mp_type_RuntimeError, "Capture Failed")); nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_RuntimeError, "Capture Failed: %d", ret));
} }
return image; return image;
@ -95,7 +97,7 @@ static mp_obj_t py_sensor_skip_frames(uint n_args, const mp_obj_t *args, mp_map_
uint32_t millis = systick_current_millis(); uint32_t millis = systick_current_millis();
if (!n_args) { if (!n_args) {
while ((systick_current_millis() - millis) < time) { // 32-bit math handles wrap arrounds... while ((systick_current_millis() - millis) < time) { // 32-bit math handles wrap around...
py_sensor_snapshot(0, NULL, NULL); py_sensor_snapshot(0, NULL, NULL);
} }
} else { } else {

View File

@ -37,7 +37,7 @@ DCMI_HandleTypeDef DCMIHandle = {0};
extern uint8_t _line_buf; extern uint8_t _line_buf;
static uint8_t *dest_fb = NULL; static uint8_t *dest_fb = NULL;
static volatile int line = 0; static volatile int offset = 0;
static volatile bool jpeg_buffer_overflow = false; static volatile bool jpeg_buffer_overflow = false;
static volatile bool waiting_for_data = false; static volatile bool waiting_for_data = false;
@ -208,6 +208,15 @@ static void dcmi_abort()
} }
} }
// Returns true if a crop is being applied to the frame buffer.
static bool cropped()
{
return MAIN_FB()->x // needs to be zero if not being cropped.
|| MAIN_FB()->y // needs to be zero if not being cropped.
|| (MAIN_FB()->u != resolution[sensor.framesize][0]) // should be equal to the resolution if not cropped.
|| (MAIN_FB()->v != resolution[sensor.framesize][1]); // should be equal to the resolution if not cropped.
}
void sensor_init0() void sensor_init0()
{ {
dcmi_abort(); dcmi_abort();
@ -527,14 +536,9 @@ int sensor_write_reg(uint16_t reg_addr, uint16_t reg_data)
int sensor_set_pixformat(pixformat_t pixformat) int sensor_set_pixformat(pixformat_t pixformat)
{ {
if ((pixformat == PIXFORMAT_JPEG) if (sensor.pixformat == pixformat) {
&& (MAIN_FB()->x // non-zero // No change
|| MAIN_FB()->y // non-zero return 0;
|| (MAIN_FB()->u != resolution[sensor.framesize][0]) // it was changed
|| (MAIN_FB()->v != resolution[sensor.framesize][1]) // it was changed
|| sensor.transpose
|| sensor.auto_rotation)) {
return -1;
} }
// sensor_check_buffsize() will switch from PIXFORMAT_BAYER to PIXFORMAT_RGB565 to try to fit // sensor_check_buffsize() will switch from PIXFORMAT_BAYER to PIXFORMAT_RGB565 to try to fit
@ -542,6 +546,10 @@ int sensor_set_pixformat(pixformat_t pixformat)
// and that would be bigger than the RAM buffer we would just switch back. // and that would be bigger than the RAM buffer we would just switch back.
// //
// So, just short-circuit doing any work. // So, just short-circuit doing any work.
//
// This code is explicitly here to allow users to set the resolution to RGB565 and have it
// switch to BAYER only once even though they are setting the resolution to RGB565 repeatedly
// in a loop. Only RGB565->BAYER has this problem and needs this fix because of sensor_check_buffsize().
if ((sensor.pixformat == PIXFORMAT_BAYER) if ((sensor.pixformat == PIXFORMAT_BAYER)
&& (pixformat == PIXFORMAT_RGB565) && (pixformat == PIXFORMAT_RGB565)
&& (MAIN_FB()->u * MAIN_FB()->v * 2 > OMV_RAW_BUF_SIZE) && (MAIN_FB()->u * MAIN_FB()->v * 2 > OMV_RAW_BUF_SIZE)
@ -550,9 +558,9 @@ int sensor_set_pixformat(pixformat_t pixformat)
return 0; return 0;
} }
if (sensor.pixformat == pixformat) { // Cropping and transposing (and thus auto rotation) don't work in JPEG mode.
// No change if ((pixformat == PIXFORMAT_JPEG) && (cropped() || sensor.transpose || sensor.auto_rotation)) {
return 0; return -1;
} }
dcmi_abort(); dcmi_abort();
@ -939,8 +947,8 @@ static void sensor_check_buffsize()
sensor_set_pixformat(PIXFORMAT_BAYER); sensor_set_pixformat(PIXFORMAT_BAYER);
bpp = 1; bpp = 1;
// MAIN_FB() fits, we are done. // MAIN_FB() fits, we are done (bpp is 1).
if ((MAIN_FB()->u * MAIN_FB()->v * bpp) <= OMV_RAW_BUF_SIZE) { if (MAIN_FB()->u * MAIN_FB()->v <= OMV_RAW_BUF_SIZE) {
return; return;
} }
} }
@ -1093,7 +1101,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
// length in every line, followed by valid image data. Dummy data (0xFF) may be used as // length in every line, followed by valid image data. Dummy data (0xFF) may be used as
// padding at each line end if the current valid image data is less than the line width. // padding at each line end if the current valid image data is less than the line width.
// //
// In this mode `line` holds the size of all jpeg data transferred. // In this mode `offset` holds the size of all jpeg data transferred.
// //
// Note: We are using this mode for the OV5640 because it allows us to use the line // Note: We are using this mode for the OV5640 because it allows us to use the line
// buffers to fifo the JPEG image data input so we can handle SDRAM refresh hiccups // buffers to fifo the JPEG image data input so we can handle SDRAM refresh hiccups
@ -1101,12 +1109,12 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
// //
uint16_t size = __REV16(*src16); uint16_t size = __REV16(*src16);
// Prevent a buffer overflow when writing the jpeg data. // Prevent a buffer overflow when writing the jpeg data.
if (line + size > OMV_RAW_BUF_SIZE) { if (offset + size > OMV_RAW_BUF_SIZE) {
jpeg_buffer_overflow = true; jpeg_buffer_overflow = true;
return; return;
} }
unaligned_memcpy(MAIN_FB()->pixels + line, src16 + 1, size); unaligned_memcpy(MAIN_FB()->pixels + offset, src16 + 1, size);
line += size; offset += size;
} else { } else {
// JPEG MODE 3: // JPEG MODE 3:
// //
@ -1114,7 +1122,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
// different from the other line (there is no dummy data). In each frame, the line // different from the other line (there is no dummy data). In each frame, the line
// number may be different. // number may be different.
// //
// In this mode `line` will be incremented by one after 262,140 Bytes have been // In this mode `offset` will be incremented by one after 262,140 Bytes have been
// transferred. If 524,280 Bytes have been transferred line will be incremented again. // transferred. If 524,280 Bytes have been transferred line will be incremented again.
// The DMA counter must be used to get the amount of data transferred between. // The DMA counter must be used to get the amount of data transferred between.
// //
@ -1122,23 +1130,23 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
// is not optimal. However, it works okay for the OV2640 since the PCLK is much lower // is not optimal. However, it works okay for the OV2640 since the PCLK is much lower
// than the OV5640 PCLK. The OV5640 drops data in this mode. Hence using mode 4 above. // than the OV5640 PCLK. The OV5640 drops data in this mode. Hence using mode 4 above.
// //
line += 1; offset += 1;
} }
return; return;
} }
// Implement per line, per pixel cropping, and image transposing (for image rotation) in // Implement per line, per pixel cropping, and image transposing (for image rotation) in
// in software using the CPU to transfer the image from the line buffers to the frame buffer. // in software using the CPU to transfer the image from the line buffers to the frame buffer.
if (line >= MAIN_FB()->y && line <= (MAIN_FB()->y + MAIN_FB()->h)) { if (offset >= MAIN_FB()->y && offset <= (MAIN_FB()->y + MAIN_FB()->h)) {
if (!sensor.transpose) { if (!sensor.transpose) {
switch (sensor.pixformat) { switch (sensor.pixformat) {
case PIXFORMAT_BAYER: case PIXFORMAT_BAYER:
dst += (line - MAIN_FB()->y) * MAIN_FB()->w; dst += (offset - MAIN_FB()->y) * MAIN_FB()->w;
src += MAIN_FB()->x; src += MAIN_FB()->x;
unaligned_memcpy(dst, src, MAIN_FB()->w); unaligned_memcpy(dst, src, MAIN_FB()->w);
break; break;
case PIXFORMAT_GRAYSCALE: case PIXFORMAT_GRAYSCALE:
dst += (line - MAIN_FB()->y) * MAIN_FB()->w; dst += (offset - MAIN_FB()->y) * MAIN_FB()->w;
if (sensor.gs_bpp == 1) { if (sensor.gs_bpp == 1) {
// 1BPP GRAYSCALE. // 1BPP GRAYSCALE.
src += MAIN_FB()->x; src += MAIN_FB()->x;
@ -1151,7 +1159,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
break; break;
case PIXFORMAT_YUV422: case PIXFORMAT_YUV422:
case PIXFORMAT_RGB565: case PIXFORMAT_RGB565:
dst16 += (line - MAIN_FB()->y) * MAIN_FB()->w; dst16 += (offset - MAIN_FB()->y) * MAIN_FB()->w;
src16 += MAIN_FB()->x; src16 += MAIN_FB()->x;
unaligned_memcpy(dst16, src16, MAIN_FB()->w * sizeof(uint16_t)); unaligned_memcpy(dst16, src16, MAIN_FB()->w * sizeof(uint16_t));
break; break;
@ -1161,7 +1169,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
} else { } else {
switch (sensor.pixformat) { switch (sensor.pixformat) {
case PIXFORMAT_BAYER: case PIXFORMAT_BAYER:
dst += line - MAIN_FB()->y; dst += offset - MAIN_FB()->y;
src += MAIN_FB()->x; src += MAIN_FB()->x;
for (int i = MAIN_FB()->w, h = MAIN_FB()->h; i; i--) { for (int i = MAIN_FB()->w, h = MAIN_FB()->h; i; i--) {
*dst = *src++; *dst = *src++;
@ -1169,7 +1177,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
} }
break; break;
case PIXFORMAT_GRAYSCALE: case PIXFORMAT_GRAYSCALE:
dst += line - MAIN_FB()->y; dst += offset - MAIN_FB()->y;
if (sensor.gs_bpp == 1) { if (sensor.gs_bpp == 1) {
src += MAIN_FB()->x; src += MAIN_FB()->x;
// 1BPP GRAYSCALE. // 1BPP GRAYSCALE.
@ -1188,7 +1196,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
break; break;
case PIXFORMAT_YUV422: case PIXFORMAT_YUV422:
case PIXFORMAT_RGB565: case PIXFORMAT_RGB565:
dst16 += line - MAIN_FB()->y; dst16 += offset - MAIN_FB()->y;
src16 += MAIN_FB()->x; src16 += MAIN_FB()->x;
for (int i = MAIN_FB()->w, h = MAIN_FB()->h; i; i--) { for (int i = MAIN_FB()->w, h = MAIN_FB()->h; i; i--) {
*dst16 = *src16++; *dst16 = *src16++;
@ -1201,7 +1209,7 @@ void DCMI_DMAConvCpltUser(uint32_t addr)
} }
} }
line++; offset++;
} }
// This is the default snapshot function, which can be replaced in sensor_init functions. This function // This is the default snapshot function, which can be replaced in sensor_init functions. This function
@ -1284,20 +1292,20 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, streaming_cb_t streaming_c
} }
break; break;
default: default:
return -1; // Error out if the pixformat is not set. return -2; // Error out if the pixformat is not set.
} }
// Error out if the frame size wasn't set or the line width is larger than the camera line buffers. // Error out if the frame size wasn't set or the line width is larger than the camera line buffers.
if ((!length) || (((length / h) > (OMV_LINE_BUF_SIZE / 2)) && (addr == ((uint32_t) &_line_buf)))) { if ((!length) || (((length / h) > (OMV_LINE_BUF_SIZE / 2)) && (addr == ((uint32_t) &_line_buf)))) {
return -1; return -3;
} }
// If two frames fit in ram, use double buffering in streaming mode. // If two frames fit in ram, use double buffering in streaming mode.
doublebuf = ((length*2) <= OMV_RAW_BUF_SIZE); doublebuf = ((length*2) <= OMV_RAW_BUF_SIZE);
do { do {
// Clear the line counter variable before we allow more data to be received. // Clear the offset counter variable before we allow more data to be received.
line = 0; offset = 0;
// Clear jpeg error flag before we allow more data to be received. // Clear jpeg error flag before we allow more data to be received.
jpeg_buffer_overflow = false; jpeg_buffer_overflow = false;
@ -1392,7 +1400,7 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, streaming_cb_t streaming_c
} }
#endif #endif
return -1; return -4;
} }
} }
@ -1412,7 +1420,7 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, streaming_cb_t streaming_c
// The JPEG in the frame buffer is actually invalid. // The JPEG in the frame buffer is actually invalid.
if (jpeg_buffer_overflow) { if (jpeg_buffer_overflow) {
return -1; return -5;
} }
// After the above loop we have received all data in the frame. The DCMI hardware is left // After the above loop we have received all data in the frame. The DCMI hardware is left
@ -1450,13 +1458,13 @@ int sensor_snapshot(sensor_t *sensor, image_t *image, streaming_cb_t streaming_c
break; break;
case PIXFORMAT_JPEG: case PIXFORMAT_JPEG:
if (sensor->chip_id == OV5640_ID) { if (sensor->chip_id == OV5640_ID) {
// Line contains the sum of all the bytes transferred from the line buffers // Offset contains the sum of all the bytes transferred from the offset buffers
// while in DCMI_DMAConvCpltUser(). // while in DCMI_DMAConvCpltUser().
MAIN_FB()->bpp = line; MAIN_FB()->bpp = offset;
} else { } else {
// line contains the number of MAX_XFER_SIZE transfers completed. To get the number of bytes transferred // Offset contains the number of MAX_XFER_SIZE transfers completed. To get the number of bytes transferred
// within a transfer we have to look at the DMA counter and see how much data was moved. // within a transfer we have to look at the DMA counter and see how much data was moved.
MAIN_FB()->bpp = (line * MAX_XFER_SIZE) + ((MAX_XFER_SIZE/4) - __HAL_DMA_GET_COUNTER(&DMAHandle))*4; MAIN_FB()->bpp = (offset * MAX_XFER_SIZE) + ((MAX_XFER_SIZE/4) - __HAL_DMA_GET_COUNTER(&DMAHandle))*4;
// DMA has most likely corrupted FB alloc state and or more. // DMA has most likely corrupted FB alloc state and or more.
if (MAIN_FB()->bpp > OMV_RAW_BUF_SIZE) { if (MAIN_FB()->bpp > OMV_RAW_BUF_SIZE) {