pdat->index = (pdat->index + 1) & 0x1;
memcpy(pdat->vram[pdat->index], render->pixels, render->pixlen);
dma_cache_sync(pdat->vram[pdat->index], render->pixlen, DMA_TO_DEVICE);
f1c100s_debe_set_address(pdat, pdat->vram[pdat->index]);
double buffer切换vram时,是直接改layer0的buffer地址,我的疑问是,这个地址是每个帧开始时奇效还是立即生效,如果立即生效,那么生效时如果上个frame刚显示一半,那么就会造成一帧数据显示的不一致,导致flicker
我之所以这么怀疑,是发现我画的动画在移动过程中能发现图案的边缘在闪烁,我不确定是这个原因还是LCD的拖尾效应导致的。
我查了microchip 的SAMA5和NXP的RT1052, 他们都有两个buffer地址,一个是current,一个是next,要求在一个帧中断时准备好next,也就是说它的实现肯定是帧同步的,不会有flicker效应
离线
楼主 现在搞定ddr了吗
我用的xboot,是初始化了dram的
离线
下一帧开始时生效,没人会做立即生效这么难实现又会出撕裂问题的控制器
但是rt1052为什么要两个地址寄存器,还说明了直接写current地址会导致flicker
离线
看了下显卡的垂直同步,是我理解错了,这个同步是帧率的同步,而不是画面的撕裂。我的动画有闪烁是因为帧率不够以及时间不一致导致的
离线
达克罗德 说:Jin劲 说:楼主 现在搞定ddr了吗
我用的xboot,是初始化了dram的
很想了解初始化过程,但是那个唯一的datasheet没看到在哪有这部分内容或者ddr介绍
只能连猜带蒙,从start.s还有mksunxitool中分析了个大概
离线
晕哥公司感觉很开放呀,你们上班时候可以玩玩这些板子。
公司做项目也用这些方案吗?
离线
达克罗德 说:jlau 说:下一帧开始时生效,没人会做立即生效这么难实现又会出撕裂问题的控制器
但是rt1052为什么要两个地址寄存器,还说明了直接写current地址会导致flicker
那些没有两个地址寄存器的lcd controller也是有一个外部不可访问的内部寄存器的,在输出完当前帧的最后一行时会把用户可见的地址寄存器的值拷贝到内部的地址寄存器,然后开始读取framebuffer数据到内部fifo。在这个时间点之后配置地址寄存器只会在下一帧生效。
直接写current地址会导致flicker可能是把这个内部寄存器开放出来了吧,这样方便回读当前framebuffer地址。也有可能是指写current地址指向的framebuffer。
嗯你说的有道理,非常感谢!另外人家是有切换中断的,所以支持类似显卡的60hz垂直同步功能,真正做到60hz同步显示不丢帧。而全志不支持这个功能,在fps=60hz时,其实有可能丢一两帧没有被显示。不过也没关系,真要到60hz估计人眼很难看出差异了
离线
达克罗德 说:jlau 说:那些没有两个地址寄存器的lcd controller也是有一个外部不可访问的内部寄存器的,在输出完当前帧的最后一行时会把用户可见的地址寄存器的值拷贝到内部的地址寄存器,然后开始读取framebuffer数据到内部fifo。在这个时间点之后配置地址寄存器只会在下一帧生效。
直接写current地址会导致flicker可能是把这个内部寄存器开放出来了吧,这样方便回读当前framebuffer地址。也有可能是指写current地址指向的framebuffer。嗯你说的有道理,非常感谢!另外人家是有切换中断的,所以支持类似显卡的60hz垂直同步功能,真正做到60hz同步显示不丢帧。而全志不支持这个功能,在fps=60hz时,其实有可能丢一两帧没有被显示。不过也没关系,真要到60hz估计人眼很难看出差异了
你要怀疑c100s只有一个地址寄存器的话可以使能vertical blanking interrupt,在中断来时修改地址寄存器。
根据lcd controller设计的不同,VBI来时修改地址寄存器也不一定来得及。因为framebuffer读取是DEBE来做的,通常DEBE内部都会有fifo来缓存几行framebuffer。DEBE设计为fifo输出完立马读取后续数据的话VBI来时修改地址寄存器就来不及了,可以用c100s的line trigger interrupt提前设置,但是SY0设置为多少合适又要不断尝试了。当然DEBE设计为tcon即将开始输出时再读取后续数据的话VBI来时修改地址寄存器就来得及了。
非常感谢解答,你知道的真多!
离线
达克罗德 说:jlau 说:那些没有两个地址寄存器的lcd controller也是有一个外部不可访问的内部寄存器的,在输出完当前帧的最后一行时会把用户可见的地址寄存器的值拷贝到内部的地址寄存器,然后开始读取framebuffer数据到内部fifo。在这个时间点之后配置地址寄存器只会在下一帧生效。
直接写current地址会导致flicker可能是把这个内部寄存器开放出来了吧,这样方便回读当前framebuffer地址。也有可能是指写current地址指向的framebuffer。嗯你说的有道理,非常感谢!另外人家是有切换中断的,所以支持类似显卡的60hz垂直同步功能,真正做到60hz同步显示不丢帧。而全志不支持这个功能,在fps=60hz时,其实有可能丢一两帧没有被显示。不过也没关系,真要到60hz估计人眼很难看出差异了
你要怀疑c100s只有一个地址寄存器的话可以使能vertical blanking interrupt,在中断来时修改地址寄存器。
根据lcd controller设计的不同,VBI来时修改地址寄存器也不一定来得及。因为framebuffer读取是DEBE来做的,通常DEBE内部都会有fifo来缓存几行framebuffer。DEBE设计为fifo输出完立马读取后续数据的话VBI来时修改地址寄存器就来不及了,可以用c100s的line trigger interrupt提前设置,但是SY0设置为多少合适又要不断尝试了。当然DEBE设计为tcon即将开始输出时再读取后续数据的话VBI来时修改地址寄存器就来得及了。
非常感谢你的解释,解决了我一个闪烁的问题,当切换framebuffer地址的速度大于60hz时,由于vram地址每次在VBI才生效,就会出现vram0新地址还没生效,画图代码已经在写新的vram1了,这时候vram1其实还在被LCD读呢。
解决方法就是等VBI,可以用中断的方式,也可以直接polling等状态位
static void fb_wait_vbi(struct f1c100s_tcon_reg_t * tcon)
{
u32_t int_reg = 0;
/* when the dma end, it clear this bit automatically */
while (!(int_reg & 0x8000) ) {
int_reg = read32((virtual_addr_t)&tcon->int0);
}
}
static void fb_clear_vbi(struct f1c100s_tcon_reg_t * tcon)
{
u32_t int_reg = read32((virtual_addr_t)&tcon->int0);
write32((virtual_addr_t)&tcon->int0, int_reg & ~(1 << 15));
}
static int fb_switch_vram(struct framebuffer_t * fb)
{
struct fb_f1c100s_pdata_t * pdat = (struct fb_f1c100s_pdata_t *)fb->priv;
if(pdat)
{
pdat->index = (pdat->index + 1) & 0x1;
dma_cache_sync(pdat->vram[pdat->index], pdat->width * pdat->height * pdat->bytes_per_pixel, DMA_TO_DEVICE);
f1c100s_debe_set_address(pdat, pdat->vram[pdat->index]);
fb_clear_vbi((struct f1c100s_tcon_reg_t *)pdat->virttcon);
fb_wait_vbi((struct f1c100s_tcon_reg_t *)pdat->virttcon);
return (pdat->index + 1) & 0x1;
}
return -1;
}
现在真正做到了垂直同步,不过fps最多到60hz了
离线
xboot的代码由于fps刚好是小于60的所以能工作,但是如果某几帧时间小于16ms的话也是有风险的。我是这次用大于60hz的刷屏方式才发现这个问题。
离线
按照肠子网友说的实现了3缓冲方式,其实不需要在中断中切换显存地址,查询方式判断帧同步即可
static int fb_switch_vram(struct framebuffer_t * fb)
{
struct fb_f1c100s_pdata_t * pdat = (struct fb_f1c100s_pdata_t *)fb->priv;
if(pdat)
{
pdat->index = (pdat->index + 1) % 3;
dma_cache_sync(pdat->vram[pdat->index], pdat->width * pdat->height * pdat->bytes_per_pixel, DMA_TO_DEVICE);
fb_wait_vbi((struct f1c100s_tcon_reg_t *)pdat->virttcon);
f1c100s_debe_set_address(pdat, pdat->vram[pdat->index]);
fb_clear_vbi((struct f1c100s_tcon_reg_t *)pdat->virttcon);
return (pdat->index + 1) % 3;
}
return -1;
}
该函数返回的即是可安全画图的空闲buffer。该方式能节省memcpy方式的大约18ms开销,在我的测试中,刷新率从18Hz提高到28hz。
离线
解决了,加个vsync的检查,保证同步
离线