ov9650攝像頭驅動之——linux內核v4l2架構分析2


NO.2 Camera解碼器、控制器

 

1.根據camera控制器的描述,圖像傳輸有兩個DMA通道,我們用的是C通道,所以先將DMA內存初始化,因為在V4L2操作中有VIDIOC_REQBUFS中分配的數據緩存轉換成物理地址的操作

所以DMA在用之前要初始化,包括實際物理地址的計算

init_image_buffer(camera_dev);// 初始化

 

 

 

static int __inline__ init_image_buffer(struct s5pc100_camera_device *cam)

{

unsigned long size;

unsigned int order;

cam->frame = img_buff;

 

size = MAX_WIDTH * MAX_HEIGHT * formats[3].depth / 8; //sizeof image buffer is 600KBytes 

 

 

printk("each image buffer is %dKBytes.\n", (int)(size/1024));

 

order = get_order(size); //系統函數,size應該是2的n次冪,內存按頁分配

img_buff[0].order = order;

img_buff[0].virt_base = __get_free_pages(GFP_KERNEL|GFP_DMA, img_buff[0].order);//申請DMA空間,該函數可分配多個頁並返回分配內存的首地址,分配的頁數為2的order次冪,分配的頁也不清零。order允許的最大值是10(即1024頁)或者11(即2048頁),具體依賴於硬件平台。

img_buff[0].img_size = size;

img_buff[0].phy_base = img_buff[0].virt_base - PAGE_OFFSET + PHYS_OFFSET;// the DMA address.申請的DMA的物理地址,怎么計算的呢?首先要減去PAGE_OFFSET

why?因為在linux系統中,進程的4G空間被分為用戶空間和內核空間兩部分,用戶空間的地址一般分布為0-3G(即RAGE_OFFSET),這樣剩下的3-4G為內核空間,然后再加上 +PHYS_OFFSET(這個是由具體的cpu決定的,RAM的物理起始地址),這樣的話phy_base就對應上了真正的物理地址

printk("get pages for img_buff[0..3] done.\n");

return 0;

error0:

return -ENOMEM;

}

 

 

 

 

2.camera控制器的初始化

 

  • 圖像源的格式設置
  • window cut的設置
  • 目標圖像格式的設置
  • 圖像的縮放、旋轉設置
  • (可選,如果是用本地LCD顯示的話)將輸出buffer地址定位在Framebuffer顯存地址中(即內存重疊,這樣的話LCD就能直接顯示了),因為這里沒用到LCD,所以這個就省略

 

具體代碼:

 

init_camif_config(camera_dev);

 

static void init_camif_config(struct s5pc100_camera_device* c)

{

struct s5pc100_camera_device*cam = c;

 

cam->format = 3;// FIXME, C-path default format, see formats[] for detail.選擇C通道

 

 

cam->srcHsize = 640;//  FIXME, the OV9650's horizontal output pixels.設置圖像源的大小

 

cam->srcVsize = 480;// FIXME, the OV9650's verical output pixels.

 

設置圖像源的大小

 

 

 

 

 

cam->wndHsize = 640;

 

cam->wndVsize = 480; //window cut的設置

 

cam->targetHsize = cam->wndHsize;//

目標圖像格式的設置,與window圖像重疊,全覆蓋

 

cam->targetVsize = cam->wndVsize;

旋轉沒有設置

到目前為止,只是填充了cam的數據,但是camera控制器的源地址寄存器、目的地址寄存器都還沒有配置

這兩個寄存器的配置依賴於上面初始化的參數

 

update_camera_config(cam, (u32)-1);//這個函數中集成了一個函數,這個函數就是配置兩個寄存器的操作

 

}

 

static void update_camera_config (struct s5pc100_camera_device *c, u32 cmdcode)

{

struct s5pc100_camera_device *cam = c;

update_camera_regs(cam);// config the regs directly.封裝了下面的兩個函數,其實沒必要

}

 

static void __inline__ update_camera_regs(struct s5pc100_camera_device * cam)

{

update_source_fmt_regs(cam);

update_target_fmt_regs(cam);

}

 

 

 

初始化source寄存器

static void __inline__ update_source_fmt_regs(struct s5pc100_camera_device *c)
{
struct s5pc100_camera_device *cam = c;
u32 cfg;
 
cfg = (1<<31)// ITU-R BT.601 YCbCr 8-bit mode
|(0<<30)// CB,Cr value offset cntrol for YCbCr
|(640<<16)// target image width
|(0<<14)// input order is YCbYCr
|(640<<0);// source image height
writel(cfg, cam->reg_base + S5PC100_CISRCFMT);    //0xEE20_0000 + 0000_0000 圖像源地址
printk("S5PC100_CIGCFMT = %x\n", readl(cam->reg_base + S5PC100_CISRCFMT));
 
cfg = (1<<15)
|(1<<14)
|(1<<30)
|(1<<29);
 
writel(cfg, cam->reg_base + S5PC100_CIWDOFST);///0xEE20_0000 + 0000_0004 清緩存fifo
cfg = (1<<26)
|(1<<29)
|(1<<16)
|(1<<7)
|(0<<0);
writel(cfg, cam->reg_base + S5PC100_CIGCTRL);///0xEE20_0000 + 0000_0008全局變量控制寄存器,包含了使能IRQ中斷等操作
printk("S5PC100_CIGCTRL = %x\n", readl(cam->reg_base + S5PC100_CIGCTRL));
writel(0, cam->reg_base + S5PC100_CIWDOFST2);//0xEE20_0000 + 0000_0014窗口偏移寄存器
printk("OV9650_VGA mode\n");
}
 

 


初始化目的寄存器
static void __inline__ update_target_fmt_regs(struct s5pc100_camera_device * cam)
{
u32 cfg;
u32 h_shift;
u32 v_shift;
u32 prescaler_v_ratio;
u32 prescaler_h_ratio;
u32 main_v_ratio;
u32 main_h_ratio;
switch (formats[cam->format].pixelformat)
{
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YUYV:
/* YCbCr 1 plane*/
printk("format V4L2_PIX_FMT_YUYV");
writel(img_buff[0].phy_base, cam->reg_base + S5PC100_CIOYSA1);//
 0xEE20_0000 + 0000_0018 
DMAY1輸出開始地址寄存器
            將配置好的DMA物理開始地址賦給上述寄存器                                                                       
/* CIPRTRGFMT. */
cfg = (2 << 29) | (cam->targetHsize << 16)| (cam->targetVsize << 0)|(1<<13)|(1<<14)|(1<<15);
將cam里已經初始化好的大小信息移位,寫入對應的位置
writel(cfg, cam->reg_base + S5PC100_CITRGFMT);    //
 0xEE20_0000 + 0000_0048 目標格式寄存器
/* CISCPRERATIO. */
calculate_prescaler_ratio_shift(cam->srcHsize, cam->targetHsize, &prescaler_h_ratio, &h_shift);//將源的橫坐標進行壓縮,返回 壓縮率和移位數
calculate_prescaler_ratio_shift(cam->srcVsize, cam->targetVsize, &prescaler_v_ratio, &v_shift);//將源的縱坐標進行壓縮
 
main_h_ratio = (cam->srcHsize << 8) / (cam->targetHsize << h_shift);
main_v_ratio = (cam->srcVsize << 8) / (cam->targetVsize << v_shift);
 
cfg = ((10 - (h_shift + v_shift)) << 28) | (prescaler_h_ratio << 16) | (prescaler_v_ratio << 0);       //移位因子,即共移位多少次
writel(cfg, cam->reg_base + S5PC100_CISCPRERATIO);//
 0xEE20_0000 + 0000_0050縮放比例寄存器,實現了圖像的縮放處理
 
cfg = (cam->targetHsize << 16) | (cam->targetVsize << 0);
writel(cfg, cam->reg_base + S5PC100_CISCPREDST); //
 0xEE20_0000 + 0000_0054
最初的目的定位寄存器
 
cfg = (main_h_ratio << 16) | (main_v_ratio << 0);
writel(cfg, cam->reg_base + S5PC100_CISCCTRL); //main-scaler control Reg的配置
 
cfg = cam->targetVsize * cam->targetHsize;        //長*寬,0-27位,滿足了
writel(cfg, cam->reg_base + S5PC100_CITAREA);//輸出目標區域大小寄存器
 
cfg = (cam->targetVsize << 0) | (cam->targetHsize << 16);
writel(cfg, cam->reg_base + S5PC100_ORGOSIZE); //
0xEE20_0000 + 0000_0184 
DMA圖像開始坐標寄存器
break;
 
}
}
下面的函數的意思是:傳進來兩個參數,一個是源的大小,另個是目的的大小,如果源是目標的64倍以上就錯了,否則進行縮放,即源的大小是目標的32-64倍之間,就返回ratio(縮放比例)和shift(2的多少次冪),縮放比例是2的多少次冪,這樣做的目的是方便移位,因為移位都是2的倍數
int calculate_prescaler_ratio_shift(unsigned int SrcSize, unsigned int DstSize, unsigned int*ratio,unsigned int  *shift)
{
if(SrcSize>=64*DstSize) {
return -EINVAL;
}
else if(SrcSize>=32*DstSize) {
*ratio=32;
*shift=5;
}
else if(SrcSize>=16*DstSize) {
*ratio=16;
*shift=4;
}
else if(SrcSize>=8*DstSize) {
*ratio=8;
*shift=3;
}
else if(SrcSize>=4*DstSize) {
*ratio=4;
*shift=2;
}
else if(SrcSize>=2*DstSize) {
*ratio=2;
*shift=1;
}
else {
*ratio=1;
*shift=0;
} 
return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM