AI-Talk开发板之Camera
一、说明
AI-Talk开发板配备了一只DVP摄像头,型号GC0328,像素30万。
1、接口
2、与处理器的信号连接
使用i2c1接口。
二、工程
1、测试代码
使用duomotai_ap sdk中的例程进行测试。
2、设备树
设备树文件路径:duomotai_ap/.sdk/csk/boards/arm/csk6011a_box_lite/csk6011a_box_lite.dts
在i2c1节点下添加gc0328的配置
gc0328: gc0328@21 {compatible = "galaxyc,gc0328";status = "okay";reg = <0x21>;reset-gpios = <&exgpioa 1 1>;pwdn-gpios = <&exgpioc 7 0>;
};
3、驱动
驱动文件路径:duomotai_ap/.sdk/csk/drivers/video/gc0328.c。
内核加载驱动后,首先执行gc0328_init()函数,启动函数会设置pwdn_gpios和reset_gpios的状态,代码如下:
static int gc0328_init(const struct device *dev)
{LOG_INF("Galaxyc GC0328 init");struct gc0328_data *drv_data = dev->data;int ret = 0;if (drv_data->pwdn_gpios.port) {gpio_pin_configure_dt(&drv_data->pwdn_gpios, GPIO_OUTPUT_ACTIVE);gpio_pin_set_dt(&drv_data->pwdn_gpios, 0);}if (drv_data->reset_gpios.port) {gpio_pin_configure_dt(&drv_data->reset_gpios, GPIO_OUTPUT_ACTIVE);gpio_pin_set_dt(&drv_data->reset_gpios, 0);k_sleep(K_MSEC(3));gpio_pin_set_dt(&drv_data->reset_gpios, 1);k_sleep(K_MSEC(1));}// ret = gc0328_reg_init(dev);return ret;
}
如果pwdn_gpios和reset_gpios使用的是exmcu的管脚,那可能不会成功,根据启动日志可以看出,内核会先加载gc0328的驱动,再加载exmcu的驱动,那么加载gc0328的驱动时,exmcu还无法操作。
由于内核加载gc0328的驱动时,csk6011a还未输出mclk,所以没有在gc0328_init()中执行gc0328_reg_init(dev)函数,而是应用启动之后调用gc0328_set_ctrl()函数初始化sensor。
static int gc0328_set_ctrl(const struct device *dev, unsigned int cid, void *value)
{LOG_DBG("gc0328 set ctrl %d", cid);int ret = 0;switch (cid) {case VIDEO_CID_HFLIP:ret = gc0328_set_horizontal_mirror(dev, *(int *)value);break;case VIDEO_CID_VFLIP:ret = gc0328_set_vertical_flip(dev, *(int *)value);break;/*该sensor只有在mclk有输入时钟的情况下,i2c才能正常通信,所以并不能在内核设备初始化流程中进行sensor初始化。目前是通过set_ctrl来提供sensor初始化的api.*/case VIDEO_CID_INIT:k_sleep(K_MSEC(10));ret = gc0328_reg_init(dev);break;default:return -ENOTSUP;}return ret;
}
三、调试
1、启动日志
[00:00:00.000,000] [<inf> gc0328: Galaxyc GC0328 init[00:00:00.050,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.100,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.150,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.200,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.251,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.301,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.351,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.401,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.454,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.504,000] [1;31m<err> i2c_csk: Wait I2C complete time out.[0m
[00:00:00.505,000] [0m<inf> csk6_spi: SPI REG ADDR:0x45500000[0m
[00:00:00.506,000] [0m<inf> csk6_spi: SPI REG ADDR:0x45400000[0m
[00:00:00.506,000] [0m<inf> csk6_exmcu_i2c: exmcu addr:0x6C[0m
[00:00:00.546,000] [0m<inf> csk6_exmcu_i2c: exmcu info, chip type:ch32v003, ver:1.3
[00:00:00.546,000] [0m<inf> pwm_csk_ch32v003: pwm csk ch32v003 init, freq:48000000, pres:480
[00:00:00.546,000] [0m<inf> display_st7789v: st7789v_init
[00:00:00.567,000] [0m<dbg> display_st7789v: st7789v_reset_display: Resetting display[0m[00:00:00.726,000] [0m<inf> display_st7789v: st7789v_init done
m<inf> csk6_dvp: sensor dev gc0328@21
[00:00:00.736,000] [0m<inf> gc0328: Galaxyc GC0328 init successful, pid 0x9D
2、分析日志
内核启动后会先初始化gc0328,但不成功,有两种原因。
一是此时由于csk6011a还未产生mclk,导致gc0328没有启动,所以i2c通信失败。
二是由于reset和pwdn是接在exmcu上的,此时还没加载exmcu的驱动,无法将reset和pwdn设置到正确的状态,gc0328可能处于复位或关机状态。
四、修改驱动
1、修改gc0328_init()函数
如果pwdn_gpios和reset_gpios使用的是exmcu的引脚,这里设置状态也无效,所以屏蔽函数里面所有的代码:
static int gc0328_init(const struct device *dev)
{LOG_INF("Galaxyc GC0328 init null");
/* struct gc0328_data *drv_data = dev->data;int ret = 0;if (drv_data->pwdn_gpios.port) {gpio_pin_configure_dt(&drv_data->pwdn_gpios, GPIO_OUTPUT_ACTIVE);gpio_pin_set_dt(&drv_data->pwdn_gpios, 0);}if (drv_data->reset_gpios.port) {gpio_pin_configure_dt(&drv_data->reset_gpios, GPIO_OUTPUT_ACTIVE);gpio_pin_set_dt(&drv_data->reset_gpios, 0);k_sleep(K_MSEC(3));gpio_pin_set_dt(&drv_data->reset_gpios, 1);k_sleep(K_MSEC(1));}
*/// ret = gc0328_reg_init(dev);//return ret;return 0;
}
2、修改gc0328_set_ctrl()函数
在代码“case VIDEO_CID_INIT:”之后设置pwdn_gpios和reset_gpios状态的代码,修改之后代码如下:
case VIDEO_CID_INIT:struct gc0328_data *drv_data = dev->data;if (drv_data->pwdn_gpios.port) {gpio_pin_configure_dt(&drv_data->pwdn_gpios, GPIO_OUTPUT_ACTIVE);gpio_pin_set_dt(&drv_data->pwdn_gpios, 0);}if (drv_data->reset_gpios.port) {gpio_pin_configure_dt(&drv_data->reset_gpios, GPIO_OUTPUT_ACTIVE);gpio_pin_set_dt(&drv_data->reset_gpios, 0);k_sleep(K_MSEC(3));gpio_pin_set_dt(&drv_data->reset_gpios, 1);k_sleep(K_MSEC(1));}k_sleep(K_MSEC(10));ret = gc0328_reg_init(dev);break;
如果pwdn_gpios和reset_gpios使用的是exmcu的引脚,这样才能将pwdn_gpios和reset_gpios设置到正确的状态。