这篇文章讲一下如何点亮一个新的sensor,以在RK3588平台,点亮IMX577为例。
目录
(2)SENSOR_TYPE_RAW和SENSOR_TYPE_SOC
①sensor的chipID可以通过i2c正确读取到,也就是i2c可以正常通信;
②使用media-ctl工具可以看到pipeline,可以看到sensor具体的分辨率和格式;
③使用V4L2工具抓图没有报错,有正常的数据输出,且使用V4L2的命令可以实现曝光增益等的控制,即可认为驱动没问题;
④xml配置SOC模式下,使用apk可以预览出图(图像可能会偏暗偏绿,后续再讲xml如何配置),到这一步可认为HAL没问题;
⑤自行移植其他sensor的效果文件,可以出图(图像效果可能会有异常,后续再讲如何初步修改效果文件),到这一步接下去就可以开始sensor的效果调试,如果需要找RK调试效果,也必须进行到这一步。
这是配置给cameraHAL,确认sensor是什么类型。
SENSOR_TYPE_RAW:一般是RAWRGB的sensor,需要turnning 3A效果才能正常出图,需要正确的效果文件路径,才可以使用;
SENSOR_TYPE_SOC:一般是输出YUV或者RGB888/RGB565之类的sensor,不需要跑3A效果,一般用于自带ISP的sensor,不需要效果文件就可以使用;
一般调试RAW sensor过程中,如果使用V4L2已经可以抓图,那么可以先将sensor配置成SENSOR_TYPE_SOC模式,确认不跑3A情况下是否可以出图。
sensor的驱动位于drivers/media/i2c下,sensor驱动和RKCIF、RKISP控制器的驱动独立,二者异步注册,通过v4l2和media-framework框架,将pipeline连接。这里主要介绍一下sensor驱动的代码,dts配置等。sensor驱动主要分为几个部分:
在supported_modes来定义不同的初始化mode,主要配置分辨率、图像格式、帧率、寄存器初始化列表等等,寄存器初始化列表,可直接按照厂家提供的填写。hts_def和vts_def可直接按照寄存器初始化列表填入值即可,exp_def可以看下datesheet是否有默认值,或者一般填写比vts略小。
static const struct imx577_mode supported_modes[] = {
{
.width = 4056,
.height = 3040,
.max_fps = {
.numerator = 10000,
.denominator = 300000,
},
.exp_def = 0x0c10,
.hts_def = 0x2318,
.vts_def = 0x0c2c,
.bpp = 10,
.bus_fmt = MEDIA_BUS_FMT_SRGGB10_1X10,
.reg_list = imx577_linear_10bit_4056x3040_30fps_regs,
.hdr_mode = NO_HDR,
.link_freq_idx = 1,
.vc[PAD0] = V4L2_MBUS_CSI2_CHANNEL_0,
},
不同的sensor上电时序不同,有的sensor对时序要求不严格,有的sensor则需要严格按照时序进行上电,否则可能会出现i2c不通的现象。
sensor的datasheet一般都有上电时序图,驱动代码中,按照时序配置即可,imx577上电时序如下,同样的,下电时序也需要按照datasheet描述实现。
static int __imx577_power_on(struct imx577 *imx577)
{
int ret;
u32 delay_us;
struct device *dev = &imx577->client->dev;
if (!IS_ERR(imx577->power_gpio))
gpiod_set_value_cansleep(imx577->power_gpio, 1);
usleep_range(1000, 2000);
if (!IS_ERR_OR_NULL(imx577->pins_default)) {
ret = pinctrl_select_state(imx577->pinctrl,
imx577->pins_default);
if (ret < 0)
dev_err(dev, "could not set pins\n");
}
ret = clk_set_rate(imx577->xvclk, IMX577_XVCLK_FREQ);
if (ret < 0)
dev_warn(dev, "Failed to set xvclk rate (24MHz)\n");
if (clk_get_rate(imx577->xvclk) != IMX577_XVCLK_FREQ)
dev_warn(dev, "xvclk mismatched, modes are based on 24MHz\n");
ret = clk_prepare_enable(imx577->xvclk);
if (ret < 0) {
dev_err(dev, "Failed to enable xvclk\n");
return ret;
}
if (!IS_ERR(imx577->reset_gpio))
gpiod_set_value_cansleep(imx577->reset_gpio, 0);
ret = regulator_bulk_enable(IMX577_NUM_SUPPLIES, imx577->supplies);
if (ret < 0) {
dev_err(dev, "Failed to enable regulators\n");
goto disable_clk;
}
if (!IS_ERR(imx577->reset_gpio))
gpiod_set_value_cansleep(imx577->reset_gpio, 1);
usleep_range(500, 1000);
if (!IS_ERR(imx577->pwdn_gpio))
gpiod_set_value_cansleep(imx577->pwdn_gpio, 1);
/* 8192 cycles prior to first SCCB transaction */
delay_us = imx577_cal_delay(8192);
usleep_range(delay_us, delay_us * 2);
return 0;
disable_clk:
clk_disable_unprepare(imx577->xvclk);
return ret;
}
v4l2_subdev_ops是框架控制sensor驱动的核心,这里介绍一下几个必不可少的回调函数:
.s_power,上下电函数,camera上下电的时候会调用这个地方。一般会用到pm_rntime来管理。
.ioctl,提供ioctl的接口。
s_stream,开关数据流的接口,包括stream on和stream off
.enum_mbus_code,枚举驱动支持的图像格式。
.enum_frame_size,枚举驱动支持的分辨率
.enum_frame_interval,这里除了反馈驱动支持的格式分辨率帧率以外,还有HDR模式的时候,也需要通过fie->reserved[0]成员进行反馈。
.get_fmt,获取sensor当前的format
.set_fmt,设置sensor的format
.get_selection,获取裁减信息
.get_mbus_config,获取bus配置,包括mipi/dvp接口,lane数,极性等等。
一般raw sensor需要控制exposure、gain、vblank等等,所以需要实现对应的接口函数
在驱动注册的函数中,除了对dts的解析,获取时钟电源等等,比较重要的是media entity、V4L2 subdev的注册。关键点如下:
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi_in_ucam0: endpoint@1 {
reg = <1>;
remote-endpoint = <&imx577_out0>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi2_csi2_input>;
data-lanes = <1 2 3 4>;
};
};
};
};
&i2c3 {
status = "okay";
pinctrl-0 = <&i2c3m0_xfer>;
imx577: imx577@1a {
compatible = "sony,imx577";
reg = <0x1a>;
clocks = <&cru CLK_MIPI_CAMARAOUT_M3>;
clock-names = "xvclk";
pinctrl-names = "default";
pinctrl-0 = <&mipim0_camera3_clk>;
power-domains = <&power RK3588_PD_VI>;
pwdn-gpios = <&gpio1 RK_PB3 GPIO_ACTIVE_HIGH>;
// reset-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>;
// power-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>;
avdd-supply = <&vcc_mipicsi0>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "default";
rockchip,camera-module-lens-name = "default";
port {
imx577_out0: endpoint {
remote-endpoint = <&mipi_in_ucam0>;
data-lanes = <1 2 3 4>;
};
};
};
};
&csi2_dphy0_hw {
status = "okay";
};
&mipi2_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi2_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidphy0_out>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi2_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi_in2>;
data-lanes = <1 2 3 4>;
};
};
};
};
&rkcif {
status = "okay";
};
&rkcif_mipi_lvds2 {
status = "okay";
port {
cif_mipi_in2: endpoint {
remote-endpoint = <&mipi2_csi2_output>;
};
};
};
&rkcif_mipi_lvds2_sditf {
status = "okay";
port {
mipi_lvds2_sditf: endpoint {
remote-endpoint = <&isp0_vir0>;
};
};
};
&rkcif_mmu {
status = "okay";
};
&rkisp0 {
status = "okay";
};
&isp0_mmu {
status = "okay";
};
&rkisp0_vir0 {
status = "okay";
// rockchip,hw = <&rkisp_unite>;
port {
#address-cells = <1>;
#size-cells = <0>;
isp0_vir0: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi_lvds2_sditf>;
};
};
};
dts的配置主要是pipeline的配置,可参考RK官方的描述,7路camera对应的配置如下:

sensor的驱动调试主要有以下关键点:
①移植sensor驱动:参考上述的介绍进行驱动代码的移植;
②根据使用的mipi接口来配置对应的dts,rk3588支持多个camera,因此这个步骤必须正确;
③确认i2c是否通讯成功,i2c通信成功才能正确设置sensor的寄存器;
④media-ctl 工具查看拓扑结构是否正常
⑤使用V4L2抓取图像,设置exp、gain等参数可以生效。
驱动调试完毕,还需要再HAL注册sensor,才能使用apk点亮。HAL获取sensor是通过解析xml文件的,对应设备的/vendor/etc/camera/camera3_profiles.xml,对应SDK代码的SDK/hardware/rockchip/camera/etc/camera/camera3_profiles_rk3588.xml。
①初步点亮的时候,可以先复制其他sensor的配置,修改name参数,对应驱动代码的中的名字,必须一致;
②修改moduleID参数,该参数对应dts的index,必须一致否则无法注册;
③修改添加该sensor对应的分辨率帧率等。
④dumpsys media.camera命令可以查看是否成功注册sensor,如果没有注册上,一般是xml配置错误,检查name和moduleID这两个属性。
⑤初步调试,还没效果文件,可以先设置SOC模式进行点亮,turnning完毕之后改成RAW模式。
总结一下,一个camera的初步点亮,主要就是驱动、HAL配置完成,即可使用apk预览。后面再详细说一下i2c通信失败排查、常用的调试手段、XML文件的配置解释以及常见的调试问题分析。
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
Rackup通过Rack的默认处理程序成功运行任何Rack应用程序。例如:classRackAppdefcall(environment)['200',{'Content-Type'=>'text/html'},["Helloworld"]]endendrunRackApp.new但是当最后一行更改为使用Rack的内置CGI处理程序时,rackup给出“NoMethodErrorat/undefinedmethod`call'fornil:NilClass”:Rack::Handler::CGI.runRackApp.newRack的其他内置处理程序也提出了同样的反对意见。例如Rack
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何
我想要做的是有2个不同的Controller,client和test_client。客户端Controller已经构建,我想创建一个test_clientController,我可以使用它来玩弄客户端的UI并根据需要进行调整。我主要是想绕过我在客户端中内置的验证及其对加载数据的管理Controller的依赖。所以我希望test_clientController加载示例数据集,然后呈现客户端Controller的索引View,以便我可以调整客户端UI。就是这样。我在test_clients索引方法中试过这个:classTestClientdefindexrender:template=>