2020-10-18
补充下代码仓库地址:
环境:STM32F103CBT6+OLED128*32(SSD1306)+HAL库+emWin5.36
背景:希望能使用FramBuffer的方式写屏,以提高刷屏效率
一、查阅控制器SSD1306手册
首先得知道怎么向屏写数据以及屏的显示方式。
![](https://i-blog.csdnimg.cn/blog_migrate/13c9ab906a387531cc0e521b0d6b6de9.png)
上图所示的是SSD1306的Dram结构,实际对应屏的像素点。这里一个Page对应8行、128列,也就是写完一个Page就是128x8的像素,按照1bit/pixel来算,一共需要写128字节的数据。
![](https://i-blog.csdnimg.cn/blog_migrate/b3ae6f634b6c850602fff9ec7294d98b.png)
上图所示的是每个PAGE的细节,每写一个字节对应的是一列的8个点。
关于整屏写的方向问题,控制器提供了好几种方式:
![](https://i-blog.csdnimg.cn/blog_migrate/9e8b64ffd155e477b029732eee3de35c.png)
![](https://i-blog.csdnimg.cn/blog_migrate/190d2578fef0d4792b237edd49407535.png)
具体怎么选择还需要根据emWin的RAM更新方式而定。
二、查阅emWin的驱动实现
阅读手册,关于Display Driver一节,要通过FrameBuffer向屏更新数据,可以使用的驱动有
![](https://i-blog.csdnimg.cn/blog_migrate/f9f51a468f6880318d9431fb45d19913.png)
及
![](https://i-blog.csdnimg.cn/blog_migrate/1c9d5782f841b623cf016364f5a53653.png)
GUIDRV_SPage驱动里面有个跟SSD1306比较相近的SSD1305,嗯……去看看驱动描述的细节:
![](https://i-blog.csdnimg.cn/blog_migrate/624985021831d4a244ecc7a4e7e44881.png)
可以看到,GUIDRV_SPage直接支持SSD1306,Good!
关于选择GUIDRV_SLin还是GUIDRV_SPage,我们先看看这两种驱动RAM的组织方式:
1、GUIDRV_SLin
![](https://i-blog.csdnimg.cn/blog_migrate/2a8d0ee165fb482b4ef9db1a99384442.png)
写RAM的方式水平线性的,跟上一节提到的SSD1306数据更新方式都对应不上,不过,通过emWin的水平/垂直翻转还是可以使用SSD1306的垂直地址方式来更新的。因为经过翻转变化需要消耗CPU时间,牺牲了效率,所以不建议使用这种驱动。本人也利用这个驱动实现过,效率嘛……呵呵……可能还会涉及大小端变化的问题……
2、GUIDRV_SPage
对于这种组织方式,一个PAGE一个PAGE的写,正好符合SSD1306的水平地址模式。接下来看看怎么怎么使用这个驱动。
三、驱动移植
1、驱动及色彩选择
驱动最后为1是表示需要缓存,也就是FramBuffer,为了提高效率,当然选这个了。颜色的话,GUICC_1就好了,表示单色。
![](https://i-blog.csdnimg.cn/blog_migrate/dfea60bf5d8cfb670f1a0e41049a0dd9.png)
2、示例
挪到手册屏驱动章节的GUIDRV_SPage一节的最后,看看使用例程:
![](https://i-blog.csdnimg.cn/blog_migrate/ea0c24468f28fc3eb8aacfba1ff843a4.png)
除开一些标准需要调用的接口外,还需要调用一些特定的接口。
![](https://i-blog.csdnimg.cn/blog_migrate/1f3015ca7bcb1a828a88a6ea9ebcd2f7.png)
![](https://i-blog.csdnimg.cn/blog_migrate/4ba01bdbbe97c836e9a0e6e4ba13542a.png)
(居然把SSD1306给漏了……)
关于第2个和第3个接口,看看手册:
![](https://i-blog.csdnimg.cn/blog_migrate/99da03a148d0984a126ca281f8055d5e.png)
这个接口主要把底层的驱动如写命令、写数据、批量写数据接口注册到emWin里面去。
![](https://i-blog.csdnimg.cn/blog_migrate/be2dc81cbc37c2c8e516e7ce4461bf32.png)
这个就比较明显了,是选择具体的控制器(根据具体的控制器选择不同的接口)
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
}
四、效果
![](https://i-blog.csdnimg.cn/blog_migrate/d64386eb13bd8c7c03d74375d52a901e.png)