乐鑫官方ESP-WHO解决方案移植
无论是Arduino还是MicroPython,封装好的库极大地方便了开发者的开发流程,但是对于没有得到支持的部分,就需要开发者自己阅读官方提供的源码并对其进行修改来适配对应的场景。
1.1 ESP-WHO简介
ESP-WHO 是基于乐鑫芯片的图像处理开发平台,其中包含了实际应用中可能出现的开发示例。ESP-WHO 提供了例如人脸检测、人脸识别、猫脸检测和手势识别等示例。您可以基于这些示例,衍生出丰富的实际应用。ESP-WHO 的运行基于 ESP-IDF。[ESP-DL](https://github.com/espressif/esp-dl) 为 ESP-WHO 提供了丰富的深度学习相关接口,配合各种外设可以实现许多有趣的应用。
1.2 驱动接口适配
官方提供的样例都是基于特定开发板实现的,其中没有对FireBeetle2 S3这款开发板进行适配,这时就需要我们修改代码来适配我们的工程。首先,需要根据我们的硬件来修改相应的底层驱动代码,这样示例程序才能正确的驱动外设来执行程序。
1.2.1 电源管理芯片程序移植
通过查看ESP-WHO中的who camera程序,其中是没有电源驱动的程序的,而FireBeetle2 S3的摄像头供电使用电源管理芯片来控制的,所以在使用摄像头之前需要对电源进行配置。DFRobot_AXP313A的驱动库中有对ESP-IDF的驱动程序,对其进行修改后就可以驱动电源管理芯片给摄像头供电。
将驱动库中的DFRobot_AXP313A.c和DFRobot_AXP313A.h放置到ESP-WHO仓库的\components\modules\camera目录下。
头文件和源文件的代码如下
#ifndef _DFROBOT_AXP313A_H_
#define _DFROBOT_AXP313A_H_
#include "stdio.h"
#include "driver/i2c.h"
#define OV2640 0
#define OV7725 1
#define TIME6S 0
#define TIME10S 0
extern i2c_port_t _i2c_num;
extern uint8_t _addr;
void begin(i2c_port_t i2c_num, uint8_t addr);
void enableCameraPower(uint8_t camera);
void disablePower(void);
void setShutdownKeyLevelTime(uint8_t offLevelTime);
void setCameraPower(float DVDD, float AVDDorDOVDD);
esp_err_t i2c_master_init(void);
#endif
#include "DFRobot_AXP313A.h"
i2c_port_t _i2c_num = 0;
uint8_t _addr = 0x36;
static esp_err_t __attribute__((unused)) i2cWriteData(i2c_port_t i2c_num, uint8_t *data_wr, size_t size)
{
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (_addr << 1) | I2C_MASTER_WRITE, 0x1);
i2c_master_write(cmd, data_wr, size, 0x1);
i2c_master_stop(cmd);
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
i2c_cmd_link_delete(cmd);
return ret;
}
void begin(i2c_port_t i2c_num, uint8_t addr)
{
_i2c_num = i2c_num;
_addr = addr;
uint8_t data[2];
data[0] = 0x00;
data[1] = 0x04;
int ret = i2cWriteData(_i2c_num, data, 2);
vTaskDelay(100);
}
void setCameraPower(float DVDD, float AVDDorDOVDD)
{
uint8_t ALDOData = 0;
uint8_t DLDOData = 0;
uint8_t state = 0x19;
uint8_t data[2];
if (DVDD < 0.5 || AVDDorDOVDD < 0.5)
{
ALDOData = 0;
DLDOData = 0;
}
else if (DVDD > 3.5 || AVDDorDOVDD > 3.5)
{
ALDOData = 31;
DLDOData = 31;
}
else
{
ALDOData = (DVDD - 0.5) * 10;
DLDOData = (AVDDorDOVDD - 0.5) * 10;
}
data[0] = 0x10;
data[1] = state;
i2cWriteData(_i2c_num, data, 2);
vTaskDelay(100);
data[0] = 0x16;
data[1] = ALDOData;
i2cWriteData(_i2c_num, data, 2);
vTaskDelay(100);
data[0] = 0x17;
data[1] = DLDOData;
i2cWriteData(_i2c_num, data, 2);
vTaskDelay(100);
}
void disablePower(void)
{
uint8_t data[2];
data[0] = 0x10;
data[1] = 0x01;
i2cWriteData(_i2c_num, data, 2);
vTaskDelay(100);
}
void enableCameraPower(uint8_t camera)
{
if (camera == 0)
{
setCameraPower(1.2, 2.8);
}
else
{
setCameraPower(1.8, 3.3);
}
}
void setShutdownKeyLevelTime(uint8_t offLevelTime)
{
uint8_t data[2];
data[0] = 0x1E;
data[1] = offLevelTime << 1;
i2cWriteData(_i2c_num, data, 2);
vTaskDelay(100);
}
esp_err_t i2c_master_init(void)
{
int i2c_master_port = 0;
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = 1,
.scl_io_num = 2,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 400000,
};
i2c_param_config(i2c_master_port, &conf);
return i2c_driver_install(i2c_master_port, conf.mode, 0, 0, 0);
}
另外在同一目录的who_camera.c中的register_camera函数中添加电源管理芯片的操作。用于给摄像头供电。
void register_camera(const pixformat_t pixel_fromat,
const framesize_t frame_size,
const uint8_t fb_count,
const QueueHandle_t frame_o)
{
......
i2c_master_init();
begin(_i2c_num, _addr);
enableCameraPower(OV2640);
......
}
1.2.2 摄像头驱动程序移植
由于摄像头的引脚和ESP32 S3之间的连接是根据开发板而定的,所以也需要对代码进行修改来适配开发板。
在乐鑫官方提供的menuconfig中可以对自定义的开发板的摄像头引脚进行指定。在命令中输入idf menuconfig 进入配置界面,但是这里有一个问题,有的引脚限制了IO序号的范围,导致有的引脚无法配置。这里需要对KConfig文件(该文件位于\components\modules下)进行修改来保证选择指定的引脚,修改方式也很简单,只要修改对应项的取值范围即可,示例如下:
config CAMERA_PIN_XCLK
depends on CAMERA_MODULE_CUSTOM
int "XCLK pin"
range 0 48
default 21
help
Select Camera XCLK pin.
按照IO管脚的分配图,在对应的配置项中选择相应的管脚,即可完成摄像头的驱动配置。另外,在Wifi 配置项中填写相应的账号和密码信息。
在命令行中输入idf flash monitor
即可完成对开发板的固件烧写。
示例程序的运行如下所示,与Ardinuo中给出的示例程序的运行效果类似,但是不如其流畅,这里就需要调试来解决问题。
1.2.3 Bug修改
通过串口监视可以确定任务who_camera中出现了堆栈溢出的问题,为了解决这一问题,我们需要修改分配给该任务的内存大小,
原始示例代码中,register_camera函数
中分配给该任务的堆栈大小为4K,重新分配其大小为16K,则可以使任务顺利运行。