OLED的MIPI屏幕实时亮度改变问题
-
如题,在驱动中有个接口:
/* sel: 0:lcd0; 1:lcd1 */
static s32 LCD_set_bright(u32 sel, u32 bright)
{
sunxi_lcd_dsi_dcs_write_1para(sel,0x51,bright);
return 0;
}操作这个接口调整亮度的话,显示是无法正常的。
是否驱动在操作这个接口过程中需要等待屏幕数据发帧结束?
感觉是要等的,但是目前还没详细看代码流程。
先来问一波!期待大佬解惑!
-
@tevet 发送命令要处于LP模式,在送帧(HP模式)的时候去切换模式肯定会导致黑屏的,需要在中断的消隐区间去设置背光
-
@anruliu
感谢大佬,请教下, 中断的这个状态如何同步到呢? -
@tevet 可以翻一下lcd调试说明文档,里面有esd这个章节,显示驱动中也有esd相关代码,做esd就是在中断的消隐区间去读mipi的寄存器,判断屏的状态。可以读那么就可以写了
-
@anruliu
请教下大佬, 模仿esd程序进行中断中修改亮度操作,
可以写入亮度成功,也可以读到东西,但是中断就无法重新进入了。
是否有什么注意到的地方。static s32 lcd_set_oled_bright(u32 sel,u32 bright) { s32 ret = 0; u8 result[16] = {0}; s32 nump = 1; ret = sunxi_lcd_dsi_dcs_read(0, 0x54, result,&nump); dsi_dcs_wr_1para(sel, 0xFE, 0x00); //{ 0xFE,1,{0x00} }, dsi_dcs_wr_1para(sel, 0x51, 0x50); printk(KERN_WARNING "wwwwwwwwwwww lcd_set_oled_bright :bright = %d read result :%02x \n",bright,result[0]); return 0; } /*此处省略*/ struct __lcd_panel rm69330_139_panel = { /* panel driver name, must mach the name of * lcd_drv_name in sys_config.fex */ .name = "rm69330_139", .func = { .cfg_panel_info = lcd_cfg_panel_info, .cfg_open_flow = lcd_open_flow, .cfg_close_flow = lcd_close_flow, .lcd_user_defined_func = lcd_user_defined_func, .set_bright = LCD_set_bright, .esd_check = lcd_esd_check, .reset_panel = lcd_reset_panel, .set_esd_info = lcd_set_esd_info, .oled_set_bright = lcd_set_oled_bright, }, };
#if defined(__LINUX_PLAT__) static irqreturn_t disp_lcd_event_proc(int irq, void *parg) #else static irqreturn_t disp_lcd_event_proc(void *parg) #endif { struct disp_device *lcd = (struct disp_device *)parg; struct disp_lcd_private_data *lcdp = NULL; struct disp_manager *mgr = NULL; #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) struct disp_eink_manager *eink_manager = NULL; #endif u32 hwdev_index; u32 irq_flag = 0; unsigned int panel_extend_dirty; unsigned int panel_extend_modify_oledbright; unsigned long flags; if (lcd == NULL) return DISP_IRQ_RETURN; hwdev_index = lcd->hwdev_index; lcdp = disp_lcd_get_priv(lcd); if (lcdp == NULL) return DISP_IRQ_RETURN; #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) eink_manager = disp_get_eink_manager(0); if (eink_manager == NULL) return DISP_IRQ_RETURN; #endif if (disp_al_lcd_query_irq (hwdev_index, LCD_IRQ_TCON0_VBLK, &lcdp->panel_info)) { #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) eink_display_one_frame(eink_manager); #else int cur_line = disp_al_lcd_get_cur_line(hwdev_index, &lcdp->panel_info); int start_delay = disp_al_lcd_get_start_delay(hwdev_index, &lcdp->panel_info); #if defined(CONFIG_DISP2_LCD_ESD_DETECT) if (lcdp->lcd_panel_fun.esd_check && lcdp->lcd_panel_fun.reset_panel) { ++lcdp->esd_inf.cnt; if (cur_line < 2 && !atomic_read(&lcdp->lcd_resetting) && lcdp->esd_inf.cnt >= lcdp->esd_inf.freq) { disp_al_lcd_disable_irq(hwdev_index, LCD_IRQ_TCON0_VBLK, &lcdp->panel_info); if (!lcdp->esd_inf.esd_check_func_pos || lcdp->lcd_panel_fun.esd_check(lcd->disp)) { /*request reset*/ atomic_set(&lcdp->lcd_resetting, 1); schedule_work(&lcdp->reflush_work); printk(KERN_WARNING "wwwwwwwwwwww lcd_esd_check disp_lcd_event_proc 1633 \n"); } disp_al_lcd_enable_irq(hwdev_index, LCD_IRQ_TCON0_VBLK, &lcdp->panel_info); printk(KERN_WARNING "wwwwwwwwwwww after lcd_esd_check disp_lcd_event_proc 1635 \n"); lcdp->esd_inf.cnt = 0; } } #endif mgr = lcd->manager; if (mgr == NULL) { printk(KERN_WARNING "wwwwwwwwwwww after if (mgr == NULL) 1644 \n"); return DISP_IRQ_RETURN; } if (cur_line <= (start_delay - lcdp->judge_line)) sync_event_proc(mgr->disp, false); else sync_event_proc(mgr->disp, true); #endif } else { irq_flag = disp_al_lcd_query_irq(hwdev_index, LCD_IRQ_TCON0_CNTR, &lcdp->panel_info); irq_flag |= disp_al_lcd_query_irq(hwdev_index, LCD_IRQ_TCON0_TRIF, &lcdp->panel_info); if (irq_flag == 0) goto exit; if (disp_al_lcd_tri_busy(hwdev_index, &lcdp->panel_info)) { /* if lcd is still busy when tri/cnt irq coming, * take it as failture, record failture times, * when it reach 2 times, clear counter */ lcdp->tri_finish_fail++; lcdp->tri_finish_fail = (lcdp->tri_finish_fail == 2) ? 0 : lcdp->tri_finish_fail; } else lcdp->tri_finish_fail = 0; mgr = lcd->manager; if (mgr == NULL) return DISP_IRQ_RETURN; #if defined(CONFIG_DISP2_LCD_ESD_DETECT) if (lcdp->lcd_panel_fun.esd_check && lcdp->lcd_panel_fun.reset_panel) { ++lcdp->esd_inf.cnt; if (!atomic_read(&lcdp->lcd_resetting) && lcdp->esd_inf.cnt >= lcdp->esd_inf.freq) { if (!lcdp->esd_inf.esd_check_func_pos || lcdp->lcd_panel_fun.esd_check(lcd->disp)) { /*request reset*/ atomic_set(&lcdp->lcd_resetting, 1); schedule_work(&lcdp->reflush_work); printk(KERN_WARNING "wwwwwwwwwwww lcd_esd_check disp_lcd_event_proc 1685 \n"); } printk(KERN_WARNING "wwwwwwwwwwww after lcd_esd_check disp_lcd_event_proc 1688 \n"); lcdp->esd_inf.cnt = 0; } } #endif if (lcdp->tri_finish_fail == 0) { sync_event_proc(mgr->disp, false); disp_al_lcd_tri_start(hwdev_index, &lcdp->panel_info); } else sync_event_proc(mgr->disp, true); } spin_lock_irqsave(&lcd_data_lock, flags); panel_extend_dirty = lcdp->panel_extend_dirty; lcdp->panel_extend_dirty = 0; /*这里是我添加的调整oled亮度的地方, bright的值通过ioctl修改,并 lcdp->panel_extend_modify_oledbright; 置位,让中断来处理这个亮度*/ panel_extend_modify_oledbright = lcdp->panel_extend_modify_oledbright; lcdp->panel_extend_modify_oledbright = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); if (panel_extend_dirty == 1) disp_al_lcd_cfg_ext(lcd->disp, &lcdp->panel_extend_info_set); if(panel_extend_modify_oledbright == 1) { if(lcdp->lcd_panel_fun.oled_set_bright) { u32 getbl = disp_lcd_get_bright(lcd); lcdp->lcd_panel_fun.oled_set_bright(lcd->disp,getbl); } } exit: printk(KERN_WARNING "wwwwwwwwwwww before DISP_IRQ_RETURN 1709 \n"); /*尝试加入的打印信息, 一旦执行了亮度调整,这个中断服务不再重新进入了,但是亮度调节是成功的*/ return DISP_IRQ_RETURN; }
-
已经搞定了,感谢大佬的指导,非常给力。
#if 1 if(panel_extend_modify_oledbright == 1) { if(lcdp->lcd_panel_fun.oled_set_bright) { u32 getbl = disp_lcd_get_bright(lcd); lcdp->lcd_panel_fun.oled_set_bright(lcd->disp,getbl); /*加入下面这部分逻辑,让他重新触发中断即可*/ if (lcdp->tri_finish_fail == 0) { sync_event_proc(mgr->disp, false); disp_al_lcd_tri_start(hwdev_index, &lcdp->panel_info); } else sync_event_proc(mgr->disp, true); } }
-
@tevet
中断中不要加入太多打印,读取和写寄存器前后要调用dsi_read_mode_enstatic s32 lcd_set_oled_bright(u32 sel,u32 bright) { s32 ret = 0; u8 result[16] = {0}; s32 nump = 1; dsi_read_mode_en(0, 1); ret = sunxi_lcd_dsi_dcs_read(0, 0x54, result,&nump); dsi_dcs_wr_1para(sel, 0xFE, 0x00); //{ 0xFE,1,{0x00} }, dsi_dcs_wr_1para(sel, 0x51, 0x50); dsi_read_mode_en(0, 0); return 0; }
中断处理函数中,调用背光设置的代码要放在前面,满足cur_line < 2,并且尽量减少这里面的代码调用
if (cur_line < 2 && panel_extend_modify_oledbright == 1 && lcdp->lcd_panel_fun.set_oled_bright) { lcdp->lcd_panel_fun.oled_set_bright(lcd->disp, fix_bright); }
这样修改后应该就不用再重新触发中断
-
@anruliu
感谢,感觉还是我的操作骚了,马上搞起来试试看。谢谢大佬提示!
-
@anruliu
按照大佬的方式修改,是不行的喔。static s32 lcd_set_oled_bright(u32 sel,u32 bright) { s32 ret = 0; u8 result[16] = {0}; s32 nump = 1; #if 1 dsi_read_mode_en(0, 1); ret = sunxi_lcd_dsi_dcs_read(0, 0x54, result,&nump); dsi_dcs_wr_1para(sel, 0xFE, 0x00); //{ 0xFE,1,{0x00} }, dsi_dcs_wr_1para(sel, 0x51, bright); dsi_read_mode_en(0, 0); #endif return 0; }
#if defined(__LINUX_PLAT__) static irqreturn_t disp_lcd_event_proc(int irq, void *parg) #else static irqreturn_t disp_lcd_event_proc(void *parg) #endif { struct disp_device *lcd = (struct disp_device *)parg; struct disp_lcd_private_data *lcdp = NULL; struct disp_manager *mgr = NULL; #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) struct disp_eink_manager *eink_manager = NULL; #endif u32 hwdev_index; u32 irq_flag = 0; unsigned int panel_extend_dirty; unsigned int panel_extend_modify_oledbright; unsigned long flags; if (lcd == NULL) return DISP_IRQ_RETURN; hwdev_index = lcd->hwdev_index; lcdp = disp_lcd_get_priv(lcd); if (lcdp == NULL) return DISP_IRQ_RETURN; #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) eink_manager = disp_get_eink_manager(0); if (eink_manager == NULL) return DISP_IRQ_RETURN; #endif if (disp_al_lcd_query_irq (hwdev_index, LCD_IRQ_TCON0_VBLK, &lcdp->panel_info)) { #if defined(SUPPORT_EINK) && defined(CONFIG_EINK_PANEL_USED) eink_display_one_frame(eink_manager); #else int cur_line = disp_al_lcd_get_cur_line(hwdev_index, &lcdp->panel_info); int start_delay = disp_al_lcd_get_start_delay(hwdev_index, &lcdp->panel_info); #if defined(CONFIG_DISP2_LCD_ESD_DETECT) if (lcdp->lcd_panel_fun.esd_check && lcdp->lcd_panel_fun.reset_panel) { ++lcdp->esd_inf.cnt; if (cur_line < 2 && !atomic_read(&lcdp->lcd_resetting) && lcdp->esd_inf.cnt >= lcdp->esd_inf.freq) { disp_al_lcd_disable_irq(hwdev_index, LCD_IRQ_TCON0_VBLK, &lcdp->panel_info); if (!lcdp->esd_inf.esd_check_func_pos || lcdp->lcd_panel_fun.esd_check(lcd->disp)) { /*request reset*/ atomic_set(&lcdp->lcd_resetting, 1); schedule_work(&lcdp->reflush_work); printk(KERN_WARNING "wwwwwwwwwwww lcd_esd_check disp_lcd_event_proc 1633 \n"); } disp_al_lcd_enable_irq(hwdev_index, LCD_IRQ_TCON0_VBLK, &lcdp->panel_info); printk(KERN_WARNING "wwwwwwwwwwww after lcd_esd_check disp_lcd_event_proc 1635 \n"); lcdp->esd_inf.cnt = 0; } } #endif #if 1 if ((cur_line < 2) && (lcdp->panel_extend_modify_oledbright) && (lcdp->lcd_panel_fun.oled_set_bright)) { spin_lock_irqsave(&lcd_data_lock, flags); panel_extend_modify_oledbright = lcdp->panel_extend_modify_oledbright; lcdp->panel_extend_modify_oledbright = 0; spin_unlock_irqrestore(&lcd_data_lock, flags); #if 1 //if(panel_extend_modify_oledbright == 1) { // if(lcdp->lcd_panel_fun.oled_set_bright) { u32 getbl = disp_lcd_get_bright(lcd); lcdp->lcd_panel_fun.oled_set_bright(lcd->disp,getbl); //if (lcdp->tri_finish_fail == 0) { // sync_event_proc(mgr->disp, false); // disp_al_lcd_tri_start(hwdev_index, &lcdp->panel_info); //} else // sync_event_proc(mgr->disp, true); } } } #endif #endif mgr = lcd->manager; if (mgr == NULL) { printk(KERN_WARNING "wwwwwwwwwwww after if (mgr == NULL) 1644 \n"); return DISP_IRQ_RETURN; } if (cur_line <= (start_delay - lcdp->judge_line)) sync_event_proc(mgr->disp, false); else sync_event_proc(mgr->disp, true); #endif }
我前面的操作是正常的,咋测都OK 。按照你这个改一下就黑屏了。
我那样改有啥隐患没,毕竟不是一直改亮度。 -
@anruliu 请教一下,是不是直接放到esd的detect也可以,我的是818平台,结果放detect里不行,加dsi_read_mode_en也不行
-
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号