New ESP32-CAM module

Deouss
Posts: 315
Joined: Tue Mar 20, 2018 11:36 am

New ESP32-CAM module

Postby Deouss » Tue Oct 09, 2018 2:59 pm

I just ordered ESP32 Camera Development Board with Camera Module OV2640 2MP
I plan to experiment with camera transmission/reception.
Maybe someone has already tried that model and can share the insides )

Hopefully it is going to work fine ;)

Image

chegewara
Posts: 652
Joined: Wed Jun 14, 2017 9:00 pm

Re: New ESP32-CAM module

Postby chegewara » Tue Oct 09, 2018 10:51 pm


Deouss
Posts: 315
Joined: Tue Mar 20, 2018 11:36 am

Re: New ESP32-CAM module

Postby Deouss » Wed Oct 10, 2018 11:41 am

Thanks for the example code for the exact model!
Will try as soon as I receive my module )

chegewara
Posts: 652
Joined: Wed Jun 14, 2017 9:00 pm

Re: New ESP32-CAM module

Postby chegewara » Fri Nov 02, 2018 7:51 pm

I have to say it was really fun to playing with this board. My final result is esp32 http server with options to change resolution and jpeg quality(compression level) from website on the fly and capture image on demand.

denyeau
Posts: 1
Joined: Tue Nov 20, 2018 9:17 am

Re: New ESP32-CAM module

Postby denyeau » Tue Nov 20, 2018 9:31 am

Hi, I also bought a copy. However, I'm new to ESP32. I have to connect this to the USB port of my computer somehow, right? How do I do that?

I have one of these that I had bought for ESP8266, would that be useful at all? https://www.aliexpress.com/item/USB-swi ... 75353.html

stonemull
Posts: 1
Joined: Wed Dec 05, 2018 12:21 pm

Re: New ESP32-CAM module

Postby stonemull » Wed Dec 05, 2018 12:29 pm

yeh you can use one of those to program it though you will need to mod one thing, you need 5v.
So need to connect up the 5v and gnd pin on the opposites corner of the camera module to 5v which is not available on the header of that device but you can find it on the regulator easily enough, then you need rx to the module U0T and tx to camera U0R, you can then open a terminal program and verify the camera is talking, close that, connect camera IO0 (between IO18 and ground, it looks like IO6 on my silkscreen) and hit reset and camera will be ready for an upload.

click on first link "spec" on this page for a bit of camera info https://m.seeedstudio.com/productDetail/3153

TheNitek
Posts: 2
Joined: Thu Jan 25, 2018 6:03 pm

Re: New ESP32-CAM module

Postby TheNitek » Fri Dec 07, 2018 9:41 am

chegewara wrote:
Fri Nov 02, 2018 7:51 pm
I have to say it was really fun to playing with this board. My final result is esp32 http server with options to change resolution and jpeg quality(compression level) from website on the fly and capture image on demand.
Is this code available somewhere?

chegewara
Posts: 652
Joined: Wed Jun 14, 2017 9:00 pm

Re: New ESP32-CAM module

Postby chegewara » Fri Dec 07, 2018 11:02 am

Sorry, its not yet. It was part of paid project, but i hope it can be open sourced soon.

Deouss
Posts: 315
Joined: Tue Mar 20, 2018 11:36 am

Re: New ESP32-CAM module

Postby Deouss » Wed Jan 02, 2019 7:07 pm

OK. So I played a little with the camera module and was able to control capture data however I do not want to use http server as the video gui.
I am able to get full frame in bytes in JPEG format but it is apparently missing some jpeg header data or maybe something else.
Camera uses JPEG as default and when I switched to CAMERA_PF_RGB565 I get error:
E (6861) camera: Failed to allocate frame buffer
E (6861) camera_demo: Camera init failed with error 0x101

I will try to use other camera OV7725 and see if maybe can get BMP format.

Maybe someone knows how to add JPEG header to raw jpeg impage data bytes in c++?
I know the dimensions of the picture and size in bytes

chegewara
Posts: 652
Joined: Wed Jun 14, 2017 9:00 pm

Re: New ESP32-CAM module

Postby chegewara » Thu Jan 03, 2019 5:57 am

To change image format on the fly you have to perform full re-init camera. Its not clean code, but this is how i did it:

Code: Select all

// from httpd handler
	set_frame_size(camera_config->frame_size);
	set_pixel_format(camera_config->pixel_format, camera_config->jpeg_quality);
	reinit_dma();

Code: Select all

// camera.c modifications
esp_err_t allocate_fb() {
	s_state->fb = (uint8_t*) calloc(s_state->fb_size, 1);
	if (s_state->fb == NULL) {
		ESP_LOGE(TAG, "Failed to allocate frame buffer");
		esp_err_t err = ESP_ERR_NO_MEM;
		return err;
	}

	ESP_LOGI(TAG,
			"in_bpp: %d, fb_bpp: %d, fb_size: %d, mode: %d, width: %d height: %d, quality: %u",
			s_state->in_bytes_per_pixel, s_state->fb_bytes_per_pixel,
			s_state->fb_size, s_state->sampling_mode, s_state->width,
			s_state->height, s_state->config.jpeg_quality);

	ESP_LOGW(TAG, "Allocating frame buffer (%d bytes)", s_state->fb_size);
	heap_caps_print_heap_info(MALLOC_CAP_SPIRAM);
	return ESP_OK;
}

esp_err_t set_jpeg_quality(int qp) {
	if(qp == 0)
		qp = s_state->config.jpeg_quality;
	else
		s_state->config.jpeg_quality = qp;
	ESP_LOGI(TAG, "jpeg quality --> %u", qp);
	int compression_ratio_bound;
	if (qp <= 10) {
		compression_ratio_bound = 5;
	} else if (qp <= 30) {
		compression_ratio_bound = 10;
	} else {
		compression_ratio_bound = 20;
	}
	(*s_state->sensor.set_quality)(&s_state->sensor, qp);
	size_t equiv_line_count = s_state->height / compression_ratio_bound;
	s_state->fb_size = s_state->width * equiv_line_count * 2 /* bpp */;

	return ESP_OK;
}

esp_err_t set_frame_size(camera_framesize_t cam_frame_size) {
	framesize_t frame_size = (framesize_t) cam_frame_size;
	s_state->width = resolution[frame_size][0];
	s_state->height = resolution[frame_size][1];

	if (s_state->sensor.set_framesize(&s_state->sensor, frame_size) != 0) {
		ESP_LOGE(TAG, "Failed to set frame size --> %u", frame_size);
		esp_err_t err = ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE;
		return err;
	}
	ESP_LOGI(TAG, "set frame size --> %u", frame_size);
	return ESP_OK;
}

esp_err_t set_pixel_format(camera_pixelformat_t format, int qp) {

	if(s_state->fb != NULL) {
		free(s_state->fb);
		s_state->fb = NULL;
		heap_caps_print_heap_info(MALLOC_CAP_SPIRAM);
	}
	esp_err_t err;
	pixformat_t pix_format = (pixformat_t)format;
	s_state->sensor.set_pixformat(&s_state->sensor, pix_format);
	if (pix_format == PIXFORMAT_GRAYSCALE) {
		s_state->fb_size = s_state->width * s_state->height * 3;
		if (is_hs_mode()) {
			s_state->sampling_mode = SM_0A0B_0B0C;
			s_state->dma_filter = &dma_filter_grayscale_highspeed;
		} else {
			s_state->sampling_mode = SM_0A0B_0C0D;
			s_state->dma_filter = &dma_filter_grayscale;
		}
		s_state->in_bytes_per_pixel = 2;       // camera sends YUYV
		s_state->fb_bytes_per_pixel = 1;       // frame buffer stores Y8
	} else if (pix_format == PIXFORMAT_RGB565) {
		s_state->fb_size = s_state->width * s_state->height * 3;
		if (is_hs_mode()) {
			s_state->sampling_mode = SM_0A0B_0B0C;
		} else {
			s_state->sampling_mode = SM_0A00_0B00;
		}
		s_state->in_bytes_per_pixel = 2;       // camera sends RGB565 (2 bytes)
		s_state->fb_bytes_per_pixel = 3;       // frame buffer stores RGB888
		s_state->dma_filter = &dma_filter_rgb565;
		ESP_LOGW(TAG, " set RGB565 size --> %u", s_state->fb_size);

	} else if (pix_format == PIXFORMAT_JPEG) {
		if (s_state->sensor.id.PID != OV2640_PID) {
			ESP_LOGE(TAG, "JPEG format is only supported for ov2640");
			err = ESP_ERR_NOT_SUPPORTED;
			goto fail;
		}
		set_jpeg_quality(qp);

		s_state->dma_filter = &dma_filter_jpeg;
		if (is_hs_mode()) {
			s_state->sampling_mode = SM_0A0B_0B0C;
		} else {
			s_state->sampling_mode = SM_0A00_0B00;
		}
		s_state->in_bytes_per_pixel = 2;
		s_state->fb_bytes_per_pixel = 2;
		ESP_LOGW(TAG, "set JPEG frame size --> %u", s_state->fb_size);
	} else {
		ESP_LOGE(TAG, "Requested format is not supported");
		err = ESP_ERR_NOT_SUPPORTED;
		goto fail;
	}
	
	allocate_fb();
	if(s_state->dma_filter_task != NULL){ 
		vTaskDelete(s_state->dma_filter_task);
		vTaskDelay(10/portTICK_PERIOD_MS);
		if (!xTaskCreatePinnedToCore(&dma_filter_task, "dma_filter", 4096, NULL, 10,
				&s_state->dma_filter_task, 1)) {
			ESP_LOGE(TAG, "Failed to create DMA filter task");
			err = ESP_ERR_NO_MEM;
			goto fail;
		}
	}

	return ESP_OK;
fail:
	return err;
}

void reinit_dma() {
	dma_desc_deinit();
	dma_desc_init();
}
esp_err_t camera_init(camera_config_t* config) {
	if (!s_state) {
		return ESP_ERR_INVALID_STATE;
	}
	if (s_state->sensor.id.PID == 0) {
		return ESP_ERR_CAMERA_NOT_SUPPORTED;
	}
	// memcpy(&s_state->config, config, sizeof(*config));
	s_state->config = *config;
	esp_err_t err = ESP_OK;
	framesize_t frame_size = (framesize_t) config->frame_size;
	pixformat_t pix_format = (pixformat_t) config->pixel_format;

	ESP_LOGD(TAG, "Setting frame size to %dx%d", s_state->width, s_state->height);
	if (set_frame_size(config->frame_size) != 0) {
		ESP_LOGE(TAG, "Failed to set frame size");
		err = ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE;
		goto fail;
	}
	// s_state->sensor.set_pixformat(&s_state->sensor, pix_format);

#if ENABLE_TEST_PATTERN
	/* Test pattern may get handy
	 if you are unable to get the live image right.
	 Once test pattern is enable, sensor will output
	 vertical shaded bars instead of live image.
	 */
	s_state->sensor.set_colorbar(&s_state->sensor, 1);
	ESP_LOGD(TAG, "Test pattern enabled");
#endif

	err = set_pixel_format(config->pixel_format, 0);
	
	if(err) {
		ESP_LOGE(TAG, "Requested format is not supported");
		err = ESP_ERR_NOT_SUPPORTED;
		goto fail;
	}

	ESP_LOGD(TAG,
			"in_bpp: %d, fb_bpp: %d, fb_size: %d, mode: %d, width: %d height: %d",
			s_state->in_bytes_per_pixel, s_state->fb_bytes_per_pixel,
			s_state->fb_size, s_state->sampling_mode, s_state->width,
			s_state->height);

	ESP_LOGW(TAG, "Initializing I2S and DMA");
	i2s_init();
	err = dma_desc_init();
	if (err != ESP_OK) {
		ESP_LOGE(TAG, "Failed to initialize I2S and DMA");
		goto fail;
	}

	s_state->data_ready = xQueueCreate(16, sizeof(size_t));
	s_state->frame_ready = xSemaphoreCreateBinary();
	if (s_state->data_ready == NULL || s_state->frame_ready == NULL) {
		ESP_LOGE(TAG, "Failed to create semaphores");
		err = ESP_ERR_NO_MEM;
		goto fail;
	}
	if (!xTaskCreatePinnedToCore(&dma_filter_task, "dma_filter", 4096, NULL, 10,
			&s_state->dma_filter_task, 1)) {
		ESP_LOGE(TAG, "Failed to create DMA filter task");
		err = ESP_ERR_NO_MEM;
		goto fail;
	}

	ESP_LOGD(TAG, "Initializing GPIO interrupts");
	gpio_set_intr_type(s_state->config.pin_vsync, GPIO_INTR_NEGEDGE); // GPIO ISR
	gpio_intr_enable(s_state->config.pin_vsync);
	err = gpio_isr_register(&gpio_isr, (void*) TAG,
	ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_IRAM,
			&s_state->vsync_intr_handle);
	if (err != ESP_OK) {
		ESP_LOGE(TAG, "gpio_isr_register failed (%x)", err);
		goto fail;
	}

	// skip at least one frame after changing camera settings
	while (gpio_get_level(s_state->config.pin_vsync) == 0) {
		;
	}
	while (gpio_get_level(s_state->config.pin_vsync) != 0) {
		;
	}
	while (gpio_get_level(s_state->config.pin_vsync) == 0) {
		;
	}
	s_state->frame_count = 0;
	ESP_LOGD(TAG, "Init done");
	return ESP_OK;

	fail: camera_deinit();
	return err;
}

Who is online

Users browsing this forum: No registered users and 6 guests