环境:STM32F103CBT6+OLED128*32(SSD1306)+HAL库+emWin5.36
背景:希望能使用FramBuffer的方式写屏,以提高刷屏效率
一、查阅控制器SSD1306手册
首先得知道怎么向屏写数据以及屏的显示方式。
上图所示的是SSD1306的Dram结构,实际对应屏的像素点。这里一个Page对应8行、128列,也就是写完一个Page就是128x8的像素,按照1bit/pixel来算,一共需要写128字节的数据。
上图所示的是每个PAGE的细节,每写一个字节对应的是一列的8个点。
关于整屏写的方向问题,控制器提供了好几种方式:
具体怎么选择还需要根据emWin的RAM更新方式而定。
二、查阅emWin的驱动实现
阅读手册,关于Display Driver一节,要通过FrameBuffer向屏更新数据,可以使用的驱动有
及
GUIDRV_SPage驱动里面有个跟SSD1306比较相近的SSD1305,嗯……去看看驱动描述的细节:
可以看到,GUIDRV_SPage直接支持SSD1306,Good!
关于选择GUIDRV_SLin还是GUIDRV_SPage,我们先看看这两种驱动RAM的组织方式:
1、GUIDRV_SLin
写RAM的方式水平线性的,跟上一节提到的SSD1306数据更新方式都对应不上,不过,通过emWin的水平/垂直翻转还是可以使用SSD1306的垂直地址方式来更新的。因为经过翻转变化需要消耗CPU时间,牺牲了效率,所以不建议使用这种驱动。本人也利用这个驱动实现过,效率嘛……呵呵……可能还会涉及大小端变化的问题……
2、GUIDRV_SPage
对于这种组织方式,一个PAGE一个PAGE的写,正好符合SSD1306的水平地址模式。接下来看看怎么怎么使用这个驱动。
三、驱动移植
1、驱动及色彩选择
驱动最后为1是表示需要缓存,也就是FramBuffer,为了提高效率,当然选这个了。颜色的话,GUICC_1就好了,表示单色。
2、示例
挪到手册屏驱动章节的GUIDRV_SPage一节的最后,看看使用例程:
除开一些标准需要调用的接口外,还需要调用一些特定的接口。
(居然把SSD1306给漏了……)
关于第2个和第3个接口,看看手册:
这个接口主要把底层的驱动如写命令、写数据、批量写数据接口注册到emWin里面去。
这个就比较明显了,是选择具体的控制器(根据具体的控制器选择不同的接口)
3、移植好的代码
文件:lcd_config.c
主要是这个函数,从模板过来的其它的函数不用改了
#define XSIZE_PHYS 128
#define YSIZE_PHYS 32
//
// Color conversion
//
#define COLOR_CONVERSION GUICC_1
//
// Display driver
//
#define DISPLAY_DRIVER GUIDRV_SPAGE_1C1
extern uint8_t SSD1306_Buffer[]; // Size: 128*32/8
void LCD_X_Config(void)
{
GUI_PORT_API PortAPI = {0};
CONFIG_SPAGE sPageConfig = {0};
GUI_DEVICE * pDevice;
// Set display driver and color conversion for 1st layer
pDevice = GUI_DEVICE_CreateAndLink(DISPLAY_DRIVER, COLOR_CONVERSION, 0, 0);
// Display driver configuration, required for Lin-driver
if (LCD_GetSwapXY())
{
LCD_SetSizeEx (0, YSIZE_PHYS, XSIZE_PHYS);
LCD_SetVSizeEx(0, YSIZE_PHYS * NUM_VSCREENS, XSIZE_PHYS);
}
else
{
LCD_SetSizeEx (0, XSIZE_PHYS, YSIZE_PHYS);
LCD_SetVSizeEx(0, XSIZE_PHYS, YSIZE_PHYS * NUM_VSCREENS);
}
sPageConfig.FirstSEG = 0;
GUIDRV_SPage_Config(pDevice, &sPageConfig);
PortAPI.pfWrite8_A0 = ssd1306_write8_A0; // Write CMD
PortAPI.pfWrite8_A1 = ssd1306_write8_A1; // Write sigle data
PortAPI.pfWriteM8_A1 = ssd1306_writeM8_A1; // Write multi data
PortAPI.pfReadM8_A1 = 0; // No need to read
GUIDRV_SPage_SetBus8(pDevice, &PortAPI);
GUIDRV_SPage_Set1510(pDevice); // SSD1306
}
四、效果