Linux下i2c驱动OLED ssd1306
参数
dts修改
&i2c0 {
status = "okay";
ssd1306:ssd1306@3c {
compatible = "oled12832,ssd1306";
reg = <0x3c>;
};
};
编译
修改好了dts设备树,需要重新编译,见教程:传送
最后得到image镜像,在milkv-duo上烧录即可。
i2cdetect -yr 0
源代码获取KO文件
在sdk下新建driver,然后再新建ssd1306文件夹,接着新文件命名为ssd1306.c,不想分头文件
借鉴某位大佬源代码,稍微修改
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kdev_t.h>
#include <linux/module.h>
#include <linux/stat.h>
#include <linux/uaccess.h>
#define OK (0)
#define ERROR (-1)
static struct i2c_driver oled_driver;
static struct i2c_client *oled_client;
static unsigned short addr = 0x3C;
static unsigned short address_list[] = {0x3c, 0xfffeU};
static dev_t devid;
static struct class *oled_class;
static struct cdev i2c_cdev;
static const u8 ASCII6x8[][6] =
{
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0x00, 0x00, 0x00, 0x2f, 0x00, 0x00},
{0x00, 0x00, 0x07, 0x00, 0x07, 0x00},
{0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14},
{0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12},
{0x00, 0x62, 0x64, 0x08, 0x13, 0x23},
{0x00, 0x36, 0x49, 0x55, 0x22, 0x50},
{0x00, 0x00, 0x05, 0x03, 0x00, 0x00},
{0x00, 0x00, 0x1c, 0x22, 0x41, 0x00},
{0x00, 0x00, 0x41, 0x22, 0x1c, 0x00},
{0x00, 0x14, 0x08, 0x3E, 0x08, 0x14},
{0x00, 0x08, 0x08, 0x3E, 0x08, 0x08},
{0x00, 0x00, 0x00, 0xA0, 0x60, 0x00},
{0x00, 0x08, 0x08, 0x08, 0x08, 0x08},
{0x00, 0x00, 0x60, 0x60, 0x00, 0x00},
{0x00, 0x20, 0x10, 0x08, 0x04, 0x02},
{0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E},
{0x00, 0x00, 0x42, 0x7F, 0x40, 0x00},
{0x00, 0x42, 0x61, 0x51, 0x49, 0x46},
{0x00, 0x21, 0x41, 0x45, 0x4B, 0x31},
{0x00, 0x18, 0x14, 0x12, 0x7F, 0x10},
{0x00, 0x27, 0x45, 0x45, 0x45, 0x39},
{0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30},
{0x00, 0x01, 0x71, 0x09, 0x05, 0x03},
{0x00, 0x36, 0x49, 0x49, 0x49, 0x36},
{0x00, 0x06, 0x49, 0x49, 0x29, 0x1E},
{0x00, 0x00, 0x36, 0x36, 0x00, 0x00},
{0x00, 0x00, 0x56, 0x36, 0x00, 0x00},
{0x00, 0x08, 0x14, 0x22, 0x41, 0x00},
{0x00, 0x14, 0x14, 0x14, 0x14, 0x14},
{0x00, 0x00, 0x41, 0x22, 0x14, 0x08},
{0x00, 0x02, 0x01, 0x51, 0x09, 0x06},
{0x00, 0x32, 0x49, 0x59, 0x51, 0x3E},
{0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C},
{0x00, 0x7F, 0x49, 0x49, 0x49, 0x36},
{0x00, 0x3E, 0x41, 0x41, 0x41, 0x22},
{0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C},
{0x00, 0x7F, 0x49, 0x49, 0x49, 0x41},
{0x00, 0x7F, 0x09, 0x09, 0x09, 0x01},
{0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A},
{0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F},
{0x00, 0x00, 0x41, 0x7F, 0x41, 0x00},
{0x00, 0x20, 0x40, 0x41, 0x3F, 0x01},
{0x00, 0x7F, 0x08, 0x14, 0x22, 0x41},
{0x00, 0x7F, 0x40, 0x40, 0x40, 0x40},
{0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F},
{0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F},
{0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E},
{0x00, 0x7F, 0x09, 0x09, 0x09, 0x06},
{0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E},
{0x00, 0x7F, 0x09, 0x19, 0x29, 0x46},
{0x00, 0x46, 0x49, 0x49, 0x49, 0x31},
{0x00, 0x01, 0x01, 0x7F, 0x01, 0x01},
{0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F},
{0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F},
{0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F},
{0x00, 0x63, 0x14, 0x08, 0x14, 0x63},
{0x00, 0x07, 0x08, 0x70, 0x08, 0x07},
{0x00, 0x61, 0x51, 0x49, 0x45, 0x43},
{0x00, 0x00, 0x7F, 0x41, 0x41, 0x00},
{0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55},
{0x00, 0x00, 0x41, 0x41, 0x7F, 0x00},
{0x00, 0x04, 0x02, 0x01, 0x02, 0x04},
{0x00, 0x40, 0x40, 0x40, 0x40, 0x40},
{0x00, 0x00, 0x01, 0x02, 0x04, 0x00},
{0x00, 0x20, 0x54, 0x54, 0x54, 0x78},
{0x00, 0x7F, 0x48, 0x44, 0x44, 0x38},
{0x00, 0x38, 0x44, 0x44, 0x44, 0x20},
{0x00, 0x38, 0x44, 0x44, 0x48, 0x7F},
{0x00, 0x38, 0x54, 0x54, 0x54, 0x18},
{0x00, 0x08, 0x7E, 0x09, 0x01, 0x02},
{0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C},
{0x00, 0x7F, 0x08, 0x04, 0x04, 0x78},
{0x00, 0x00, 0x44, 0x7D, 0x40, 0x00},
{0x00, 0x40, 0x80, 0x84, 0x7D, 0x00},
{0x00, 0x7F, 0x10, 0x28, 0x44, 0x00},
{0x00, 0x00, 0x41, 0x7F, 0x40, 0x00},
{0x00, 0x7C, 0x04, 0x18, 0x04, 0x78},
{0x00, 0x7C, 0x08, 0x04, 0x04, 0x78},
{0x00, 0x38, 0x44, 0x44, 0x44, 0x38},
{0x00, 0xFC, 0x24, 0x24, 0x24, 0x18},
{0x00, 0x18, 0x24, 0x24, 0x18, 0xFC},
{0x00, 0x7C, 0x08, 0x04, 0x04, 0x08},
{0x00, 0x48, 0x54, 0x54, 0x54, 0x20},
{0x00, 0x04, 0x3F, 0x44, 0x40, 0x20},
{0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C},
{0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C},
{0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C},
{0x00, 0x44, 0x28, 0x10, 0x28, 0x44},
{0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C},
{0x00, 0x44, 0x64, 0x54, 0x4C, 0x44},
{0x14, 0x14, 0x14, 0x14, 0x14, 0x14}
};
static int oled_write_cmd(unsigned char cmd)
{
struct i2c_msg msg[1];
unsigned char cmds[2];
cmds[0] = 0x00;
cmds[1] = cmd;
msg[0].addr = oled_client->addr;
msg[0].buf = cmds;
msg[0].len = 2;
msg[0].flags = 0;
if (i2c_transfer(oled_client->adapter, msg, 1) == 1)
return 2;
else
return ERROR;
}
static int oled_write_data(unsigned char data)
{
struct i2c_msg msg[1];
unsigned char datas[2];
datas[0] = 0x40;
datas[1] = data;
msg[0].addr = oled_client->addr;
msg[0].buf = datas;
msg[0].len = 2;
msg[0].flags = 0;
if (i2c_transfer(oled_client->adapter, msg, 1) == 1)
return 2;
else
return ERROR;
}
static void oled_pos(u8 x, u8 y)
{
oled_write_cmd(0xB0 + y);
oled_write_cmd(((x & 0xF0) >> 4) | 0x10);
oled_write_cmd(x & 0x0F);
}
static void oled_clear(void)
{
u8 x;
u8 y;
for (y = 0; y < 8; y++)
{
oled_write_cmd(0xB0 + y);
oled_write_cmd(0x00);
oled_write_cmd(0x10);
for (x = 0; x < 0x80; x++)
oled_write_data(0x00);
}
}
static void oled_p6x8str(u8 x, u8 y, u8 *str)
{
u8 i = 0;
u8 j = 0;
u8 k = 0;
while (str[j] != '\0')
{
while ((str[j] < 0x20) || (str[j] > 0x80))
str[j] = 32;
k = str[j] - 32;
if (x > 121)
{
x = 0;
y++;
}
oled_pos(x, y);
for (i = 0; i < 6; i++)
oled_write_data(ASCII6x8[k][i]);
x += 6;
j++;
}
}
static int oledinit(void)
{
oled_write_cmd(0xAE);
oled_write_cmd(0x40);
oled_write_cmd(0xB0);
oled_write_cmd(0xC8);
oled_write_cmd(0x81);
oled_write_cmd(0xFF);
oled_write_cmd(0xA1);
oled_write_cmd(0xA6);
oled_write_cmd(0xA8);
oled_write_cmd(0x1F);
oled_write_cmd(0xD3);
oled_write_cmd(0x00);
oled_write_cmd(0xD5);
oled_write_cmd(0xF0);
oled_write_cmd(0xD9);
oled_write_cmd(0x22);
oled_write_cmd(0xDA);
oled_write_cmd(0x02);
oled_write_cmd(0xDB);
oled_write_cmd(0x49);
oled_write_cmd(0x8D);
oled_write_cmd(0x14);
oled_write_cmd(0xAF);
return 0;
}
static int oled_open(struct inode *inode, struct file *filp)
{
oledinit();
oled_clear();
oled_pos(0, 0);
printk(KERN_INFO "oled open\n");
return 0;
}
static ssize_t oled_write(struct file *filp, const char __user *buffer, size_t size, loff_t *off)
{
unsigned char data[168];
copy_from_user(data, buffer, 168);
oled_p6x8str(0, 0, data);
return 0;
}
static struct file_operations oled_fops = {
.owner = THIS_MODULE,
.write = oled_write,
.open = oled_open,
};
static int oled_probe(struct i2c_client *client, const struct i2c_device_id *i2c_device)
{
int result;
if (alloc_chrdev_region(&devid, 0, 1, "oled") == OK)
{
printk(KERN_INFO "alloc device number : major:[%d], minor:[%d] succeed!\n", MAJOR(devid), MINOR(devid));
}
else
{
printk(KERN_INFO "register device number error!\n");
return ERROR;
}
cdev_init(&i2c_cdev, &oled_fops);
cdev_add(&i2c_cdev, devid, 1);
oled_class = class_create(THIS_MODULE, "oled_class");
if (IS_ERR(oled_class))
{
printk("can't create class\n");
return ERROR;
}
device_create(oled_class, NULL, devid, NULL, "oled");
printk(KERN_INFO "create device file 'oled' succeed!\n");
oled_client = client;
printk(KERN_INFO "get i2c_client, client name = %s, addr = 0x%x\n", oled_client->name, oled_client->addr);
printk(KERN_INFO "get i2c_adapter, adapter name = %s\n", oled_client->adapter->name);
printk(KERN_INFO "oled probe\n");
return 0;
}
static int oled_remove(struct i2c_client *client)
{
device_destroy(oled_class, devid);
class_destroy(oled_class);
cdev_del(&i2c_cdev);
unregister_chrdev_region(devid, 1);
printk(KERN_INFO "oled remove\n");
return 0;
}
static int oled_detect(struct i2c_client *client, struct i2c_board_info *info)
{
printk(KERN_INFO "oled detect success\n");
strcpy(info->type, "oled");
return OK;
}
static const struct i2c_device_id oled_id[] = {
{"ssd1306", 0},
{}
};
static struct i2c_driver oled_driver = {
.probe = oled_probe,
.remove = oled_remove,
.driver = {
.name = "oled",
.owner = THIS_MODULE,
},
.address_list = address_list,
.detect = oled_detect,
.id_table = oled_id,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
};
static int __init oled_init(void)
{
i2c_add_driver(&oled_driver);
printk(KERN_INFO "oled i2c_driver was added into the system.\n");
return 0;
}
static void __exit oled_exit(void)
{
i2c_del_driver(&oled_driver);
printk(KERN_INFO "oled i2c_driver was deleted from the system.\n");
return;
}
module_init(oled_init);
module_exit(oled_exit);
MODULE_AUTHOR("rx-ted");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("oled device driver, 2023-07-18");
再建立makefile,如
SDK_DIR = ~/buildroot
KERN_DIR = $(SDK_DIR)/linux_5.10/build/cv1800b_milkv_duo_sd
all:
make -C $(KERN_DIR) M=$(PWD) modules
clean:
make -C $(KERN_DIR) M=$(PWD) modules clean
rm -rf modules.order
obj-m += ssd1306.o
这样可以到一个ssd1306.ko文件
传送milkv-duo
将ssd1306.ko传送milkv-duo
scp driver/ssd1306/ssd1306.ko root@192.168.42.1:/mnt/system/ko
进入milkv-duo,这样命令
[root@milkv]~
Module Size Used by Tainted: GF
cvi_vc_driver 879138 0 [permanent]
cv180x_jpeg 25220 1 cvi_vc_driver,[permanent]
cv180x_vcodec 28451 2 cvi_vc_driver,cv180x_jpeg,[permanent]
cv180x_tpu 32041 0 [permanent]
cv180x_clock_cooling 5953 0 [permanent]
cv180x_thermal 3404 0
cv180x_rgn 100809 0 [permanent]
cv180x_dwa 48669 0 [permanent]
cv180x_vpss 280938 0 [permanent]
cv180x_vi 338826 0 [permanent]
snsr_i2c 9341 0 [permanent]
cvi_mipi_rx 54306 0 [permanent]
cv180x_fast_image 32955 0 [permanent]
cv180x_rtos_cmdqu 25922 1 cv180x_fast_image,[permanent]
cv180x_base 96472 8 cvi_vc_driver,cv180x_rgn,cv180x_dwa,cv180x_vpss,cv180x_vi,snsr_i2c,cvi_mipi_rx,cv180x_rtos_cmdqu,[permanent]
cv180x_sys 64161 7 cvi_vc_driver,cv180x_rgn,cv180x_dwa,cv180x_vpss,cv180x_vi,cv180x_fast_image,cv180x_base,[permanent]
[root@milkv]~
[root@milkv]~
Module Size Used by Tainted: GF
ssd1306 5654 0
cvi_vc_driver 879138 0 [permanent]
cv180x_jpeg 25220 1 cvi_vc_driver,[permanent]
cv180x_vcodec 28451 2 cvi_vc_driver,cv180x_jpeg,[permanent]
cv180x_tpu 32041 0 [permanent]
cv180x_clock_cooling 5953 0 [permanent]
cv180x_thermal 3404 0
cv180x_rgn 100809 0 [permanent]
cv180x_dwa 48669 0 [permanent]
cv180x_vpss 280938 0 [permanent]
cv180x_vi 338826 0 [permanent]
snsr_i2c 9341 0 [permanent]
cvi_mipi_rx 54306 0 [permanent]
cv180x_fast_image 32955 0 [permanent]
cv180x_rtos_cmdqu 25922 1 cv180x_fast_image,[permanent]
cv180x_base 96472 8 cvi_vc_driver,cv180x_rgn,cv180x_dwa,cv180x_vpss,cv180x_vi,snsr_i2c,cvi_mipi_rx,cv180x_rtos_cmdqu,[permanent]
cv180x_sys 64161 7 cvi_vc_driver,cv180x_rgn,cv180x_dwa,cv180x_vpss,cv180x_vi,cv180x_fast_image,cv180x_base,[permanent]
[root@milkv]~
[ 412.711906] create device file 'oled' succeed!
[ 412.711920] get i2c_client, client name = ssd1306, addr = 0x3c
[ 412.711927] get i2c_adapter, adapter name = Synopsys DesignWare I2C adapter
[ 412.711933] oled probe
[ 412.712132] oled i2c_driver was added into the system.
[root@milkv]~
^C
[root@milkv]~
^C
演示效果