这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 软件与操作系统 » 关于S3C2440 linux下使用CODEC通道采集UYVY422图像,并输出

共14条 1/2 1 2 跳转至

关于S3C2440 linux下使用CODEC通道采集UYVY422图像,并输出YUV422、YUV420P图像文件的驱动代码、测试代码

高工
2015-05-12 10:24:29     打赏

关于S3C2440,linux下使用CODEC通道采集UYVY422图像,并输出YUV422、YUV420P图像文件 1280x1024。

在mini2440开发板上,linux-2.6.32.2下驱动S3C2440 codec通道,采集ov9650摄像头UYVY422图像的方法:

1.首先必须的文件材料:
资料文档:
S3C2440 camera接口使用说明(关键是寄存器说明),OV9650 datesheet;
软件:
使用mini2440的linux-2.6.32.2版本,这其中自带了S3C2440 camera 接口preview通道的驱动文件;(我在此基础上进行CODEC通道的驱动修改)其中包含的文件有s3c440camif.c、s3c2440camif.h、s3c2440_ov9650.c、sccb.c、sccb.h 五个文件。
硬件:
mini2440开发板,ov9650摄像头模组。

2.修改驱动文件:
其中修改主要为codec通道寄存器的使用,所以按照原有驱动文件中的寄存器修改顺心来修改;
A、寄存器CISRCFMT
此处的驱动无需修改,只将bit29位设置成0即可,完整代码如下:

/* update CISRCFMT only. */
static void __inline__ update_source_fmt_regs(struct s3c2440camif_dev * pdev)
{
u32 cisrcfmt;

cisrcfmt = (1<<31) // ITU-R BT.601 YCbCr 8-bit mode
|(0<<30) // CB,Cr value offset cntrol for YCbCr
|(0<<29) //changed by yecx
|(pdev->srcHsize<<16) // source image width
//    |(0<<14) // input order is YCbYCr /*changed by yecx*/
//    |(1<<14) // input order is YCrYCb
|(2<<14) // input order is CbYCrY /*changed by yecs*/
//    |(3<<14) // input order is CrYCbY
|(pdev->srcVsize<<0); // source image height

iowrite32(cisrcfmt, S3C244X_CISRCFMT);
}

B、寄存器
* CODEC path:
*  CICOYSA1 ~ CICOYSA4
*  CICOCBSA1 ~ CICOCBSA4
*  CICOCRSA1 ~ CICOCRSA4
*  CICOTRGFMT
*  CICOCTRL
*  CICOTAREA
等修改:
将原有的preview通道代码注释掉,主要修改codec通道的DMA存储虚拟地址,输入图像格式(YCbCr422)输出图像格式依然是(YCbCr422),计算BURST的SIZE,全部修改如以下代码:
/* update registers:
* PREVIEW path:
*  CIPRCLRSA1 ~ CIPRCLRSA4
*  CIPRTRGFMT
*  CIPRCTRL
*  CIPRSCCTRL
*  CIPRTAREA
* CODEC path:
*  CICOYSA1 ~ CICOYSA4
*  CICOCBSA1 ~ CICOCBSA4
*  CICOCRSA1 ~ CICOCRSA4
*  CICOTRGFMT
*  CICOCTRL
*  CICOTAREA
*/
static void __inline__ update_target_fmt_regs(struct s3c2440camif_dev * pdev)
{
#if 0
u32 ciprtrgfmt;
u32 ciprctrl;
u32 ciprscctrl;

u32 mainBurstSize, remainedBurstSize;

/* CIPRCLRSA1 ~ CIPRCLRSA4. */
iowrite32(img_buff[0].phy_base, S3C244X_CIPRCLRSA1);
iowrite32(img_buff[1].phy_base, S3C244X_CIPRCLRSA2);
iowrite32(img_buff[2].phy_base, S3C244X_CIPRCLRSA3);
iowrite32(img_buff[3].phy_base, S3C244X_CIPRCLRSA4);

/* CIPRTRGFMT. */
ciprtrgfmt = (pdev->preTargetHsize<<16) // horizontal pixel number of target image
|(0<<14) // don't mirror or rotation.
|(pdev->preTargetVsize<<0); // vertical pixel number of target image
iowrite32(ciprtrgfmt, S3C244X_CIPRTRGFMT);

/* CIPRCTRL. */
calc_burst_size(2, pdev->preTargetHsize, &mainBurstSize, &remainedBurstSize);
ciprctrl = (mainBurstSize<<19)|(remainedBurstSize<<14);
iowrite32(ciprctrl, S3C244X_CIPRCTRL);

/* CIPRSCCTRL. */
ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= 1<<15; // clear all other info except 'preview scaler start'.
ciprscctrl |= 0<<30; // 16-bits RGB
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL); // 16-bit RGB

/* CIPRTAREA. */
iowrite32(pdev->preTargetHsize * pdev->preTargetVsize, S3C244X_CIPRTAREA);
#endif
/************changed by yecx***************************/
/*
*  CICOYSA1 ~ CICOYSA4
*  CICOCBSA1 ~ CICOCBSA4
*  CICOCRSA1 ~ CICOCRSA4
*/

u32 cicotrgfmt;
u32 cicoctrl;

u32 mainBurstSizeY, remainedBurstSizeY;
u32 mainBurstSizeC, remainedBurstSizeC;
//#if 0
//UYVY422
iowrite32(img_buff[0].phy_base, S3C244X_CICOYSA1);
iowrite32(img_buff[0].phy_base+(1280*1024), S3C244X_CICOCBSA1);
iowrite32(img_buff[0].phy_base+(1280*1024)+(1280*1024/2), S3C244X_CICOCRSA1);

iowrite32(img_buff[1].phy_base, S3C244X_CICOYSA2);
iowrite32(img_buff[1].phy_base+(1280*1024), S3C244X_CICOCBSA2);
iowrite32(img_buff[1].phy_base+(1280*1024)+(1280*1024/2), S3C244X_CICOCRSA2);

iowrite32(img_buff[2].phy_base, S3C244X_CICOYSA3);
iowrite32(img_buff[2].phy_base+(1280*1024), S3C244X_CICOCBSA3);
iowrite32(img_buff[2].phy_base+(1280*1024)+(1280*1024/2), S3C244X_CICOCRSA3);

iowrite32(img_buff[3].phy_base, S3C244X_CICOYSA4);
iowrite32(img_buff[3].phy_base+(1280*1024), S3C244X_CICOCBSA4);
iowrite32(img_buff[3].phy_base+(1280*1024)+(1280*1024/2), S3C244X_CICOCRSA4);
//#endif

/* CICOTRGFMT. */
cicotrgfmt = (1<<31) //In422_Co YCbCr4:2:2
|(1<<30) //Out422_Co YCbCr4:2:2
|(pdev->coTargetHsize<<16) // horizontal pixel number of target image
|(0<<14) // don't mirror or rotation.
|(pdev->coTargetVsize<<0); // vertical pixel number of target image
iowrite32(cicotrgfmt, S3C244X_CICOTRGFMT);

/* CICOCTRL. */
calc_burst_size(4, pdev->coTargetHsize, &mainBurstSizeY, &remainedBurstSizeY);
calc_burst_size(4, pdev->coTargetHsize/2, &mainBurstSizeC, &remainedBurstSizeC);
cicoctrl = (mainBurstSizeY<<19)|(remainedBurstSizeY<<14)|(mainBurstSizeC<<9)|(remainedBurstSizeC);
iowrite32(cicoctrl, S3C244X_CICOCTRL);

/* CIPRTAREA. */
iowrite32(pdev->coTargetHsize * pdev->coTargetVsize, S3C244X_CICOTAREA);
/************changed by yecx***************************/
}

C、寄存器CIWDOFST 无需多改动:
代码改动结果如下:

/* update CIWDOFST only. */
static void __inline__ update_target_wnd_regs(struct s3c2440camif_dev * pdev)
{
u32 ciwdofst;
u32 winHorOfst, winVerOfst;

winHorOfst = (pdev->srcHsize - pdev->wndHsize)>>1;
winVerOfst = (pdev->srcVsize - pdev->wndVsize)>>1;

winHorOfst &= 0xFFFFFFF8;
winVerOfst &= 0xFFFFFFF8;
if ((winHorOfst == 0)&&(winVerOfst == 0))
{
ciwdofst = 0; // disable windows offset.
}
else
{
ciwdofst = (1<<31) // window offset enable
|(1<<30) // clear the overflow ind flag of input CODEC FIFO Y
|(winHorOfst<<16) // windows horizontal offset
|(1<<15) // clear the overflow ind flag of input CODEC FIFO Cb
|(1<<14) // clear the overflow ind flag of input CODEC FIFO Cr
|(1<<13) // clear the overflow ind flag of input PREVIEW FIFO Cb
|(1<<12) // clear the overflow ind flag of input PREVIEW FIFO Cr
|(winVerOfst<<0); // window vertical offset
}

iowrite32(ciwdofst, S3C244X_CIWDOFST);
}

D、寄存器

* CODEC path:
*  CICOSCPRERATIO
*  CICOSCPREDST
*  CICOSCCTRL

修改为:

static void __inline__ update_target_zoom_regs(struct s3c2440camif_dev * pdev)
{
#if 0
u32 preHratio, preVratio;
u32 Hshift, Vshift;
u32 shfactor;
u32 preDstWidth, preDstHeight;
u32 Hscale, Vscale;
u32 mainHratio, mainVratio;

u32 ciprscpreratio;
u32 ciprscpredst;
u32 ciprscctrl;


/* CIPRSCPRERATIO. */
calc_prescaler_ratio_shift(pdev->wndHsize, pdev->preTargetHsize,
&preHratio, &Hshift);
calc_prescaler_ratio_shift(pdev->wndVsize, pdev->preTargetVsize,
&preVratio, &Vshift);

shfactor = 10 - (Hshift + Vshift);

ciprscpreratio = (shfactor<<28) // shift factor for preview pre-scaler
|(preHratio<<16) // horizontal ratio of preview pre-scaler
|(preVratio<<0); // vertical ratio of preview pre-scaler
iowrite32(ciprscpreratio, S3C244X_CIPRSCPRERATIO);

/* CIPRSCPREDST. */
preDstWidth = pdev->wndHsize / preHratio;
preDstHeight = pdev->wndVsize / preVratio;
ciprscpredst = (preDstWidth<<16) // destination width for preview pre-scaler
|(preDstHeight<<0); // destination height for preview pre-scaler
iowrite32(ciprscpredst, S3C244X_CIPRSCPREDST);

/* CIPRSCCTRL. */
Hscale = (pdev->wndHsize >= pdev->preTargetHsize)?0:1;
Vscale = (pdev->wndVsize >= pdev->preTargetVsize)?0:1;
mainHratio = (pdev->wndHsize<<8)/(pdev->preTargetHsize< mainVratio = (pdev->wndVsize<<8)/(pdev->preTargetVsize< ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl &= (1<<30)|(1<<15); // keep preview image format (RGB565 or RGB24), and preview scaler start state.
ciprscctrl |= (1<<31) // this bit should be always 1.
|(Hscale<<29) // ???, horizontal scale up/down.
|(Vscale<<28) // ???, vertical scale up/down.
|(mainHratio<<16) // horizontal scale ratio for preview main-scaler
|(mainVratio<<0); // vertical scale ratio for preview main-scaler
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);
#endif
/************************changed by yecx**************************/
u32 coHratio, coVratio;
u32 Hshift_co, Vshift_co;
u32 shfactor_co;
u32 coDstWidth, coDstHeight;
u32 Hscale_co, Vscale_co;
u32 mainHratio_co, mainVratio_co;

u32 cicoscpreratio;
u32 cicoscpredst;
u32 cicoscctrl;

/* CICOSCPRERATIO. */
calc_prescaler_ratio_shift(pdev->wndHsize, pdev->coTargetHsize,
&coHratio, &Hshift_co);
calc_prescaler_ratio_shift(pdev->wndVsize, pdev->coTargetVsize,
&coVratio, &Vshift_co);

shfactor_co = 10 - (Hshift_co + Vshift_co);

cicoscpreratio = (shfactor_co<<28) // shift factor for preview pre-scaler
|(coHratio<<16) // horizontal ratio of preview pre-scaler
|(coVratio<<0); // vertical ratio of preview pre-scaler
iowrite32(cicoscpreratio, S3C244X_CICOSCPRERATIO);

/* CICOSCPREDST. */
coDstWidth = pdev->wndHsize / coHratio;
coDstHeight = pdev->wndVsize / coVratio;
cicoscpredst = (coDstWidth<<16) // destination width for preview pre-scaler
|(coDstHeight<<0); // destination height for preview pre-scaler
iowrite32(cicoscpredst, S3C244X_CICOSCPREDST);

/* CICOSCCTRL. */
Hscale_co = (pdev->wndHsize >= pdev->coTargetHsize)?0:1;
Vscale_co = (pdev->wndVsize >= pdev->coTargetVsize)?0:1;
mainHratio_co = (pdev->wndHsize<<8)/(pdev->coTargetHsize< mainVratio_co = (pdev->wndVsize<<8)/(pdev->coTargetVsize< cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
//cicoscctrl &= (1<<30)|(1<<15); // keep preview image format (RGB565 or RGB24), and preview scaler start state.
cicoscctrl |= (0<<31) // this bit should be always 1.
|(Hscale_co<<30) // ???, horizontal scale up/down.
|(Vscale_co<<29) // ???, vertical scale up/down.
|(mainHratio_co<<16) // horizontal scale ratio for preview main-scaler
|(mainVratio_co<<0); // vertical scale ratio for preview main-scaler
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
/************************changed by yecx**************************/
}

E、然后是采集的程序修改:

/* start image capture.
*
* param 'stream' means capture pictures streamly or capture only one picture.
*/
static int start_capture(struct s3c2440camif_dev * pdev, int stream)
{
#if 0
int ret;

u32 ciwdofst;
u32 ciprscctrl;
u32 ciimgcpt;

ciwdofst = ioread32(S3C244X_CIWDOFST);
ciwdofst |= (1<<30) // Clear the overflow indication flag of input CODEC FIFO Y
|(1<<15) // Clear the overflow indication flag of input CODEC FIFO Cb
|(1<<14) // Clear the overflow indication flag of input CODEC FIFO Cr
|(1<<13) // Clear the overflow indication flag of input PREVIEW FIFO Cb
|(1<<12); // Clear the overflow indication flag of input PREVIEW FIFO Cr
iowrite32(ciwdofst, S3C244X_CIWDOFST);

ciprscctrl = ioread32(S3C244X_CIPRSCCTRL);
ciprscctrl |= 1<<15; // preview scaler start
iowrite32(ciprscctrl, S3C244X_CIPRSCCTRL);

pdev->state = CAMIF_STATE_PREVIEWING;

ciimgcpt = (1<<31) // camera interface global capture enable
|(1<<29); // capture enable for preview scaler.
iowrite32(ciimgcpt, S3C244X_CIIMGCPT);

ret = 0;
if (stream == 0)
{
pdev->cmdcode = CAMIF_CMD_STOP;

ret = wait_event_interruptible(pdev->cmdqueue, pdev->cmdcode == CAMIF_CMD_NONE);
}
return ret;
#endif
/*******************************changedn by yecx******************************/
int ret;

u32 ciwdofst;
u32 cicoscctrl;
u32 ciimgcpt;

ciwdofst = ioread32(S3C244X_CIWDOFST);
ciwdofst |= (1<<30) // Clear the overflow indication flag of input CODEC FIFO Y
|(1<<15) // Clear the overflow indication flag of input CODEC FIFO Cb
|(1<<14) // Clear the overflow indication flag of input CODEC FIFO Cr
|(1<<13) // Clear the overflow indication flag of input PREVIEW FIFO Cb
|(1<<12); // Clear the overflow indication flag of input PREVIEW FIFO Cr
iowrite32(ciwdofst, S3C244X_CIWDOFST);
printk("S3C244X_CIWDOFST = 0x%08x\n",ioread32(S3C244X_CIWDOFST));//debug

cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl |= 1<<15; // preview scaler start
cicoscctrl |= 1<<31;
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
printk("S3C244X_CICOSCCTRL = 0x%08x\n",ioread32(S3C244X_CICOSCCTRL));//debug

pdev->state = CAMIF_STATE_CODECING;

ciimgcpt = ioread32(S3C244X_CIIMGCPT);
ciimgcpt |= (6<<29); // camera interface global capture enable
// capture enable for codec scaler.
iowrite32(ciimgcpt, S3C244X_CIIMGCPT);
printk("S3C244X_CIIMGCPT = 0x%08x\n",ioread32(S3C244X_CIIMGCPT));//debug

ret = 0;
if (stream == 0)
{
pdev->cmdcode = CAMIF_CMD_STOP;

ret = wait_event_interruptible(pdev->cmdqueue, pdev->cmdcode == CAMIF_CMD_NONE);
}
return ret;
/*******************************changedn by yecx******************************/
}

F、最后一步非常重要,设置DMAbuf的启动,不然会采集不到数据。
在下面的中断函数体中增加一句代码:
static irqreturn_t on_camif_irq_c(int irq, void * dev){
。。。。。。。。。。
。。。。。。。。。。
pdev = (struct s3c2440camif_dev *)dev;

/* valid img_buff[x] just DMAed. */
frame = (cicostatus&(3<<26))>>26;
frame = (frame+4-1)%4;
img_buff[frame].state = CAMIF_BUFF_YCbCr422;  //changed by yecx 此处为增加的代码

if (pdev->cmdcode & CAMIF_CMD_STOP)
{
stop_capture(pdev);

pdev->state = CAMIF_STATE_READY;
}
else
。。。。。。。。。。
。。。。。。。。。。

}

2、修改上述代码采集YUV420 YV12代码;

主要是DMA 通道地址,和out put 420 bit位修改,代码如下:

u32 cicotrgfmt;
u32 cicoctrl;

u32 mainBurstSizeY, remainedBurstSizeY;
u32 mainBurstSizeC, remainedBurstSizeC;
//#if 0
//UYVY420
iowrite32(img_buff[0].phy_base, S3C244X_CICOYSA1);
iowrite32(img_buff[0].phy_base+(1280*1024), S3C244X_CICOCBSA1);
iowrite32(img_buff[0].phy_base+(1280*1024)+(1280*1024/4), S3C244X_CICOCRSA1);

iowrite32(img_buff[1].phy_base, S3C244X_CICOYSA2);
iowrite32(img_buff[1].phy_base+(1280*1024), S3C244X_CICOCBSA2);
iowrite32(img_buff[1].phy_base+(1280*1024)+(1280*1024/4), S3C244X_CICOCRSA2);

iowrite32(img_buff[2].phy_base, S3C244X_CICOYSA3);
iowrite32(img_buff[2].phy_base+(1280*1024), S3C244X_CICOCBSA3);
iowrite32(img_buff[2].phy_base+(1280*1024)+(1280*1024/4), S3C244X_CICOCRSA3);

iowrite32(img_buff[3].phy_base, S3C244X_CICOYSA4);
iowrite32(img_buff[3].phy_base+(1280*1024), S3C244X_CICOCBSA4);
iowrite32(img_buff[3].phy_base+(1280*1024)+(1280*1024/4), S3C244X_CICOCRSA4);
//#endif

/* CICOTRGFMT. */
cicotrgfmt = (1<<31) //In422_Co YCbCr4:2:2
|(0<<30) //Out422_Co YCbCr4:2:0
|(pdev->coTargetHsize<<16) // horizontal pixel number of target image
|(0<<14) // don't mirror or rotation.
|(pdev->coTargetVsize<<0); // vertical pixel number of target image
iowrite32(cicotrgfmt, S3C244X_CICOTRGFMT);

/* CICOCTRL. */
calc_burst_size(4, pdev->coTargetHsize, &mainBurstSizeY, &remainedBurstSizeY);
calc_burst_size(4, pdev->coTargetHsize/2, &mainBurstSizeC, &remainedBurstSizeC);
cicoctrl = (mainBurstSizeY<<19)|(remainedBurstSizeY<<14)|(mainBurstSizeC<<9)|(remainedBurstSizeC);
iowrite32(cicoctrl, S3C244X_CICOCTRL);

/* CIPRTAREA. */
iowrite32(pdev->coTargetHsize * pdev->coTargetVsize, S3C244X_CICOTAREA);
/************changed by yecx***************************/

修改采集代码驱动部分:


cicoscctrl = ioread32(S3C244X_CICOSCCTRL);
cicoscctrl |= 1<<15; // preview scaler start
cicoscctrl |= 0<<31; // YUV422 SET BIT 1,YUV420 SET BIT 0,changed by yecx
iowrite32(cicoscctrl, S3C244X_CICOSCCTRL);
printk("S3C244X_CICOSCCTRL = 0x%08x\n",ioread32(S3C244X_CICOSCCTRL));//debug

pdev->state = CAMIF_STATE_CODECING;




大家最关心的代码(包括驱动代码,测试代码):

——回复可见内容——


采集到的图像文件上传一下:

采集到的图像文件YUV422 YUV420.zip


用于播放图像的软件上传一下:

图像播放软件.zip


enjoy it !!!

后面还采用了X264库编写的采集压缩yuv420p视频文件为x264视频文件。如果有需要的童鞋,我会另外开一个贴发出。 压缩速率很低,目前还在探索中。


x264压缩文件:

encode100f.zip

上面的文件可以用VLC打开看看的,格式是264的压缩视频文件。




关键词: 关于S3C2440     linux下使用CODEC通道    

院士
2015-05-12 10:28:30     打赏
2楼
我勒个去~~~~

高工
2015-05-12 11:04:46     打赏
3楼
知道了。

菜鸟
2015-09-28 17:29:15     打赏
4楼
学习一下

菜鸟
2015-12-17 16:41:11     打赏
5楼
修改好了,看看效果

菜鸟
2016-05-19 21:43:00     打赏
6楼
不知道楼主是怎么存储的呢?

菜鸟
2016-06-07 00:37:17     打赏
7楼
参观参观

菜鸟
2017-06-22 11:09:07     打赏
8楼
学习学习

菜鸟
2017-07-21 23:38:29     打赏
9楼
好好学习天天向上

菜鸟
2022-04-25 11:08:01     打赏
10楼

谢谢分享~


共14条 1/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]