ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

答辩项目草稿

答辩项目草稿 LED源码实现由设备树的compatible找到匹配到的驱动文件该文件对应的宏CONFIG_LEDS_GPIO在.config里面找到这个宏确定有没有编译进内核驱动代码讲解gpio_led_driver (平台驱动) ├── 模块加载 (module_platform_driver) │ └── 注册平台驱动 │ ├── 设备探测 (gpio_led_probe) │ ├── 路径A板级数据 (pdata存在) │ │ └── 遍历 pdata-leds[] │ │ ├── gpio_led_get_gpiod() │ │ │ ├── 尝试 devm_gpiod_get_index() (descriptor方式) │ │ │ └── 失败则回退到 GPIO 号方式 (legacy) │ │ └── create_gpio_led() │ │ │ ├── 路径B设备树/ACPI (pdata为空) │ │ └── gpio_leds_create() │ │ └── 遍历设备树子节点 │ │ ├── devm_fwnode_get_gpiod_from_child() (获取GPIO) │ │ ├── 读取DT属性 (default-state, trigger等) │ │ └── create_gpio_led() │ │ │ └── platform_set_drvdata() (保存私有数据) │ ├── create_gpio_led() (核心初始化) │ ├── 配置 led_classdev │ │ ├── default_trigger (默认触发器) │ │ ├── brightness_set / brightness_set_blocking (回调) │ │ └── blink_set (闪烁回调可选) │ ├── 确定初始状态 │ │ ├── KEEP → 读取当前GPIO电平 │ │ └── ON/OFF → 直接设置 │ ├── 配置 flags │ │ ├── LED_CORE_SUSPENDRESUME (挂起恢复) │ │ ├── LED_PANIC_INDICATOR (panic指示) │ │ └── LED_RETAIN_AT_SHUTDOWN (关机保留) │ ├── gpiod_direction_output() (设置GPIO方向) │ └── devm_led_classdev_register_ext() (注册到LED子系统) │ ├── 运行时操作 │ ├── gpio_led_set() (设置亮度) │ │ ├── 如果正在闪烁 → 停止闪烁并设置电平 │ │ └── 直接设置GPIO电平 │ │ ├── can_sleep → gpiod_set_value_cansleep() │ │ └── 非sleep → gpiod_set_value() │ └── gpio_blink_set() (设置闪烁) │ └── 调用 platform_gpio_blink_set() (平台自定义) │ └── 系统关机 (gpio_led_shutdown) └── 遍历 priv-leds[] └── 检查 flags 是否含 LED_RETAIN_AT_SHUTDOWN ├── 是 → 保持当前状态 └── 否 → gpio_led_set(..., LED_OFF) 关闭LED硬件可得LED1的控制连接到芯片的PZ5自己的驱动文件杂项设备驱动框架混杂设备也叫杂项设备是对普通的字符设备(struct cdev)的一种封装。专门为简化小型、功能简单且不符合标准设备分类的硬件设备驱动开发而设计特点1.主设备号固定为102.简化驱动开发流程无需手动申请设备号、注册字符设备结构体等繁琐步骤3.统一设备节点路径注册后再/dev/misc目录下创建设备节点1. ioctl 方式 int fd open(/dev/led-driver, O_RDWR); ioctl(fd, 0x01); // 开灯 ioctl(fd, 0x11); // 关灯 close(fd); 2. write 方式 echo -n 1 /dev/led-driver # 开灯 echo -n 0 /dev/led-driver # 关灯 3. sysfs 方式 echo 1 /sys/devices/platform/led-driver/led_status # 开灯 echo 0 /sys/devices/platform/led-driver/led_status # 关灯 cat /sys/devices/platform/led-driver/led_status # 读取状态驱动实现通过 Platform 总线与设备树匹配在 probe 阶段获取 GPIO 资源并初始化一个 miscdevice 杂项设备用户空间可通过 /dev/led-driver 设备节点使用 ioctl 或 write 系统调用来控制 LED 的亮灭同时驱动还创建了 sysfs 属性文件 /sys/devices/platform/.../led_status 允许通过读写文件方式查询和设置 LED 状态实现了多种用户空间交互方式。实验现象i2c硬件可得SDA连接到芯片的PF15SCL连到芯片的PF14其控制器节点数据数可得控制器驱动为i2c-stm32f7.c芯片手册可得i2c命令得到从机地址为0x40温湿度处理公式并表明16位返回得复位时间5-15msI2C 速率最大 400kHz读写时序得到iic字节传输的是大端用regmap是为了把“怎么读”I2C/SPI/MMIO 的总线细节和“读什么”设备的寄存器/命令彻底分开从而大幅减少重复代码并免费获得缓存、字节序转换、调试日志等工业级功能。代码实现通过regmap框架统一管理 I2C 读写操作当用户读取温湿度时IIO 子系统的read_raw回调触发si7006_measure_temp/rh函数该函数通过regmap_raw_read向 SI7006 芯片发送单字节命令0xE3读温度或0xE5读湿度regmap自动调用底层si7006_regmap_read构造 I2C 时序先写命令再读数据读取芯片返回的 2 字节原始数据后用芯片手册公式换算成物理值放大 100 倍最终通过/sys/bus/iio/devices/iio:device0/in_temp_raw返回给用户空间。温度采集值要除以 100因为内核涨了 100 倍湿度采集值直接使用因为内核没涨1. 读取温度 ./i2c-app temp 2. 读取湿度 ./i2c-app rh 3. 同时读取温湿度 ./i2c-app all驱动实现驱动通过 I2C 总线与芯片通信采用 regmap 框架统一管理寄存器读写操作并实现了 regmap 的读写回调函数来适配 I2C 传输。驱动在 probe 阶段初始化芯片执行软复位操作然后注册 IIO 设备提供温度和湿度两个通道。用户空间可通过标准的 IIO 接口读取原始的温湿度数据驱动内部会通过公式将原始值转换为实际的温度值和湿度值并支持获取转换比例因子实现传感器数据的标准访问。现象错误表示I2C 设备没有响应 ACK应答信号i2c_smbus_write_byte(client, cmd)发送的 I2C 时序是START 0x40(W) ACK 0xFE ACK STOP只发 1 个字节命令没有额外数据。而之前的regmap_write会发送START 0x40(W) ACK 0xFE ACK 0x00 ACK 0x00 ACK STOP发了 3 个字节命令 2 字节数据芯片不认识直接 NACK。regmap框架按照val_bits 16的配置把复位命令0xFE当成了寄存器地址自动在后面附加了 2 字节数据0x00 0x00导致芯片不认识多余的字节而回复 NACK所以返回了-6。芯片手册表示这些命令都是单字节命令没有额外的数据字节。SPI数码管硬件驱动将多个字节放在同一个spi_message的spi_transfer链表中确保CS在整个多字节传输期间保持低电平只在所有数据发送完成后才释放上升沿从而自动触发74HC595锁存实现一次SPI写入数据传输自动锁存的简洁设计。共阴级可得SPI4_NSS、SPI4_SCK、SPI4_MISO分别连接着PE11、PE12、PE1374HC595 串行转并行移位寄存器。两个 74HC595 采用级联方式协同工作一个负责“段选”控制数码管显示什么字符另一个负责“位选”控制哪一位数码管被点亮。它们配合动态扫描实现多位数码管的稳定显示。设备树控制器设备树宏定义含义说明SPI_CPHA时钟相位支持配置 CPHA数据在时钟上升沿/下降沿采样SPI_CPOL时钟极性支持配置 CPOL时钟空闲时高电平/低电平SPI_CS_HIGH片选极性支持片选信号高电平有效默认低电平有效SPI_LSB_FIRST位序支持 LSB 先传输默认 MSB 先传输SPI_3WIRE三线模式支持双向数据MISO/MOSI 共用一根线可得最大频率是10MHz45行可得数据在 SCK 上升沿被采样数据在 SCK 下降沿不采样所以CPHA0SCLR 先把移位寄存器清空准备好。在 SCK 的节奏下SER 的数据被逐位移入。8 位数据全部移入后RCK 发出一个脉冲数据被锁存并输出数据在上升沿期间稳定 → 上升沿是采样边沿得CPHA0可得SCK 在空闲时处于低电平所以采样模式是00数据处理温度采集4位如2532除以10丢弃最后一位在十位后加小数点显示3位数字单位C25.3C湿度采集4位如0046丢弃千位第一位在个位后加小数点显示3位数字单位H46.0H。驱动实现驱动在 probe 阶段注册字符设备并创建 /dev/m74hc595 设备节点用户空间应用程序可通过 write 系统调用向驱动写入 2 字节数据驱动将这两个字节通过 spi_write 发送给 74HC595 芯片芯片将串行数据转换为并行输出从而控制 8 位输出引脚的电平状态实现对数码管或 LED 的显示控制。该驱动利用 SPI 总线的 MOSI、SCK 和片选信号完成数据发送并借助 74HC595 的锁存功能在传输完成后更新输出。现象触摸屏硬件芯片手册通过规格书可得MIPI 屏幕硬件分辨率480和854表明了复位引脚低电平复位可得该芯片支持两种从机地址下图表明拉低引脚对应的时间T1需要大于100us拉高后还需要等T35ms表示芯片支持上升沿/下降沿触发读写时序寄存器位置采集到的坐标数据看是否采集到坐标Normal mode 扫描周期 5~20ms所以轮询20msjiffies 是 Linux 内核中记录系统启动以来时钟滴答Tick次数的全局变量每个 Tick 的时长由内核配置 HZ 决定msecs_to_jiffies(40)在HZ100时通过 (40×100999)/1000 4的整数除法截断精确返回 4 个 jiffies对应 40ms不存在误差。jiffies 溢出回绕是指当jiffies变量累加到其数据类型的最大值后再增加 1 就会变回 0像里程表归零一样重新开始计数。判断当前时间jiffies是否在timeout之前还没超时。芯片上报的 Y0 在顶部屏幕显示习惯0 在底部所以翻转y 854 - y# 1. 加载驱动 insmod TP-driver.ko insmod LCD-driver.ko 2. 校准首次必须 /usr/local/tslib/bin/ts_calibrate 3. 画线测试 /usr/local/tslib/bin/ts_test 4. 打印坐标测试 /usr/local/tslib/bin/ts_print 5. 运行你的应用 ./TP-app-tslib原来的显示驱动panel-sitronix-st7701.cCONFIG_DRM_PANEL_SITRONIX_ST7701驱动实现过程触摸屏驱动通过I2C总线与触摸芯片通信系统启动时申请GPIO作为复位和中断引脚复位时序初始化芯片并读取分辨率运行时触摸芯片通过中断引脚通知主控驱动在中断处理函数中读取状态寄存器获取触摸点数再连续读取坐标寄存器得到各手指的X、Y坐标和面积数据通过Linux输入子系统的接口上报多点触摸数据最后同步完成一帧事件使上层应用能够通过设备节点获取触摸信息实现人机交互。现象显示屏硬件背光源码匹配到的设备树数据流环节硬件设备树节点内核驱动驱动做的内存DDR无drm_fbdev_emulation无关LTDC显示控制器display-controller5a001000ltdc.c提供st7701_modeDSIMIPI DSI 主机dsi5a000000dw-mipi-dsi-stm.c配置format、lanes、flagsPanelST7701 屏panel0驱动复位、初始化、背光、分辨率配置不一致的后果Framebuffer 24 位DSI 发送 RGB565颜色错乱高位数据被截断Framebuffer 16 位DSI 发送 RGB888颜色缺失低位补 0LTDC 输出格式与 DSI 不匹配显示异常或花屏芯片手册读显示ID命令返回3字节第1参数虚拟数据第2参数LCD制造商ID第3参数LCD模块/驱动版本ID复位低电平有效驱动代码延时值数据手册参数手册值类型设计目的msleep(20)①20 msTRW≥ 10 µs安全余量 2000×确保复位被可靠识别msleep(30)②30 msTRT≤ 5 ms安全余量 6×NVM加载 状态稳定msleep(20)③20 msTRW≥ 10 µs安全余量 2000×二次复位全面重置msleep(120)④120 msTRT(Sleep Out)≤ 120 ms精确匹配DC/DC放电 Blanking NVM加载 完全初始化Command 2 Table 2扩展命令集显示行设置命令LDE_EN决定行数是不是8的整数倍如果是就只用基础行数配置不是则需要用到额外行数配置NL 面板的总行数垂直分辨率因为我们的分辨率是856不是8倍数所以LDE_EN为0前后廊控制命令配置 LCD 显示时序中的垂直前廊VFP和垂直后廊VBP参数。垂直/水平同步脉冲前后用于同步、电压稳定、消隐的空白时间。1) 同步信号识别2) 给 DC/DC 和 Gate Driver 稳定时间3) 行/帧消隐防止残留4) 兼容性。反转选择 帧率控制命令LCD 屏幕如果长时间给像素施加同一方向的电压液晶分子会被「极化」而失去旋转能力导致残影Image Sticking和烧屏Burn-in。为了防止这个问题驱动芯片需要交替改变像素电压的极性。RTNI每行最小 PCLK 数量。芯片内部计数器用它来决定一行结束的时间点。PCLK/行每行需要的 PCLK 总数包括有效像素 水平消隐期。HTotal 480 12 12 38 542简单说RTNI 是芯片内部的「定时器基准」只要它大于实际 HTotal芯片就能正常工作。HTotal542RTNI 基准608留出了 66 个 PCLK 的余量。参数值计算公式含义.hdisplay480-水平有效显示区屏幕一行实际显示的像素数。对于你的屏幕就是 480 列。.hsync_start518480 38行同步起始位置从有效像素结束到HSYNC 信号开始之间的像素数。这里的 38 就是HFPHorizontal Front Porch水平前沿。.hsync_end530480 38 12行同步结束位置从有效像素结束到HSYNC 信号结束之间的像素数。HSYNC 脉冲本身的宽度就是12个像素周期。.htotal542480 38 12 12一行总像素数从一行开始到下一行开始的总像素数。剩下的 12 是HBPHorizontal Back Porch水平后沿。主控侧的 LTDC显示控制器从内存中的 Framebuffer 读取 RGB 图像数据暂存于 FIFO 中缓冲DSI Host 控制器Packet Handler将这些 RGB 数据打包成 MIPI-DSI 规定的长包格式打包好的数据通过 D-PHY 物理层以高速差分信号发送出去屏幕侧的 D-PHY 接收信号并恢复数据ST7701S 内部解包并识别数据类型命令或图像数据最后图像数据被送入源极驱动器驱动 LCD 面板显示画面。用户空间的应用程序如 Qt 程序负责图像渲染通过libdrm库将 ioctl 封装为 API向内核发送显示请求。内核空间的KMSKernel Mode Setting是 DRM 的核心管理单元将显示硬件抽象为以下标准化对象Framebuffer描述单帧图像在内存中的布局分辨率、像素格式等本身不拥有内存。Plane代表硬件图层支持多个图层的独立配置与硬件叠加合成。CRTC代表显示控制器引擎硬件对应 LTDC负责从 Framebuffer 扫描像素数据并生成时序信号。Encoder负责格式编码与协议打包硬件对应 DSI 主机控制器将 CRTC 输出的并行 RGB 信号转换为 MIPI-DSI 协议包。Connector代表物理显示连接器DSI 接口负责设备接入检测与 EDID 解析。Panel代表显示面板本身硬件对应 ST7701S LCD 面板负责上电时序、初始化序列与模式报告。内存管理方面GEM负责显示缓冲区的分配、释放与共享支持连续与非连续物理内存DUMB是 GEM 的简化版本仅支持连续物理内存PRIME基于 DMA-BUF 实现跨设备缓冲区共享Fence基于 dma_fence 机制实现缓冲区同步。DRM 框架中各组件分别对应到 MIPI-DSI 硬件链路的特定层次CRTC对应发送端的时序产生与像素读取LTDCEncoder对应发送端的 Protocol 打包与 Lane 分配DSI 主机控制器Connector对应物理连接器差分信号线接口Panel对应接收端的整个链路ST7701S 的 PHY 接收、Protocol 解包、Application 执行Framebuffer对应 Application 层产生或存储的像素流数据GEM对应存放 RGB 值的实际物理内存。MIPI-DSI 在 Linux 内核中的实现类似于 I2C 总线架构分为 dsi-host主设备和 dsi-device从设备两个部分。首先系统会创建 dsi-host 作为总线控制器然后遍历设备树子节点为每个连接的面板生成对应的 dsi-device。面板驱动 probe 时会调用 drm_panel_init 和 drm_panel_add 创建 drm_panel 对象然后主动调用 attach 函数将 dsi-device 绑定到 dsi-host 上之后在 DRM 框架的组件绑定阶段框架会根据已注册的 drm_panel 自动创建 panel-bridge。而真正的主设备 bridge 则由 DSI 主机控制器驱动创建它的作用是将 encoder 和 panel 连接起来。这两个 bridge 的绑定并不需要 framebufferframebuffer 只是运行时用户空间写入图像数据的内存区域与驱动 probe 阶段的硬件连接无关。在 DRM 框架中LTDC 驱动会创建 drm_device 和 encoder而 encoder 通过设备树中的endpoint属性描述的数据流向与主设备的 bridge 完成绑定。与此同时panel-bridge 中也有一个绑定函数会将主设备的 bridge 和 panel-bridge 连接起来这样 encoder 和 panel 就通过 bridge 串联在一起了。panel-bridge 的绑定函数还会进一步创建connectorconnector 是 DRM 框架中代表物理接口的对象它最终和外面的 panel 连接在一起完成整个显示管线的建立。最终完整的显示路径为CRTC → Encoder → Bridge → Connector → Panel。modetest 测试工具modetest 是 libdrm 提供的一个命令行测试工具用于查看和测试 DRM/KMS 显示子系统。它可以帮助开发者快速验证显示链路是否正常工作是调试显示驱动时最常用的工具之一。基本用法# 1. 查看连接器找到 ID第一次使用 modetest -c # 2. 查看图层找到 Plane ID modetest -p # 3. 显示彩条测试图案 modetest -s 34:480x854XR24 # 4. 显示彩条 指定图层 modetest -s 34:480x854XR24 -P 3133:480x854XR24 # 5. 带详细日志 modetest -s 34:480x854XR24 -v modetest -M stm -P 3537:480x854AR24启动流程显示屏的启动流程从硬件上电开始主控 SoC 提供稳定的电源通常为 3.3V 和 5V并释放复位信号RESX后屏幕驱动芯片 ST7701S 开始内部初始化。此时Linux 内核中的 DRM 框架按照组件依赖关系依次完成 LTDC显示控制器、DSI 主机控制器和 Panel 驱动的 probe并在组件绑定阶段将 CRTC、Encoder、Bridge 和 Connector 连接成完整的显示管线。随后DRM 框架调用 Panel 驱动的prepare回调函数该函数通过 MIPI-DSI 总线以低功耗模式LPM发送初始化命令序列包括0xFF切换寄存器页面、0xC0设置行数、0xB1配置 VCOM 电压、0x11退出睡眠等完成芯片内部寄存器配置等待 120ms 至 800ms 确保电压和时钟稳定后发送0x29打开显示并等待画面稳定。接着 DRM 框架调用enable回调函数通过 PWM 信号打开背光此时屏幕正常显示画面。在显示阶段系统以 Video Mode 并通过 Burst 模式持续刷新图像数据。关闭时DRM 框架依次调用disable关闭背光和unprepare发送0x10进入睡眠、复位引脚拉低并关闭电源有序释放硬件资源。摄像头硬件CMOS摄像头FS-MP157使用的是ov5640可以找到对应的驱动文件。发现设备树中自带了i2c5总线下的ov5640HSYNC行同步告诉主控“这一行像素数据发完了下一行要来了”VSYNC帧同步告诉主控“这一帧图像数据发完了下一帧要开始了”。简单比喻VSYNC是“翻页”HSYNC是“换行”PIXCLK是“写每个字”。数据流向步骤模块作用数据形态① 引脚输入DCMI_D[13:0]PIXCLKHSYNCVSYNC摄像头通过14根数据线时钟同步信号把原始像素数据送进来并行数据流② 同步Synchronizer根据PIXCLK时钟信号把数据同步到芯片内部时钟域同步后的并行数据③ 数据提取Data Extraction根据配置8位/10位/12位/14位模式提取有效数据位。比如 OV5640 常用 8-bit 模式就只取 D[7:0]有效像素数据④ 数据格式化FIFO/Data Formatter暂存数据并按照要求重组格式如 YUYV 排列成 Y-U-Y-V 顺序准备送给 DMA格式化后的数据包⑤ DMA传输DCMI_DMA这是关键DMA直接内存访问不经过 CPU直接把数据搬运到内存DDR中内存中的图像数据⑥ 控制Control/Status RegisterCPU 通过读写这些寄存器来配置 DCMI启停、设置格式、查询状态等控制信号非数据流struct stm32_dcmi (驱动核心结构体)├── struct v4l2_device (V4L2 顶层设备)│ ├── struct video_device (/dev/video0)│ │ └── struct vb2_queue (视频缓冲区队列)│ └── struct v4l2_subdev (OV5640 传感器子设备)└── struct media_device (媒体控制器设备与 v4l2_device 平级)└── 描述整个数据流的拓扑结构 (entities, pads, links)dcmi-mdev与dcmi-v4l2_dev是平级协作关系通过v4l2_dev.mdev dcmi-mdev相互关联。v4l2_device负责管理控制路径设备节点、子设备media_device负责描述数据路径拓扑谁连谁。它们共同构成了完整的 V4L2 Media Controller 驱动框架。media_pad和remote-endpoint是前后衔接的关系而不是互相替代设备树remote-endpoint在启动时告诉内核“DCMI 连到了 OV5640”。驱动解析remote-endpoint驱动读取设备树知道 DCMI 的对端是 OV5640。Media Controller 初始化media_pad驱动在probe函数中把 DCMI 的vid_cap_pad标记为SINK。Media Controller 创建连接驱动调用media_create_pad_link()把 OV5640 的SOURCEpad 和 DCMI 的SINKpad 连接起来形成完整的拓扑。绑定流程注册“等待列表”在 DCMI 驱动作为“桥接驱动”/bridge driver初始化时它会通过v4l2_async_notifier_add_subdev函数向 V4L2 核心框架注册一个“等待列表”告诉框架“我正在等待一个符合某条件比如固件节点fwnode匹配的v4l2_subdev出现”。这个等待列表维护在notifier-waiting链表里。sensor驱动加载当系统加载ov5640驱动时它会调用v4l2_async_register_subdev()函数向 V4L2 核心框架注册自己。框架“撮合”匹配V4L2 核心框架在注册新的subdev后会去检查现有的所有 notifier看是否有“等待列表”里的条件与新注册的subdev匹配。匹配的依据就是你之前看到的match_type可以是V4L2_ASYNC_MATCH_FWNODE匹配固件节点或V4L2_ASYNC_MATCH_I2C匹配 I2C 地址等。触发.bound回调一旦匹配成功框架就会立即调用 DCMI 驱动在dcmi_graph_notify_ops里注册的.bound函数并把这个新加载的 sensorsubdev的指针作为参数传给它。四大框架总结框架作用负责内容类比V4L2提供标准用户空间 API让应用通过/dev/videoX控制摄像头open/read/ioctl/mmap/poll等系统调用管理v4l2_device和v4l2_subdev处理用户请求查能力、设格式、申请 buffer、启停流前台服务员接收点单告知菜单传给后厨Media Controller描述整个视频硬件管道的拓扑结构media_device、media_entity、media_pad、media_linkmedia_create_pad_link()连接 sensor SOURCE 和 DCMI SINK用户空间通过/dev/mediaX查看后厨布局图标明配菜间→灶台→出菜口的完整路径vb2管理视频缓冲区的分配、流转和回收管理vb2_queue定义缓冲区生命周期分配→入队→填充→出队支持 MMAP/READ/DMABUF 三种模式通过vb2_ops回调与驱动交互传菜员厨师做好菜放盘里端给顾客空盘回收循环使用DMA不占用 CPU直接把硬件采集的图像数据搬运到内存配置 DMA 通道源 DCMI_DR、目标 buffer 地址、长度dmaengine_submit()提交传输完成后触发dcmi_dma_callback()通知搬运工推小车从灶台搬到冷库CPU 不用亲自跑腿协同工作流程总结应用程序↓ open /dev/videoXV4L2前台接待 → 接收指令转给下层↓vb2传菜员 → 准备好 buffer入队↓Media Controller管道图 → 确认路径畅通↓DMA搬运工 → 从 DCMI 硬件搬数据到 buffer↓DMA 完成 → 触发中断 → 通知 vb2↓vb2 → 通知 V4L2 → 应用程序 dqbuf 取走图像ov5640.c驱动ov5640.c 是一个 I2C 从设备驱动通过 V4L2 子设备v4l2_subdev框架与主控DCMI通信。它的核心任务是① 上电/复位/检测芯片 ID② 配置输出格式、分辨率、帧率③ 提供控制接口曝光、增益、白平衡等④ 在需要时开始/停止输出视频流ov5640.c是一个 I2C 传感器驱动通过 V4L2 子设备框架与 DCMI 通信。它负责上电/复位、解析设备树总线参数、提供 9 种分辨率和多种格式YUV/RGB/JPEG/Raw、实现 V4L2 控制项曝光/增益/白平衡并通过s_stream控制数据输出。它的寄存器配置表是“硬编码”的通过 I2C 批量写入来切换工作模式。模式设置水平总周期htot 有效像素hact 水平消隐期其中消隐期是传感器在每行有效数据之间插入的空白间隔用于确保硬件有足够时间处理数据保证数据传输稳定。采样Subsampling像“抽样调查”每隔几行几列取一个像素直接丢掉其他像素速度飞快但画质会损失适合低分辨率输出。缩放Scaling像“图像算法处理”读取周围多个像素用加权平均算出新像素画质好但计算量大、功耗高适合需要保留细节的高分辨率输出。采样和缩放两种模式下传感器读取像素的方式不同导致每帧的实际曝光时间积分时间发生变化。如果直接切换不重新计算曝光画面亮度会突变变亮或变暗。ov5640_set_mode_exposure_calc()会根据新旧模式的时序参数计算出新的曝光值和增益值确保切换前后画面亮度平滑过渡。曝光积分时间就是传感器收集光线的时长时长越长图像越亮。切换分辨率时读出速度变化会导致相同的曝光设定对应的实际时长改变所以驱动要重新计算曝光值保证切换前后画面亮度一致。时序逻辑展开时序层级信号作用帧VSYNC高电平时表示一帧开始低电平时表示帧结束帧消隐期行HREF高电平时表示一行有效像素开始低电平时表示行消隐期像素PCLKDATA在 HREF 高电平期间每个 PCLK 周期DATA 线上传输一个像素数据完整时序流程VSYNC高 → 开始一帧└── HREF高 → 开始一行└── PCLK边沿触发 → 逐个传输该行像素└── HREF低 → 行消隐期一行结束... 重复多行 ...VSYNC低 → 帧消隐期一帧结束关键点独立同步信号VSYNC 和 HREF 是独立的硬件信号线不占用数据线并行传输DATA 线宽度决定一个 PCLK 周期传多少 bit如 8-bit 一次传 1 字节采样边沿由pclk-sample决定上升沿或下降沿采样MIPI CSI-2 通过 LP 模式发送控制命令通过 HS 模式发送数据包以“状态切换序列”控制数据传输的开始和结束数据按“包→帧→行→像素”的层级串行传输。时序逻辑展开时序阶段状态/信号作用空闲LP11数据线处于空闲状态无数据传输进入HS模式LP11 → LP01 → LP00 → HS-0握手序列告诉接收端“准备接收高速数据”数据包开始SoTStart of Transmission发送同步码标志数据包开始数据传输HS-0/HS-1高速差分信号传输数据包包头 → 负载 → CRC校验数据包结束EoTEnd of Transmission标志数据包结束返回空闲HS-TRAIL → LP11回到空闲状态等待下一次传输关键点状态切换序列进入/退出 HS 模式有严格的时序序列如 LP11→LP01→LP00数据包格式每个数据包包含包头含帧/行信息、有效负载图像数据、CRC校验时钟内嵌数据线中包含时钟信息无需独立时钟线精确时序参数tHS-PREPARE、tHS-ZERO、tHS-TRAIL等需精确满足V4L2 应用层编程本质是打开设备 → 设置格式 → 申请/映射缓冲区 → 入队 → 启动流 → 循环取帧DQBUF/QBUF→ 停止流 → 释放资源。应用: ioctl(fd, VIDIOC_STREAMON, type)↓VFS: file-f_op-unlocked_ioctl → video_ioctl2↓V4L2 框架: video_ioctl2() → 查映射表 → 命令码转偏移量↓从 vdev-ioctl_opsdcmi_ioctl_ops中取出 .vidioc_streamon↓驱动注册的: dcmi_ioctl_ops.vidioc_streamon vb2_ioctl_streamon↓vb2 框架: vb2_ioctl_streamon()↓vb2 框架内部: 调用 vb2_queue-start_streaming 回调↓驱动注册的: dcmi_video_qops.start_streaming dcmi_start_streaming↓驱动执行: dcmi_start_streaming() ← 在 stm32-dcmi.c
返回列表