![[ZYNQ Linux] V4L2視頻驅(qū)動(dòng)](http://pic.xiahunao.cn/yaotu/[ZYNQ Linux] V4L2視頻驅(qū)動(dòng))
[ZYNQ Linux] V4L2視頻驅(qū)動(dòng)文章目錄[ZYNQ Linux] V4L2視頻驅(qū)動(dòng)數(shù)據(jù)流搭建過(guò)程及問(wèn)題AXI VDMA圖像接收思路V4L2驅(qū)動(dòng)V4L2驅(qū)動(dòng)——視頻設(shè)備ioctl_ops、vb2層與vb2_ops的調(diào)用關(guān)系A(chǔ)XI VDMA實(shí)現(xiàn)細(xì)節(jié)將緩沖區(qū)加入圖像隊(duì)列——buf_queue啟動(dòng)流式傳輸——start_streaming停止流式傳輸清空緩沖區(qū)隊(duì)列——stop_streaming設(shè)備樹(shù)設(shè)計(jì)用戶(hù)空間使用代碼使用步驟命令行工具 v4l2-ctlTODO其它問(wèn)題數(shù)據(jù)流搭建過(guò)程及問(wèn)題HDMI輸入 → ADV7611解碼 →AXIVDMA →PSADV7611復(fù)位接到了PL需要進(jìn)行復(fù)位使用一個(gè)axi gpio進(jìn)行復(fù)位axi gpio會(huì)注冊(cè)一個(gè)gpiochip出來(lái)。echo507/sys/class/gpio/exportechoout/sys/class/gpio/gpio507/directionecho0/sys/class/gpio/gpio507/valuesleep1echo1/sys/class/gpio/gpio507/valueADV7611初始化配置一些寄存器i2cdetect -r -y掃描不到0x4C等地址不過(guò)可以讀到數(shù)據(jù)可能是設(shè)備沒(méi)有對(duì)i2cdetect的掃描進(jìn)行響應(yīng)不要過(guò)度依賴(lài)和相信工具i2cget-y10x4c 0x42重新嘗試了下死活配置不成功改用AXI IIC后i2cdetect能掃描到初步判斷PS I2C1轉(zhuǎn)EMIO出來(lái)的問(wèn)題不知道是不是需要一些特殊處理。EDID設(shè)置問(wèn)題插電腦不能識(shí)別屏幕。HDMI接口的I2C沒(méi)連接到解碼芯片需要連接到一個(gè)EEPROM的IP核。EDID IP核需要配置1080的文件里面的名稱(chēng)不能空著添加之后連接到電腦電腦會(huì)識(shí)別到一個(gè)屏幕。時(shí)鐘和緩沖問(wèn)題問(wèn)題VDMA傳輸?shù)囊粠瑘D像只有前幾行有效其余全0。數(shù)據(jù)流程中有一個(gè)IP核把視頻時(shí)序轉(zhuǎn)為了AXI Stream格式需要考慮寫(xiě)入速率寫(xiě)入時(shí)鐘和讀取速率讀出時(shí)鐘的問(wèn)題。位寬一樣的話(huà)讀出時(shí)鐘的頻率要高于寫(xiě)入時(shí)鐘。輸入是148.5M(1080p60幀)AXIVDMA的時(shí)鐘也要高于或者等于該時(shí)鐘。還要考慮緩沖區(qū)設(shè)置多大比較合適。AXI VDMA圖像接收思路通過(guò)DMA接口申請(qǐng)連續(xù)的內(nèi)存塊DMA傳輸需要特殊的內(nèi)存塊不能是malloc常規(guī)申請(qǐng)的調(diào)用DMA接口接收數(shù)據(jù)到內(nèi)存空間內(nèi)核空間提供mmap接口供用戶(hù)空間使用用戶(hù)空間調(diào)用mmap獲取圖像常規(guī)的圖像接收思路原理都是類(lèi)似的提供的API接口或者使用方式有所區(qū)別。還會(huì)有緩沖池、緩沖區(qū)、隊(duì)列等等的區(qū)別。V4L2驅(qū)動(dòng)V4L2驅(qū)動(dòng)——視頻設(shè)備接口說(shuō)明int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev);注冊(cè) V4L2 設(shè)備實(shí)例管理設(shè)備的數(shù)據(jù)結(jié)構(gòu)用戶(hù)空間不可見(jiàn)int video_register_device(struct video_device *vdev,int type, int nr);注冊(cè)視頻設(shè)備由V4L2設(shè)備進(jìn)行管理即和上面注冊(cè)v4l2設(shè)備關(guān)聯(lián)創(chuàng)建/dev/videoX的設(shè)備節(jié)點(diǎn)struct video_device視頻設(shè)備結(jié)構(gòu)體設(shè)備的核心操作接口fops和ioctl_ops圖像隊(duì)列queueconst struct v4l2_file_operations *fops;open、release、mmap等內(nèi)核有通用的vb2_fop_mmap操作接口等等const struct v4l2_ioctl_ops *ioctl_ops;ioctl操作一大堆需要實(shí)現(xiàn)一些關(guān)鍵的structvb2_queue*queue;管理視頻緩沖區(qū)的隊(duì)列一個(gè)緩沖區(qū)或者緩沖池內(nèi)核fops通用接口v4l2_fh_open打開(kāi)文件vb2_fop_release釋放與視頻緩沖區(qū)相關(guān)的資源vb2_fop_mmap內(nèi)存映射vb2_fop_pollpoll機(jī)制內(nèi)核ioctl_ops通用接口vb2_ioctl_create_bufs創(chuàng)建視頻緩沖區(qū)vb2_ioctl_expbuf導(dǎo)出視頻緩沖區(qū)可以與其他設(shè)備或進(jìn)程共享內(nèi)存ioctl_ops用戶(hù)實(shí)現(xiàn)vidioc_querycap查詢(xún)?cè)O(shè)備能力vidioc_g_fmt_vid_cap當(dāng)前數(shù)據(jù)格式包括分辨率、像素格式等參數(shù) get formatvidioc_try_fmt_vid_cap嘗試設(shè)置視頻捕獲格式但不實(shí)際應(yīng)用vidioc_s_fmt_vid_cap設(shè)置視頻捕獲設(shè)備的格式如分辨率、像素格式set formatvidioc_enum_fmt_vid_cap枚舉視頻捕獲設(shè)備支持的像素格式 enum formatvidioc_reqbufs申請(qǐng)視頻緩沖區(qū)內(nèi)存vidioc_querybuf查詢(xún)已申請(qǐng)緩沖區(qū)的詳細(xì)信息包括內(nèi)存偏移、長(zhǎng)度等vidioc_qbuf將緩沖區(qū)放入隊(duì)列或隊(duì)列 queue buffervidioc_dqbuf從隊(duì)列中取出緩沖區(qū) dequeue buffervidioc_streamon啟動(dòng)視頻流傳輸vidioc_streamoff停止視頻流傳輸struct vb2_queue緩沖區(qū)隊(duì)列需要實(shí)現(xiàn)對(duì)隊(duì)列的操作vb2_ops內(nèi)存操作mem_opsqueue_setup初始化視頻緩沖區(qū)隊(duì)列分配緩沖區(qū)內(nèi)存buf_prepare準(zhǔn)備緩沖區(qū)數(shù)據(jù)buf_queue將緩沖區(qū)加入隊(duì)列start_streaming啟動(dòng)流式傳輸stop_streaming停止流式傳輸清空緩沖區(qū)隊(duì)列wait_prepare等待緩沖區(qū)準(zhǔn)備完成wait_finish等待緩沖區(qū)處理完vb2video buffer的通用接口vb2_fop層、vb2_ioctls層、vb2層、vb2_ops層vb2_ops_wait_finish等待所有緩沖區(qū)操作完成vb2_ops_wait_prepare等待所有緩沖區(qū)準(zhǔn)備完成vb2_plane_vaddr獲取緩沖區(qū)的虛擬地址vb2_plane_size獲取緩沖區(qū)平面的大小vb2_set_plane_payload設(shè)置緩沖區(qū)平面的有效載荷大小vb2_is_busy檢查緩沖區(qū)隊(duì)列是否正忙vb2_reqbufs請(qǐng)求分配緩沖區(qū)vb2_querybuf查詢(xún)緩沖區(qū)信息vb2_qbuf將緩沖區(qū)加入隊(duì)列vb2_dqbuf從隊(duì)列中取出緩沖區(qū)vb2_streamon啟動(dòng)流式傳輸vb2_streamoff停止流式傳輸vb2_buffer_done標(biāo)記緩沖區(qū)處理完成vb2_dma_contig_plane_dma_addr獲取DMA連續(xù)緩沖區(qū)的物理地址vb2_is_streaming檢查是否正在流式傳輸vb2_queue_init初始化視頻緩沖區(qū)隊(duì)列vb2_dma_contig_memopsDMA內(nèi)存操作集合可傳給mem_opsioctl_ops、vb2層與vb2_ops的調(diào)用關(guān)系方向用戶(hù)空間 → ioctl_ops → vb2層 → vb2_ops。用戶(hù)空間通過(guò)ioctl系統(tǒng)調(diào)用傳遞到驅(qū)動(dòng)中定義的ioctl_ops結(jié)構(gòu)體ioctl_ops調(diào)用vb2層如vidioc_streamon等會(huì)進(jìn)一步調(diào)用vb2層的通用接口vb2_streamonvb2層回調(diào)驅(qū)動(dòng)實(shí)現(xiàn)的vb2_opsvb2_streamon回調(diào)start_streaming分工ioctl_ops處理用戶(hù)請(qǐng)求的解析與轉(zhuǎn)發(fā)。vb2層實(shí)現(xiàn)通用緩沖區(qū)管理邏輯。vb2_ops由驅(qū)動(dòng)實(shí)現(xiàn)硬件細(xì)節(jié)。AXI VDMA實(shí)現(xiàn)細(xì)節(jié)將緩沖區(qū)加入圖像隊(duì)列——buf_queue獲取緩沖區(qū)的物理地址用于DMA傳輸——vb2_dma_contig_plane_dma_addr準(zhǔn)備交錯(cuò)傳輸DMA描述符需要設(shè)置DMA地址等參數(shù)——dmaengine_prep_interleaved_dma設(shè)置描述符的回調(diào)函數(shù)如果DMA傳輸完成就把緩沖區(qū)標(biāo)記為有圖像數(shù)據(jù)VB2_BUF_STATE_DONE)將描述符提交到 DMA 控制器的工作隊(duì)列提交未開(kāi)始——dmaengine_submit把緩沖區(qū)放到活動(dòng)緩沖區(qū)隊(duì)列里面后續(xù)獲取圖像就是從這個(gè)隊(duì)列里面獲取觸發(fā) DMA 控制器開(kāi)始執(zhí)行已提交的傳輸——dma_async_issue_pending啟動(dòng)流式傳輸——start_streaming讓DMA開(kāi)始工作就行——dma_async_issue_pending停止流式傳輸清空緩沖區(qū)隊(duì)列——stop_streaming結(jié)束DMA傳輸——dmaengine_terminate_all將活動(dòng)緩沖區(qū)隊(duì)列里面的緩沖區(qū)設(shè)置為無(wú)效VB2_BUF_STATE_ERROR設(shè)備樹(shù)設(shè)計(jì)vdma_capture:vdma-capture{compatiblexlnx,axi-vdma-capture;dmasaxi_vdma_11;dma-namesport0;};用戶(hù)空間使用代碼使用步驟打開(kāi)設(shè)備使用open()函數(shù)打開(kāi)V4L2設(shè)備文件通常是/dev/video0。根據(jù)需要可以選擇阻塞或非阻塞模式。查詢(xún)?cè)O(shè)備能力通過(guò)VIDIOC_QUERYCAP命令獲取設(shè)備的能力例如是否支持視頻采集V4L2_CAP_VIDEO_CAPTURE和流式I/OV4L2_CAP_STREAMING。設(shè)置圖像格式使用VIDIOC_S_FMT命令配置采集的圖像格式包括寬度、高度和像素格式如YUYV、MJPEG等。這是決定圖像數(shù)據(jù)如何組織的關(guān)鍵一步。申請(qǐng)與映射緩沖區(qū)申請(qǐng)緩沖區(qū)通過(guò)VIDIOC_REQBUFS向驅(qū)動(dòng)程序申請(qǐng)若干個(gè)視頻緩沖區(qū)。映射緩沖區(qū)對(duì)于內(nèi)存映射mmap方式使用VIDIOC_QUERYBUF查詢(xún)每個(gè)緩沖區(qū)信息然后通過(guò)mmap()系統(tǒng)調(diào)用將內(nèi)核空間的緩沖區(qū)映射到用戶(hù)空間以便應(yīng)用程序可以直接訪問(wèn)。這是最常用且高效的方式。緩沖區(qū)入隊(duì)在開(kāi)始采集前需要通過(guò)VIDIOC_QBUF命令將所有空閑的緩沖區(qū)放入驅(qū)動(dòng)層的輸入隊(duì)列中。開(kāi)始/停止視頻流通過(guò)VIDIOC_STREAMON命令啟動(dòng)視頻采集驅(qū)動(dòng)程序開(kāi)始向隊(duì)列中的緩沖區(qū)填充數(shù)據(jù)。在循環(huán)中使用VIDIOC_DQBUF從驅(qū)動(dòng)層的輸出隊(duì)列中取出已填充好數(shù)據(jù)的緩沖區(qū)。應(yīng)用程序處理完該幀數(shù)據(jù)后必須再次調(diào)用VIDIOC_QBUF將其放回輸入隊(duì)列以便驅(qū)動(dòng)程序循環(huán)使用。采集完成后通過(guò)VIDIOC_STREAMOFF命令停止視頻流。關(guān)閉設(shè)備使用close()函數(shù)關(guān)閉設(shè)備文件并釋放所有資源。命令行工具 v4l2-ctlTODO解碼芯片在用戶(hù)空間單獨(dú)進(jìn)行初始化和配置未加入到驅(qū)動(dòng)框架里邊??梢允鼓軆?nèi)核相關(guān)驅(qū)動(dòng)作為v4l2子設(shè)備添加。聯(lián)動(dòng)Framebuffer、DRM進(jìn)行圖像輸出。其它問(wèn)題內(nèi)核有個(gè)VVIP的驅(qū)動(dòng)不是給AXI-VDMA用的是給另外的IP核用的不能直接使用。no VDMA channel foundVVIP驅(qū)動(dòng)沒(méi)找到DMA通道設(shè)備樹(shù)通道有問(wèn)題1是寫(xiě)從DMA向外寫(xiě)S2MM。[2.246473]xilinx-video axi-video-cap: no VDMA channel found[2.251733]xilinx-video axi-video-cap: /axi-video-cap/ports/port0 initialization failed[2.259907]xilinx-video axi-video-cap: DMA initialization failed\linux-xlnx\Documentation\devicetree\bindings\dma\xilinx\xilinx_dma.txt* DMA client Required properties: - dmas: a list of[Video DMA device phandle][Channel ID]pairs, where Channel ID is0forwrite/tx and1forread/rx channel. For MCMDA, MM2S channel(write/tx)ID start from0and isin[0-15]range. S2MM channel(read/rx)ID start from16and isin[16-31]range. These channels ID are fixed irrespective of IP configuration. - dma-names: a list of DMA channel names, one perdmasentryno subdev found in graphVVIP驅(qū)動(dòng)沒(méi)有子設(shè)備v4l2驅(qū)動(dòng)需要子設(shè)備構(gòu)成一個(gè)完整的數(shù)據(jù)流[2.253037]xilinx-video axi-video-cap: /axi-video-cap/ports/port0 initialization failed[2.260727]xilinx-video axi-video-cap: DMA initialization failed[4.528033]xilinx-video axi-video-cap: no subdev foundingraph[4.539722]xilinx-video: probe of axi-video-cap failed with error-2創(chuàng)建一個(gè)虛擬的子設(shè)備可以創(chuàng)建成功但還是不能用VVIP驅(qū)動(dòng)驅(qū)動(dòng)里面還是用不了沒(méi)能成功獲取到圖像格式需要另一個(gè)IP核的支持。[2.373491]xilinx-video axi-video-cap: /axi-video-cap/ports/port0 initialization failed[2.381152]xilinx-video axi-video-cap: DMA initialization failed[4.646649]xilinx-video axi-video-cap: device registered