使用u8g2 使用硬件iic驱动某些page为4个字节 带灰度的lcd显示屏幕的时候有时候只显示上半部,下半部不显示,例如uc1617等。
原因:
以uc1617为例,链接https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_uc1617.c
在u8x8_d_uc1617_common方法中的case U8X8_MSG_DISPLAY_DRAW_TILE分支
uint8_t u8x8_d_uc1617_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
uint8_t x, y, c, a;
uint8_t *ptr;
switch(msg)
{
case U8X8_MSG_DISPLAY_DRAW_TILE:
u8x8_cad_StartTransfer(u8x8);
y = ((u8x8_tile_t *)arg_ptr)->y_pos;
y*=2;
x = ((u8x8_tile_t *)arg_ptr)->x_pos;
x *= 8;
x += u8x8->x_offset;
u8x8_cad_SendCmd(u8x8, 0x060 | (x&15));
u8x8_cad_SendCmd(u8x8, 0x070 | (x>>4));
u8x8_cad_SendCmd(u8x8, 0x00 | (y));
#ifdef NOT_REQUIRED
u8x8_cad_SendCmd(u8x8, 0xf8 ); /* disable window */
u8x8_cad_SendCmd(u8x8, 0xf4 ); /* page start */
u8x8_cad_SendCmd(u8x8, y );
u8x8_cad_SendCmd(u8x8, 0xf5 ); /* x start */
u8x8_cad_SendCmd(u8x8, x );
u8x8_cad_SendCmd(u8x8, 0xf6 ); /* page end */
u8x8_cad_SendCmd(u8x8, y );
u8x8_cad_SendCmd(u8x8, 0xf7 ); /* x end */
u8x8_cad_SendCmd(u8x8, 127 );
u8x8_cad_SendCmd(u8x8, 0xf9 ); /* enable window */
#endif
a = arg_int;
do
{
c = ((u8x8_tile_t *)arg_ptr)->cnt;
ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
do
{
u8x8_cad_SendData(u8x8, 8, u8x8_convert_tile_for_uc1617_lower4bit(ptr));
ptr += 8;
x += 8;
c--;
} while( c > 0 );
a--;
} while( a > 0 );
x = ((u8x8_tile_t *)arg_ptr)->x_pos;
x *= 8;
x += u8x8->x_offset;
u8x8_cad_SendCmd(u8x8, 0x060 | (x&15));
u8x8_cad_SendCmd(u8x8, 0x070 | (x>>4));
u8x8_cad_SendCmd(u8x8, 0x00 | (y+1));
a = arg_int;
do
{
c = ((u8x8_tile_t *)arg_ptr)->cnt;
ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
do
{
u8x8_cad_SendData(u8x8, 8, u8x8_convert_tile_for_uc1617_upper4bit(ptr));
ptr += 8;
x += 8;
c--;
} while( c > 0 );
a--;
} while( a > 0 );
u8x8_cad_EndTransfer(u8x8);
break;
case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
if ( arg_int == 0 )
u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_powersave0_seq);
else
u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_powersave1_seq);
break;
case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
if ( arg_int == 0 )
{
u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_flip0_seq);
u8x8->x_offset = u8x8->display_info->default_x_offset;
}
else
{
u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_flip1_seq);
u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
}
break;
#ifdef U8X8_WITH_SET_CONTRAST
case U8X8_MSG_DISPLAY_SET_CONTRAST:
u8x8_cad_StartTransfer(u8x8);
u8x8_cad_SendCmd(u8x8, 0x081 );
u8x8_cad_SendArg(u8x8, arg_int ); /* uc1617 has range from 0 to 255 */
u8x8_cad_EndTransfer(u8x8);
break;
#endif
default:
return 0;
}
return 1;
}
在往lcd显示屏写写数据的时候,先用命令写显示地址,再写数据,命令和数据的区别在于iic地址不同,例如写命令使用iic地址0x78,写数据使用iic地址0x79,具体根据不同lcd数据手册iic地址有所不同。上面的分支U8X8_MSG_DISPLAY_DRAW_TILE作用是向lcd先写地址,再写数据,在这个分支中,只有一个u8x8_cad_StartTransfer与u8x8_cad_EndTransfer包含整个方法。
u8x8_cad_EndTransfer用于产生一个iic终止信号,代表操作完成
而在这个方法中,有2个写不同iic地址的行为,但是只产生了一个终止信号,导致可能后半部分无效,所以只显示半面。
解决方案:
添加多个u8x8_cad_StartTransfer与u8x8_cad_EndTransfer。
把对一个地址的操作行为用u8x8_cad_StartTransfer与u8x8_cad_EndTransfer包含起来
例如:
uint8_t u8x8_d_uc1617_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
uint8_t x, y, c, a;
uint8_t *ptr;
switch(msg)
{
case U8X8_MSG_DISPLAY_DRAW_TILE:
u8x8_cad_StartTransfer(u8x8);
y = ((u8x8_tile_t *)arg_ptr)->y_pos;
y*=2;
x = ((u8x8_tile_t *)arg_ptr)->x_pos;
x *= 8;
x += u8x8->x_offset;
u8x8_cad_SendCmd(u8x8, 0x060 | (x&15));
u8x8_cad_SendCmd(u8x8, 0x070 | (x>>4));
u8x8_cad_SendCmd(u8x8, 0x00 | (y));
#ifdef NOT_REQUIRED
u8x8_cad_SendCmd(u8x8, 0xf8 ); /* disable window */
u8x8_cad_SendCmd(u8x8, 0xf4 ); /* page start */
u8x8_cad_SendCmd(u8x8, y );
u8x8_cad_SendCmd(u8x8, 0xf5 ); /* x start */
u8x8_cad_SendCmd(u8x8, x );
u8x8_cad_SendCmd(u8x8, 0xf6 ); /* page end */
u8x8_cad_SendCmd(u8x8, y );
u8x8_cad_SendCmd(u8x8, 0xf7 ); /* x end */
u8x8_cad_SendCmd(u8x8, 127 );
u8x8_cad_SendCmd(u8x8, 0xf9 ); /* enable window */
#endif
a = arg_int;
do
{
c = ((u8x8_tile_t *)arg_ptr)->cnt;
ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
do
{
u8x8_cad_SendData(u8x8, 8, u8x8_convert_tile_for_uc1617_lower4bit(ptr));
ptr += 8;
x += 8;
c--;
} while( c > 0 );
a--;
} while( a > 0 );
// 下面这2行是添加的
u8x8_cad_EndTransfer(u8x8);
u8x8_cad_StartTransfer(u8x8);
x = ((u8x8_tile_t *)arg_ptr)->x_pos;
x *= 8;
x += u8x8->x_offset;
u8x8_cad_SendCmd(u8x8, 0x060 | (x&15));
u8x8_cad_SendCmd(u8x8, 0x070 | (x>>4));
u8x8_cad_SendCmd(u8x8, 0x00 | (y+1));
a = arg_int;
do
{
c = ((u8x8_tile_t *)arg_ptr)->cnt;
ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;
do
{
u8x8_cad_SendData(u8x8, 8, u8x8_convert_tile_for_uc1617_upper4bit(ptr));
ptr += 8;
x += 8;
c--;
} while( c > 0 );
a--;
} while( a > 0 );
u8x8_cad_EndTransfer(u8x8);
break;
case U8X8_MSG_DISPLAY_SET_POWER_SAVE:
if ( arg_int == 0 )
u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_powersave0_seq);
else
u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_powersave1_seq);
break;
case U8X8_MSG_DISPLAY_SET_FLIP_MODE:
if ( arg_int == 0 )
{
u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_flip0_seq);
u8x8->x_offset = u8x8->display_info->default_x_offset;
}
else
{
u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_flip1_seq);
u8x8->x_offset = u8x8->display_info->flipmode_x_offset;
}
break;
#ifdef U8X8_WITH_SET_CONTRAST
case U8X8_MSG_DISPLAY_SET_CONTRAST:
u8x8_cad_StartTransfer(u8x8);
u8x8_cad_SendCmd(u8x8, 0x081 );
u8x8_cad_SendArg(u8x8, arg_int ); /* uc1617 has range from 0 to 255 */
u8x8_cad_EndTransfer(u8x8);
break;
#endif
default:
return 0;
}
return 1;
}