5345|1

468

帖子

0

TA的资源

纯净的硅(高级)

楼主
 

如何实现OV9650摄像头拍照(作者gooogleman/wogoyixikexie@gliet) [复制链接]

如何实现OV9650摄像头拍照(作者[email=gooogleman/wogoyixikexie@gliet]gooogleman/wogoyixikexie@gliet[/email])
//-------------------------------------------------------------------------------------------------
// Topic:如何实现OV9650摄像头拍照
// 作者:[email=wogoyixikexie@gliet]wogoyixikexie@gliet[/email]
// 论坛账号:gooogleman (经常在CSDN出没)
// 版权:桂林电子科技大学一系科协[email=wogoyixikexie@gliet]wogoyixikexie@gliet[/email]
// 平台:wince5.0 2440 5.0 BSP (飞凌FL2440开发板)
// 发布日期:2009年10月20日
// 最后修改:2009年11月4日 8:40:45
// 注意事项:未经作者同意,不得在转载的时候擅自修改、删除文章的任何部分
//-------------------------------------------------------------------------------------------------
       嘿嘿,最近很晕,实在是太忙了,一个月没有写一篇技术文章,破了我的记录,公司的事情,还有其他网友的事情,搞的我好累,以前我每个月至少十篇原创的,趁着现在不是很忙,写一下camera拍照的文档吧。
       在EVC camera拍照的程序里面有
       ret=DeviceIoControl(m_hled,CAM_IOCTL_SAMSUNG_CAM_PR,NULL,NULL,(PBYTE)&image,NULL,NULL,NULL);
CAM_IOCTL_SAMSUNG_CAM_PR是个命令,发送到camera 驱动中,在
CIS_IOControl函数中会接收这个命令。
case CAM_IOCTL_SAMSUNG_CAM_PR:  // ID=0x522
                     RETAILMSG(MSG_EN_1,(_T("CAM_IOCTL_SAMSUNG_CAM_PR\r\n")));
                     Samsung_camcoder_pr(pBufOut);// 和拍照相关
                     break;
       从代码看,完全是通过DeviceIoControl取得camera驱动中的数据,然后建立个BMP图像,把数据填写到BMP里面,这样保存就形成了图像。嘿嘿,现在来看看这个Samsung_camcoder_pr(pBufOut)到底干了什么。
void Samsung_camcoder_pr(U8 *pBufOut)
{
       U8 *pImage;
       PINGPONG_PR prinfo;
       pImage = pBufOut;
       if ( rgb_flag )
       {
              prinfo.flag = 1;
              prinfo.rgb_address = rgb_address;
              memcpy(pImage, &prinfo, sizeof(PINGPONG_PR));
              rgb_flag = 0;
       }     
}
       从上面的代码可以看出,其实只是获得rgb_address,即把rgb_address传递给EVC应用程序,现在再来看rgb_address是从哪里来的。
       嘿嘿,找到了,在下面的函数中用到了!


void Buffer_preview_info_update()
{
//     U32 Y_size;
       int temp;
       unsigned int buffer_rgb;

       temp = (s2440CAM->rCIPRSTATUS>>26)&3;
       temp = (temp + 2) % 4;

       RETAILMSG(MSG_EN_2,(_T("preview index = %d, size %d\r\n"), temp, image_size));

       switch (temp)
       {
       case 0:
              buffer_rgb = s2440CAM->rCIPRCLRSA1;
              break;
       case 1:
              buffer_rgb = s2440CAM->rCIPRCLRSA2;
              break;
       case 2:
              buffer_rgb = s2440CAM->rCIPRCLRSA3;
              break;
       case 3:
              buffer_rgb = s2440CAM->rCIPRCLRSA4;
              break;
       default :
              buffer_rgb = s2440CAM->rCIPRCLRSA1;
              break;
       }

       buffer_rgb += VIRTUAL_ADDR_OFFSET;
#if 0
       RETAILMSG(MSG_EN_1,(_T("buffer_rgb = 0x%x\r\n"), buffer_rgb));
#endif
       if( rgb_flag )   RETAILMSG(MSG_EN_1,(_T("Buffer is not read\r\n")));
       rgb_flag = 1;
       rgb_address = buffer_rgb;// RGB的地址,这个地址到底是多大?万一我要显示很大的图像怎么办?在哪里有设置的?
}
       暂时不理会上面的疑问,看看Buffer_preview_info_update在哪里被调用了先。嘿嘿,这个在中断的线程里面呢。
if (cam_intr == BIT_SUB_CAM_P)
{
       RETAILMSG(1, (TEXT(" Camera interrupt.....BIT_SUB_CAM_P@@@@")));
       Buffer_preview_info_update();
}

哦,这个Buffer_preview_info_update();还是和P通道中断相关的,C通道根本没有用。这也正常,因为我们的BMP图像时裸二进制的,未经压缩,所以用P通道合情合理。以后有空也可以玩玩C通道拍照。
       到目前为止,这个拍照过程就走完了。现在就来解决一个问题,如何拍照保存成一个较大的图片,这个我已经有了点思路,午休后再来尝试一下。
       刚才看到一个拍照关键的地方
switch (temp)
       {
       case 0:
              buffer_rgb = s2440CAM->rCIPRCLRSA1;
              break;
       case 1:
              buffer_rgb = s2440CAM->rCIPRCLRSA2;
              break;
       case 2:
              buffer_rgb = s2440CAM->rCIPRCLRSA3;
              break;
       case 3:
              buffer_rgb = s2440CAM->rCIPRCLRSA4;
              break;
       default :
              buffer_rgb = s2440CAM->rCIPRCLRSA1;
              break;
       }
buffer_rgb =?是关键,看了一下,是在
void CamInit(U32 CoDstWidth, U32 CoDstHeight, U32 PrDstWidth, U32 PrDstHeight,
                     U32 WinHorOffset, U32 WinVerOffset,  U32 CoFrameBuffer, U32 PrFrameBuffer)
里面有下面的代码
///////////////// preview port setting
s2440CAM->rCIPRCLRSA1=PrFrameBuffer;     // RGB帧地址,直接和保留的DMA地址绑定
s2440CAM->rCIPRCLRSA2=s2440CAM->rCIPRCLRSA1+PrDstWidth*PrDstHeight*multiplier;
s2440CAM->rCIPRCLRSA3=s2440CAM->rCIPRCLRSA2+PrDstWidth*PrDstHeight*multiplier;
s2440CAM->rCIPRCLRSA4=s2440CAM->rCIPRCLRSA3+PrDstWidth*PrDstHeight*multiplier;
// RGB帧地址是连续的,并且每一帧都保留了一定的空间(通过multiplier),当EVC程序拍照的时候就取得一帧的地址,然后就读下来。哦,看来要想把照片拍的大一些除了要修改应用以外,还要修改驱动中的PrDstWidth以及PrDstHeigh大小即可。
       好了,看懂了,明天再试试吧。
刚才我把camera EVC程序修改了一下图像大小,就立即产生了异常——原因是驱动中并没有设置足够的帧空间。
//width = 320;
//height = 240;
//
// if don't match the parameter of CamInit funtion---- U32 PrDstWidth, U32 PrDstHeight,
// will exception.Because the memory is not enough
//
width = 640;   
height = 480;


我把帧空间扩大了,
//
// 320*240
//
//CamInit(320, 240, 320, 240, 0, 0, COPIFRAMEBUFFER_B, COPIFRAMEBUFFER_A);

//
// 640*480
//
CamInit(320, 240, 640, 480, 0, 0, COPIFRAMEBUFFER_B, COPIFRAMEBUFFER_A);
现在是不会产生异常了,但是摄像头显示却变乱了,看来的确是要修改一下摄像头显示部分的代码。晕,拍照照样存在上面的异常,咋回事,现在这个空间都已经够了啊,难道是C通道和P通道的大小必须一致的?!改成一样试试。
我觉得还是内存空间不足造成的,因为我发现:
//
// 640*480
//
CamInit(320, 240, 640, 480, 0, 0, COPIFRAMEBUFFER_B, COPIFRAMEBUFFER_A);
看看COPIFRAMEBUFFER_B, COPIFRAMEBUFFER_A到底分配有多大?
#define COPIFRAMEBUFFER_A        0x32000000  // config.bib 82000000
#define COPIFRAMEBUFFER_B        0x32110000  // config.bib 82110000  
在config.bib里面有
;===================for camera DMA==================
CAMERA                            82000000  00110000    RESERVED
CAMERA_CODE                 82110000  00800000    RESERVED

如果要存储640*480的图片,那么从代码中可以看出
///////////////// preview port setting
s2440CAM->rCIPRCLRSA1=PrFrameBuffer;
s2440CAM->rCIPRCLRSA2=s2440CAM->rCIPRCLRSA1+PrDstWidth*PrDstHeight*multiplier;
s2440CAM->rCIPRCLRSA3=s2440CAM->rCIPRCLRSA2+PrDstWidth*PrDstHeight*multiplier;
s2440CAM->rCIPRCLRSA4=s2440CAM->rCIPRCLRSA3+PrDstWidth*PrDstHeight*multiplier;
这样就至少要物理内存空间640*480*2*4=0x00258000>0x00110000
也许问题就在这里了,嘿嘿,有办法解决。把P通道的内存和C通道的互换,这样就有空间了(0x00800000>0x00258000),先试试看看。晕死了,还是会产生一样的异常,为什么?在DNW窗口输出:
SENDING command id 0x03E8 to CDialog target.
Data Abort: Thread=985a3000 Proc=82936bb0 'Cameratest.exe'
AKY=00000801 PC=0005190c(Cameratest.exe+0x0004190c) RA=00051b70(Cameratest.exe+0x00041b70) BVA=7c0165e8 FSR=0000000f
找到对应的map文件地址
0001:000318fc [email=?PreSubclassWindow@CWnd@@UAAXXZ]?PreSubclassWindow@CWnd@@UAAXXZ[/email] 000428fc f   uafxwced:wincore.obj
0001:00031910       [email=?AfxWndProc@@YAJPAUHWND__@@IIJ@Z]?AfxWndProc@@YAJPAUHWND__@@IIJ@Z[/email] 00042910 f   uafxwced:wincore.obj

觉得不对劲啊,看来不能用普通的方法去排除这个异常。
       哦,目前产生异常,是否是这样原因?就是图像太大了,没有读完,这个camera又产生下一帧的中断了?我试试关闭中断在读的过程中
s2440INT->rINTMSK |= BIT_CAM;// 关闭camera中断
读图片的过程
s2440INT->rINTMSK &= ~BIT_CAM;// 打开camera中断
晕,关闭也没有用。后来娜娜提示我犯了严重的错误。真的好低级啊,居然是内存分配不够大。
//
       //320*240
       //
       //WORD width=GetSystemMetrics(SM_CXSCREEN);
       //WORD height=GetSystemMetrics(SM_CYSCREEN);
       BYTE* DDBdata=new BYTE[width*height*2];
因为是3.5寸的LCD,导致了这个郁闷的事情。OK,后来拍照成功!不过显示倒是不行了!再次按照如下修改,再次显示成功。
memcpy((void *)(IMAGE_FRAMEBUFFER_UA_BASE+ (240*2*pos_y + pos_x*2) + y*240*2),(void *)buffer_rgb,(size_x*2));
              //RETAILMSG(1,(_T("IMAGE_FRAMEBUFFER_UA_BASE(2)\r\n")));
              //跳到图像的下一行开始指针
              //buffer_rgb += (QCIF_XSIZE*2);      //320*240
              buffer_rgb += (640*2);  // 640*480
OK,完工,发布博客!
转载请标明:作者[email=wogoyixikexie@gliet]wogoyixikexie@gliet[/email].桂林电子科技大学一系科协,原文地址:http://www.cnblogs.com/wogoyixikexie/(或者我在CSDN的博客:http://blog.csdn.net/gooogleman)——如有错误,希望能够留言指出;如果你有更加好的方法,也请在博客后面留言,我会感激你的批评和分享。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gooogleman/archive/2009/11/04/4765653.aspx
此帖出自单片机论坛

最新回复

gooogleman目前在一家广州的公司做wince驱动工程师,并且兼职做2440/6410/2416开发板销售和技术支持,如果有需要请联系: 邮箱:gooogleman2@163.com 旺旺:gooogleman2 Q Q:1341675560 ---经常在线,如果旺旺无回复的时候,请及时加我的QQ。 开发板销售群:105082467 承诺:我卖开发板和一般人不一样,绝大多数人卖了之后是不回答源码问题的,但是我愿意回答bootloader以及wince驱动的问题,其余不懂的我也会给一些意见。我就当做学习,因为我在CSDN回帖一年多,感觉帮助别人也是帮助自己,我相信有我的帮助,至少在wince驱动方面,你会上手更快,bootloader我想我也能助你一臂之力。希望我们可以获得共同点,希望大家可以互惠互利。  详情 回复 发表于 2010-9-6 23:48
点赞 关注
个人签名
 

回复
举报

2

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
gooogleman目前在一家广州的公司做wince驱动工程师,并且兼职做2440/6410/2416开发板销售和技术支持,如果有需要请联系:
邮箱:gooogleman2@163.com
旺旺:gooogleman2
Q Q:1341675560 ---经常在线,如果旺旺无回复的时候,请及时加我的QQ。
开发板销售群:105082467

承诺:我卖开发板和一般人不一样,绝大多数人卖了之后是不回答源码问题的,但是我愿意回答bootloader以及wince驱动的问题,其余不懂的我也会给一些意见。我就当做学习,因为我在CSDN回帖一年多,感觉帮助别人也是帮助自己,我相信有我的帮助,至少在wince驱动方面,你会上手更快,bootloader我想我也能助你一臂之力。希望我们可以获得共同点,希望大家可以互惠互利。
此帖出自单片机论坛
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表