



要操作OLED,只需要使用spi接口发送数据,并不需要使用SPI接口读取数据。除此之外,还需要控制D/C引脚
OLED上有128*64个像素,每个像素只有2中状态:亮、灭。

OLED内部有显存GDDRAM(Graphic Display Data RAM):

显存中,每位对应一个像素,如下图所示:

OLED有三种寻址模式:
页地址模式(Page addressing mode):每写入1个字节,行地址不变,列地址增1,列地址达到127后会从0开始

水平地址模式(Horizontal addressing mode):

垂直地址模式(Vertical addressing mode):

对于OLED的初始化,在参考手册中,列出了流程图:

设置地址模式,如果为页地址模式时,先写命令0x22,在写命令0x02,页地址模式是默认的,可以不设置。

设置页地址:有0~7页,想设置哪一页(n)就发出命令:0xB0|n

设置列地址:列地址范围是0~127,需要使用2个命令来设置列地址

让D/C引脚为高,发起SPI写操作就可以了。
DC引脚使用GPIO0_B5,在APP里直接控制DC引脚,无需在设备树里指定。
引脚号为 = 0 * 32 + 1 * 8 + 5 = 13
&spi0 {
oled: oled@00{
compatible = "spidev";
reg = <0>;
spi-max-frequency = <10000000>;
status="okay";
};
};
// SPDX-License-Identifier: GPL-2.0
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "font.h"
#define OLED_CMD 0
#define OLED_DATA 1
static int fd_spidev;
static int dc_pin_num;
void dc_pin_init(int number)
{
char cmd[100];
dc_pin_num = number;
sprintf(cmd, "echo %d > /sys/class/gpio/export", dc_pin_num);
system(cmd);
sprintf(cmd, "echo out > /sys/class/gpio/gpio%d/direction", dc_pin_num);
system(cmd);
}
void oled_set_dc_pin(int val)
{
char cmd[100];
sprintf(cmd, "echo %d > /sys/class/gpio/gpio%d/value", val, dc_pin_num);
system(cmd);
}
void spi_write_datas(unsigned char *buf, int len)
{
write(fd_spidev, buf, len);
}
void oled_write_cmd_data(unsigned char uc_data, unsigned char uc_cmd)
{
unsigned char uc_read = 0;
if(uc_cmd == 0) {
oled_set_dc_pin(0);
} else {
oled_set_dc_pin(1);
}
spi_write_datas(&uc_data, 1);
}
int oled_init(void)
{
oled_write_cmd_data(0xae, OLED_CMD);
oled_write_cmd_data(0x00, OLED_CMD);
oled_write_cmd_data(0x10, OLED_CMD);
oled_write_cmd_data(0x40, OLED_CMD);
oled_write_cmd_data(0xb0, OLED_CMD);
oled_write_cmd_data(0x81, OLED_CMD);
oled_write_cmd_data(0x66, OLED_CMD);
oled_write_cmd_data(0xa1, OLED_CMD);
oled_write_cmd_data(0xa6, OLED_CMD);
oled_write_cmd_data(0xa8, OLED_CMD);
oled_write_cmd_data(0x3f, OLED_CMD);
oled_write_cmd_data(0xc8, OLED_CMD);
oled_write_cmd_data(0xd3, OLED_CMD);
oled_write_cmd_data(0x00, OLED_CMD);
oled_write_cmd_data(0xd5, OLED_CMD);
oled_write_cmd_data(0x80, OLED_CMD);
oled_write_cmd_data(0xd9, OLED_CMD);
oled_write_cmd_data(0x1f, OLED_CMD);
oled_write_cmd_data(0xda, OLED_CMD);
oled_write_cmd_data(0x12, OLED_CMD);
oled_write_cmd_data(0xdb, OLED_CMD);
oled_write_cmd_data(0x30, OLED_CMD);
oled_write_cmd_data(0x8d, OLED_CMD);
oled_write_cmd_data(0x14, OLED_CMD);
oled_write_cmd_data(0xaf, OLED_CMD);
return 0;
}
void OLED_DIsp_Set_Pos(int x, int y)
{
oled_write_cmd_data(0xb0+y, OLED_CMD);
oled_write_cmd_data((x&0x0f), OLED_CMD);
oled_write_cmd_data(((x&0xf0)>>4)|0x10, OLED_CMD);
}
void OLED_DIsp_Char(int x, int y, unsigned char c)
{
int i=0;
const unsigned char *dots = oled_asc2_8x16[ c - ' '];
OLED_DIsp_Set_Pos(x, y);
for(i=0;i<8;i++) {
oled_write_cmd_data(dots[i], OLED_DATA);
}
OLED_DIsp_Set_Pos(x, y+1);
for(i=0;i<8;i++) {
oled_write_cmd_data(dots[i+8], OLED_DATA);
}
}
void OLED_DIsp_String(int x, int y, char *str)
{
unsigned char j=0;
while(str[j]) {
OLED_DIsp_Char(x, y, str[j]);
x += 8;
if(x > 127) {
x = 0;
y += 2;
}
j++;
}
}
void OLED_DIsp_Test(void)
{
int i;
OLED_DIsp_String(0, 0, "wiki.100ask.net");
OLED_DIsp_String(0, 2, "book.100ask.net");
OLED_DIsp_String(0, 4, "bbs.100ask.net");
}
/* spi_oled /dev/spidevB.D */
int main(int argc, char **argv)
{
int dc_pin;
if(argc != 3) {
printf("Usage: %s \n" , argv[0]);
return -1;
}
fd_spidev = open(argv[1], O_RDWR);
if(fd_spidev < 0) {
printf("open %s failed\n", argv[1]);
return -1;
}
dc_pin = strtoul(argv[2], NULL, 0);
dc_pin_init(dc_pin);
oled_init();
OLED_DIsp_Test();
close(fd_spidev);
return 0;
}
[root@firefly-rk3288:/home/picture/spi]# ./spidev-oled /dev/spidev0.0 13
[root@firefly-rk3288:/home/picture/spi]#
