使用lcd显示摄像头数据的时候,发现720*480的cvbs摄像头头几帧会闪绿屏,而1280*720的mipi摄像头却没有问题,4in1的大图,也是同样的问题。dump前几帧数据,没有发现什么问题。感觉这个问题吧,与屏幕尺寸相关,我们的屏幕是1064*600的,也就是接近16:9。而720*480的尺寸比例是3:2;这个应该就是问题的所在吧。
fb的写入,是 ioctl DISP_LAYER_SET_CONFIG,传入的是物理地址。一开始加上了bsp_disp_shadow_protect,但是完全没什么卵用,依然存在问题。因此想自己设置一张黑色的图像传过去,当前的想法是,直接将一个buffer 设置成 width*height个0x00,然后将1/2width*height设置成128,这样就是nv12格式的黑色了。问题是,操作的时候,显示画面是花屏,不是黑屏。。。
1,通过DISP_MEM_GETADR获取到lcd缓冲的物理地址。
2,通过mmap将physical地址转换成virtual地址,那么第一个疑问就是,这个physical与virtual的关系是?physical应用没法操作,那么应用操作virtual的内容,会对physical地址的内容产生什么影响呢?
3,将dq出来的图像buffer数据,传给virtual,然后将virtual地址传给 fb,通过ioctl DISP_LAYER_SET_CONFIG 传入。这样显示是正常的。
4,构建一个buffer,将 width*height 设置成 0x00,然后将1/2width*height设置成128。然后,将这个数据memcpy到virtual地址。问题是,这个显示花屏,修改数据,就是乱七八糟的颜色。。。
5,dump buffer,发现数据不对,并不是 buffer拷贝进去的数据。然后做了反向测试,将v4l2 buffer里面的数据,拷贝到 buffer中,发现也不一样。memcpy,mmap,physical地址,virsual地址。问题,到底在哪???
首先,了解一下mmap的原理,
virtualAddr = mmap(phyAddr, PAGE_SIZE, PROT_WRITE, MAP_SHARED, f, paddr & PAGE_MASK);
用户调用mmap后,在进入disp_mmap之前,就已经为在进程空间申请号了进程地址空间,会存到一个新的vma结构体中,如果mmap第一个入参为NULL,则这块地址空间的起始地址有linux 自动分配,长度为第二个参数。fb_mmap的入参vma就是之前分配的vma。vm_pgoff 是前面mmap传入的paddr。
int disp_mmap(struct file *file, struct vm_area_struct * vma)
{
unsigned long mypfn = vma->vm_pgoff;
unsigned long vmsize = vma->vm_end-vma->vm_start;
if (!disp_mem_check_valid(mypfn))
return -EINVAL;
vma->vm_pgoff = 0;
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
if (remap_pfn_range(vma,//虚拟内存区域,即设备地址将要映射到这里
vma->vm_start,//虚拟空间的起始地址
mypfn,//与物理内存对应的页帧号,物理地址右移12位
vmsize,//映射区域大小,一般是页大小的整数倍
vma->vm_page_prot))//保护属性,
return -EAGAIN;
return 0;
}
mmap系统调用的最终目的是将,设备或文件映射到用户进程的虚拟地址空间,实现用户进程对文件的直接读写,这个任务可以分为以下三步:
1.在用户虚拟地址空间中寻找空闲的满足要求的一段连续的虚拟地址空间,为映射做准备(由内核mmap系统调用完成)
2. 建立虚拟地址空间和文件或设备的物理地址之间的映射(设备驱动完成)
建立文件映射的第二步就是建立虚拟地址和具体的物理地址之间的映射,这是通过修改进程页表来实现的.mmap方法是file_opeartions结构的成员: disp_mmap,
3. 当实际访问新映射的页面时的操作(由缺页中断完成)
总的来说,将物理内存映射到用户空间,使用虚拟内存来访问。看了video的代码,貌似copy完了之后,都会进行一次flushcach,为啥呢?