Refactor: Use esp_video component (#1245)
* refactor: migrate camera module to esp-video library * refactor: migrate boards to esp-video API (1/2) * refactor: migrate boards to esp-video API (2/2) * fix: use ESP-IDF 5.5 * refactor: migrate the JPEG encoder to `esp_new_jpeg` * feat: add YUV422 support * feat: improve pixelformat and device selection process * feat: use ESP32-P4 Hardware JPEG Encoder
This commit is contained in:
@ -133,58 +133,53 @@ private:
|
||||
// 初始化摄像头:ov2640;
|
||||
// 根据正点原子官方示例参数
|
||||
void InitializeCamera() {
|
||||
|
||||
xl9555_->SetOutputState(OV_PWDN_IO, 0); // PWDN=低 (上电)
|
||||
xl9555_->SetOutputState(OV_RESET_IO, 0); // 确保复位
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); // 延长复位保持时间
|
||||
xl9555_->SetOutputState(OV_RESET_IO, 1); // 释放复位
|
||||
vTaskDelay(pdMS_TO_TICKS(50)); // 延长 50ms
|
||||
|
||||
camera_config_t config = {};
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAM_PIN_D0,
|
||||
[1] = CAM_PIN_D1,
|
||||
[2] = CAM_PIN_D2,
|
||||
[3] = CAM_PIN_D3,
|
||||
[4] = CAM_PIN_D4,
|
||||
[5] = CAM_PIN_D5,
|
||||
[6] = CAM_PIN_D6,
|
||||
[7] = CAM_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAM_PIN_VSYNC,
|
||||
.de_io = CAM_PIN_HREF,
|
||||
.pclk_io = CAM_PIN_PCLK,
|
||||
.xclk_io = CAM_PIN_XCLK,
|
||||
};
|
||||
|
||||
config.pin_pwdn = CAM_PIN_PWDN; // 实际由 XL9555 控制
|
||||
config.pin_reset = CAM_PIN_RESET;// 实际由 XL9555 控制
|
||||
config.pin_xclk = CAM_PIN_XCLK;
|
||||
config.pin_sccb_sda = CAM_PIN_SIOD;
|
||||
config.pin_sccb_scl = CAM_PIN_SIOC;
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = 1,
|
||||
.scl_pin = CAM_PIN_SIOC,
|
||||
.sda_pin = CAM_PIN_SIOD,
|
||||
},
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
config.pin_d7 = CAM_PIN_D7;
|
||||
config.pin_d6 = CAM_PIN_D6;
|
||||
config.pin_d5 = CAM_PIN_D5;
|
||||
config.pin_d4 = CAM_PIN_D4;
|
||||
config.pin_d3 = CAM_PIN_D3;
|
||||
config.pin_d2 = CAM_PIN_D2;
|
||||
config.pin_d1 = CAM_PIN_D1;
|
||||
config.pin_d0 = CAM_PIN_D0;
|
||||
config.pin_vsync = CAM_PIN_VSYNC;
|
||||
config.pin_href = CAM_PIN_HREF;
|
||||
config.pin_pclk = CAM_PIN_PCLK;
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAM_PIN_RESET, // 实际由 XL9555 控制
|
||||
.pwdn_pin = CAM_PIN_PWDN, // 实际由 XL9555 控制
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = 24000000,
|
||||
};
|
||||
|
||||
/* XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) */
|
||||
config.xclk_freq_hz = 24000000;
|
||||
config.ledc_timer = LEDC_TIMER_0;
|
||||
config.ledc_channel = LEDC_CHANNEL_0;
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
config.pixel_format = PIXFORMAT_RGB565; /* YUV422,GRAYSCALE,RGB565,JPEG */
|
||||
config.frame_size = FRAMESIZE_QVGA; /* QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates */
|
||||
|
||||
config.jpeg_quality = 12; /* 0-63, for OV series camera sensors, lower number means higher quality */
|
||||
config.fb_count = 2; /* When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode */
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
|
||||
esp_err_t err = esp_camera_init(&config); // 测试相机是否存在
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Camera is not plugged in or not supported, error: %s", esp_err_to_name(err));
|
||||
// 如果摄像头初始化失败,设置 camera_ 为 nullptr
|
||||
camera_ = nullptr;
|
||||
return;
|
||||
}else
|
||||
{
|
||||
esp_camera_deinit();// 释放之前的摄像头资源,为正确初始化做准备
|
||||
camera_ = new Esp32Camera(config);
|
||||
}
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -14,6 +14,12 @@ AtomS3R CAM、AtomS3R M12 是 M5Stack 推出的基于 ESP32-S3-PICO-1-N8R8 的
|
||||
|
||||
两款开发版均**不带屏幕、不带额外按键**,需要使用语音唤醒。必要时,需要使用 `idf.py monitor` 查看 log 以确定运行状态。
|
||||
|
||||
> ![NOTE]
|
||||
>
|
||||
> 自版本 [待定] 起,由于依赖库不支持 OV3660 传感器,AtomS3R M12 无法使用摄像头识别功能。
|
||||
>
|
||||
> AtomS3R CAM 不受影响;使用旧版本小智固件的 AtomS3R M12 不受影响。
|
||||
|
||||
## 配置、编译命令
|
||||
|
||||
**配置编译目标为 ESP32S3**
|
||||
|
||||
@ -123,36 +123,51 @@ private:
|
||||
|
||||
ESP_LOGI(TAG, "Camera Power Enabled");
|
||||
|
||||
vTaskDelay(pdMS_TO_TICKS(300));
|
||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t config = {};
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = CAMERA_PIN_SIOD;
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 1;
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_QVGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
camera_ = new Esp32Camera(config);
|
||||
void InitializeCamera() {
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = 1,
|
||||
.scl_pin = CAMERA_PIN_SIOC,
|
||||
.sda_pin = CAMERA_PIN_SIOD,
|
||||
},
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
camera_->SetHMirror(false);
|
||||
}
|
||||
|
||||
|
||||
@ -5,7 +5,10 @@
|
||||
"name": "atoms3r-cam-m12-echo-base",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_ESPTOOLPY_FLASHSIZE_8MB=y",
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\""
|
||||
"CONFIG_PARTITION_TABLE_CUSTOM_FILENAME=\"partitions/v2/8m.csv\"",
|
||||
"CONFIG_CAMERA_GC0308=y",
|
||||
"CONFIG_CAMERA_GC0308_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_GC0308_DVP_YUV422_320X240_20FPS=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -126,32 +126,47 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t config = {};
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = CAMERA_PIN_SIOD;
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 0;
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_QVGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
camera_ = new Esp32Camera(config);
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = 0,
|
||||
.scl_pin = CAMERA_PIN_SIOC,
|
||||
.sda_pin = CAMERA_PIN_SIOD,
|
||||
},
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
camera_->SetHMirror(false);
|
||||
}
|
||||
|
||||
|
||||
@ -1,37 +1,307 @@
|
||||
#include "esp32_camera.h"
|
||||
#include "mcp_server.h"
|
||||
#include "display.h"
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include "board.h"
|
||||
#include "system_info.h"
|
||||
#include "lvgl_display.h"
|
||||
#include "display.h"
|
||||
#include "esp_video_device.h"
|
||||
#include "esp_video_init.h"
|
||||
#include "jpg/image_to_jpeg.h"
|
||||
#include "linux/videodev2.h"
|
||||
#include "lvgl_display.h"
|
||||
#include "mcp_server.h"
|
||||
#include "system_info.h"
|
||||
|
||||
#include <esp_log.h>
|
||||
#ifdef CONFIG_XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
#undef LOG_LOCAL_LEVEL
|
||||
#define LOG_LOCAL_LEVEL MAX(CONFIG_LOG_DEFAULT_LEVEL, ESP_LOG_DEBUG)
|
||||
#endif // CONFIG_XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
|
||||
#include <errno.h>
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_log.h>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#define TAG "Esp32Camera"
|
||||
|
||||
Esp32Camera::Esp32Camera(const camera_config_t& config) {
|
||||
// camera init
|
||||
esp_err_t err = esp_camera_init(&config); // 配置上面定义的参数
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Camera init failed with error 0x%x", err);
|
||||
#if defined(CONFIG_CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER) || defined(CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP)
|
||||
#warning "CAMERA_SENSOR_SWAP_PIXEL_BYTE_ORDER or CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP is enabled, which may cause image corruption in YUV422 format!"
|
||||
#endif
|
||||
|
||||
#if CONFIG_XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
#define CAM_PRINT_FOURCC(pixelformat) \
|
||||
char fourcc[5]; \
|
||||
fourcc[0] = pixelformat & 0xFF; \
|
||||
fourcc[1] = (pixelformat >> 8) & 0xFF; \
|
||||
fourcc[2] = (pixelformat >> 16) & 0xFF; \
|
||||
fourcc[3] = (pixelformat >> 24) & 0xFF; \
|
||||
fourcc[4] = '\0'; \
|
||||
ESP_LOGD(TAG, "FOURCC: '%c%c%c%c'", fourcc[0], fourcc[1], fourcc[2], fourcc[3]);
|
||||
|
||||
static void log_available_video_devices() {
|
||||
for (int i = 0; i < 50; i++) {
|
||||
char path[16];
|
||||
snprintf(path, sizeof(path), "/dev/video%d", i);
|
||||
int fd = open(path, O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
ESP_LOGD(TAG, "found video device: %s", path);
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define CAM_PRINT_FOURCC(pixelformat) (void)0;
|
||||
#endif // CONFIG_XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
|
||||
Esp32Camera::Esp32Camera(const esp_video_init_config_t& config) {
|
||||
if (esp_video_init(&config) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "esp_video_init failed");
|
||||
return;
|
||||
}
|
||||
|
||||
sensor_t *s = esp_camera_sensor_get(); // 获取摄像头型号
|
||||
if (s->id.PID == GC0308_PID) {
|
||||
s->set_hmirror(s, 0); // 这里控制摄像头镜像 写1镜像 写0不镜像
|
||||
#ifdef CONFIG_XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
esp_log_level_set(TAG, ESP_LOG_DEBUG);
|
||||
#endif // CONFIG_XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
|
||||
const char* video_device_name = nullptr;
|
||||
|
||||
if (false) { /* 用于构建 else if */
|
||||
}
|
||||
#if CONFIG_ESP_VIDEO_ENABLE_MIPI_CSI_VIDEO_DEVICE
|
||||
else if (config.csi != nullptr) {
|
||||
video_device_name = ESP_VIDEO_MIPI_CSI_DEVICE_NAME;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE
|
||||
else if (config.dvp != nullptr) {
|
||||
video_device_name = ESP_VIDEO_DVP_DEVICE_NAME;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ESP_VIDEO_ENABLE_HW_JPEG_VIDEO_DEVICE
|
||||
else if (config.jpeg != nullptr) {
|
||||
video_device_name = ESP_VIDEO_JPEG_DEVICE_NAME;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ESP_VIDEO_ENABLE_SPI_VIDEO_DEVICE
|
||||
else if (config.spi != nullptr) {
|
||||
video_device_name = ESP_VIDEO_SPI_DEVICE_NAME;
|
||||
}
|
||||
#endif
|
||||
#if CONFIG_ESP_VIDEO_ENABLE_USB_UVC_VIDEO_DEVICE
|
||||
else if (config.usb_uvc != nullptr) {
|
||||
video_device_name = ESP_VIDEO_USB_UVC_DEVICE_NAME(config.usb_uvc->uvc.uvc_dev_num);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (video_device_name == nullptr) {
|
||||
ESP_LOGE(TAG, "no video device is enabled");
|
||||
return;
|
||||
}
|
||||
|
||||
video_fd_ = open(video_device_name, O_RDWR);
|
||||
|
||||
if (video_fd_ < 0) {
|
||||
ESP_LOGE(TAG, "open %s failed, errno=%d(%s)", video_device_name, errno, strerror(errno));
|
||||
#if CONFIG_XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
log_available_video_devices();
|
||||
#endif // CONFIG_XIAOZHI_ENABLE_CAMERA_DEBUG_MODE
|
||||
return;
|
||||
}
|
||||
|
||||
struct v4l2_capability cap = {};
|
||||
if (ioctl(video_fd_, VIDIOC_QUERYCAP, &cap) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_QUERYCAP failed, errno=%d(%s)", errno, strerror(errno));
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(
|
||||
TAG,
|
||||
"VIDIOC_QUERYCAP: driver=%s, card=%s, bus_info=%s, version=0x%08x, capabilities=0x%08x, device_caps=0x%08x",
|
||||
cap.driver, cap.card, cap.bus_info, cap.version, cap.capabilities, cap.device_caps);
|
||||
|
||||
struct v4l2_format format = {};
|
||||
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl(video_fd_, VIDIOC_G_FMT, &format) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_G_FMT failed, errno=%d(%s)", errno, strerror(errno));
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "VIDIOC_G_FMT: pixelformat=0x%08x, width=%d, height=%d", format.fmt.pix.pixelformat,
|
||||
format.fmt.pix.width, format.fmt.pix.height);
|
||||
CAM_PRINT_FOURCC(format.fmt.pix.pixelformat);
|
||||
|
||||
struct v4l2_format setformat = {};
|
||||
setformat.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
setformat.fmt.pix.width = format.fmt.pix.width;
|
||||
setformat.fmt.pix.height = format.fmt.pix.height;
|
||||
|
||||
struct v4l2_fmtdesc fmtdesc = {};
|
||||
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
fmtdesc.index = 0;
|
||||
uint32_t best_fmt = 0;
|
||||
int best_rank = 1 << 30; // large number
|
||||
// 优先级: YUV422P > RGB565 > RGB24 > GREY
|
||||
// 注: 当前版本中 YUV422P 实际输出为 YUYV。YUYV 色彩格式在后续的处理中更节省内存空间。
|
||||
auto get_rank = [](uint32_t fmt) -> int {
|
||||
switch (fmt) {
|
||||
case V4L2_PIX_FMT_YUV422P:
|
||||
return 0;
|
||||
case V4L2_PIX_FMT_RGB565:
|
||||
return 1;
|
||||
case V4L2_PIX_FMT_RGB24:
|
||||
return 2;
|
||||
case V4L2_PIX_FMT_GREY:
|
||||
return 3;
|
||||
default:
|
||||
return 1 << 29; // unsupported
|
||||
}
|
||||
};
|
||||
while (ioctl(video_fd_, VIDIOC_ENUM_FMT, &fmtdesc) == 0) {
|
||||
ESP_LOGD(TAG, "VIDIOC_ENUM_FMT: pixelformat=0x%08x, description=%s", fmtdesc.pixelformat, fmtdesc.description);
|
||||
CAM_PRINT_FOURCC(fmtdesc.pixelformat);
|
||||
int rank = get_rank(fmtdesc.pixelformat);
|
||||
if (rank < best_rank) {
|
||||
best_rank = rank;
|
||||
best_fmt = fmtdesc.pixelformat;
|
||||
}
|
||||
fmtdesc.index++;
|
||||
}
|
||||
if (best_rank < (1 << 29)) {
|
||||
setformat.fmt.pix.pixelformat = best_fmt;
|
||||
sensor_format_ = best_fmt;
|
||||
}
|
||||
|
||||
if (!setformat.fmt.pix.pixelformat) {
|
||||
ESP_LOGE(TAG, "no supported pixel format found");
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
sensor_format_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "selected pixel format: 0x%08x", setformat.fmt.pix.pixelformat);
|
||||
|
||||
if (ioctl(video_fd_, VIDIOC_S_FMT, &setformat) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_S_FMT failed, errno=%d(%s)", errno, strerror(errno));
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
sensor_format_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
frame_.width = setformat.fmt.pix.width;
|
||||
frame_.height = setformat.fmt.pix.height;
|
||||
|
||||
// 申请缓冲并mmap
|
||||
struct v4l2_requestbuffers req = {};
|
||||
req.count = strcmp(video_device_name, ESP_VIDEO_MIPI_CSI_DEVICE_NAME) == 0 ? 2 : 1;
|
||||
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
req.memory = V4L2_MEMORY_MMAP;
|
||||
if (ioctl(video_fd_, VIDIOC_REQBUFS, &req) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_REQBUFS failed");
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
sensor_format_ = 0;
|
||||
return;
|
||||
}
|
||||
mmap_buffers_.resize(req.count);
|
||||
for (uint32_t i = 0; i < req.count; i++) {
|
||||
struct v4l2_buffer buf = {};
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
buf.index = i;
|
||||
if (ioctl(video_fd_, VIDIOC_QUERYBUF, &buf) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_QUERYBUF failed");
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
sensor_format_ = 0;
|
||||
return;
|
||||
}
|
||||
void* start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, video_fd_, buf.m.offset);
|
||||
if (start == MAP_FAILED) {
|
||||
ESP_LOGE(TAG, "mmap failed");
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
sensor_format_ = 0;
|
||||
return;
|
||||
}
|
||||
mmap_buffers_[i].start = start;
|
||||
mmap_buffers_[i].length = buf.length;
|
||||
|
||||
if (ioctl(video_fd_, VIDIOC_QBUF, &buf) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_QBUF failed");
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
sensor_format_ = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl(video_fd_, VIDIOC_STREAMON, &type) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_STREAMON failed");
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
sensor_format_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ESP_VIDEO_ENABLE_ISP_VIDEO_DEVICE
|
||||
// 当启用 ISP 时,ISP 需要一些照片来初始化参数,因此开启后后台拍摄5s照片并丢弃
|
||||
xTaskCreate(
|
||||
[](void* arg) {
|
||||
Esp32Camera* self = static_cast<Esp32Camera*>(arg);
|
||||
uint16_t capture_count = 0;
|
||||
TickType_t start = xTaskGetTickCount();
|
||||
TickType_t duration = 5000 / portTICK_PERIOD_MS; // 5s
|
||||
while ((xTaskGetTickCount() - start) < duration) {
|
||||
struct v4l2_buffer buf = {};
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
if (ioctl(self->video_fd_, VIDIOC_DQBUF, &buf) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_DQBUF failed during init");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
continue;
|
||||
}
|
||||
if (ioctl(self->video_fd_, VIDIOC_QBUF, &buf) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_QBUF failed during init");
|
||||
}
|
||||
capture_count++;
|
||||
}
|
||||
ESP_LOGI(TAG, "Camera init success, captured %d frames in %dms", capture_count,
|
||||
(xTaskGetTickCount() - start) * portTICK_PERIOD_MS);
|
||||
self->streaming_on_ = true;
|
||||
vTaskDelete(NULL);
|
||||
},
|
||||
"CameraInitTask", 4096, this, 5, nullptr);
|
||||
#else
|
||||
ESP_LOGI(TAG, "Camera init success");
|
||||
streaming_on_ = true;
|
||||
#endif // CONFIG_ESP_VIDEO_ENABLE_ISP_VIDEO_DEVICE
|
||||
}
|
||||
|
||||
Esp32Camera::~Esp32Camera() {
|
||||
if (fb_) {
|
||||
esp_camera_fb_return(fb_);
|
||||
fb_ = nullptr;
|
||||
if (streaming_on_ && video_fd_ >= 0) {
|
||||
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
ioctl(video_fd_, VIDIOC_STREAMOFF, &type);
|
||||
}
|
||||
esp_camera_deinit();
|
||||
for (auto& b : mmap_buffers_) {
|
||||
if (b.start && b.length) {
|
||||
munmap(b.start, b.length);
|
||||
}
|
||||
}
|
||||
if (video_fd_ >= 0) {
|
||||
close(video_fd_);
|
||||
video_fd_ = -1;
|
||||
}
|
||||
sensor_format_ = 0;
|
||||
esp_video_deinit();
|
||||
}
|
||||
|
||||
void Esp32Camera::SetExplainUrl(const std::string& url, const std::string& token) {
|
||||
@ -44,98 +314,266 @@ bool Esp32Camera::Capture() {
|
||||
encoder_thread_.join();
|
||||
}
|
||||
|
||||
auto start_time = esp_timer_get_time();
|
||||
int frames_to_get = 2;
|
||||
// Try to get a stable frame
|
||||
for (int i = 0; i < frames_to_get; i++) {
|
||||
if (fb_ != nullptr) {
|
||||
esp_camera_fb_return(fb_);
|
||||
}
|
||||
fb_ = esp_camera_fb_get();
|
||||
if (fb_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Camera capture failed");
|
||||
if (!streaming_on_ || video_fd_ < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
struct v4l2_buffer buf = {};
|
||||
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buf.memory = V4L2_MEMORY_MMAP;
|
||||
if (ioctl(video_fd_, VIDIOC_DQBUF, &buf) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_DQBUF failed");
|
||||
return false;
|
||||
}
|
||||
if (i == 2) {
|
||||
// 保存帧副本到PSRAM
|
||||
if (frame_.data) {
|
||||
heap_caps_free(frame_.data);
|
||||
frame_.data = nullptr;
|
||||
frame_.format = 0;
|
||||
}
|
||||
frame_.len = buf.bytesused;
|
||||
frame_.data = (uint8_t*)heap_caps_malloc(frame_.len, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (!frame_.data) {
|
||||
ESP_LOGE(TAG, "alloc frame copy failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "frame.len = %d, frame.width = %d, frame.height = %d", frame_.len, frame_.width,
|
||||
frame_.height);
|
||||
ESP_LOG_BUFFER_HEXDUMP(TAG, frame_.data, MIN(frame_.len, 256), ESP_LOG_DEBUG);
|
||||
|
||||
switch (sensor_format_) {
|
||||
case V4L2_PIX_FMT_RGB565:
|
||||
case V4L2_PIX_FMT_RGB24:
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
#ifdef CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP
|
||||
{
|
||||
auto src16 = (uint16_t*)mmap_buffers_[buf.index].start;
|
||||
auto dst16 = (uint16_t*)frame_.data;
|
||||
size_t count = (size_t)mmap_buffers_[buf.index].length / 2;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
dst16[i] = __builtin_bswap16(src16[i]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
memcpy(frame_.data, mmap_buffers_[buf.index].start, frame_.len);
|
||||
#endif // CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP
|
||||
frame_.format = sensor_format_;
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUV422P: {
|
||||
// 这个格式是 422 YUYV,不是 planer
|
||||
frame_.format = V4L2_PIX_FMT_YUYV;
|
||||
#ifdef CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP
|
||||
{
|
||||
auto src16 = (uint16_t*)mmap_buffers_[buf.index].start;
|
||||
auto dst16 = (uint16_t*)frame_.data;
|
||||
size_t count = (size_t)mmap_buffers_[buf.index].length / 2;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
dst16[i] = __builtin_bswap16(src16[i]);
|
||||
}
|
||||
}
|
||||
#else
|
||||
memcpy(frame_.data, mmap_buffers_[buf.index].start, frame_.len);
|
||||
#endif // CONFIG_XIAOZHI_ENABLE_CAMERA_ENDIANNESS_SWAP
|
||||
break;
|
||||
}
|
||||
case V4L2_PIX_FMT_RGB565X: {
|
||||
// 大端序的 RGB565 需要转换为小端序
|
||||
// 目前 esp_video 的大小端都会返回格式为 RGB565,不会返回格式为 RGB565X,此 case 用于未来版本兼容
|
||||
auto src16 = (uint16_t*)mmap_buffers_[buf.index].start;
|
||||
auto dst16 = (uint16_t*)frame_.data;
|
||||
size_t pixel_count = (size_t)frame_.width * (size_t)frame_.height;
|
||||
for (size_t i = 0; i < pixel_count; i++) {
|
||||
dst16[i] = __builtin_bswap16(src16[i]);
|
||||
}
|
||||
frame_.format = V4L2_PIX_FMT_RGB565;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(TAG, "unsupported sensor format: 0x%08x", sensor_format_);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (ioctl(video_fd_, VIDIOC_QBUF, &buf) != 0) {
|
||||
ESP_LOGE(TAG, "VIDIOC_QBUF failed");
|
||||
}
|
||||
}
|
||||
auto end_time = esp_timer_get_time();
|
||||
ESP_LOGI(TAG, "Camera captured %d frames in %d ms", frames_to_get, int((end_time - start_time) / 1000));
|
||||
|
||||
// 显示预览图片
|
||||
auto display = dynamic_cast<LvglDisplay*>(Board::GetInstance().GetDisplay());
|
||||
if (display != nullptr) {
|
||||
auto data = (uint8_t*)heap_caps_malloc(fb_->len, MALLOC_CAP_SPIRAM);
|
||||
if (data == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for preview image");
|
||||
if (!frame_.data) {
|
||||
return false;
|
||||
}
|
||||
uint16_t w = frame_.width;
|
||||
uint16_t h = frame_.height;
|
||||
size_t lvgl_image_size = frame_.len;
|
||||
size_t stride = ((w * 2) + 3) & ~3; // 4字节对齐
|
||||
lv_color_format_t color_format = LV_COLOR_FORMAT_RGB565;
|
||||
uint8_t* data = nullptr;
|
||||
|
||||
auto src = (uint16_t*)fb_->buf;
|
||||
auto dst = (uint16_t*)data;
|
||||
size_t pixel_count = fb_->len / 2;
|
||||
for (size_t i = 0; i < pixel_count; i++) {
|
||||
// 交换每个16位字内的字节
|
||||
dst[i] = __builtin_bswap16(src[i]);
|
||||
switch (frame_.format) {
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
// color_format = LV_COLOR_FORMAT_YUY2;
|
||||
// [[fallthrough]];
|
||||
// LV_COLOR_FORMAT_YUY2 的显示似乎有问题,暂时转换为 RGB565 显示
|
||||
{
|
||||
color_format = LV_COLOR_FORMAT_RGB565;
|
||||
data = (uint8_t*)heap_caps_malloc(w * h * 2, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
lvgl_image_size = w * h * 2;
|
||||
if (data == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for preview image");
|
||||
return false;
|
||||
}
|
||||
const uint8_t* src = (const uint8_t*)frame_.data;
|
||||
size_t src_len = frame_.len;
|
||||
size_t dst_off = 0;
|
||||
|
||||
auto clamp = [](int v) -> uint8_t {
|
||||
if (v < 0) return 0;
|
||||
if (v > 255) return 255;
|
||||
return (uint8_t)v;
|
||||
};
|
||||
|
||||
// 每 4 字节处理两个像素: Y0 U Y1 V
|
||||
for (size_t i = 0; i + 3 < src_len; i += 4) {
|
||||
int y0 = (int)src[i + 0];
|
||||
int u = (int)src[i + 1];
|
||||
int y1 = (int)src[i + 2];
|
||||
int v = (int)src[i + 3];
|
||||
|
||||
int c0 = y0 - 16;
|
||||
int c1 = y1 - 16;
|
||||
int d = u - 128;
|
||||
int e = v - 128;
|
||||
|
||||
// 常用整数近似转换
|
||||
int r0 = (298 * c0 + 409 * e + 128) >> 8;
|
||||
int g0 = (298 * c0 - 100 * d - 208 * e + 128) >> 8;
|
||||
int b0 = (298 * c0 + 516 * d + 128) >> 8;
|
||||
|
||||
int r1 = (298 * c1 + 409 * e + 128) >> 8;
|
||||
int g1 = (298 * c1 - 100 * d - 208 * e + 128) >> 8;
|
||||
int b1 = (298 * c1 + 516 * d + 128) >> 8;
|
||||
|
||||
uint8_t cr0 = clamp(r0);
|
||||
uint8_t cg0 = clamp(g0);
|
||||
uint8_t cb0 = clamp(b0);
|
||||
|
||||
uint8_t cr1 = clamp(r1);
|
||||
uint8_t cg1 = clamp(g1);
|
||||
uint8_t cb1 = clamp(b1);
|
||||
|
||||
// RGB565 打包
|
||||
uint16_t pix0 = (uint16_t)(((cr0 >> 3) << 11) | ((cg0 >> 2) << 5) | (cb0 >> 3));
|
||||
uint16_t pix1 = (uint16_t)(((cr1 >> 3) << 11) | ((cg1 >> 2) << 5) | (cb1 >> 3));
|
||||
|
||||
// 小端序:低字节先写入
|
||||
data[dst_off++] = (uint8_t)(pix0 & 0xFF);
|
||||
data[dst_off++] = (uint8_t)((pix0 >> 8) & 0xFF);
|
||||
|
||||
data[dst_off++] = (uint8_t)(pix1 & 0xFF);
|
||||
data[dst_off++] = (uint8_t)((pix1 >> 8) & 0xFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case V4L2_PIX_FMT_RGB565:
|
||||
// 默认的 color_format 就是 LV_COLOR_FORMAT_RGB565
|
||||
data = (uint8_t*)heap_caps_malloc(w * h * 2, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (data == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for preview image");
|
||||
return false;
|
||||
}
|
||||
memcpy(data, frame_.data, frame_.len);
|
||||
lvgl_image_size = frame_.len; // fallthrough 时兼顾 YUYV 与 RGB565
|
||||
break;
|
||||
|
||||
case V4L2_PIX_FMT_RGB24: {
|
||||
// RGB888 需要转换为 RGB565
|
||||
color_format = LV_COLOR_FORMAT_RGB565;
|
||||
data = (uint8_t*)heap_caps_malloc(w * h * 2, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
uint16_t* dst16 = (uint16_t*)data;
|
||||
if (data == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to allocate memory for preview image");
|
||||
return false;
|
||||
}
|
||||
const uint8_t* src = frame_.data;
|
||||
size_t pixel_count = (size_t)w * (size_t)h;
|
||||
for (size_t i = 0; i < pixel_count; i++) {
|
||||
uint8_t r = src[i * 3 + 0];
|
||||
uint8_t g = src[i * 3 + 1];
|
||||
uint8_t b = src[i * 3 + 2];
|
||||
dst16[i] = (uint16_t)(((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3));
|
||||
}
|
||||
lvgl_image_size = w * h * 2;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGE(TAG, "unsupported frame format: 0x%08x", frame_.format);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto image = std::make_unique<LvglAllocatedImage>(data, fb_->len, fb_->width, fb_->height, fb_->width * 2, LV_COLOR_FORMAT_RGB565);
|
||||
auto image = std::make_unique<LvglAllocatedImage>(data, lvgl_image_size, w, h, stride, color_format);
|
||||
display->SetPreviewImage(std::move(image));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Esp32Camera::SetHMirror(bool enabled) {
|
||||
sensor_t *s = esp_camera_sensor_get();
|
||||
if (s == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to get camera sensor");
|
||||
if (video_fd_ < 0)
|
||||
return false;
|
||||
struct v4l2_ext_controls ctrls = {};
|
||||
struct v4l2_ext_control ctrl = {};
|
||||
ctrl.id = V4L2_CID_HFLIP;
|
||||
ctrl.value = enabled ? 1 : 0;
|
||||
ctrls.ctrl_class = V4L2_CTRL_CLASS_USER;
|
||||
ctrls.count = 1;
|
||||
ctrls.controls = &ctrl;
|
||||
if (ioctl(video_fd_, VIDIOC_S_EXT_CTRLS, &ctrls) != 0) {
|
||||
ESP_LOGE(TAG, "set HFLIP failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t err = s->set_hmirror(s, enabled);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set horizontal mirror: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Camera horizontal mirror set to: %s", enabled ? "enabled" : "disabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Esp32Camera::SetVFlip(bool enabled) {
|
||||
sensor_t *s = esp_camera_sensor_get();
|
||||
if (s == nullptr) {
|
||||
ESP_LOGE(TAG, "Failed to get camera sensor");
|
||||
if (video_fd_ < 0)
|
||||
return false;
|
||||
struct v4l2_ext_controls ctrls = {};
|
||||
struct v4l2_ext_control ctrl = {};
|
||||
ctrl.id = V4L2_CID_VFLIP;
|
||||
ctrl.value = enabled ? 1 : 0;
|
||||
ctrls.ctrl_class = V4L2_CTRL_CLASS_USER;
|
||||
ctrls.count = 1;
|
||||
ctrls.controls = &ctrl;
|
||||
if (ioctl(video_fd_, VIDIOC_S_EXT_CTRLS, &ctrls) != 0) {
|
||||
ESP_LOGE(TAG, "set VFLIP failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
esp_err_t err = s->set_vflip(s, enabled);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set vertical flip: %d", err);
|
||||
return false;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Camera vertical flip set to: %s", enabled ? "enabled" : "disabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将摄像头捕获的图像发送到远程服务器进行AI分析和解释
|
||||
*
|
||||
*
|
||||
* 该函数将当前摄像头缓冲区中的图像编码为JPEG格式,并通过HTTP POST请求
|
||||
* 以multipart/form-data的形式发送到指定的解释服务器。服务器将根据提供的
|
||||
* 问题对图像进行AI分析并返回结果。
|
||||
*
|
||||
*
|
||||
* 实现特点:
|
||||
* - 使用独立线程编码JPEG,与主线程分离
|
||||
* - 采用分块传输编码(chunked transfer encoding)优化内存使用
|
||||
* - 通过队列机制实现编码线程和发送线程的数据同步
|
||||
* - 支持设备ID、客户端ID和认证令牌的HTTP头部配置
|
||||
*
|
||||
*
|
||||
* @param question 要向AI提出的关于图像的问题,将作为表单字段发送
|
||||
* @return std::string 服务器返回的JSON格式响应字符串
|
||||
* 成功时包含AI分析结果,失败时包含错误信息
|
||||
* 格式示例:{"success": true, "result": "分析结果"}
|
||||
* {"success": false, "message": "错误信息"}
|
||||
*
|
||||
*
|
||||
* @note 调用此函数前必须先调用SetExplainUrl()设置服务器URL
|
||||
* @note 函数会等待之前的编码线程完成后再开始新的处理
|
||||
* @warning 如果摄像头缓冲区为空或网络连接失败,将返回错误信息
|
||||
@ -154,17 +592,19 @@ std::string Esp32Camera::Explain(const std::string& question) {
|
||||
|
||||
// We spawn a thread to encode the image to JPEG using optimized encoder (cost about 500ms and 8KB SRAM)
|
||||
encoder_thread_ = std::thread([this, jpeg_queue]() {
|
||||
image_to_jpeg_cb(fb_->buf, fb_->len, fb_->width, fb_->height, fb_->format, 80,
|
||||
uint16_t w = frame_.width ? frame_.width : 320;
|
||||
uint16_t h = frame_.height ? frame_.height : 240;
|
||||
v4l2_pix_fmt_t enc_fmt = frame_.format;
|
||||
image_to_jpeg_cb(
|
||||
frame_.data, frame_.len, w, h, enc_fmt, 80,
|
||||
[](void* arg, size_t index, const void* data, size_t len) -> size_t {
|
||||
auto jpeg_queue = (QueueHandle_t)arg;
|
||||
JpegChunk chunk = {
|
||||
.data = (uint8_t*)heap_caps_aligned_alloc(16, len, MALLOC_CAP_SPIRAM),
|
||||
.len = len
|
||||
};
|
||||
memcpy(chunk.data, data, len);
|
||||
xQueueSend(jpeg_queue, &chunk, portMAX_DELAY);
|
||||
return len;
|
||||
}, jpeg_queue);
|
||||
auto jpeg_queue = (QueueHandle_t)arg;
|
||||
JpegChunk chunk = {.data = (uint8_t*)heap_caps_aligned_alloc(16, len, MALLOC_CAP_SPIRAM), .len = len};
|
||||
memcpy(chunk.data, data, len);
|
||||
xQueueSend(jpeg_queue, &chunk, portMAX_DELAY);
|
||||
return len;
|
||||
},
|
||||
jpeg_queue);
|
||||
});
|
||||
|
||||
auto network = Board::GetInstance().GetNetwork();
|
||||
@ -195,7 +635,7 @@ std::string Esp32Camera::Explain(const std::string& question) {
|
||||
vQueueDelete(jpeg_queue);
|
||||
throw std::runtime_error("Failed to connect to explain URL");
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// 第一块:question字段
|
||||
std::string question_field;
|
||||
@ -224,7 +664,7 @@ std::string Esp32Camera::Explain(const std::string& question) {
|
||||
break;
|
||||
}
|
||||
if (chunk.data == nullptr) {
|
||||
break; // The last chunk
|
||||
break; // The last chunk
|
||||
}
|
||||
http->Write((const char*)chunk.data, chunk.len);
|
||||
total_sent += chunk.len;
|
||||
@ -254,7 +694,7 @@ std::string Esp32Camera::Explain(const std::string& question) {
|
||||
|
||||
// Get remain task stack size
|
||||
size_t remain_stack_size = uxTaskGetStackHighWaterMark(nullptr);
|
||||
ESP_LOGI(TAG, "Explain image size=%dx%d, compressed size=%d, remain stack size=%d, question=%s\n%s",
|
||||
fb_->width, fb_->height, total_sent, remain_stack_size, question.c_str(), result.c_str());
|
||||
ESP_LOGI(TAG, "Explain image size=%d bytes, compressed size=%d, remain stack size=%d, question=%s\n%s",
|
||||
(int)frame_.len, (int)total_sent, (int)remain_stack_size, question.c_str(), result.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1,15 +1,18 @@
|
||||
#ifndef ESP32_CAMERA_H
|
||||
#define ESP32_CAMERA_H
|
||||
#pragma once
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include <esp_camera.h>
|
||||
#ifndef CONFIG_IDF_TARGET_ESP32
|
||||
#include <lvgl.h>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/queue.h>
|
||||
|
||||
#include "camera.h"
|
||||
#include "jpg/image_to_jpeg.h"
|
||||
#include "esp_video_init.h"
|
||||
|
||||
struct JpegChunk {
|
||||
uint8_t* data;
|
||||
@ -18,13 +21,24 @@ struct JpegChunk {
|
||||
|
||||
class Esp32Camera : public Camera {
|
||||
private:
|
||||
camera_fb_t* fb_ = nullptr;
|
||||
struct FrameBuffer {
|
||||
uint8_t *data = nullptr;
|
||||
size_t len = 0;
|
||||
uint16_t width = 0;
|
||||
uint16_t height = 0;
|
||||
v4l2_pix_fmt_t format = 0;
|
||||
} frame_;
|
||||
v4l2_pix_fmt_t sensor_format_ = 0;
|
||||
int video_fd_ = -1;
|
||||
bool streaming_on_ = false;
|
||||
struct MmapBuffer { void *start = nullptr; size_t length = 0; };
|
||||
std::vector<MmapBuffer> mmap_buffers_;
|
||||
std::string explain_url_;
|
||||
std::string explain_token_;
|
||||
std::thread encoder_thread_;
|
||||
|
||||
public:
|
||||
Esp32Camera(const camera_config_t& config);
|
||||
Esp32Camera(const esp_video_init_config_t& config);
|
||||
~Esp32Camera();
|
||||
|
||||
virtual void SetExplainUrl(const std::string& url, const std::string& token);
|
||||
@ -35,4 +49,4 @@ public:
|
||||
virtual std::string Explain(const std::string& question);
|
||||
};
|
||||
|
||||
#endif // ESP32_CAMERA_H
|
||||
#endif // ndef CONFIG_IDF_TARGET_ESP32
|
||||
@ -42,15 +42,15 @@
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
|
||||
/* DFRobot K10 Camera pins */
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM -1
|
||||
#define XCLK_GPIO_NUM 7
|
||||
#define PWDN_GPIO_NUM GPIO_NUM_NC
|
||||
#define RESET_GPIO_NUM GPIO_NUM_NC
|
||||
#define XCLK_GPIO_NUM GPIO_NUM_7
|
||||
|
||||
#define VSYNC_GPIO_NUM 4
|
||||
#define HREF_GPIO_NUM 5
|
||||
#define PCLK_GPIO_NUM 17
|
||||
#define SIOD_GPIO_NUM 20
|
||||
#define SIOC_GPIO_NUM 19
|
||||
#define VSYNC_GPIO_NUM GPIO_NUM_4
|
||||
#define HREF_GPIO_NUM GPIO_NUM_5
|
||||
#define PCLK_GPIO_NUM GPIO_NUM_17
|
||||
#define SIOD_GPIO_NUM GPIO_NUM_20
|
||||
#define SIOC_GPIO_NUM GPIO_NUM_19
|
||||
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN PWDN_GPIO_NUM
|
||||
@ -59,14 +59,14 @@
|
||||
#define CAMERA_PIN_SIOD SIOD_GPIO_NUM
|
||||
#define CAMERA_PIN_SIOC SIOC_GPIO_NUM
|
||||
|
||||
#define CAMERA_PIN_D9 6
|
||||
#define CAMERA_PIN_D8 15
|
||||
#define CAMERA_PIN_D7 16
|
||||
#define CAMERA_PIN_D6 18
|
||||
#define CAMERA_PIN_D5 9
|
||||
#define CAMERA_PIN_D4 11
|
||||
#define CAMERA_PIN_D3 10
|
||||
#define CAMERA_PIN_D2 8
|
||||
#define CAMERA_PIN_D9 GPIO_NUM_6
|
||||
#define CAMERA_PIN_D8 GPIO_NUM_15
|
||||
#define CAMERA_PIN_D7 GPIO_NUM_16
|
||||
#define CAMERA_PIN_D6 GPIO_NUM_18
|
||||
#define CAMERA_PIN_D5 GPIO_NUM_9
|
||||
#define CAMERA_PIN_D4 GPIO_NUM_11
|
||||
#define CAMERA_PIN_D3 GPIO_NUM_10
|
||||
#define CAMERA_PIN_D2 GPIO_NUM_8
|
||||
#define CAMERA_PIN_VSYNC VSYNC_GPIO_NUM
|
||||
#define CAMERA_PIN_HREF HREF_GPIO_NUM
|
||||
#define CAMERA_PIN_PCLK PCLK_GPIO_NUM
|
||||
|
||||
@ -167,36 +167,43 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D2,
|
||||
[1] = CAMERA_PIN_D3,
|
||||
[2] = CAMERA_PIN_D4,
|
||||
[3] = CAMERA_PIN_D5,
|
||||
[4] = CAMERA_PIN_D6,
|
||||
[5] = CAMERA_PIN_D7,
|
||||
[6] = CAMERA_PIN_D8,
|
||||
[7] = CAMERA_PIN_D9,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
camera_config_t config = {};
|
||||
config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用
|
||||
config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用
|
||||
config.pin_d0 = CAMERA_PIN_D2;
|
||||
config.pin_d1 = CAMERA_PIN_D3;
|
||||
config.pin_d2 = CAMERA_PIN_D4;
|
||||
config.pin_d3 = CAMERA_PIN_D5;
|
||||
config.pin_d4 = CAMERA_PIN_D6;
|
||||
config.pin_d5 = CAMERA_PIN_D7;
|
||||
config.pin_d6 = CAMERA_PIN_D8;
|
||||
config.pin_d7 = CAMERA_PIN_D9;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = -1; // 这里如果写-1 表示使用已经初始化的I2C接口
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 1; // 这里如果写1 默认使用I2C1
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_VGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = false,
|
||||
.i2c_handle = i2c_bus_,
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(config);
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
}
|
||||
|
||||
void InitializeIli9341Display() {
|
||||
|
||||
@ -22,22 +22,22 @@
|
||||
#define RESET_FACTORY_BUTTON_GPIO GPIO_NUM_NC
|
||||
|
||||
/* DFRobot Camera pins */
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM -1
|
||||
#define XCLK_GPIO_NUM 5
|
||||
#define Y9_GPIO_NUM 4
|
||||
#define Y8_GPIO_NUM 6
|
||||
#define Y7_GPIO_NUM 7
|
||||
#define Y6_GPIO_NUM 14
|
||||
#define Y5_GPIO_NUM 17
|
||||
#define Y4_GPIO_NUM 21
|
||||
#define Y3_GPIO_NUM 18
|
||||
#define Y2_GPIO_NUM 16
|
||||
#define VSYNC_GPIO_NUM 1
|
||||
#define HREF_GPIO_NUM 2
|
||||
#define PCLK_GPIO_NUM 15
|
||||
#define SIOD_GPIO_NUM 8
|
||||
#define SIOC_GPIO_NUM 9
|
||||
#define PWDN_GPIO_NUM GPIO_NUM_NC
|
||||
#define RESET_GPIO_NUM GPIO_NUM_NC
|
||||
#define XCLK_GPIO_NUM GPIO_NUM_5
|
||||
#define Y9_GPIO_NUM GPIO_NUM_4
|
||||
#define Y8_GPIO_NUM GPIO_NUM_6
|
||||
#define Y7_GPIO_NUM GPIO_NUM_7
|
||||
#define Y6_GPIO_NUM GPIO_NUM_14
|
||||
#define Y5_GPIO_NUM GPIO_NUM_17
|
||||
#define Y4_GPIO_NUM GPIO_NUM_21
|
||||
#define Y3_GPIO_NUM GPIO_NUM_18
|
||||
#define Y2_GPIO_NUM GPIO_NUM_16
|
||||
#define VSYNC_GPIO_NUM GPIO_NUM_1
|
||||
#define HREF_GPIO_NUM GPIO_NUM_2
|
||||
#define PCLK_GPIO_NUM GPIO_NUM_15
|
||||
#define SIOD_GPIO_NUM GPIO_NUM_8
|
||||
#define SIOC_GPIO_NUM GPIO_NUM_9
|
||||
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN PWDN_GPIO_NUM
|
||||
|
||||
@ -30,35 +30,47 @@ class DfrobotEsp32S3AiCam : public WifiBoard {
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t config = {};
|
||||
config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用
|
||||
config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = CAMERA_PIN_SIOD; // 这里如果写-1 表示使用已经初始化的I2C接口
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 1; // 这里如果写1 默认使用I2C1
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_VGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(config);
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = 1,
|
||||
.scl_pin = CAMERA_PIN_SIOC,
|
||||
.sda_pin = CAMERA_PIN_SIOD,
|
||||
},
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
camera_->SetVFlip(1);
|
||||
}
|
||||
|
||||
|
||||
@ -3,7 +3,11 @@
|
||||
"builds": [
|
||||
{
|
||||
"name": "esp-sparkbot",
|
||||
"sdkconfig_append": []
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_CAMERA_OV2640=y",
|
||||
"CONFIG_CAMERA_OV2640_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_OV2640_DVP_YUV422_240X240_25FPS=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -121,41 +121,48 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t camera_config = {};
|
||||
|
||||
camera_config.pin_pwdn = SPARKBOT_CAMERA_PWDN;
|
||||
camera_config.pin_reset = SPARKBOT_CAMERA_RESET;
|
||||
camera_config.pin_xclk = SPARKBOT_CAMERA_XCLK;
|
||||
camera_config.pin_pclk = SPARKBOT_CAMERA_PCLK;
|
||||
camera_config.pin_sccb_sda = SPARKBOT_CAMERA_SIOD;
|
||||
camera_config.pin_sccb_scl = SPARKBOT_CAMERA_SIOC;
|
||||
// DVP pin configuration
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = SPARKBOT_CAMERA_D0,
|
||||
[1] = SPARKBOT_CAMERA_D1,
|
||||
[2] = SPARKBOT_CAMERA_D2,
|
||||
[3] = SPARKBOT_CAMERA_D3,
|
||||
[4] = SPARKBOT_CAMERA_D4,
|
||||
[5] = SPARKBOT_CAMERA_D5,
|
||||
[6] = SPARKBOT_CAMERA_D6,
|
||||
[7] = SPARKBOT_CAMERA_D7,
|
||||
},
|
||||
.vsync_io = SPARKBOT_CAMERA_VSYNC,
|
||||
.de_io = SPARKBOT_CAMERA_HSYNC,
|
||||
.pclk_io = SPARKBOT_CAMERA_PCLK,
|
||||
.xclk_io = SPARKBOT_CAMERA_XCLK,
|
||||
};
|
||||
|
||||
camera_config.pin_d0 = SPARKBOT_CAMERA_D0;
|
||||
camera_config.pin_d1 = SPARKBOT_CAMERA_D1;
|
||||
camera_config.pin_d2 = SPARKBOT_CAMERA_D2;
|
||||
camera_config.pin_d3 = SPARKBOT_CAMERA_D3;
|
||||
camera_config.pin_d4 = SPARKBOT_CAMERA_D4;
|
||||
camera_config.pin_d5 = SPARKBOT_CAMERA_D5;
|
||||
camera_config.pin_d6 = SPARKBOT_CAMERA_D6;
|
||||
camera_config.pin_d7 = SPARKBOT_CAMERA_D7;
|
||||
// 复用 I2C 总线
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = false, // 不初始化新的 SCCB,使用现有的 I2C 总线
|
||||
.i2c_handle = i2c_bus_, // 使用现有的 I2C 总线句柄
|
||||
.freq = 100000, // 100kHz
|
||||
};
|
||||
|
||||
camera_config.pin_vsync = SPARKBOT_CAMERA_VSYNC;
|
||||
camera_config.pin_href = SPARKBOT_CAMERA_HSYNC;
|
||||
camera_config.pin_pclk = SPARKBOT_CAMERA_PCLK;
|
||||
camera_config.xclk_freq_hz = SPARKBOT_CAMERA_XCLK_FREQ;
|
||||
camera_config.ledc_timer = SPARKBOT_LEDC_TIMER;
|
||||
camera_config.ledc_channel = SPARKBOT_LEDC_CHANNEL;
|
||||
camera_config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
// DVP configuration
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = SPARKBOT_CAMERA_RESET,
|
||||
.pwdn_pin = SPARKBOT_CAMERA_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = SPARKBOT_CAMERA_XCLK_FREQ,
|
||||
};
|
||||
|
||||
// Main video configuration
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_config.sccb_i2c_port = I2C_NUM_0;
|
||||
|
||||
camera_config.pixel_format = PIXFORMAT_RGB565;
|
||||
camera_config.frame_size = FRAMESIZE_240X240;
|
||||
camera_config.jpeg_quality = 12;
|
||||
camera_config.fb_count = 1;
|
||||
camera_config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
|
||||
camera_ = new Esp32Camera(camera_config);
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
|
||||
Settings settings("sparkbot", false);
|
||||
// 考虑到部分复刻使用了不可动摄像头的设计,默认启用翻转
|
||||
|
||||
@ -174,51 +174,47 @@ private:
|
||||
ESP_ERROR_CHECK(spi_bus_initialize(SPI3_HOST, &buscfg, SPI_DMA_CH_AUTO));
|
||||
}
|
||||
void InitializeCamera() {
|
||||
camera_config_t config = {};
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAM_PIN_D0,
|
||||
[1] = CAM_PIN_D1,
|
||||
[2] = CAM_PIN_D2,
|
||||
[3] = CAM_PIN_D3,
|
||||
[4] = CAM_PIN_D4,
|
||||
[5] = CAM_PIN_D5,
|
||||
[6] = CAM_PIN_D6,
|
||||
[7] = CAM_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAM_PIN_VSYNC,
|
||||
.de_io = CAM_PIN_HREF,
|
||||
.pclk_io = CAM_PIN_PCLK,
|
||||
.xclk_io = CAM_PIN_XCLK,
|
||||
};
|
||||
|
||||
config.pin_pwdn = CAM_PIN_PWDN;
|
||||
config.pin_reset = CAM_PIN_RESET;
|
||||
config.pin_xclk = CAM_PIN_XCLK;
|
||||
config.pin_sccb_sda = CAM_PIN_SIOD;
|
||||
config.pin_sccb_scl = CAM_PIN_SIOC;
|
||||
config.sccb_i2c_port = I2C_NUM_0;
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = I2C_NUM_0,
|
||||
.scl_pin = CAM_PIN_SIOC,
|
||||
.sda_pin = CAM_PIN_SIOD,
|
||||
},
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
config.pin_d7 = CAM_PIN_D7;
|
||||
config.pin_d6 = CAM_PIN_D6;
|
||||
config.pin_d5 = CAM_PIN_D5;
|
||||
config.pin_d4 = CAM_PIN_D4;
|
||||
config.pin_d3 = CAM_PIN_D3;
|
||||
config.pin_d2 = CAM_PIN_D2;
|
||||
config.pin_d1 = CAM_PIN_D1;
|
||||
config.pin_d0 = CAM_PIN_D0;
|
||||
config.pin_vsync = CAM_PIN_VSYNC;
|
||||
config.pin_href = CAM_PIN_HREF;
|
||||
config.pin_pclk = CAM_PIN_PCLK;
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAM_PIN_RESET,
|
||||
.pwdn_pin = CAM_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = 10000000,
|
||||
};
|
||||
|
||||
/* XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) */
|
||||
config.xclk_freq_hz = 10000000;
|
||||
config.ledc_timer = LEDC_TIMER_1;
|
||||
config.ledc_channel = LEDC_CHANNEL_0;
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
config.pixel_format = PIXFORMAT_RGB565; /* YUV422,GRAYSCALE,RGB565,JPEG */
|
||||
config.frame_size = FRAMESIZE_240X240; /* QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates */
|
||||
|
||||
config.jpeg_quality = 12; /* 0-63, for OV series camera sensors, lower number means higher quality */
|
||||
config.fb_count = 2; /* When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode */
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
|
||||
esp_err_t err = esp_camera_init(&config); // 测试相机是否存在
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Camera is not plugged in or not supported, error: %s", esp_err_to_name(err));
|
||||
// 如果摄像头初始化失败,设置 camera_ 为 nullptr
|
||||
camera_ = nullptr;
|
||||
return;
|
||||
}else
|
||||
{
|
||||
esp_camera_deinit();// 释放之前的摄像头资源,为正确初始化做准备
|
||||
camera_ = new Esp32Camera(config);
|
||||
}
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -59,23 +59,23 @@
|
||||
#define DISPLAY_BACKLIGHT_PIN GPIO_NUM_NC
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT false
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN -1
|
||||
#define CAMERA_PIN_RESET -1
|
||||
#define CAMERA_PIN_XCLK 40
|
||||
#define CAMERA_PIN_SIOD 17
|
||||
#define CAMERA_PIN_SIOC 18
|
||||
#define CAMERA_PIN_PWDN GPIO_NUM_NC
|
||||
#define CAMERA_PIN_RESET GPIO_NUM_NC
|
||||
#define CAMERA_PIN_XCLK GPIO_NUM_40
|
||||
#define CAMERA_PIN_SIOD GPIO_NUM_17
|
||||
#define CAMERA_PIN_SIOC GPIO_NUM_18
|
||||
|
||||
#define CAMERA_PIN_D7 39
|
||||
#define CAMERA_PIN_D6 41
|
||||
#define CAMERA_PIN_D5 42
|
||||
#define CAMERA_PIN_D4 12
|
||||
#define CAMERA_PIN_D3 3
|
||||
#define CAMERA_PIN_D2 14
|
||||
#define CAMERA_PIN_D1 47
|
||||
#define CAMERA_PIN_D0 13
|
||||
#define CAMERA_PIN_VSYNC 21
|
||||
#define CAMERA_PIN_HREF 38
|
||||
#define CAMERA_PIN_PCLK 11
|
||||
#define CAMERA_PIN_D7 GPIO_NUM_39
|
||||
#define CAMERA_PIN_D6 GPIO_NUM_41
|
||||
#define CAMERA_PIN_D5 GPIO_NUM_42
|
||||
#define CAMERA_PIN_D4 GPIO_NUM_12
|
||||
#define CAMERA_PIN_D3 GPIO_NUM_3
|
||||
#define CAMERA_PIN_D2 GPIO_NUM_14
|
||||
#define CAMERA_PIN_D1 GPIO_NUM_47
|
||||
#define CAMERA_PIN_D0 GPIO_NUM_13
|
||||
#define CAMERA_PIN_VSYNC GPIO_NUM_21
|
||||
#define CAMERA_PIN_HREF GPIO_NUM_38
|
||||
#define CAMERA_PIN_PCLK GPIO_NUM_11
|
||||
|
||||
#define XCLK_FREQ_HZ 20000000
|
||||
#endif // _BOARD_CONFIG_H_
|
||||
@ -333,37 +333,43 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
// Open camera power
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
camera_config_t config = {};
|
||||
config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用
|
||||
config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = -1; // 这里写-1 表示使用已经初始化的I2C接口
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 1;
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_VGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = false,
|
||||
.i2c_handle = i2c_bus_,
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(config);
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -84,37 +84,47 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
// Open camera power
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
camera_config_t config = {};
|
||||
config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用
|
||||
config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = CAMERA_PIN_SIOD; // 这里写-1 表示使用已经初始化的I2C接口
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 1;
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_VGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = 1,
|
||||
.scl_pin = CAMERA_PIN_SIOC,
|
||||
.sda_pin = CAMERA_PIN_SIOD,
|
||||
},
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(config);
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -43,23 +43,23 @@
|
||||
#define ML307_RX_PIN GPIO_NUM_12
|
||||
#define ML307_TX_PIN GPIO_NUM_13
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN -1
|
||||
#define CAMERA_PIN_RESET -1
|
||||
#define CAMERA_PIN_XCLK 15
|
||||
#define CAMERA_PIN_SIOD 4
|
||||
#define CAMERA_PIN_SIOC 5
|
||||
#define CAMERA_PIN_PWDN GPIO_NUM_NC
|
||||
#define CAMERA_PIN_RESET GPIO_NUM_NC
|
||||
#define CAMERA_PIN_XCLK GPIO_NUM_15
|
||||
#define CAMERA_PIN_SIOD GPIO_NUM_4
|
||||
#define CAMERA_PIN_SIOC GPIO_NUM_5
|
||||
|
||||
#define CAMERA_PIN_D7 16
|
||||
#define CAMERA_PIN_D6 17
|
||||
#define CAMERA_PIN_D5 18
|
||||
#define CAMERA_PIN_D4 12
|
||||
#define CAMERA_PIN_D3 10
|
||||
#define CAMERA_PIN_D2 8
|
||||
#define CAMERA_PIN_D1 9
|
||||
#define CAMERA_PIN_D0 11
|
||||
#define CAMERA_PIN_VSYNC 6
|
||||
#define CAMERA_PIN_HREF 7
|
||||
#define CAMERA_PIN_PCLK 13
|
||||
#define CAMERA_PIN_D7 GPIO_NUM_16
|
||||
#define CAMERA_PIN_D6 GPIO_NUM_17
|
||||
#define CAMERA_PIN_D5 GPIO_NUM_18
|
||||
#define CAMERA_PIN_D4 GPIO_NUM_12
|
||||
#define CAMERA_PIN_D3 GPIO_NUM_10
|
||||
#define CAMERA_PIN_D2 GPIO_NUM_8
|
||||
#define CAMERA_PIN_D1 GPIO_NUM_9
|
||||
#define CAMERA_PIN_D0 GPIO_NUM_11
|
||||
#define CAMERA_PIN_VSYNC GPIO_NUM_6
|
||||
#define CAMERA_PIN_HREF GPIO_NUM_7
|
||||
#define CAMERA_PIN_PCLK GPIO_NUM_13
|
||||
|
||||
#define XCLK_FREQ_HZ 20000000
|
||||
|
||||
|
||||
@ -99,37 +99,47 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
// Open camera power
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
camera_config_t config = {};
|
||||
config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用
|
||||
config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = -1; // 这里写-1 表示使用已经初始化的I2C接口
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 1;
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_VGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = 1,
|
||||
.scl_pin = CAMERA_PIN_SIOC,
|
||||
.sda_pin = GPIO_NUM_NC,
|
||||
},
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(config);
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -38,23 +38,23 @@
|
||||
#define DISPLAY_BACKLIGHT_OUTPUT_INVERT true
|
||||
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN -1
|
||||
#define CAMERA_PIN_RESET -1
|
||||
#define CAMERA_PIN_XCLK 5
|
||||
#define CAMERA_PIN_SIOD 1
|
||||
#define CAMERA_PIN_SIOC 2
|
||||
#define CAMERA_PIN_PWDN GPIO_NUM_NC
|
||||
#define CAMERA_PIN_RESET GPIO_NUM_NC
|
||||
#define CAMERA_PIN_XCLK GPIO_NUM_5
|
||||
#define CAMERA_PIN_SIOD GPIO_NUM_1
|
||||
#define CAMERA_PIN_SIOC GPIO_NUM_2
|
||||
|
||||
#define CAMERA_PIN_D7 9
|
||||
#define CAMERA_PIN_D6 4
|
||||
#define CAMERA_PIN_D5 6
|
||||
#define CAMERA_PIN_D4 15
|
||||
#define CAMERA_PIN_D3 17
|
||||
#define CAMERA_PIN_D2 8
|
||||
#define CAMERA_PIN_D1 18
|
||||
#define CAMERA_PIN_D0 16
|
||||
#define CAMERA_PIN_VSYNC 3
|
||||
#define CAMERA_PIN_HREF 46
|
||||
#define CAMERA_PIN_PCLK 7
|
||||
#define CAMERA_PIN_D7 GPIO_NUM_9
|
||||
#define CAMERA_PIN_D6 GPIO_NUM_4
|
||||
#define CAMERA_PIN_D5 GPIO_NUM_6
|
||||
#define CAMERA_PIN_D4 GPIO_NUM_15
|
||||
#define CAMERA_PIN_D3 GPIO_NUM_17
|
||||
#define CAMERA_PIN_D2 GPIO_NUM_8
|
||||
#define CAMERA_PIN_D1 GPIO_NUM_18
|
||||
#define CAMERA_PIN_D0 GPIO_NUM_16
|
||||
#define CAMERA_PIN_VSYNC GPIO_NUM_3
|
||||
#define CAMERA_PIN_HREF GPIO_NUM_46
|
||||
#define CAMERA_PIN_PCLK GPIO_NUM_7
|
||||
|
||||
#define XCLK_FREQ_HZ 24000000
|
||||
|
||||
|
||||
@ -195,35 +195,43 @@ private:
|
||||
// Open camera power
|
||||
pca9557_->SetOutputState(2, 0);
|
||||
|
||||
camera_config_t config = {};
|
||||
config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用
|
||||
config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = -1; // 这里写-1 表示使用已经初始化的I2C接口
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 1;
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_VGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(config);
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = false,
|
||||
.i2c_handle = i2c_bus_,
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -224,41 +224,56 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t config = {};
|
||||
config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用
|
||||
config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用
|
||||
config.pin_d0 = Y2_GPIO_NUM;
|
||||
config.pin_d1 = Y3_GPIO_NUM;
|
||||
config.pin_d2 = Y4_GPIO_NUM;
|
||||
config.pin_d3 = Y5_GPIO_NUM;
|
||||
config.pin_d4 = Y6_GPIO_NUM;
|
||||
config.pin_d5 = Y7_GPIO_NUM;
|
||||
config.pin_d6 = Y8_GPIO_NUM;
|
||||
config.pin_d7 = Y9_GPIO_NUM;
|
||||
config.pin_xclk = XCLK_GPIO_NUM;
|
||||
config.pin_pclk = PCLK_GPIO_NUM;
|
||||
config.pin_vsync = VSYNC_GPIO_NUM;
|
||||
config.pin_href = HREF_GPIO_NUM;
|
||||
#ifdef CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_0_V1_1
|
||||
config.pin_sccb_sda = -1; // 这里如果写-1 表示使用已经初始化的I2C接口
|
||||
config.pin_sccb_scl = SIOC_GPIO_NUM;
|
||||
config.sccb_i2c_port = 0; // 这里如果写0 默认使用I2C0
|
||||
#elif defined CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_2
|
||||
config.pin_sccb_sda = SIOD_GPIO_NUM;
|
||||
config.pin_sccb_scl = SIOC_GPIO_NUM;
|
||||
config.sccb_i2c_port = 1;
|
||||
#endif
|
||||
config.pin_pwdn = PWDN_GPIO_NUM;
|
||||
config.pin_reset = RESET_GPIO_NUM;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_240X240;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = Y2_GPIO_NUM,
|
||||
[1] = Y3_GPIO_NUM,
|
||||
[2] = Y4_GPIO_NUM,
|
||||
[3] = Y5_GPIO_NUM,
|
||||
[4] = Y6_GPIO_NUM,
|
||||
[5] = Y7_GPIO_NUM,
|
||||
[6] = Y8_GPIO_NUM,
|
||||
[7] = Y9_GPIO_NUM,
|
||||
},
|
||||
.vsync_io = VSYNC_GPIO_NUM,
|
||||
.de_io = HREF_GPIO_NUM,
|
||||
.pclk_io = PCLK_GPIO_NUM,
|
||||
.xclk_io = XCLK_GPIO_NUM,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(config);
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
#ifdef CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_0_V1_1
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = 0,
|
||||
.scl_pin = SIOC_GPIO_NUM,
|
||||
.sda_pin = GPIO_NUM_NC,
|
||||
},
|
||||
#elif defined CONFIG_BOARD_TYPE_LILYGO_T_CAMERAPLUS_S3_V1_2
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = 1,
|
||||
.scl_pin = SIOC_GPIO_NUM,
|
||||
.sda_pin = SIOD_GPIO_NUM,
|
||||
},
|
||||
#endif
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = RESET_GPIO_NUM,
|
||||
.pwdn_pin = PWDN_GPIO_NUM,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
camera_->SetVFlip(1);
|
||||
camera_->SetHMirror(1);
|
||||
}
|
||||
|
||||
@ -16,90 +16,90 @@
|
||||
#ifdef T_CameraPlus_S3_V1_0_V1_1
|
||||
|
||||
// SPI
|
||||
#define SPI_SCLK 36
|
||||
#define SPI_MOSI 35
|
||||
#define SPI_MISO 37
|
||||
#define SPI_SCLK GPIO_NUM_36
|
||||
#define SPI_MOSI GPIO_NUM_35
|
||||
#define SPI_MISO GPIO_NUM_37
|
||||
|
||||
// IIC
|
||||
#define IIC_SDA 1
|
||||
#define IIC_SCL 2
|
||||
#define IIC_SDA GPIO_NUM_1
|
||||
#define IIC_SCL GPIO_NUM_2
|
||||
|
||||
// MSM261
|
||||
#define MSM261_BCLK 18
|
||||
#define MSM261_WS 39
|
||||
#define MSM261_DATA 40
|
||||
#define MSM261_BCLK GPIO_NUM_18
|
||||
#define MSM261_WS GPIO_NUM_39
|
||||
#define MSM261_DATA GPIO_NUM_40
|
||||
|
||||
// MAX98357A
|
||||
#define MAX98357A_DATA 38
|
||||
#define MAX98357A_DATA GPIO_NUM_38
|
||||
|
||||
// FP-133H01D
|
||||
#define LCD_CS 34
|
||||
#define LCD_RST 33
|
||||
#define LCD_CS GPIO_NUM_34
|
||||
#define LCD_RST GPIO_NUM_33
|
||||
|
||||
// OV2640
|
||||
#define OV2640_PWDN -1
|
||||
#define OV2640_RESET 3
|
||||
#define OV2640_VSYNC 4
|
||||
#define OV2640_PWDN GPIO_NUM_NC
|
||||
#define OV2640_RESET GPIO_NUM_3
|
||||
#define OV2640_VSYNC GPIO_NUM_4
|
||||
|
||||
// CST816
|
||||
#define TP_RST 48
|
||||
#define TP_RST GPIO_NUM_48
|
||||
|
||||
// SY6970
|
||||
#define SY6970_INT 47
|
||||
#define SY6970_INT GPIO_NUM_47
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef T_CameraPlus_S3_V1_2
|
||||
|
||||
// SPI
|
||||
#define SPI_SCLK 35
|
||||
#define SPI_MOSI 34
|
||||
#define SPI_MISO 48
|
||||
#define SPI_SCLK GPIO_NUM_35
|
||||
#define SPI_MOSI GPIO_NUM_34
|
||||
#define SPI_MISO GPIO_NUM_48
|
||||
|
||||
// IIC
|
||||
#define IIC_SDA 33
|
||||
#define IIC_SCL 37
|
||||
#define IIC_SDA GPIO_NUM_33
|
||||
#define IIC_SCL GPIO_NUM_37
|
||||
|
||||
// MP34DT05TR
|
||||
#define MP34DT05TR_LRCLK 40
|
||||
#define MP34DT05TR_DATA 38
|
||||
#define MP34DT05TR_LRCLK GPIO_NUM_40
|
||||
#define MP34DT05TR_DATA GPIO_NUM_38
|
||||
|
||||
#define MP34DT05TR_MAX98357_EN 18
|
||||
#define MP34DT05TR_MAX98357_EN GPIO_NUM_18
|
||||
|
||||
// MAX98357A
|
||||
#define MAX98357A_DATA 39
|
||||
#define MAX98357A_DATA GPIO_NUM_39
|
||||
|
||||
// FP-133H01D
|
||||
#define LCD_CS 36
|
||||
#define LCD_RST -1
|
||||
#define LCD_CS GPIO_NUM_36
|
||||
#define LCD_RST GPIO_NUM_NC
|
||||
|
||||
// OV2640
|
||||
#define OV2640_PWDN 4
|
||||
#define OV2640_RESET -1
|
||||
#define OV2640_VSYNC 3
|
||||
#define OV2640_PWDN GPIO_NUM_4
|
||||
#define OV2640_RESET GPIO_NUM_NC
|
||||
#define OV2640_VSYNC GPIO_NUM_3
|
||||
|
||||
// CST816
|
||||
#define TP_RST -1
|
||||
#define TP_RST GPIO_NUM_NC
|
||||
|
||||
#endif
|
||||
|
||||
// SD
|
||||
#define SD_CS 21
|
||||
#define SD_CS GPIO_NUM_21
|
||||
#define SD_SCLK SPI_SCLK
|
||||
#define SD_MOSI SPI_MOSI
|
||||
#define SD_MISO SPI_MISO
|
||||
|
||||
// MAX98357A
|
||||
#define MAX98357A_BCLK 41
|
||||
#define MAX98357A_LRCLK 42
|
||||
#define MAX98357A_BCLK GPIO_NUM_41
|
||||
#define MAX98357A_LRCLK GPIO_NUM_42
|
||||
|
||||
// FP-133H01D
|
||||
#define LCD_WIDTH 240
|
||||
#define LCD_HEIGHT 240
|
||||
#define LCD_BL 46
|
||||
#define LCD_BL GPIO_NUM_46
|
||||
#define LCD_MOSI SPI_MOSI
|
||||
#define LCD_SCLK SPI_SCLK
|
||||
#define LCD_DC 45
|
||||
#define LCD_DC GPIO_NUM_45
|
||||
|
||||
// SY6970
|
||||
#define SY6970_SDA IIC_SDA
|
||||
@ -107,19 +107,19 @@
|
||||
#define SY6970_ADDRESS 0x6A
|
||||
|
||||
// OV2640
|
||||
#define OV2640_XCLK 7
|
||||
#define OV2640_SDA 1
|
||||
#define OV2640_SCL 2
|
||||
#define OV2640_D9 6
|
||||
#define OV2640_D8 8
|
||||
#define OV2640_D7 9
|
||||
#define OV2640_D6 11
|
||||
#define OV2640_D5 13
|
||||
#define OV2640_D4 15
|
||||
#define OV2640_D3 14
|
||||
#define OV2640_D2 12
|
||||
#define OV2640_HREF 5
|
||||
#define OV2640_PCLK 10
|
||||
#define OV2640_XCLK GPIO_NUM_7
|
||||
#define OV2640_SDA GPIO_NUM_1
|
||||
#define OV2640_SCL GPIO_NUM_2
|
||||
#define OV2640_D9 GPIO_NUM_6
|
||||
#define OV2640_D8 GPIO_NUM_8
|
||||
#define OV2640_D7 GPIO_NUM_9
|
||||
#define OV2640_D6 GPIO_NUM_11
|
||||
#define OV2640_D5 GPIO_NUM_13
|
||||
#define OV2640_D4 GPIO_NUM_15
|
||||
#define OV2640_D3 GPIO_NUM_14
|
||||
#define OV2640_D2 GPIO_NUM_12
|
||||
#define OV2640_HREF GPIO_NUM_5
|
||||
#define OV2640_PCLK GPIO_NUM_10
|
||||
|
||||
#define PWDN_GPIO_NUM OV2640_PWDN
|
||||
#define RESET_GPIO_NUM OV2640_RESET
|
||||
@ -145,10 +145,10 @@
|
||||
#define CST816_ADDRESS 0x15
|
||||
#define TP_SDA IIC_SDA
|
||||
#define TP_SCL IIC_SCL
|
||||
#define TP_INT 47
|
||||
#define TP_INT GPIO_NUM_47
|
||||
|
||||
// AP1511B
|
||||
#define AP1511B_FBC 16
|
||||
#define AP1511B_FBC GPIO_NUM_16
|
||||
|
||||
// KEY
|
||||
#define KEY1 17
|
||||
#define KEY1 GPIO_NUM_17
|
||||
|
||||
@ -4,7 +4,10 @@
|
||||
{
|
||||
"name": "m5stack-core-s3",
|
||||
"sdkconfig_append": [
|
||||
"CONFIG_SPIRAM_MODE_QUAD=y"
|
||||
"CONFIG_SPIRAM_MODE_QUAD=y",
|
||||
"CONFIG_CAMERA_GC0308=y",
|
||||
"CONFIG_CAMERA_GC0308_AUTO_DETECT_DVP_INTERFACE_SENSOR=y",
|
||||
"CONFIG_CAMERA_GC0308_DVP_YUV422_320X240_20FPS=y"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@ -291,33 +291,44 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
// Open camera power
|
||||
camera_config_t config = {};
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = CAMERA_PIN_SIOD;
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 1;
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_QVGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
camera_ = new Esp32Camera(config);
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = false,
|
||||
.i2c_handle = i2c_bus_,
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
camera_->SetHMirror(false);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@ -39,23 +39,23 @@
|
||||
#define DISPLAY_SPI_SCLK_HZ (20 * 1000 * 1000)
|
||||
|
||||
/* Camera pins */
|
||||
#define CAMERA_PIN_PWDN -1
|
||||
#define CAMERA_PIN_RESET -1
|
||||
#define CAMERA_PIN_XCLK 43
|
||||
#define CAMERA_PIN_SIOD -1
|
||||
#define CAMERA_PIN_SIOC -1
|
||||
#define CAMERA_PIN_PWDN GPIO_NUM_NC
|
||||
#define CAMERA_PIN_RESET GPIO_NUM_NC
|
||||
#define CAMERA_PIN_XCLK GPIO_NUM_43
|
||||
#define CAMERA_PIN_SIOD GPIO_NUM_NC
|
||||
#define CAMERA_PIN_SIOC GPIO_NUM_NC
|
||||
|
||||
#define CAMERA_PIN_D7 48
|
||||
#define CAMERA_PIN_D6 47
|
||||
#define CAMERA_PIN_D5 46
|
||||
#define CAMERA_PIN_D4 45
|
||||
#define CAMERA_PIN_D3 39
|
||||
#define CAMERA_PIN_D2 18
|
||||
#define CAMERA_PIN_D1 17
|
||||
#define CAMERA_PIN_D0 2
|
||||
#define CAMERA_PIN_VSYNC 21
|
||||
#define CAMERA_PIN_HREF 1
|
||||
#define CAMERA_PIN_PCLK 44
|
||||
#define CAMERA_PIN_D7 GPIO_NUM_48
|
||||
#define CAMERA_PIN_D6 GPIO_NUM_47
|
||||
#define CAMERA_PIN_D5 GPIO_NUM_46
|
||||
#define CAMERA_PIN_D4 GPIO_NUM_45
|
||||
#define CAMERA_PIN_D3 GPIO_NUM_39
|
||||
#define CAMERA_PIN_D2 GPIO_NUM_18
|
||||
#define CAMERA_PIN_D1 GPIO_NUM_17
|
||||
#define CAMERA_PIN_D0 GPIO_NUM_2
|
||||
#define CAMERA_PIN_VSYNC GPIO_NUM_21
|
||||
#define CAMERA_PIN_HREF GPIO_NUM_1
|
||||
#define CAMERA_PIN_PCLK GPIO_NUM_44
|
||||
|
||||
#define XCLK_FREQ_HZ 20000000
|
||||
|
||||
|
||||
@ -156,35 +156,47 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t config = {};
|
||||
config.ledc_channel = LEDC_CHANNEL_2; // LEDC通道选择 用于生成XCLK时钟 但是S3不用
|
||||
config.ledc_timer = LEDC_TIMER_2; // LEDC timer选择 用于生成XCLK时钟 但是S3不用
|
||||
config.pin_d0 = CAMERA_PIN_D0;
|
||||
config.pin_d1 = CAMERA_PIN_D1;
|
||||
config.pin_d2 = CAMERA_PIN_D2;
|
||||
config.pin_d3 = CAMERA_PIN_D3;
|
||||
config.pin_d4 = CAMERA_PIN_D4;
|
||||
config.pin_d5 = CAMERA_PIN_D5;
|
||||
config.pin_d6 = CAMERA_PIN_D6;
|
||||
config.pin_d7 = CAMERA_PIN_D7;
|
||||
config.pin_xclk = CAMERA_PIN_XCLK;
|
||||
config.pin_pclk = CAMERA_PIN_PCLK;
|
||||
config.pin_vsync = CAMERA_PIN_VSYNC;
|
||||
config.pin_href = CAMERA_PIN_HREF;
|
||||
config.pin_sccb_sda = CAMERA_PIN_SIOD; // 这里如果写-1 表示使用已经初始化的I2C接口
|
||||
config.pin_sccb_scl = CAMERA_PIN_SIOC;
|
||||
config.sccb_i2c_port = 0; // 这里如果写1 默认使用I2C1
|
||||
config.pin_pwdn = CAMERA_PIN_PWDN;
|
||||
config.pin_reset = CAMERA_PIN_RESET;
|
||||
config.xclk_freq_hz = XCLK_FREQ_HZ;
|
||||
config.pixel_format = PIXFORMAT_RGB565;
|
||||
config.frame_size = FRAMESIZE_QVGA;
|
||||
config.jpeg_quality = 12;
|
||||
config.fb_count = 1;
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAMERA_PIN_D0,
|
||||
[1] = CAMERA_PIN_D1,
|
||||
[2] = CAMERA_PIN_D2,
|
||||
[3] = CAMERA_PIN_D3,
|
||||
[4] = CAMERA_PIN_D4,
|
||||
[5] = CAMERA_PIN_D5,
|
||||
[6] = CAMERA_PIN_D6,
|
||||
[7] = CAMERA_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAMERA_PIN_VSYNC,
|
||||
.de_io = CAMERA_PIN_HREF,
|
||||
.pclk_io = CAMERA_PIN_PCLK,
|
||||
.xclk_io = CAMERA_PIN_XCLK,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(config);
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = 0,
|
||||
.scl_pin = CAMERA_PIN_SIOC,
|
||||
.sda_pin = CAMERA_PIN_SIOD,
|
||||
},
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAMERA_PIN_RESET,
|
||||
.pwdn_pin = CAMERA_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = XCLK_FREQ_HZ,
|
||||
};
|
||||
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
camera_->SetVFlip(1);
|
||||
}
|
||||
public:
|
||||
|
||||
@ -177,51 +177,47 @@ private:
|
||||
}
|
||||
|
||||
void InitializeCamera() {
|
||||
camera_config_t config = {};
|
||||
static esp_cam_ctlr_dvp_pin_config_t dvp_pin_config = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
[0] = CAM_PIN_D0,
|
||||
[1] = CAM_PIN_D1,
|
||||
[2] = CAM_PIN_D2,
|
||||
[3] = CAM_PIN_D3,
|
||||
[4] = CAM_PIN_D4,
|
||||
[5] = CAM_PIN_D5,
|
||||
[6] = CAM_PIN_D6,
|
||||
[7] = CAM_PIN_D7,
|
||||
},
|
||||
.vsync_io = CAM_PIN_VSYNC,
|
||||
.de_io = CAM_PIN_HREF,
|
||||
.pclk_io = CAM_PIN_PCLK,
|
||||
.xclk_io = CAM_PIN_XCLK,
|
||||
};
|
||||
|
||||
config.pin_pwdn = CAM_PIN_PWDN;
|
||||
config.pin_reset = CAM_PIN_RESET;
|
||||
config.pin_xclk = CAM_PIN_XCLK;
|
||||
config.pin_sccb_sda = CAM_PIN_SIOD;
|
||||
config.pin_sccb_scl = CAM_PIN_SIOC;
|
||||
config.sccb_i2c_port = I2C_NUM_0;
|
||||
esp_video_init_sccb_config_t sccb_config = {
|
||||
.init_sccb = true,
|
||||
.i2c_config = {
|
||||
.port = I2C_NUM_0,
|
||||
.scl_pin = CAM_PIN_SIOC,
|
||||
.sda_pin = CAM_PIN_SIOD,
|
||||
},
|
||||
.freq = 100000,
|
||||
};
|
||||
|
||||
config.pin_d7 = CAM_PIN_D7;
|
||||
config.pin_d6 = CAM_PIN_D6;
|
||||
config.pin_d5 = CAM_PIN_D5;
|
||||
config.pin_d4 = CAM_PIN_D4;
|
||||
config.pin_d3 = CAM_PIN_D3;
|
||||
config.pin_d2 = CAM_PIN_D2;
|
||||
config.pin_d1 = CAM_PIN_D1;
|
||||
config.pin_d0 = CAM_PIN_D0;
|
||||
config.pin_vsync = CAM_PIN_VSYNC;
|
||||
config.pin_href = CAM_PIN_HREF;
|
||||
config.pin_pclk = CAM_PIN_PCLK;
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = sccb_config,
|
||||
.reset_pin = CAM_PIN_RESET,
|
||||
.pwdn_pin = CAM_PIN_PWDN,
|
||||
.dvp_pin = dvp_pin_config,
|
||||
.xclk_freq = 10000000,
|
||||
};
|
||||
|
||||
/* XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) */
|
||||
config.xclk_freq_hz = 10000000;
|
||||
config.ledc_timer = LEDC_TIMER_1;
|
||||
config.ledc_channel = LEDC_CHANNEL_0;
|
||||
esp_video_init_config_t video_config = {
|
||||
.dvp = &dvp_config,
|
||||
};
|
||||
|
||||
config.pixel_format = PIXFORMAT_RGB565; /* YUV422,GRAYSCALE,RGB565,JPEG */
|
||||
config.frame_size = FRAMESIZE_240X240; /* QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates */
|
||||
|
||||
config.jpeg_quality = 12; /* 0-63, for OV series camera sensors, lower number means higher quality */
|
||||
config.fb_count = 2; /* When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode */
|
||||
config.fb_location = CAMERA_FB_IN_PSRAM;
|
||||
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||
|
||||
esp_err_t err = esp_camera_init(&config); // 测试相机是否存在
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Camera is not plugged in or not supported, error: %s", esp_err_to_name(err));
|
||||
// 如果摄像头初始化失败,设置 camera_ 为 nullptr
|
||||
camera_ = nullptr;
|
||||
return;
|
||||
}else
|
||||
{
|
||||
esp_camera_deinit();// 释放之前的摄像头资源,为正确初始化做准备
|
||||
camera_ = new Esp32Camera(config);
|
||||
}
|
||||
camera_ = new Esp32Camera(video_config);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user