针对K230移植单通道MIPI事件流摄像头并读取RAW数据的实现方案,以下是详细步骤(以Linux平台为基础,结合底层驱动和用户空间程序):
arch/riscv/boot/dts/canaan/ 或相似路径下找到目标板DTS文件。关键内容:
&csi {
status = "okay";
port {
csi_in: endpoint {
remote-endpoint = <&sensor_out>;
data-lanes = <1>; // 单通道配置为1
clock-lanes = <0>; // 时钟通道号
clock-noncontinuous; // 部分传感器需要
};
};
};
&i2c0 { // 根据实际连接的I2C总线号修改
status = "okay";
camera_sensor: sensor@3c { // 替换为实际I2C地址
compatible = "custom,event-sensor"; // 关键:需匹配驱动
reg = <0x3c>;
reset-gpios = <&gpio 12 GPIO_ACTIVE_LOW>; // 复位引脚(可选)
powerdown-gpios = <&gpio 13 GPIO_ACTIVE_LOW>; // 下电引脚(可选)
port {
sensor_out: endpoint {
remote-endpoint = <&csi_in>;
data-lanes = <1>;
clock-lanes = <0>;
};
};
};
};V4L2 Subdevice框架实现(参考drivers/media/i2c/sensors/下的同类驱动)。关键修改点:
// 1. 在probe函数中设置CSI参数
static int sensor_probe(struct i2c_client *client) {
// ... 初始化代码
struct v4l2_subdev *sd;
// 配置MIPI参数
struct v4l2_mbus_config mbus_cfg = {
.type = V4L2_MBUS_CSI2_DPHY, // 明确指定CSI-2 D-PHY
.flags = V4L2_MBUS_CSI2_1_LANE | // 单通道模式
V4L2_MBUS_CSI2_CONTINUOUS_CLOCK, // 或自定义标志
};
sensor_write_reg(sd, REG_CTRL_MODE, EVENT_STREAM_MODE); // 设置事件流模式
// ... 注册subdev
}
// 2. 实现事件流格式定义
static int sensor_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code) {
switch (code->index) {
case 0:
code->code = MEDIA_BUS_FMT_EVENT_STREAM; // 自定义或使用RAW格式
return 0;
default:
return -EINVAL;
}
}drivers/media/platform/canaan) 支持RAW数据直通模式。修改CSI控制器代码关闭ISP处理:// 在CSI接收路径(例如csi_rx_start函数)
if (is_event_stream) {
csi_reg_write(CSI_CTRL_REG, CSI_CTRL_BYPASS_ISP); // 关键:绕过ISP
csi_reg_write(CSI_FMT_REG, RAW_DATA_FORMAT); // 设置原始数据格式
}# 列出摄像头设备
v4l2-ctl --list-devices
# 设置RAW格式并捕获数据(假设设备为/dev/video0)
v4l2-ctl -d /dev/video0 --set-fmt-video=width=640,height=480,pixelformat=GREY
v4l2-ctl --stream-mmap --stream-count=10 --stream-to=event_data.rawimport cv2
# 如果V4L2支持,直接用VideoCapture读RAW
cap = cv2.VideoCapture("/dev/video0")
cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc('Y','1','0',' ')) # 设置GREY格式
while True:
ret, frame = cap.read()
if ret:
# frame即为RAW数据(Numpy数组)
process_event_data(frame) # 自定义事件解析函数#include
#include
#include
int main() {
int fd = open("/dev/video0", O_RDWR);
struct v4l2_format fmt = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
.fmt.pix = {
.width = 640,
.height = 480,
.pixelformat = V4L2_PIX_FMT_GREY, // 或自定义格式
}
};
ioctl(fd, VIDIOC_S_FMT, &fmt); // 设置格式
// 申请DMA缓冲区
struct v4l2_requestbuffers req = {0};
req.count = 4;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_REQBUFS, &req);
// 映射缓冲区并启动采集
for (int i = 0; i < req.count; i++) {
struct v4l2_buffer buf = {0};
buf.type = req.type;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ioctl(fd, VIDIOC_QUERYBUF, &buf);
void *mem = mmap(NULL, buf.length, PROT_READ, MAP_SHARED, fd, buf.m.offset);
// 加入队列
ioctl(fd, VIDIOC_QBUF, &buf);
}
ioctl(fd, VIDIOC_STREAMON, &req.type);
while (1) {
struct v4l2_buffer buf = {0};
buf.type = req.type;
buf.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_DQBUF, &buf); // 出队
parse_event_stream(mem, buf.bytesused); // 解析事件流
ioctl(fd, VIDIOC_QBUF, &buf); // 重新入队
}
}(x, y, timestamp, polarity))。i2cdetect -y 0检查设备地址是否正确。dmesg | grep csi 查看CSI控制器初始化状态。devmem2工具直接读写传感器寄存器调试。
注意:若使用 RT-Smart,需在内核启用
CONFIG_MEDIA_SUPPORT并重新编译BSP,用户空间改用RT-Thread的V4L2 API或定制驱动接口。
通过以上步骤,您可在K230上完整实现事件流摄像头的RAW数据传输与解析。
举报
更多回帖