9.1.6. PXA 摄像头主机驱动¶
作者:Robert Jarzmik <robert.jarzmik@free.fr>
9.1.6.1. 约束¶
YUV422P 格式的图像尺寸 所有 YUV422P 图像都被强制要求宽度 x 高度 % 16 = 0。这是由于 DMA 约束,它只传输 8 字节倍数的平面。
9.1.6.2. 全局视频工作流程¶
QCI 已停止 最初,QCI 接口是停止的。当一个缓冲区被排队时,调用 start_streaming,并且 QCI 启动。
QCI 已启动 当 QCI 启动时,可以排队更多缓冲区,而无需停止捕获。新的缓冲区被“附加”到 DMA 链的末尾,并一个接一个地平稳捕获帧。
一旦 QCI 接口中的缓冲区被填满,它将被标记为“完成”并从活动缓冲区列表中删除。然后它可以被用户空间应用程序重新排队或出队。
一旦最后一个缓冲区被填满,QCI 接口就会停止。
捕获全局有限状态机模式
+----+ +---+ +----+
| DQ | | Q | | DQ |
| v | v | v
+-----------+ +------------------------+
| STOP | | Wait for capture start |
+-----------+ Q +------------------------+
+-> | QCI: stop | ------------------> | QCI: run | <------------+
| | DMA: stop | | DMA: stop | |
| +-----------+ +-----> +------------------------+ |
| / | |
| / +---+ +----+ | |
|capture list empty / | Q | | DQ | | QCI Irq EOF |
| / | v | v v |
| +--------------------+ +----------------------+ |
| | DMA hotlink missed | | Capture running | |
| +--------------------+ +----------------------+ |
| | QCI: run | +-----> | QCI: run | <-+ |
| | DMA: stop | / | DMA: run | | |
| +--------------------+ / +----------------------+ | Other |
| ^ /DMA still | | channels |
| | capture list / running | DMA Irq End | not |
| | not empty / | | finished |
| | / v | yet |
| +----------------------+ +----------------------+ | |
| | Videobuf released | | Channel completed | | |
| +----------------------+ +----------------------+ | |
+-- | QCI: run | | QCI: run | --+ |
| DMA: run | | DMA: run | |
+----------------------+ +----------------------+ |
^ / | |
| no overrun / | overrun |
| / v |
+--------------------+ / +----------------------+ |
| Frame completed | / | Frame overran | |
+--------------------+ <-----+ +----------------------+ restart frame |
| QCI: run | | QCI: stop | --------------+
| DMA: run | | DMA: stop |
+--------------------+ +----------------------+
Legend: - each box is a FSM state
- each arrow is the condition to transition to another state
- an arrow with a comment is a mandatory transition (no condition)
- arrow "Q" means : a buffer was enqueued
- arrow "DQ" means : a buffer was dequeued
- "QCI: stop" means the QCI interface is not enabled
- "DMA: stop" means all 3 DMA channels are stopped
- "DMA: run" means at least 1 DMA channel is still running
9.1.6.3. DMA 使用¶
- DMA 流
排队用于捕获的第一个缓冲区 一旦第一个缓冲区被排队用于捕获,QCI 就会启动,但数据传输不会启动。在“帧结束”中断时,irq 处理程序启动 DMA 链。
捕获一个视频缓冲区 DMA 链开始将数据传输到视频缓冲区 RAM 页。当所有页面都传输完毕后,DMA irq 会在“ENDINTR”状态下被触发
完成一个视频缓冲区 DMA irq 处理程序将视频缓冲区标记为“完成”,并将其从活动运行队列中删除。同时,下一个视频缓冲区(如果有)会通过 DMA 传输
完成最后一个视频缓冲区 在最后一个视频缓冲区的 DMA irq 上,QCI 停止。
DMA 准备好的缓冲区将具有以下结构
+------------+-----+---------------+-----------------+
| desc-sg[0] | ... | desc-sg[last] | finisher/linker |
+------------+-----+---------------+-----------------+
此结构由 dma->sg_cpu 指向。描述符的使用方式如下
desc-sg[i]:第 i 个描述符,将第 i 个 sg 元素传输到视频缓冲区散列收集
finisher:具有 ddadr=DADDR_STOP,dcmd=ENDIRQEN
linker:具有 ddadr=下一个视频缓冲区的 desc-sg[0],dcmd=0
对于下一个模式,我们假设 d0=desc-sg[0] .. dN=desc-sg[N],“f”代表 finisher,“l”代表 linker。一个典型的运行链是
Videobuffer 1 Videobuffer 2
+---------+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+---+
| |
+----+
链接完成后,链看起来像
Videobuffer 1 Videobuffer 2 Videobuffer 3
+---------+----+---+ +----+----+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+-|-+ ^----+----+----+---+
| | | |
+----+ +----+
new_link
DMA 热链接时间片问题
由于 DMA 链接是在 DMA _正在_ 运行时完成的,因此链接可能在 DMA 从一个视频缓冲区跳到另一个视频缓冲区时完成。在模式上,如果遇到以下序列,这将是一个问题
DMA 链是 VideoBuffer1 + VideoBuffer2
调用 pxa_videobuf_queue() 来排队 VideoBuffer3
DMA 控制器完成 VideoBuffer2,DMA 停止
=>
Videobuffer 1 Videobuffer 2
+---------+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+-^-+
| | |
+----+ +-- DMA DDADR loads DDADR_STOP
调用 pxa_dma_add_tail_buf(),VideoBuffer2 的“finisher”被替换为到 VideoBuffer3 的“linker”(创建 new_link)
pxa_videobuf_queue() 完成
调用 DMA irq 处理程序,它终止 VideoBuffer2
VideoBuffer3 捕获未在 DMA 链上调度(因为它已停止!!!)
Videobuffer 1 Videobuffer 2 Videobuffer 3
+---------+----+---+ +----+----+----+---+ +----+----+----+---+
| d0 | .. | dN | l | | d0 | .. | dN | l | | d0 | .. | dN | f |
+---------+----+-|-+ ^----+----+----+-|-+ ^----+----+----+---+
| | | |
+----+ +----+
new_link
DMA DDADR still is DDADR_STOP
调用 pxa_camera_check_link_miss() 这会检查 DMA 是否已完成,并且缓冲区仍在 pcdev->capture 列表中。如果是这种情况,捕获将重新启动,并且 VideoBuffer3 将在 DMA 链上调度。
DMA irq 处理程序完成
注意
如果 DMA 在 pxa_camera_check_link_miss() 读取 DDADR() 值后立即停止,我们保证当 DMA 完成缓冲区时,将再次调用 DMA irq 处理程序,并且将再次调用 pxa_camera_check_link_miss(),以重新调度 VideoBuffer3。