# 点屏之I2C OLED
此文摘自群友投稿文章,感谢群友 **星空**
## 1. 硬件连接
一般市面上买到的单色oled屏幕模块一般都是同时支持spi和i2c接口的,而默认一般都是spi接口模式,需要根据说明书调整模模块上电阻的位置来转换到i2c模式。我手中这个模块一般比较常见,分辨率是128*64,需要焊接R1和R4,注意下方那个电阻位置要短接。
![](https://box.kancloud.cn/b5224472a382d668d6cf0c12f0892538_739x557.jpg)
![](https://box.kancloud.cn/ce7036790bfaf95c2cf550c4bdac079b_833x431.jpg)
然后连接到zero的i2c0的位置,reset引脚我连接到了uart2的tx脚位置。我手中暂时没有dock,如果是使用dock,请根据实际情况插到对应位置。
## 2. ssd1307fb驱动配置
Oled使用的控制芯片是ssd1306,最新版本的linux中包含Ssd1306的i2c驱动,驱动加载后会注册成功linux framebuffer,驱动文件路径是:/drivers/video/fbdev/ssd1307fb.c,该驱动可以通过配置支持ssd130x系列芯片。
所以要使用oled只需要在dts配置好就可以了
进入linux目录调出配置菜单
~~~
/linux-zero-4.10.y$ make ARCH=arm menuconfig
~~~
选中 <*> Solomon SSD1307 framebuffer support
![](https://box.kancloud.cn/aa91247dad30974e7c3058c7e5e28dea_850x391.jpg)
![](https://box.kancloud.cn/7d224ee935d3bd91da53556f8af4a5ed_918x404.jpg)
修改dts资源文件
~~~
vi arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts
~~~
添加ssd1306fb-i2c节点,0x3c是i2c设备的地址reset-getio是复位脚我选择的是PB0,
![](https://box.kancloud.cn/0f551b1cb47649be68f5dd5629a7ea90_755x450.jpg)
接下来编译内核和编译dtb
~~~
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j24 uImage
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- dtbs
~~~
然后将内核和dtbs更新到zero上,插入串口上电。
我是将驱动直接编译到内核里,可以在内核日志中看到驱动加载成功。
![](https://box.kancloud.cn/eafc995e356935d537d55d8599a5b62c_1512x268.jpg)
并且屏幕被点亮,该驱动默认不清空屏幕ram中内容,屏幕初始化后默认是花屏内容是正常的。如下状态。
![](https://box.kancloud.cn/c0bb555e7e7bfd8dc0a27cc56fc19514_630x545.jpg)
驱动注册后一般会挂载为/dev/fb0或者/dev/fb1设备文件。
写一个简单的oled模块测试程序,读取屏幕信息,并刷将荔枝派logo显示上去效果如下:
![](https://box.kancloud.cn/5331e69baa77045940264e9f4c7d70ca_760x586.jpg)
首先用photoshop做出目标图片,然后保存成bmp格式,然后使用windows自带的画图工具打开bmp,然后点击另存为保存为1位位图格式。使用字模软件将bmp转换成程序用的字节序列,我用的是zimo221这款字模工具软件
![](https://box.kancloud.cn/66d0a0ff9a97c502f5e989765e2b921f_1196x802.jpg)
注意在参数设置中要勾选字节倒叙选项。
下面写一个测试程序,加载驱动并把图像显示到屏幕上
C测试程序
~~~
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <string.h>
/*seconds: the seconds; mseconds: the micro seconds*/
void setTimer(int seconds, int mseconds)
{
struct timeval temp;
temp.tv_sec = seconds;
temp.tv_usec = mseconds;
printf("timer1\n");
select(0, NULL, NULL, NULL, &temp);
printf("timer2\n");
return ;
}
int main ()
{
char lichee[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0xE0,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x60,0x00,0x06,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x00,0x00,0x04,0x00,0x00,0x00,0xC0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x07,0x3C,0x74,0xE0,0x81,0x03,0xE0,0x0F,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x04,0x22,0x8C,0x10,0x43,0x04,0xF0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x04,0x42,0x84,0x10,0x22,0x0C,0xF8,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x04,0x03,0x84,0x08,0x22,0x08,0xFC,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x04,0x01,0x84,0x18,0x22,0x08,0xFE,0x3F,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x04,0x01,0x84,0x18,0x20,0x00,0xFE,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x00,0x04,0x01,0x84,0x08,0x20,0x00,0xFE,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,
0x40,0x10,0x04,0x03,0x84,0x18,0x20,0x00,0xFE,0xFF,0x00,0x00,0x00,0x00,0x00,0x08,
0x40,0x10,0x04,0x02,0x84,0x10,0x22,0x00,0xFF,0xFF,0x01,0x00,0x00,0x00,0x00,0x0C,
0x40,0x18,0x04,0x06,0x84,0x30,0x40,0x04,0xFF,0xFF,0x03,0x00,0x00,0x00,0x00,0x06,
0xE0,0x0F,0x1F,0x1C,0xCE,0xC1,0x80,0x03,0xFF,0xFF,0x07,0x00,0x00,0x00,0x00,0x07,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0xFF,0x0F,0x00,0x00,0x00,0x80,0x07,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xBF,0xFF,0x1F,0x00,0x00,0x00,0xC0,0x07,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xDF,0xFF,0x7F,0x00,0x00,0x00,0xE0,0x07,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xC7,0xFF,0xFF,0x00,0x00,0x00,0xF0,0x03,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC9,0xFF,0xFF,0x01,0x00,0x00,0xF0,0x03,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xC0,0xFF,0xFF,0x03,0x00,0x00,0xF8,0x03,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xC0,0xFF,0xFF,0x07,0x00,0x00,0xF0,0x03,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xC0,0xF7,0xFF,0x0F,0x00,0x00,0xF8,0x03,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xC0,0xE3,0xFF,0xFF,0x1F,0x00,0x00,0xF8,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xEF,0xFF,0xFF,0x7F,0x00,0x00,0xF8,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFB,0xFF,0xFF,0xFF,0x00,0x00,0xFC,0x01,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xFF,0xFF,0xFF,0xFF,0x03,0x00,0xFC,0x00,
0x40,0x30,0x00,0x06,0x04,0x00,0x00,0x80,0xFF,0xFF,0xFF,0xFF,0x07,0x00,0xFE,0x00,
0x40,0x10,0x02,0x06,0x04,0xC0,0x00,0x9C,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,0xFF,0x00,
0xFE,0xFF,0x07,0x06,0x04,0x80,0xC8,0x81,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,0x7F,0x00,
0x40,0x10,0x00,0x06,0x04,0x80,0x08,0x00,0xFF,0xFF,0xFF,0xFF,0x7F,0x80,0x7F,0x00,
0x40,0x13,0x00,0x16,0xCC,0x00,0x08,0x10,0xFF,0xFF,0xFF,0xFF,0xFF,0xC0,0x7F,0x00,
0x00,0xC3,0xC0,0x3F,0x04,0x00,0x08,0x0E,0xFE,0xFF,0xFF,0xFF,0xFF,0xE3,0x3F,0x00,
0x00,0xC1,0x00,0x06,0x04,0x10,0x48,0x00,0xFE,0xFF,0xFF,0xFF,0xFF,0xF7,0x3F,0x00,
0x80,0x41,0x00,0x06,0x04,0x20,0x49,0x00,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,
0x80,0x40,0x00,0x0E,0x44,0x20,0x48,0x30,0xFC,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,
0x60,0x78,0x00,0x9F,0x61,0x80,0x48,0x08,0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,
0x38,0x30,0x00,0x17,0x60,0x80,0x48,0x02,0xF8,0xFF,0xFF,0xFF,0xFF,0xFF,0x3F,0x00,
0x20,0x60,0x00,0x17,0x21,0x80,0x48,0x02,0xF0,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0x00,
0xFE,0xFB,0x83,0x06,0x30,0x40,0x48,0x02,0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0x1F,0x00,
0x30,0x23,0x02,0x06,0x12,0x70,0x44,0x04,0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0x0F,0x00,
0x30,0x23,0x42,0x06,0x1A,0x60,0x44,0x04,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0x07,0x00,
0x10,0x31,0x02,0x06,0x0C,0x40,0x44,0x08,0x80,0xFF,0xFF,0xFF,0xFF,0xFF,0x03,0x00,
0x18,0x11,0x03,0x06,0x0E,0x60,0x42,0x18,0xC0,0xFF,0xFF,0xFF,0xFF,0xFF,0x01,0x00,
0x88,0x19,0x03,0x06,0x31,0x60,0xC2,0x30,0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0x00,0x00,
0xC4,0xCD,0x01,0x86,0xE0,0x61,0x41,0x20,0xE0,0xFF,0xFF,0xFF,0xFF,0x7F,0x00,0x00,
0x00,0x82,0x01,0x36,0x80,0x00,0x00,0x00,0xF0,0xFF,0xFF,0xFF,0xFF,0x1F,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x9F,0xFF,0xFF,0xFF,0x07,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x0F,0xFF,0xFF,0xFF,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFC,0xFF,0x7F,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF0,0xFF,0x0F,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xF8,0x7F,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x01,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
int fp=0;
long screensize=0;
char *fbp = 0;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
fp = open ("/dev/fb1",O_RDWR);
if (fp < 0){
printf("Error : Can not open framebuffer device/n");
exit(1);
}
if (ioctl(fp,FBIOGET_FSCREENINFO,&finfo)){
printf("Error reading fixed information/n");
exit(2);
}
if (ioctl(fp,FBIOGET_VSCREENINFO,&vinfo)){
printf("Error reading variable information/n");
exit(3);
}
printf("The mem is :%d\n",finfo.smem_len);
printf("The line_length is :%d\n",finfo.line_length);
printf("The xres is :%d\n",vinfo.xres);
printf("The yres is :%d\n",vinfo.yres);
printf("bits_per_pixel is :%d\n",vinfo.bits_per_pixel);
screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;
printf("screensize: %d\n",screensize);
fbp =(char *) mmap (0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
fp,0);
if ((int) fbp == -1)
{
printf ("Error: failed to map framebuffer device to memory./n");
exit (4);
}
int i=0;
memset(fbp, 0x00, 1024);
setTimer(3,0);
while(1){
for(i=0;i<1024;i++){
fbp[i]=lichee[i];
}
setTimer(3,0);
memset(fbp, 0x00, 1024);
setTimer(3,0);
}
munmap (fbp, screensize);
close (fp);
}
~~~
将字节序在程序中定义为数组在荔枝板中,编译程序并执行。
![](https://box.kancloud.cn/533e4d22e84e1eaa42218f37d0b43dbd_648x299.jpg)
## 3. 单片机驱动移植为i2c驱动
一般情况下使用ssb1307fb这个驱动就很完美了了,我在发现ssd1307fb这个驱动程序之前,我将显示屏厂家提供的stm8 i2c测试代码移植到了linux上实现了一个驱动,加载驱动后效果如下
![](https://box.kancloud.cn/0bff0424a51d86f32442b91c374174d1_703x631.jpg)
我将此驱动也发出来供参考,该驱动程序直接在linux i2c设备注册中实现了oled的测试显示,该驱动包含一个基本ascii的字库和字符串显示逻辑。
~~~
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#define SSD1306_CMD 0
#define SSD1306_DAT 1
#define SSD1306_WIDTH 128
#define SSD1306_HEIGHT 64
#define SSD1306_TS_NAME "ssd1306_ts"
static uint8_t s_chDispalyBuffer[128][8];
const uint8_t c_chFont1608[95][16] = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*" ",0*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xCC,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00},/*"!",1*/
{0x00,0x00,0x08,0x00,0x30,0x00,0x60,0x00,0x08,0x00,0x30,0x00,0x60,0x00,0x00,0x00},/*""",2*/
{0x02,0x20,0x03,0xFC,0x1E,0x20,0x02,0x20,0x03,0xFC,0x1E,0x20,0x02,0x20,0x00,0x00},/*"#",3*/
{0x00,0x00,0x0E,0x18,0x11,0x04,0x3F,0xFF,0x10,0x84,0x0C,0x78,0x00,0x00,0x00,0x00},/*"$",4*/
{0x0F,0x00,0x10,0x84,0x0F,0x38,0x00,0xC0,0x07,0x78,0x18,0x84,0x00,0x78,0x00,0x00},/*"%",5*/
{0x00,0x78,0x0F,0x84,0x10,0xC4,0x11,0x24,0x0E,0x98,0x00,0xE4,0x00,0x84,0x00,0x08},/*"&",6*/
{0x08,0x00,0x68,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"'",7*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x18,0x18,0x20,0x04,0x40,0x02,0x00,0x00},/*"(",8*/
{0x00,0x00,0x40,0x02,0x20,0x04,0x18,0x18,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x00},/*")",9*/
{0x02,0x40,0x02,0x40,0x01,0x80,0x0F,0xF0,0x01,0x80,0x02,0x40,0x02,0x40,0x00,0x00},/*"*",10*/
{0x00,0x80,0x00,0x80,0x00,0x80,0x0F,0xF8,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x00},/*"+",11*/
{0x00,0x01,0x00,0x0D,0x00,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*",",12*/
{0x00,0x00,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80},/*"-",13*/
{0x00,0x00,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*".",14*/
{0x00,0x00,0x00,0x06,0x00,0x18,0x00,0x60,0x01,0x80,0x06,0x00,0x18,0x00,0x20,0x00},/*"/",15*/
{0x00,0x00,0x07,0xF0,0x08,0x08,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"0",16*/
{0x00,0x00,0x08,0x04,0x08,0x04,0x1F,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"1",17*/
{0x00,0x00,0x0E,0x0C,0x10,0x14,0x10,0x24,0x10,0x44,0x11,0x84,0x0E,0x0C,0x00,0x00},/*"2",18*/
{0x00,0x00,0x0C,0x18,0x10,0x04,0x11,0x04,0x11,0x04,0x12,0x88,0x0C,0x70,0x00,0x00},/*"3",19*/
{0x00,0x00,0x00,0xE0,0x03,0x20,0x04,0x24,0x08,0x24,0x1F,0xFC,0x00,0x24,0x00,0x00},/*"4",20*/
{0x00,0x00,0x1F,0x98,0x10,0x84,0x11,0x04,0x11,0x04,0x10,0x88,0x10,0x70,0x00,0x00},/*"5",21*/
{0x00,0x00,0x07,0xF0,0x08,0x88,0x11,0x04,0x11,0x04,0x18,0x88,0x00,0x70,0x00,0x00},/*"6",22*/
{0x00,0x00,0x1C,0x00,0x10,0x00,0x10,0xFC,0x13,0x00,0x1C,0x00,0x10,0x00,0x00,0x00},/*"7",23*/
{0x00,0x00,0x0E,0x38,0x11,0x44,0x10,0x84,0x10,0x84,0x11,0x44,0x0E,0x38,0x00,0x00},/*"8",24*/
{0x00,0x00,0x07,0x00,0x08,0x8C,0x10,0x44,0x10,0x44,0x08,0x88,0x07,0xF0,0x00,0x00},/*"9",25*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x0C,0x03,0x0C,0x00,0x00,0x00,0x00,0x00,0x00},/*":",26*/
{0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*";",27*/
{0x00,0x00,0x00,0x80,0x01,0x40,0x02,0x20,0x04,0x10,0x08,0x08,0x10,0x04,0x00,0x00},/*"<",28*/
{0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x02,0x20,0x00,0x00},/*"=",29*/
{0x00,0x00,0x10,0x04,0x08,0x08,0x04,0x10,0x02,0x20,0x01,0x40,0x00,0x80,0x00,0x00},/*">",30*/
{0x00,0x00,0x0E,0x00,0x12,0x00,0x10,0x0C,0x10,0x6C,0x10,0x80,0x0F,0x00,0x00,0x00},/*"?",31*/
{0x03,0xE0,0x0C,0x18,0x13,0xE4,0x14,0x24,0x17,0xC4,0x08,0x28,0x07,0xD0,0x00,0x00},/*"@",32*/
{0x00,0x04,0x00,0x3C,0x03,0xC4,0x1C,0x40,0x07,0x40,0x00,0xE4,0x00,0x1C,0x00,0x04},/*"A",33*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x11,0x04,0x0E,0x88,0x00,0x70,0x00,0x00},/*"B",34*/
{0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x08,0x1C,0x10,0x00,0x00},/*"C",35*/
{0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"D",36*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x17,0xC4,0x10,0x04,0x08,0x18,0x00,0x00},/*"E",37*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x17,0xC0,0x10,0x00,0x08,0x00,0x00,0x00},/*"F",38*/
{0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x44,0x1C,0x78,0x00,0x40,0x00,0x00},/*"G",39*/
{0x10,0x04,0x1F,0xFC,0x10,0x84,0x00,0x80,0x00,0x80,0x10,0x84,0x1F,0xFC,0x10,0x04},/*"H",40*/
{0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x00,0x00,0x00,0x00},/*"I",41*/
{0x00,0x03,0x00,0x01,0x10,0x01,0x10,0x01,0x1F,0xFE,0x10,0x00,0x10,0x00,0x00,0x00},/*"J",42*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x03,0x80,0x14,0x64,0x18,0x1C,0x10,0x04,0x00,0x00},/*"K",43*/
{0x10,0x04,0x1F,0xFC,0x10,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x0C,0x00,0x00},/*"L",44*/
{0x10,0x04,0x1F,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x1F,0xFC,0x10,0x04,0x00,0x00},/*"M",45*/
{0x10,0x04,0x1F,0xFC,0x0C,0x04,0x03,0x00,0x00,0xE0,0x10,0x18,0x1F,0xFC,0x10,0x00},/*"N",46*/
{0x07,0xF0,0x08,0x08,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"O",47*/
{0x10,0x04,0x1F,0xFC,0x10,0x84,0x10,0x80,0x10,0x80,0x10,0x80,0x0F,0x00,0x00,0x00},/*"P",48*/
{0x07,0xF0,0x08,0x18,0x10,0x24,0x10,0x24,0x10,0x1C,0x08,0x0A,0x07,0xF2,0x00,0x00},/*"Q",49*/
{0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x11,0xC0,0x11,0x30,0x0E,0x0C,0x00,0x04},/*"R",50*/
{0x00,0x00,0x0E,0x1C,0x11,0x04,0x10,0x84,0x10,0x84,0x10,0x44,0x1C,0x38,0x00,0x00},/*"S",51*/
{0x18,0x00,0x10,0x00,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x00,0x18,0x00,0x00,0x00},/*"T",52*/
{0x10,0x00,0x1F,0xF8,0x10,0x04,0x00,0x04,0x00,0x04,0x10,0x04,0x1F,0xF8,0x10,0x00},/*"U",53*/
{0x10,0x00,0x1E,0x00,0x11,0xE0,0x00,0x1C,0x00,0x70,0x13,0x80,0x1C,0x00,0x10,0x00},/*"V",54*/
{0x1F,0xC0,0x10,0x3C,0x00,0xE0,0x1F,0x00,0x00,0xE0,0x10,0x3C,0x1F,0xC0,0x00,0x00},/*"W",55*/
{0x10,0x04,0x18,0x0C,0x16,0x34,0x01,0xC0,0x01,0xC0,0x16,0x34,0x18,0x0C,0x10,0x04},/*"X",56*/
{0x10,0x00,0x1C,0x00,0x13,0x04,0x00,0xFC,0x13,0x04,0x1C,0x00,0x10,0x00,0x00,0x00},/*"Y",57*/
{0x08,0x04,0x10,0x1C,0x10,0x64,0x10,0x84,0x13,0x04,0x1C,0x04,0x10,0x18,0x00,0x00},/*"Z",58*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x40,0x02,0x40,0x02,0x40,0x02,0x00,0x00},/*"[",59*/
{0x00,0x00,0x30,0x00,0x0C,0x00,0x03,0x80,0x00,0x60,0x00,0x1C,0x00,0x03,0x00,0x00},/*"\",60*/
{0x00,0x00,0x40,0x02,0x40,0x02,0x40,0x02,0x7F,0xFE,0x00,0x00,0x00,0x00,0x00,0x00},/*"]",61*/
{0x00,0x00,0x00,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00},/*"^",62*/
{0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01},/*"_",63*/
{0x00,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/
{0x00,0x00,0x00,0x98,0x01,0x24,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xFC,0x00,0x04},/*"a",65*/
{0x10,0x00,0x1F,0xFC,0x00,0x88,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"b",66*/
{0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x00},/*"c",67*/
{0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x11,0x08,0x1F,0xFC,0x00,0x04},/*"d",68*/
{0x00,0x00,0x00,0xF8,0x01,0x44,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xC8,0x00,0x00},/*"e",69*/
{0x00,0x00,0x01,0x04,0x01,0x04,0x0F,0xFC,0x11,0x04,0x11,0x04,0x11,0x00,0x18,0x00},/*"f",70*/
{0x00,0x00,0x00,0xD6,0x01,0x29,0x01,0x29,0x01,0x29,0x01,0xC9,0x01,0x06,0x00,0x00},/*"g",71*/
{0x10,0x04,0x1F,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"h",72*/
{0x00,0x00,0x01,0x04,0x19,0x04,0x19,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"i",73*/
{0x00,0x00,0x00,0x03,0x00,0x01,0x01,0x01,0x19,0x01,0x19,0xFE,0x00,0x00,0x00,0x00},/*"j",74*/
{0x10,0x04,0x1F,0xFC,0x00,0x24,0x00,0x40,0x01,0xB4,0x01,0x0C,0x01,0x04,0x00,0x00},/*"k",75*/
{0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"l",76*/
{0x01,0x04,0x01,0xFC,0x01,0x04,0x01,0x00,0x01,0xFC,0x01,0x04,0x01,0x00,0x00,0xFC},/*"m",77*/
{0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"n",78*/
{0x00,0x00,0x00,0xF8,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0xF8,0x00,0x00},/*"o",79*/
{0x01,0x01,0x01,0xFF,0x00,0x85,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"p",80*/
{0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0xFF,0x00,0x01},/*"q",81*/
{0x01,0x04,0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x04,0x01,0x00,0x01,0x80,0x00,0x00},/*"r",82*/
{0x00,0x00,0x00,0xCC,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x98,0x00,0x00},/*"s",83*/
{0x00,0x00,0x01,0x00,0x01,0x00,0x07,0xF8,0x01,0x04,0x01,0x04,0x00,0x00,0x00,0x00},/*"t",84*/
{0x01,0x00,0x01,0xF8,0x00,0x04,0x00,0x04,0x00,0x04,0x01,0x08,0x01,0xFC,0x00,0x04},/*"u",85*/
{0x01,0x00,0x01,0x80,0x01,0x70,0x00,0x0C,0x00,0x10,0x01,0x60,0x01,0x80,0x01,0x00},/*"v",86*/
{0x01,0xF0,0x01,0x0C,0x00,0x30,0x01,0xC0,0x00,0x30,0x01,0x0C,0x01,0xF0,0x01,0x00},/*"w",87*/
{0x00,0x00,0x01,0x04,0x01,0x8C,0x00,0x74,0x01,0x70,0x01,0x8C,0x01,0x04,0x00,0x00},/*"x",88*/
{0x01,0x01,0x01,0x81,0x01,0x71,0x00,0x0E,0x00,0x18,0x01,0x60,0x01,0x80,0x01,0x00},/*"y",89*/
{0x00,0x00,0x01,0x84,0x01,0x0C,0x01,0x34,0x01,0x44,0x01,0x84,0x01,0x0C,0x00,0x00},/*"z",90*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x3E,0xFC,0x40,0x02,0x40,0x02},/*"{",91*/
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00},/*"|",92*/
{0x00,0x00,0x40,0x02,0x40,0x02,0x3E,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"}",93*/
{0x00,0x00,0x60,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x20,0x00},/*"~",94*/
};
struct i2c_client *ssd1306_client;
static void ssd1306_write_byte(uint8_t chData, uint8_t chCmd)
{
uint8_t cmd = 0x00;
if (chCmd) {
cmd = 0x40;
} else {
cmd = 0x00;
}
i2c_smbus_write_byte_data(ssd1306_client, cmd, chData);
}
void ssd1306_display_on(void)
{
ssd1306_write_byte(0x8D, SSD1306_CMD);
ssd1306_write_byte(0x14, SSD1306_CMD);
ssd1306_write_byte(0xAF, SSD1306_CMD);
}
/**
* @brief OLED turns off
*
* @param None
*
* @retval None
**/
void ssd1306_display_off(void)
{
ssd1306_write_byte(0x8D, SSD1306_CMD);
ssd1306_write_byte(0x10, SSD1306_CMD);
ssd1306_write_byte(0xAE, SSD1306_CMD);
}
void ssd1306_refresh_gram(void)
{
uint8_t i, j;
for (i = 0; i < 8; i ++) {
ssd1306_write_byte(0xB0 + i, SSD1306_CMD);
ssd1306_write_byte(0x02, SSD1306_CMD);
ssd1306_write_byte(0x10, SSD1306_CMD);
for (j = 0; j < 128; j ++) {
ssd1306_write_byte(s_chDispalyBuffer[j][i], SSD1306_DAT);
}
}
}
void ssd1306_clear_screen(uint8_t chFill)
{
memset(s_chDispalyBuffer,chFill, sizeof(s_chDispalyBuffer));
ssd1306_refresh_gram();
}
/**
* @brief Draws a piont on the screen
*
* @param chXpos: Specifies the X position
* @param chYpos: Specifies the Y position
* @param chPoint: 0: the point turns off 1: the piont turns on
*
* @retval None
**/
void ssd1306_draw_point(uint8_t chXpos, uint8_t chYpos, uint8_t chPoint)
{
uint8_t chPos, chBx, chTemp = 0;
if (chXpos > 127 || chYpos > 63) {
return;
}
chPos = 7 - chYpos / 8; //
chBx = chYpos % 8;
chTemp = 1 << (7 - chBx);
if (chPoint) {
s_chDispalyBuffer[chXpos][chPos] |= chTemp;
} else {
s_chDispalyBuffer[chXpos][chPos] &= ~chTemp;
}
}
/**
* @brief Fills a rectangle
*
* @param chXpos1: Specifies the X position 1 (X top left position)
* @param chYpos1: Specifies the Y position 1 (Y top left position)
* @param chXpos2: Specifies the X position 2 (X bottom right position)
* @param chYpos3: Specifies the Y position 2 (Y bottom right position)
*
* @retval
**/
void ssd1306_fill_screen(uint8_t chXpos1, uint8_t chYpos1, uint8_t chXpos2, uint8_t chYpos2, uint8_t chDot)
{
uint8_t chXpos, chYpos;
for (chXpos = chXpos1; chXpos <= chXpos2; chXpos ++) {
for (chYpos = chYpos1; chYpos <= chYpos2; chYpos ++) {
ssd1306_draw_point(chXpos, chYpos, chDot);
}
}
ssd1306_refresh_gram();
}
/**
* @brief Displays one character at the specified position
*
* @param chXpos: Specifies the X position
* @param chYpos: Specifies the Y position
* @param chSize:
* @param chMode
* @retval
**/
void ssd1306_display_char(uint8_t chXpos, uint8_t chYpos, uint8_t chChr, uint8_t chSize, uint8_t chMode)
{
uint8_t i, j;
uint8_t chTemp, chYpos0 = chYpos;
chChr = chChr - ' ';
for (i = 0; i < chSize; i ++) {
if (chMode) {
chTemp = c_chFont1608[chChr][i];
} else {
chTemp = ~c_chFont1608[chChr][i];
}
for (j = 0; j < 8; j ++) {
if (chTemp & 0x80) {
ssd1306_draw_point(chXpos, chYpos, 1);
} else {
ssd1306_draw_point(chXpos, chYpos, 0);
}
chTemp <<= 1;
chYpos ++;
if ((chYpos - chYpos0) == chSize) {
chYpos = chYpos0;
chXpos ++;
break;
}
}
}
}
/**
* @brief Displays a string on the screen
*
* @param chXpos: Specifies the X position
* @param chYpos: Specifies the Y position
* @param pchString: Pointer to a string to display on the screen
*
* @retval None
**/
void ssd1306_display_string(uint8_t chXpos, uint8_t chYpos, const uint8_t *pchString, uint8_t chSize, uint8_t chMode)
{
printk("%s, ssd1306 str = %s\n", __func__, pchString);
while (*pchString != '\0') {
if (chXpos > (SSD1306_WIDTH - chSize / 2)) {
chXpos = 0;
chYpos += chSize;
if (chYpos > (SSD1306_HEIGHT - chSize)) {
chYpos = chXpos = 0;
ssd1306_clear_screen(0x00);
}
}
ssd1306_display_char(chXpos, chYpos, *pchString, chSize, chMode);
chXpos += chSize / 2;
pchString ++;
}
}
void ssd1306_init(void)
{
ssd1306_write_byte(0xAE, SSD1306_CMD);//--turn off oled panel
ssd1306_write_byte(0x00, SSD1306_CMD);//---set low column address
ssd1306_write_byte(0x10, SSD1306_CMD);//---set high column address
ssd1306_write_byte(0x40, SSD1306_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
ssd1306_write_byte(0x81, SSD1306_CMD);//--set contrast control register
ssd1306_write_byte(0xCF, SSD1306_CMD);// Set SEG Output Current Brightness
ssd1306_write_byte(0xA1, SSD1306_CMD);//--Set SEG/Column Mapping
ssd1306_write_byte(0xC0, SSD1306_CMD);//Set COM/Row Scan Direction
ssd1306_write_byte(0xA6, SSD1306_CMD);//--set normal display
ssd1306_write_byte(0xA8, SSD1306_CMD);//--set multiplex ratio(1 to 64)
ssd1306_write_byte(0x3f, SSD1306_CMD);//--1/64 duty
ssd1306_write_byte(0xD3, SSD1306_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
ssd1306_write_byte(0x00, SSD1306_CMD);//-not offset
ssd1306_write_byte(0xd5, SSD1306_CMD);//--set display clock divide ratio/oscillator frequency
ssd1306_write_byte(0x80, SSD1306_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec
ssd1306_write_byte(0xD9, SSD1306_CMD);//--set pre-charge period
ssd1306_write_byte(0xF1, SSD1306_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
ssd1306_write_byte(0xDA, SSD1306_CMD);//--set com pins hardware configuration
ssd1306_write_byte(0x12, SSD1306_CMD);
ssd1306_write_byte(0xDB, SSD1306_CMD);//--set vcomh
ssd1306_write_byte(0x40, SSD1306_CMD);//Set VCOM Deselect Level
ssd1306_write_byte(0x20, SSD1306_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)
ssd1306_write_byte(0x02, SSD1306_CMD);//
ssd1306_write_byte(0x8D, SSD1306_CMD);//--set Charge Pump enable/disable
ssd1306_write_byte(0x14, SSD1306_CMD);//--set(0x10) disable
ssd1306_write_byte(0xA4, SSD1306_CMD);// Disable Entire Display On (0xa4/0xa5)
ssd1306_write_byte(0xA6, SSD1306_CMD);// Disable Inverse Display On (0xa6/a7)
ssd1306_write_byte(0xAF, SSD1306_CMD);//--turn on oled panel
ssd1306_display_on();
ssd1306_clear_screen(0xff);
}
static int ssd1306_ts_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
printk("ssd1306_ts_probe\n");
printk("probe %s\n",__func__);
printk("%s, addr = %x, line = %d\n", __func__, client->addr, client->adapter->nr);
printk("%s, name = %s, adapter nr = %d\n", __func__, client->adapter->name, client->adapter->nr);
ssd1306_client = client;
ssd1306_init();
ssd1306_clear_screen(0x00);
//ssd1306_display_off();
ssd1306_display_on();
ssd1306_display_string(18, 0, "Welcome!", 16, 1);
ssd1306_display_string(0, 16, "zero i2c driver", 16, 1);
ssd1306_refresh_gram();
// ssd1306_display_on();
return 0;
};
static const struct i2c_device_id ssd1306_ts_id[] = {
{ "ssd1306", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ssd1306_ts_id);
static struct i2c_driver ssd1306_ts_driver = {
.probe = ssd1306_ts_probe,
.id_table = ssd1306_ts_id,
.driver = {
.name = SSD1306_TS_NAME,
},
};
module_i2c_driver(ssd1306_ts_driver);
MODULE_LICENSE("GPL");
~~~
相应dts配置如下:
![](https://box.kancloud.cn/9a68c7be1bf1c3b3b9b9809cf18c156c_537x310.jpg)
- 前言
- 荔枝派TODO任务领取
- linux使用小贴士
- 入门篇
- 板卡介绍
- 开箱指南
- 烧录启动系统
- 联网方法
- 镜像使用
- 镜像说明
- buildroot系统使用
- debian系统使用
- 外设操作
- 外设操作概览
- 低速外设
- GPIO
- GPIO模拟低速接口
- UART
- PWM
- I2C
- SPI
- 高速接口
- SDIO
- USB
- EtherNet
- DVP CSI
- MIPI CSI
- 模拟外设
- CODEC
- LRADC
- 常见设备驱动
- USB摄像头
- USB 3G/4G 网卡
- 舵机
- 开发篇
- UBOOT适配
- UBOOT编译
- UBOOT配置
- UBOOT配置屏幕分辨率
- UBOOT配置SPI启动
- Linux内核开发
- Linux内核编译
- BSP Linux内核编译.md
- Linux内核选项
- 外设驱动与设备树
- RTL8723BS驱动
- 根文件系统定制
- buildroot定制系统
- buildroot添加软件包
- openwrt定制系统
- emdebian定制系统
- camdriod开发
- camdriod编译
- 主线Uboot引导Camdriod
- 系统镜像打包
- XBOOT适配
- 荔枝运行XBOOT
- 应用篇
- 游戏机-基于EmulationStation
- 游戏机-gnuboy
- 语音识别-科大讯飞云
- GUI-QT5
- 语音识别-离线关键词识别
- 路由器-Lichee Zero
- 投稿文章
- 荔枝派Zero开箱指南
- Zero i2c oled使用指南
- zero SPI LCD使用指南
- Zero u-boot编译和使用指南
- TF WiFi使用方法
- Zero Ethernet使用指南
- Zero 移植Qt5.4.1
- ZeroSpiNorFlash启动系统制作指南
- Visio-uboot-sunxi流程
- lichee 编译踩坑记录(ilichee ZERO)
- lichee_zero_外设GPIO接口
- TF WIFI 小白编
- 从零开始LicheePi Zero的开发
- 认识Zero的硬件
- 搭建Zero的开发环境
- 主线Uboot
- 主线kernel
- BSP kernel
- BSP内核启动
- bsp内核的摄像头使用
- BSP内核中的保留内存
- uboot启动BSP内核常见错误
- BSP内核 FBTFT移植
- BSP内核启动错误及警告解决
- buildroot 根文件系统
- emdebian 根文件系统
- SPI Flash 系统编译
- sunxi-fel增加对16M 以上flash的支持
- overlayfs的使用
- jffs2系统挂载不上的常见原因
- JFFS2 文件系统简介
- uboot对spi flash的识别
- bsp内核的SPI flash启动
- Docker开发环境
- Docker 命令速查
- 基础ubuntu系统配置
- docker离线镜像
- Zero系统烧录
- dd镜像烧录
- 分区镜像烧录
- SPI Flash系统烧录
- 一键镜像烧录
- Zero外设把玩
- I2C操作
- PWM输出
- CODEC的使用
- 以太网使用指南
- GPIO操作
- 文件IO方式
- C语言接口(mmap)
- Python操作GPIO
- pinctrl-sunxi介绍
- UART操作
- 点屏
- 点屏之RGB屏
- 点屏之SPI屏 ili9341
- 点屏之SPI OLED
- 点屏之I2C OLED
- 点屏之SPI屏 ili9488
- 点屏之MCU屏
- 点屏之触摸屏驱动
- 点屏之simple-framebuffer
- 点屏之屏幕时序
- 时钟控制器CCM
- 摄像头
- BSP DVP摄像头
- BSP MIPI 摄像头
- 主线DVP摄像头
- 主线 MIPI摄像头
- SPI 操作
- 应用层开发
- 开机自启动
- Segment Fault调试
- Zero通过OTG共享PC网络
- USB摄像头使用
- 基于QT的GUI开发
- 移植tslib
- 移植QT5.9.1
- 移植QT4.8.7
- QtCreator使用
- Qt5.x移植到Qt4.8
- Qt字体相关
- Qt移植总结
- Qt裁剪
- Qt去除鼠标指针显示
- zero_imager使用
- 驱动开发
- 设备树简介
- GPU/DRM 显示驱动
- sys下设备树查看
- atmel触摸屏驱动分析
- atmel触摸屏中断改轮询
- uboot下gpio操作
- helloworld驱动编译演示
- FBTFT分析
- 内核模块静态加载的顺序
- SPI驱动分析
- SPI 驱动编写
- Uboot开发
- 开机logo
- 看门狗的使用
- 关于系统reboot
- 内核printk等级设置