Skip to content

Merge upstream updates #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,25 @@ jobs:
target: ${{ matrix.idf_target }}
path: 'examples'

build-release-v5_0:
name: Build for ${{ matrix.idf_target }} on ${{ matrix.idf_ver }}
runs-on: ubuntu-latest
strategy:
matrix:
idf_ver: ["release-v5.0"]
idf_target: ["esp32", "esp32s2", "esp32s3"]
steps:
- name: Checkout repo
uses: actions/checkout@v2
with:
submodules: 'recursive'
- name: esp-idf build
uses: espressif/esp-idf-ci-action@main
with:
esp_idf_version: ${{ matrix.idf_ver }}
target: ${{ matrix.idf_target }}
path: 'examples'

build-release-v4_4:
name: Build for ${{ matrix.idf_target }} on ${{ matrix.idf_ver }}
runs-on: ubuntu-latest
Expand Down
22 changes: 20 additions & 2 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,12 @@ menu "Camera configuration"
bool "Subsample Mode"
endchoice

config CAMERA_TASK_STACK_SIZE
int "CAM task stack size"
default 2048
help
Camera task stack size

choice CAMERA_TASK_PINNED_TO_CORE
bool "Camera task pinned to core"
default CAMERA_CORE0
Expand All @@ -163,8 +169,8 @@ menu "Camera configuration"
default 32768
help
Maximum value of DMA buffer
Larger values may fail to allocate due to insufficient contiguous memory blocks, and smaller value may cause DMA interrupt to be too frequent
Larger values may fail to allocate due to insufficient contiguous memory blocks, and smaller value may cause DMA interrupt to be too frequent.

config CAMERA_CONVERTER_ENABLED
bool "Enable camera RGB/YUV converter"
depends on IDF_TARGET_ESP32S3
Expand All @@ -184,4 +190,16 @@ menu "Camera configuration"
config LCD_CAM_CONV_BT709_ENABLED
bool "BT709"
endchoice

config LCD_CAM_CONV_FULL_RANGE_ENABLED
bool "Camera converter full range mode"
depends on CAMERA_CONVERTER_ENABLED
default y
help
Supports format conversion under both full color range mode and limited color range mode.
If full color range mode is selected, the color range of RGB or YUV is 0~255.
If limited color range mode is selected, the color range of RGB is 16~240, and the color range of YUV is Y[16~240], UV[16~235].
Full color range mode has a wider color range, so details in the image show more clearly.
Please confirm the color range mode of the current camera sensor, incorrect color range mode may cause color difference in the final converted image.
Full range mode is used by default. If this option is not selected, the format conversion function will be done using the limited range mode.
endmenu
58 changes: 35 additions & 23 deletions conversions/to_bmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,13 @@ bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixf
*out_len = 0;

int pix_count = width*height;
size_t out_size = (pix_count * 3) + BMP_HEADER_LEN;

// With BMP, 8-bit greyscale requires a palette.
// For a 640x480 image though, that's a savings
// over going RGB-24.
int bpp = (format == PIXFORMAT_GRAYSCALE) ? 1 : 3;
int palette_size = (format == PIXFORMAT_GRAYSCALE) ? 4 * 256 : 0;
size_t out_size = (pix_count * bpp) + BMP_HEADER_LEN + palette_size;
uint8_t * out_buf = (uint8_t *)_malloc(out_size);
if(!out_buf) {
ESP_LOGE(TAG, "_malloc failed! %u", out_size);
Expand All @@ -314,45 +320,51 @@ bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixf
bmp_header_t * bitmap = (bmp_header_t*)&out_buf[2];
bitmap->reserved = 0;
bitmap->filesize = out_size;
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN + palette_size;
bitmap->dibheadersize = 40;
bitmap->width = width;
bitmap->height = -height;//set negative for top to bottom
bitmap->planes = 1;
bitmap->bitsperpixel = 24;
bitmap->bitsperpixel = bpp * 8;
bitmap->compression = 0;
bitmap->imagesize = pix_count * 3;
bitmap->imagesize = pix_count * bpp;
bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
bitmap->numcolorspallette = 0;
bitmap->mostimpcolor = 0;

uint8_t * rgb_buf = out_buf + BMP_HEADER_LEN;
uint8_t * palette_buf = out_buf + BMP_HEADER_LEN;
uint8_t * pix_buf = palette_buf + palette_size;
uint8_t * src_buf = src;

if (palette_size > 0) {
// Grayscale palette
for (int i = 0; i < 256; ++i) {
for (int j = 0; j < 3; ++j) {
*palette_buf = i;
palette_buf++;
}
// Reserved / alpha channel.
*palette_buf = 0;
palette_buf++;
}
}

//convert data to RGB888
if(format == PIXFORMAT_RGB888) {
memcpy(rgb_buf, src_buf, pix_count*3);
memcpy(pix_buf, src_buf, pix_count*3);
} else if(format == PIXFORMAT_RGB565) {
int i;
uint8_t hb, lb;
for(i=0; i<pix_count; i++) {
hb = *src_buf++;
lb = *src_buf++;
*rgb_buf++ = (lb & 0x1F) << 3;
*rgb_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
*rgb_buf++ = hb & 0xF8;
*pix_buf++ = (lb & 0x1F) << 3;
*pix_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
*pix_buf++ = hb & 0xF8;
}
} else if(format == PIXFORMAT_GRAYSCALE) {
int i;
uint8_t b;
for(i=0; i<pix_count; i++) {
b = *src_buf++;
*rgb_buf++ = b;
*rgb_buf++ = b;
*rgb_buf++ = b;
}
memcpy(pix_buf, src_buf, pix_count);
} else if(format == PIXFORMAT_YUV422) {
int i, maxi = pix_count / 2;
uint8_t y0, y1, u, v;
Expand All @@ -364,14 +376,14 @@ bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixf
v = *src_buf++;

yuv2rgb(y0, u, v, &r, &g, &b);
*rgb_buf++ = b;
*rgb_buf++ = g;
*rgb_buf++ = r;
*pix_buf++ = b;
*pix_buf++ = g;
*pix_buf++ = r;

yuv2rgb(y1, u, v, &r, &g, &b);
*rgb_buf++ = b;
*rgb_buf++ = g;
*rgb_buf++ = r;
*pix_buf++ = b;
*pix_buf++ = g;
*pix_buf++ = r;
}
}
*out = out_buf;
Expand Down
49 changes: 31 additions & 18 deletions driver/cam_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,12 @@
#endif // ESP_IDF_VERSION_MAJOR
#define ESP_CAMERA_ETS_PRINTF ets_printf

#if CONFIG_CAM_TASK_STACK_SIZE
#define CAM_TASK_STACK CONFIG_CAM_TASK_STACK_SIZE
#else
#define CAM_TASK_STACK (2*1024)
#endif

static const char *TAG = "cam_hal";
static cam_obj_t *cam_obj = NULL;

Expand All @@ -45,7 +51,7 @@ static int cam_verify_jpeg_soi(const uint8_t *inbuf, uint32_t length)
for (uint32_t i = 0; i < length; i++) {
sig = *((uint32_t *)(&inbuf[i])) & 0xFFFFFF;
if (sig == JPEG_SOI_MARKER) {
ESP_LOGW(TAG, "SOI: %d", i);
ESP_LOGW(TAG, "SOI: %d", (int) i);
return i;
}
}
Expand Down Expand Up @@ -117,7 +123,7 @@ static void cam_task(void *arg)
int frame_pos = 0;
cam_obj->state = CAM_STATE_IDLE;
cam_event_t cam_event = 0;

xQueueReset(cam_obj->event_queue);

while (1) {
Expand All @@ -140,7 +146,7 @@ static void cam_task(void *arg)
case CAM_STATE_READ_BUF: {
camera_fb_t * frame_buffer_event = &cam_obj->frames[frame_pos].fb;
size_t pixels_per_dma = (cam_obj->dma_half_buffer_size * cam_obj->fb_bytes_per_pixel) / (cam_obj->dma_bytes_per_item * cam_obj->in_bytes_per_pixel);

if (cam_event == CAM_IN_SUC_EOF_EVENT) {
if(!cam_obj->psram_mode){
if (cam_obj->fb_size < (frame_buffer_event->len + pixels_per_dma)) {
Expand All @@ -150,8 +156,8 @@ static void cam_task(void *arg)
continue;
}
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
&frame_buffer_event->buf[frame_buffer_event->len],
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
&frame_buffer_event->buf[frame_buffer_event->len],
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
cam_obj->dma_half_buffer_size);
}
//Check for JPEG SOI in the first buffer. stop if not found
Expand All @@ -173,8 +179,8 @@ static void cam_task(void *arg)
cnt--;
} else {
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
&frame_buffer_event->buf[frame_buffer_event->len],
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
&frame_buffer_event->buf[frame_buffer_event->len],
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
cam_obj->dma_half_buffer_size);
}
}
Expand All @@ -192,7 +198,7 @@ static void cam_task(void *arg)
} else if (!cam_obj->jpeg_mode) {
if (frame_buffer_event->len != cam_obj->fb_size) {
cam_obj->frames[frame_pos].en = 1;
ESP_LOGE(TAG, "FB-SIZE: %u != %u", frame_buffer_event->len, cam_obj->fb_size);
ESP_LOGE(TAG, "FB-SIZE: %u != %u", frame_buffer_event->len, (unsigned) cam_obj->fb_size);
}
}
//send frame
Expand Down Expand Up @@ -258,8 +264,9 @@ static esp_err_t cam_dma_config(const camera_config_t *config)
cam_obj->dma_node_cnt = (cam_obj->dma_buffer_size) / cam_obj->dma_node_buffer_size; // Number of DMA nodes
cam_obj->frame_copy_cnt = cam_obj->recv_size / cam_obj->dma_half_buffer_size; // Number of interrupted copies, ping-pong copy

ESP_LOGI(TAG, "buffer_size: %d, half_buffer_size: %d, node_buffer_size: %d, node_cnt: %d, total_cnt: %d",
cam_obj->dma_buffer_size, cam_obj->dma_half_buffer_size, cam_obj->dma_node_buffer_size, cam_obj->dma_node_cnt, cam_obj->frame_copy_cnt);
ESP_LOGI(TAG, "buffer_size: %d, half_buffer_size: %d, node_buffer_size: %d, node_cnt: %d, total_cnt: %d",
(int) cam_obj->dma_buffer_size, (int) cam_obj->dma_half_buffer_size, (int) cam_obj->dma_node_buffer_size,
(int) cam_obj->dma_node_cnt, (int) cam_obj->frame_copy_cnt);

cam_obj->dma_buffer = NULL;
cam_obj->dma = NULL;
Expand Down Expand Up @@ -289,13 +296,19 @@ static esp_err_t cam_dma_config(const camera_config_t *config)
cam_obj->frames[x].fb_offset = 0;
cam_obj->frames[x].en = 0;
ESP_LOGI(TAG, "Allocating %d Byte frame buffer in %s", alloc_size, _caps & MALLOC_CAP_SPIRAM ? "PSRAM" : "OnBoard RAM");
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
// In IDF v4.2 and earlier, memory returned by heap_caps_aligned_alloc must be freed using heap_caps_aligned_free.
// And heap_caps_aligned_free is deprecated on v4.3.
cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_aligned_alloc(16, alloc_size, _caps);
#else
cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_malloc(alloc_size, _caps);
#endif
CAM_CHECK(cam_obj->frames[x].fb.buf != NULL, "frame buffer malloc failed", ESP_FAIL);
if (cam_obj->psram_mode) {
//align PSRAM buffer. TODO: save the offset so proper address can be freed later
cam_obj->frames[x].fb_offset = dma_align - ((uint32_t)cam_obj->frames[x].fb.buf & (dma_align - 1));
cam_obj->frames[x].fb.buf += cam_obj->frames[x].fb_offset;
ESP_LOGI(TAG, "Frame[%d]: Offset: %u, Addr: 0x%08X", x, cam_obj->frames[x].fb_offset, (uint32_t)cam_obj->frames[x].fb.buf);
ESP_LOGI(TAG, "Frame[%d]: Offset: %u, Addr: 0x%08X", x, cam_obj->frames[x].fb_offset, (unsigned) cam_obj->frames[x].fb.buf);
cam_obj->frames[x].dma = allocate_dma_descriptors(cam_obj->dma_node_cnt, cam_obj->dma_node_buffer_size, cam_obj->frames[x].fb.buf);
CAM_CHECK(cam_obj->frames[x].dma != NULL, "frame dma malloc failed", ESP_FAIL);
}
Expand All @@ -305,8 +318,8 @@ static esp_err_t cam_dma_config(const camera_config_t *config)
if (!cam_obj->psram_mode) {
cam_obj->dma_buffer = (uint8_t *)heap_caps_malloc(cam_obj->dma_buffer_size * sizeof(uint8_t), MALLOC_CAP_DMA);
if(NULL == cam_obj->dma_buffer) {
ESP_LOGE(TAG,"%s(%d): DMA buffer %d Byte malloc failed, the current largest free block:%d Byte", __FUNCTION__, __LINE__,
cam_obj->dma_buffer_size, heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
ESP_LOGE(TAG,"%s(%d): DMA buffer %d Byte malloc failed, the current largest free block:%d Byte", __FUNCTION__, __LINE__,
(int) cam_obj->dma_buffer_size, (int) heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
return ESP_FAIL;
}

Expand Down Expand Up @@ -372,7 +385,7 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint
cam_obj->recv_size = cam_obj->width * cam_obj->height * cam_obj->in_bytes_per_pixel;
cam_obj->fb_size = cam_obj->width * cam_obj->height * cam_obj->fb_bytes_per_pixel;
}

ret = cam_dma_config(config);
CAM_CHECK_GOTO(ret == ESP_OK, "cam_dma_config failed", err);

Expand All @@ -389,16 +402,16 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint
ret = ll_cam_init_isr(cam_obj);
CAM_CHECK_GOTO(ret == ESP_OK, "cam intr alloc failed", err);


#if CONFIG_CAMERA_CORE0
xTaskCreatePinnedToCore(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 0);
xTaskCreatePinnedToCore(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 0);
#elif CONFIG_CAMERA_CORE1
#if CONFIG_FREERTOS_UNICORE
#error "Cannot pin to core 1 on unicore"
#endif
xTaskCreatePinnedToCore(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 1);
xTaskCreatePinnedToCore(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 1);
#else
xTaskCreate(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle);
xTaskCreate(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle);
#endif

ESP_LOGI(TAG, "cam config ok");
Expand Down
25 changes: 16 additions & 9 deletions driver/esp_camera.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ static const sensor_func_t g_sensors[] = {

static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out_camera_model)
{
esp_err_t ret = ESP_OK;
*out_camera_model = CAMERA_NONE;
if (s_state != NULL) {
return ESP_ERR_INVALID_STATE;
Expand All @@ -158,10 +159,15 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out

if (config->pin_sccb_sda != -1) {
ESP_LOGD(TAG, "Initializing SCCB");
SCCB_Init(config->pin_sccb_sda, config->pin_sccb_scl);
ret = SCCB_Init(config->pin_sccb_sda, config->pin_sccb_scl);
} else {
ESP_LOGD(TAG, "Using existing I2C port");
SCCB_Use_Port(config->sccb_i2c_port);
ret = SCCB_Use_Port(config->sccb_i2c_port);
}

if(ret != ESP_OK) {
ESP_LOGE(TAG, "sccb init err");
goto err;
}

if (config->pin_pwdn >= 0) {
Expand Down Expand Up @@ -191,15 +197,14 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
vTaskDelay(10 / portTICK_PERIOD_MS);
}


ESP_LOGD(TAG, "Searching for camera address");
vTaskDelay(10 / portTICK_PERIOD_MS);

uint8_t slv_addr = SCCB_Probe();

if (slv_addr == 0) {
CAMERA_DISABLE_OUT_CLOCK();
return ESP_ERR_NOT_FOUND;
ret = ESP_ERR_NOT_FOUND;
goto err;
}

ESP_LOGI(TAG, "Detected camera at address=0x%02x", slv_addr);
Expand All @@ -224,19 +229,21 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
}

if (CAMERA_NONE == *out_camera_model) { //If no supported sensors are detected
CAMERA_DISABLE_OUT_CLOCK();
ESP_LOGE(TAG, "Detected camera not supported.");
return ESP_ERR_NOT_SUPPORTED;
ret = ESP_ERR_NOT_SUPPORTED;
goto err;
}

ESP_LOGI(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x",
id->PID, id->VER, id->MIDH, id->MIDL);

ESP_LOGD(TAG, "Doing SW reset of sensor");
vTaskDelay(10 / portTICK_PERIOD_MS);
s_state->sensor.reset(&s_state->sensor);

return ESP_OK;
return s_state->sensor.reset(&s_state->sensor);
err :
CAMERA_DISABLE_OUT_CLOCK();
return ret;
}

#if CONFIG_CAMERA_CONVERTER_ENABLED
Expand Down
Loading