以前没整过 2440 ,一直都在整 2410 ,一个项目要用到摄像头,就在 2410 下,用 OV511 摄像头, USB 接口的,到是可以测试通过,但是像素太低了, 30 万的,而且听说 USB 接口的不太稳定,后来就听了 gooogleman 的建议,换了处理器,也升级了操作系统,以前都是在 4.2 下混的,现在也开始 5.0 了,呵呵
拿到 2440 板子,也不是很陌生,毕竟以前整 2410 的嘛,我自己也有块 2440 的板子,没事也倒持倒持呢。只是对于摄像头不是很熟悉,这次选的是 OV9650 的, Camera 接口、 130 万像素
调试过程中出现了好多问题,现列出,希望对大家有帮助,少走弯路
1、 Camera 驱动加载不成功
厂家给的 BSP 包里面是带 Camera.dll 文件的 , 后来自己加载的,老是编译不通过,出的信息还奇奇怪怪的,查了查,发现是细节问题,我的 sources 文件里的 TARGETNAME=camera 和我的驱动不对应,修改一致后,就可以编译通过了
2、 应用程序采集过来的图像,占半个屏幕
不管你怎么样调整应用程序,出现的老是一个在左半屏上显示
后来发现是显示参数设置不对,把这个参数给设置成了 NULL 了
// 定义显示区域的空间
DISINFO DisInfo=
{
320, //display x 显示的 X 长度
240, //display y 显示的 Y 长度
0, //display off x 显示的起点 X 坐标
0 //display off y 显示的起点 Y 坐标
};
DeviceIoControl(m_hled,CAM_IOCTL_SET_CAMIF,&CamInfo ,NULL,NULL,NULL,NULL,NULL);
3、 拍照的时候出现数据终止,只要 memcpy 就会出现数据终止,肯定是内存那出问题了
查看应用程序,代码如下
// 拍照
void COV9650Dlg::Onpaizhao()
{
// TODO: Add your control notification handler code here
PINGPONG_PR image;
WORD width=GetSystemMetrics(SM_CXSCREEN);//240
WORD height=GetSystemMetrics(SM_CYSCREEN);//320
BOOL ret;
BYTE* DDBdata=new BYTE[width*height*2];
BYTE* DIBdata;
ret=DeviceIoControl(m_hled,CAM_IOCTL_SAMSUNG_CAM_PR,NULL,NULL,(PBYTE)&image,NULL,NULL,NULL);// 采集新的一帧
if(!ret)
AfxMessageBox(_T(" 读取图片失败 !"));
else
{
SetKMode(TRUE);
memcpy(DDBdata,(void *)image.rgb_address,width*height*2);
SetKMode(FALSE);
CBitmap bitmap;// 图片
HBITMAP dstBmp;
bitmap.CreateBitmap(width,height,1,16,DDBdata);// 创建一张位图
HDC hdcSrc = CreateCompatibleDC(NULL);
HDC hdcDst = CreateCompatibleDC(NULL);
BITMAPINFOHEADER bih = {0};// 位图信息头
bih.biBitCount = 16;// 每个像素字节大小
bih.biCompression = BI_RGB;
bih.biHeight = height;// 高度
bih.biPlanes = 1;
bih.biSize = sizeof(BITMAPINFOHEADER);
bih.biSizeImage = 0;// width*height*2;// 图像数据大小
bih.biWidth = width;// 宽度
BITMAPFILEHEADER bfh = {0};// 位图文件头
bfh.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);// 到位图数据的偏移量
bfh.bfSize = bfh.bfOffBits + width*height*2;// 文件总的大小
bfh.bfType = (WORD)0x4d42;
BITMAPINFO bi={0};
bi.bmiHeader=bih;
dstBmp=CreateDIBSection(hdcDst, (BITMAPINFO*)&bi, DIB_RGB_COLORS, (void **)&DIBdata, NULL, 0);
SelectObject(hdcDst, dstBmp);
SelectObject(hdcSrc, bitmap);
BitBlt(hdcDst, 0, 0, width, height, hdcSrc, 0, 0, SRCCOPY);// 将位图复制到实际的设备环境中
CFile file(_T("123.bmp"),CFile::modeCreate|CFile::modeReadWrite);
file.Write(&bfh,sizeof(bfh));
file.Write(&bih,sizeof(bih));
file.Write(DIBdata,width*height*2);
file.Close();
}
delete []DDBdata;
}
ret=DeviceIoControl(m_hled,CAM_IOCTL_SAMSUNG_CAM_PR,NULL,NULL,(PBYTE)&image,NULL,NULL,NULL);// 采集新的一帧
采集最近的一帧,返回结构体的地址,其中,结构体中就有一项是帧信息的内存地址
memcpy(DDBdata,(void *)image.rgb_address,width*height*2);
把内存地址中的数据取出来,存放在开辟好的 DDBdata 空间中
驱动部分代码如下:
调用 CIS_IOControl ()函数,实现采集 RGB 最近一桢的内存地址
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;
然后又调用 Samsung_camcoder_pr ,取得结构体的地址
结构体如下:
typedef struct PINGPONG_PR
{
unsigned int rgb_address; //RGB 信息的内存地址
unsigned char flag; // 读标志位
} PINGPONG_PR;
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; 变量是在 Buffer_preview_info_update() 中调用的
void Buffer_preview_info_update()
{
// U32 Y_size;
int temp;
unsigned int buffer_rgb;
temp = (s2440CAM->CIPRSTATUS>>26)&3;
temp = (temp + 2) % 4;
switch (temp)
{
case 0:
buffer_rgb = s2440CAM->CIPRCLRSA1;
break;
case 1:
buffer_rgb = s2440CAM->CIPRCLRSA2;
break;
case 2:
buffer_rgb = s2440CAM->CIPRCLRSA3;
break;
case 3:
buffer_rgb = s2440CAM->CIPRCLRSA4;
break;
default :
buffer_rgb = s2440CAM->CIPRCLRSA1;
break;
}
buffer_rgb += VIRTUAL_ADDR_OFFSET;
if( rgb_flag ) RETAILMSG(MSG_EN_1,(_T("Prev Buffer is not read\r\n")));
rgb_flag = 1;
rgb_address = buffer_rgb;
}
Buffer_preview_info_update() 函数是在中断的时候,要执行的,忘了这一点,没有实时得去刷新这个 rgb_address 得到的
if (cam_intr & ( 1 << IRQ_SUB_CAM_P ))
{
// display the image
if (DisplayEnable== 1)
Display_Cam_Image(sDISINFO.pos_x,sDISINFO.pos_y,sDISINFO.dis_x, sDISINFO.dis_y, PORT_A);
//Buffer_preview_info_update();
cam_intr &= ~( 1 << IRQ_SUB_CAM_P );
}
4、 增多分辨率,出现数据终止
前边做的都是 320*240 的,现在想增加分辨率,竟然也出现了上面的现象,数据终止
仔细看了看,发现竟然是开辟空间那出错了
WORD width=GetSystemMetrics(SM_CXSCREEN);//240
WORD height=GetSystemMetrics(SM_CYSCREEN);//320
BOOL ret;
BYTE* DDBdata=new BYTE[width*height*2];
BYTE* DIBdata;
我用的是 3.5 寸的屏,所以通过 GetSystemMetrics 返回的是 320 和 240 而我后面开辟空间的时候也就开辟了 320*240*2 字节空间,而我现需要 640*480*2 ,肯定会空间不足,导致数据终止,所以在开辟空间的时候,要开辟 640*480*2 字节空间才可以
前面的都是我在调试摄像头的时候 遇到的问题,不过现在还有些东西不太明白
1 、 void Display_Cam_Image(U32 pos_x, U32 pos_y, U32 size_x, U32 size_y, U8 port)
{
U8 *buffer_rgb;
U32 y;
int temp;
//unsigned short *ptr = (unsigned short *)(FRAMEBUF_BASE+0x5dc0);
//static unsigned short transfer_data[QCIF_XSIZE*QCIF_YSIZE];
static unsigned int time,old_time;
//RETAILMSG(MSG_EN_1,(_T("Display_Cam_Image()\r\n")));
// if (port)
{
temp = (s2440CAM->CIPRSTATUS>>26)&3;
temp = (temp + 2) % 4;// 为什么要执行这步操作?
switch (temp)
{
case 0:
buffer_rgb = (U8 *)s2440CAM->CIPRCLRSA1;
break;
case 1:
buffer_rgb = (U8 *)s2440CAM->CIPRCLRSA2;
break;
case 2:
buffer_rgb = (U8 *)s2440CAM->CIPRCLRSA3;
break;
case 3:
buffer_rgb = (U8 *)s2440CAM->CIPRCLRSA4;
break;
default :
buffer_rgb = (U8 *)s2440CAM->CIPRCLRSA1;
break;
}
}
buffer_rgb += VIRTUAL_OFFSET;
CI PRCLRSA1 、 CIPRCLRSA2 、 CIPRCLRSA3 、 CIPRCLRSA4 这四个到底是有啥关系呢
2 、这个函数,为什么有的 %16 、 %8 、 %4 ,这中间有啥关系呢?
void CalculateBurstSize(unsigned int hSize,unsigned int *mainBurstSize,unsigned int *remainedBurstSize)
{
unsigned int tmp;
tmp=(hSize/4)%16;
switch(tmp) {
case 0:
*mainBurstSize=16;
*remainedBurstSize=16;
break;
case 4:
*mainBurstSize=16;
*remainedBurstSize=4;
break;
case 8:
*mainBurstSize=16;
*remainedBurstSize=8;
break;
default:
tmp=(hSize/4)%8;
switch(tmp) {
case 0:
*mainBurstSize=8;
*remainedBurstSize=8;
break;
case 4:
*mainBurstSize=8;
*remainedBurstSize=4;
default:
*mainBurstSize=4;
tmp=(hSize/4)%4;
*remainedBurstSize= (tmp) ? tmp: 4;
break;
}
break;
}
}