Hi, 6by9,
Thank you for your reply.
I copied some driver source code and overlay files.
then, I made "test_sensor.c" for driver, and "test_sensor.dts" for overlay.
I confirmed my driver can communicate with sensor via I2C, but I couldn't get any streams.
just I wanna get raw data from sensor.
What functions I need to implement?
Here's my code.The I2C address of my sensor is 0x2a.
The process I followed is in below.
1. compile "test_sensor.dts" to "test_sensor.dtbo" and locate it in "/boot/firmware/overlay/test_sensor.dtbo"
2. modify "/boot/firmware/config.txt" for overlay3. compile `test_sensor.c` to `test_sensor.ko` and insmod it
I tried some commands to get stream.
First, I set sensor's resolution and pixel format.
v4l2-ctl -v width=1024,height=1024,pixelformat=Y10P
Then, I tried some commands.
libcamera-hello
v4l2-ctl --stream-mmap=3 --stream-count=1000 --stream-to=test.rawIs there any lists of functions that driver need to implement?
I've found sensor driver requirements by libcamera.
https://github.com/raspberrypi/libcamer ... ements.rst
Thanks,
Thank you for your reply.
I copied some driver source code and overlay files.
then, I made "test_sensor.c" for driver, and "test_sensor.dts" for overlay.
I confirmed my driver can communicate with sensor via I2C, but I couldn't get any streams.
just I wanna get raw data from sensor.
What functions I need to implement?
Here's my code.
Code:
#include <asm/unaligned.h>#include <linux/clk-provider.h>#include <linux/clk.h>#include <linux/clkdev.h>#include <linux/delay.h>#include <linux/gpio/consumer.h>#include <linux/i2c.h>#include <linux/module.h>#include <linux/pm_runtime.h>#include <linux/regulator/consumer.h>#include <media/v4l2-ctrls.h>#include <media/v4l2-device.h>#include <media/v4l2-event.h>#include <media/v4l2-fwnode.h>#include <media/v4l2-mediabus.h>// #include <time.h>#define WIDTH 1024#define HEIGHT 1024struct s_test_sensor { struct v4l2_subdev sd; struct media_pad pad; struct v4l2_mbus_framefmt format; struct mutex mutex;};static int test_sensor_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, fh->state, 0); try_fmt->width = WIDTH; try_fmt->height = HEIGHT; try_fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; try_fmt->field = V4L2_FIELD_NONE; return 0;}static void test_sensor_set_default_format(struct s_test_sensor *test_sensor) { struct v4l2_mbus_framefmt *fmt = &test_sensor->format; fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->colorspace = V4L2_COLORSPACE_RAW; fmt->width = WIDTH; fmt->height = HEIGHT; fmt->field = V4L2_FIELD_NONE;}static inline struct s_test_sensor *to_test_sensor(struct v4l2_subdev *sd) { return container_of(sd, struct s_test_sensor, sd);}static int test_sensor_start_stream(struct v4l2_subdev *sd, int is_on) { struct s_test_sensor *test_sensor = to_test_sensor(sd); // MEAS_START register is located in 0x0100 unsigned char send_data[2] = {0x01, 0x00}; // get i2c_client object struct i2c_client *client = v4l2_get_subdevdata(&test_sensor->sd); if (client == NULL) { return -1; } // set address(0x0100) to write value int command_res = i2c_master_send(client, send_data, 2); unsigned char write_data[1] = {0x00}; if (is_on) { write_data[0] = 0x01; // if stream starts, set 0x01 } else { write_data[0] = 0x00; } command_res = i2c_master_send(client, write_data, 1); if (command_res < 0) { return -1; } return 0;}static int test_sensor_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { if (code->index > 0) return -EINVAL; struct s_test_sensor *test_sensor = to_test_sensor(sd); /* only supported format in the driver is Raw 10 bits SRGGB */ mutex_lock(&test_sensor->mutex); code->code = MEDIA_BUS_FMT_UYVY8_1X16; mutex_unlock(&test_sensor->mutex); return 0;}static int test_sensor_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *fmt) { struct s_test_sensor *test_sensor = to_test_sensor(sd); mutex_lock(&test_sensor->mutex); fmt->format.width = WIDTH; fmt->format.height = HEIGHT; fmt->format.code = MEDIA_BUS_FMT_UYVY8_1X16; fmt->format.field = V4L2_FIELD_NONE; mutex_unlock(&test_sensor->mutex); return 0;}static int test_sensor_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_format *format) { struct v4l2_mbus_framefmt *fmt = &format->format; struct s_test_sensor *test_sensor = to_test_sensor(sd); return 0;}static const struct v4l2_subdev_video_ops test_sensor_video_ops = { .s_stream = test_sensor_start_stream,};static const struct v4l2_subdev_pad_ops test_sensor_pad_ops = { .enum_mbus_code = test_sensor_enum_mbus_code, .get_fmt = test_sensor_get_fmt, .set_fmt = test_sensor_set_fmt,};static const struct v4l2_subdev_ops test_sensor_subdev_ops = { .video = &test_sensor_video_ops, .pad = &test_sensor_pad_ops,};static const struct v4l2_subdev_internal_ops test_sensor_internal_ops = { .open = test_sensor_open,};static int test_sensor_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct s_test_sensor *test_sensor; test_sensor = devm_kzalloc(&client->dev, sizeof(*test_sensor), GFP_KERNEL); if (!test_sensor) { return -ENOMEM; } // initialize sub device options v4l2_i2c_subdev_init(&test_sensor->sd, client, &test_sensor_subdev_ops); usleep_range(100, 110); test_sensor->sd.internal_ops = &test_sensor_internal_ops; test_sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; test_sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; test_sensor->pad.flags = MEDIA_PAD_FL_SOURCE; test_sensor->pad.index = 1; test_sensor_set_default_format(test_sensor); // intialize pad int pad_res = media_entity_pads_init(&test_sensor->sd.entity, 1, &test_sensor->pad); // register test_sensor as v4l2 device int register_res = v4l2_async_register_subdev_sensor(&test_sensor->sd); return 0;}static void test_sensor_remove(struct i2c_client *client) { struct v4l2_subdev *sd = i2c_get_clientdata(client); struct s_test_sensor *test_sensor = to_test_sensor(sd); v4l2_async_unregister_subdev(sd);}static const struct of_device_id test_sensor_dt_ids[] = { {.compatible = "MillenniumScienceSchool,test_sensor"}, {}};static struct i2c_driver test_sensor_driver = { .driver = { .name = "test_sensor", .of_match_table = test_sensor_dt_ids, }, .probe = test_sensor_probe, .remove = test_sensor_remove,};MODULE_DEVICE_TABLE(of, test_sensor_dt_ids);module_i2c_driver(test_sensor_driver);MODULE_LICENSE("GPL");
Code:
/dts-v1/;/ { compatible = "brcm,bcm2835"; fragment@0 { target = <0xffffffff>; phandle = <0x05>; __overlay__ { #address-cells = <0x01>; #size-cells = <0x00>; status = "okay"; test_sensor@2a { compatible = "MillenniumScienceSchool,test_sensor"; reg = <0x2a>; status = "okay"; clocks = <0xffffffff>; clock-names = "xclk"; VANA-supply = <0xffffffff>; VDIG-supply = <0xffffffff>; VDDL-supply = <0xffffffff>; rotation = <0x00>; orientation = <0x02>; phandle = <0x04>; port { endpoint { remote-endpoint = <0x01>; clock-lanes = <0x00>; data-lanes = <0x01 0x02>; clock-noncontinuous; link-frequencies = <0x00 0x11b3dc40>; phandle = <0x02>; }; }; }; }; }; fragment@1 { target = <0xffffffff>; phandle = <0x06>; __overlay__ { status = "okay"; brcm,media-controller; phandle = <0x03>; port { endpoint { remote-endpoint = <0x02>; clock-lanes = <0x00>; data-lanes = <0x01 0x02>; clock-noncontinuous; phandle = <0x01>; }; }; }; }; fragment@2 { target = <0xffffffff>; __overlay__ { status = "okay"; }; }; fragment@3 { target = <0xffffffff>; phandle = <0x07>; __overlay__ { clock-frequency = <0x17d78400>; status = "okay"; }; }; fragment@4 { target = <0xffffffff>; __overlay__ { status = "okay"; }; }; __overrides__ { media-controller = [00 00 00 03 62 72 63 6d 2c 6d 65 64 69 61 2d 63 6f 6e 74 72 6f 6c 6c 65 72 3f 00]; rotation = [00 00 00 04 72 6f 74 61 74 69 6f 6e 3a 30 00]; orientation = [00 00 00 04 6f 72 69 65 6e 74 61 74 69 6f 6e 3a 30 00]; cam0 = [00 00 00 05 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 06 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 07 74 61 72 67 65 74 3a 30 3d 00 ff ff ff ff 00 00 00 04 63 6c 6f 63 6b 73 3a 30 3d 00 ff ff ff ff 00 00 00 04 56 41 4e 41 2d 73 75 70 70 6c 79 3a 30 3d 00 ff ff ff ff]; }; __fixups__ { i2c_csi_dsi = "/fragment@0:target:0"; cam1_clk = "/fragment@0/__overlay__/test_sensor@2a:clocks:0\0/fragment@3:target:0"; cam1_reg = "/fragment@0/__overlay__/test_sensor@2a:VANA-supply:0"; cam_dummy_reg = "/fragment@0/__overlay__/test_sensor@2a:VDIG-supply:0\0/fragment@0/__overlay__/test_sensor@2a:VDDL-supply:0"; csi1 = "/fragment@1:target:0"; i2c0if = "/fragment@2:target:0"; i2c0mux = "/fragment@4:target:0"; i2c_csi_dsi0 = "/__overrides__:cam0:14"; csi0 = "/__overrides__:cam0:32"; cam0_clk = "/__overrides__:cam0:50\0/__overrides__:cam0:68"; cam0_reg = "/__overrides__:cam0:91"; }; __local_fixups__ { fragment@0 { __overlay__ { test_sensor@2a { port { endpoint { remote-endpoint = <0x00>; }; }; }; }; }; fragment@1 { __overlay__ { port { endpoint { remote-endpoint = <0x00>; }; }; }; }; __overrides__ { media-controller = <0x00>; rotation = <0x00>; orientation = <0x00>; cam0 = <0x00 0x12 0x24 0x36 0x48>; }; };};
The process I followed is in below.
1. compile "test_sensor.dts" to "test_sensor.dtbo" and locate it in "/boot/firmware/overlay/test_sensor.dtbo"
2. modify "/boot/firmware/config.txt" for overlay
Code:
dtoverlay=vc4-kms-v3ddtoverlay=test_sensor
I tried some commands to get stream.
First, I set sensor's resolution and pixel format.
v4l2-ctl -v width=1024,height=1024,pixelformat=Y10P
Code:
[ 1648.856060] unicam fe801000.csi: unicam_calc_format_size_bpl: fourcc: 50303159 size: 1024x1024 bpl:1280 img_size:1310720[ 1648.856089] unicam fe801000.csi: unicam_mc_try_fmt: 50303159 1024x1024 (bytesperline 1280 sizeimage 1310720)
libcamera-hello
Code:
[0:23:39.147303486] [3607] INFO Camera camera_manager.cpp:313 libcamera v0.3.0+65-6ddd79b5[0:23:39.162325264] [3610] ERROR CameraSensor camera_sensor.cpp:127 'test_sensor 10-002a': No image format found[0:23:39.162423153] [3610] ERROR RPI vc4.cpp:215 Failed to register camera test_sensor 10-002a: -22Preview window unavailableERROR: *** no cameras available ***
v4l2-ctl --stream-mmap=3 --stream-count=1000 --stream-to=test.raw
Code:
VIDIOC_STREAMON returned -1 (Invalid argument)[ 1696.000263] unicam fe801000.csi: Failed to start media pipeline: -22
I've found sensor driver requirements by libcamera.
https://github.com/raspberrypi/libcamer ... ements.rst
Thanks,
Statistics: Posted by Koyuki — Wed Sep 25, 2024 2:38 am