Files
ESP32S3_vt/components/esp32-camera/sensors/ov5640_af.c
T
Horldsence 4f893ce140 ESP32-S3 摄像头图传:固件 + Slint 客户端 + 共享协议
两块 ESP32-S3-WROOM-1-N16R8 图传板(DVP 接口接 OV2640/OV3660/OV5640),
向队伍客户端与裁判终端推 UDP 图传。固件是跑在 ESP-IDF 上的 Rust,用官方
esp32-camera 组件采集;客户端是 Rust + Slint 桌面程序。

三个 crate 各自独立构建:
  .            firmware,交叉编译到 Xtensa
  protocol/    线路格式与帧重组,两端共用,无 ESP-IDF 依赖,有单元测试
  client/      Slint 桌面客户端

视频走 UDP 而非 TCP:实测传感器产出 22 fps,TCP MJPEG 只送出 1.9 fps,
且只占用链路能力的 1%——链路是空的,帧堵在队头阻塞后面等一个实时画面
等不起的重传计时器。改为独立数据报、不重传、缺片丢整帧后达到 20.8 fps。

发现是双向的:板子每 2 秒广播 Hello,客户端广播 Subscribe,板子据此定向
推流。板子身份由 MAC 派生,重启不变,所以客户端可以把绑定存进配置。

裁判端同时收两块板子(每个发送方一个重组器),队伍端绑定其中一块并只显示
自己那一边的血量。装甲板接口已预留(ArmorSource trait + ARMOR_PORT),
当前无数据源,界面显示占位符。

vendor 了 esp32-camera 2.1.7:组件注册表的版本求解器找不到它,且需要打一处
补丁(见 components/esp32-camera/target/esp32s3/ll_cam.c)。

.gitignore 三条 target/ 都锚定在根目录,因为 protocol/ 与 client/ 各自也是
独立 crate;而 components/esp32-camera/target/ 是上游的按芯片分目录,里面是
源码,必须保留。
2026-10-05 18:22:19 +08:00

242 lines
6.1 KiB
C

/*
* OV5640 Autofocus Implementation
*
* This file contains the sensor-specific autofocus implementation for OV5640.
*/
#include "sdkconfig.h"
#if defined(CONFIG_CAMERA_AF_SUPPORT) && CONFIG_CAMERA_AF_SUPPORT
#if defined(CONFIG_OV5640_SUPPORT) && CONFIG_OV5640_SUPPORT
#include "ov5640.h"
#include "ov5640_af_firmware.h"
#include "sensor.h"
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_timer.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#define TAG ""
#else
#include "esp_log.h"
static const char *TAG = "ov5640_af";
#endif
// OV5640 AF registers
#define OV5640_CMD_MAIN 0x3022
#define OV5640_CMD_ACK 0x3023
#define OV5640_CMD_PARA0 0x3024
#define OV5640_CMD_PARA1 0x3025
#define OV5640_CMD_PARA2 0x3026
#define OV5640_CMD_PARA3 0x3027
#define OV5640_CMD_PARA4 0x3028
#define OV5640_CMD_FW_STATUS 0x3029
#define OV5640_AF_TRIG_SINGLE 0x03
#define OV5640_AF_CONTINUOUS 0x04
#define OV5640_FW_STATUS_IDLE 0x70
#define OV5640_FW_STATUS_FOCUSED 0x10
static esp_err_t ov5640_reg_write(sensor_t *sensor, int reg, int value)
{
if (sensor->set_reg(sensor, reg, 0xff, value) < 0) {
return ESP_FAIL;
}
return ESP_OK;
}
static esp_err_t ov5640_reg_read(sensor_t *sensor, int reg, int *out_value)
{
int v = sensor->get_reg(sensor, reg, 0xff);
if (v < 0) {
return ESP_FAIL;
}
*out_value = v;
return ESP_OK;
}
static esp_err_t ov5640_af_wait_ack_clear(sensor_t *sensor, uint32_t timeout_ms)
{
const uint64_t start = esp_timer_get_time();
while (true) {
int ack = 0;
if (ov5640_reg_read(sensor, OV5640_CMD_ACK, &ack) != ESP_OK) {
return ESP_FAIL;
}
if (ack == 0x00) {
return ESP_OK;
}
if (timeout_ms && ((esp_timer_get_time() - start) / 1000ULL) > timeout_ms) {
return ESP_ERR_TIMEOUT;
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}
static esp_err_t ov5640_af_wait_fw_idle(sensor_t *sensor, uint32_t timeout_ms)
{
const uint64_t start = esp_timer_get_time();
while (true) {
int st = 0;
if (ov5640_reg_read(sensor, OV5640_CMD_FW_STATUS, &st) != ESP_OK) {
return ESP_FAIL;
}
if ((uint8_t)st == OV5640_FW_STATUS_IDLE) {
return ESP_OK;
}
if (timeout_ms && ((esp_timer_get_time() - start) / 1000ULL) > timeout_ms) {
return ESP_ERR_TIMEOUT;
}
vTaskDelay(pdMS_TO_TICKS(5));
}
}
static esp_err_t ov5640_af_firmware_load(sensor_t *sensor, uint32_t timeout_ms)
{
esp_err_t ret = ov5640_reg_write(sensor, 0x3000, 0x20); // reset MCU
if (ret != ESP_OK) {
return ret;
}
uint16_t addr = 0x8000;
for (size_t i = 0; i < sizeof(ov5640_af_firmware); i++) {
ret = ov5640_reg_write(sensor, addr, ov5640_af_firmware[i]);
if (ret != ESP_OK) {
return ret;
}
addr++;
}
(void)ov5640_reg_write(sensor, OV5640_CMD_MAIN, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_ACK, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA0, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA1, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA2, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA3, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_PARA4, 0x00);
(void)ov5640_reg_write(sensor, OV5640_CMD_FW_STATUS, 0x7f);
(void)ov5640_reg_write(sensor, 0x3000, 0x00); // start MCU
return ov5640_af_wait_fw_idle(sensor, timeout_ms);
}
static esp_err_t ov5640_af_start(sensor_t *sensor, bool continuous, uint32_t timeout_ms)
{
esp_err_t ret = ov5640_reg_write(sensor, OV5640_CMD_MAIN, 0x01);
if (ret != ESP_OK) {
return ret;
}
ret = ov5640_reg_write(sensor, OV5640_CMD_MAIN, 0x08);
if (ret != ESP_OK) {
return ret;
}
ret = ov5640_af_wait_ack_clear(sensor, timeout_ms);
if (ret != ESP_OK) {
return ret;
}
ret = ov5640_reg_write(sensor, OV5640_CMD_ACK, 0x01);
if (ret != ESP_OK) {
return ret;
}
ret = ov5640_reg_write(sensor, OV5640_CMD_MAIN, continuous ? OV5640_AF_CONTINUOUS : OV5640_AF_TRIG_SINGLE);
if (ret != ESP_OK) {
return ret;
}
return ov5640_af_wait_ack_clear(sensor, timeout_ms);
}
// Sensor function pointer implementations
int ov5640_af_is_supported(sensor_t *sensor)
{
(void)sensor;
return 1; // OV5640 always supports AF
}
int ov5640_af_init(sensor_t *sensor, uint32_t timeout_ms)
{
if (!sensor) {
return -1;
}
esp_err_t ret = ov5640_af_firmware_load(sensor, timeout_ms);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "AF firmware init failed: %s", esp_err_to_name(ret));
return -1;
}
return 0;
}
int ov5640_af_set_mode(sensor_t *sensor, int mode)
{
if (!sensor) {
return -1;
}
esp_err_t ret;
switch (mode) {
case 0: // ESP_CAMERA_AF_MODE_AUTO
ret = ov5640_af_start(sensor, true, 2000);
break;
case 1: // ESP_CAMERA_AF_MODE_MANUAL
ret = ov5640_reg_write(sensor, OV5640_CMD_MAIN, 0x00);
break;
default:
return -1;
}
return (ret == ESP_OK) ? 0 : -1;
}
int ov5640_af_trigger(sensor_t *sensor)
{
if (!sensor) {
return -1;
}
esp_err_t ret = ov5640_af_start(sensor, false, 2000);
return (ret == ESP_OK) ? 0 : -1;
}
int ov5640_af_get_status(sensor_t *sensor, uint8_t *out_raw, bool *out_focused, bool *out_busy)
{
if (!sensor || !out_raw || !out_focused || !out_busy) {
return -1;
}
int st = 0;
esp_err_t ret = ov5640_reg_read(sensor, OV5640_CMD_FW_STATUS, &st);
if (ret != ESP_OK) {
return -1;
}
*out_raw = (uint8_t)st;
*out_focused = ((uint8_t)st == OV5640_FW_STATUS_FOCUSED);
*out_busy = !(((uint8_t)st == OV5640_FW_STATUS_IDLE) || *out_focused);
return 0;
}
int ov5640_af_set_manual_position(sensor_t *sensor, uint16_t position)
{
(void)sensor;
(void)position;
// Manual lens position is not exposed safely in this driver yet.
return -1;
}
#endif // CONFIG_OV5640_SUPPORT
#endif // CONFIG_CAMERA_AF_SUPPORT