Linux-oled096驱动硬件分析

源代码

&iomuxc {pinctrl-names = "default";pinctrl-0 = <&pinctrl_hog_1>;imx6ul-evk {pinctrl_i2c1: i2c1grp {fsl,pins = <MX6UL_PAD_UART4_TX_DATA__I2C1_SCL 0x4001b8b0MX6UL_PAD_UART4_RX_DATA__I2C1_SDA 0x4001b8b0>;};};
};&i2c1 {clock-frequency = <100000>;pinctrl-names = "default";pinctrl-0 = <&pinctrl_i2c1>;status = "okay";ap3216c@1e {compatible = "alientek,ap3216c";reg = <0x1e>;};oled096@3c {compatible = "alientek,oled096";reg = <0x3c>;};
};
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/input.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include "oledfont.h"#define DEV_CNT 1
#define DEV_NAME "oled096"
#define OLED_CMD 0x00  //OLED写命令
#define OLED_DATA 0x40 //OLED写数据
#define Max_Column 128struct display_stru
{int x;int y;unsigned char *buf;
};struct oled096_dev
{dev_t devt;            //设备号struct cdev cdev;      //字符设备unsigned int major;    //主设备号struct class *class;   //类struct device *device; //设备void *private_data;    //文件私有数据
};
static struct oled096_dev oled096_dev1;//oled096寄存器写函数
static int oled_write_byte(u8 reg, u8 data)
{unsigned char receive_data[2];struct i2c_msg msg;struct i2c_client *client = (struct i2c_client *)oled096_dev1.private_data;receive_data[0] = reg;   //寄存器receive_data[1] = data;  //参数msg.addr = client->addr; //oled地址, 设备树中的地址msg.flags = 0;           //标记为写msg.buf = receive_data;  //要写入的数据缓冲区msg.len = 1 + 1;         //要写入的数据长度return i2c_transfer(client->adapter, &msg, 1); //用于发送的client
}void oled_clear(void)
{u8 i, n;for (i = 0; i < 8; i++){oled_write_byte(OLED_CMD, 0xb0 + i); //设置页地址(0~7)oled_write_byte(OLED_CMD, 0x00);     //设置显示位置—列低地址oled_write_byte(OLED_CMD, 0x10);     //设置显示位置—列高地址for (n = 0; n < 128; n++){oled_write_byte(OLED_DATA, 0x00);}}
}void oled_set_pos(u8 x, u8 y)
{oled_write_byte(OLED_CMD, 0xb0 + y);oled_write_byte(OLED_CMD, ((x & 0xf0) >> 4) | 0x10);oled_write_byte(OLED_CMD, x & 0x0f);
}//写入16字节数据,1字节8位(16*8)
void oled_showchar(u8 x, u8 y, u8 chr)
{u8 c = 0, i = 0;//得到当前字符偏移量c = chr - ' ';if (x > Max_Column - 1){//另起一行x = 0;//显示到下一页y = y + 2;}//设置坐标oled_set_pos(x, y);//依次写入每个字节for (i = 0; i < 8; i++){//前8字节数据oled_write_byte(OLED_DATA, asc2_1608[c * 16 + i]);}//设置坐标(页数加1),其实是下一页起始位置oled_set_pos(x, y + 1);for (i = 0; i < 8; i++){//后8字节数据oled_write_byte(OLED_DATA, asc2_1608[c * 16 + i + 8]);}
}//写入16字节数据,1字节8位(16*8)
void oled_showchar(u8 x, u8 y, u8 chr)
{u8 c = 0, i = 0;//得到当前字符偏移量c = chr - ' ';if (x > Max_Column - 1){//另起一行x = 0;//显示到下一页y = y + 2;}//设置坐标oled_set_pos(x, y);//依次写入每个字节for (i = 0; i < 8; i++){//前8字节数据oled_write_byte(OLED_DATA, asc2_1608[c * 16 + i]);}//设置坐标(页数加1),其实是下一页起始位置oled_set_pos(x, y + 1);for (i = 0; i < 8; i++){//后8字节数据oled_write_byte(OLED_DATA, asc2_1608[c * 16 + i + 8]);}
}void oled_showstring(u8 x, u8 y, u8 *chr)
{unsigned char j = 0;while (chr[j] != '\0'){oled_showchar(x, y, chr[j]);x += 8;if (x > 120){x = 0;y += 2;}j++;}
}void OLED_ShowCHinese(u8 x, u8 y, u8 no)
{u8 t, adder = 0;OLED_Set_Pos(x, y);for (t = 0; t < 16; t++){OLED_WR_Byte(Hzk[2 * no][t], OLED_DATA);adder += 1;}OLED_Set_Pos(x, y + 1);for (t = 0; t < 16; t++){OLED_WR_Byte(Hzk[2 * no + 1][t], OLED_DATA);adder += 1;}
}void oled_init(void)
{oled_write_byte(OLED_CMD, 0xAE); /*display off*/oled_write_byte(OLED_CMD, 0x00); /*set lower column address*/oled_write_byte(OLED_CMD, 0x10); /*set higher column address*/oled_write_byte(OLED_CMD, 0x40); /* set display start line */oled_write_byte(OLED_CMD, 0x81); /* set contrast control */oled_write_byte(OLED_CMD, 0xcf);oled_write_byte(OLED_CMD, 0xa1); /* set segment remap */oled_write_byte(OLED_CMD, 0xc8); /* set normal display */oled_write_byte(OLED_CMD, 0xa6); /* set multiplex ratio */oled_write_byte(OLED_CMD, 0xa8); /* 1/32 */oled_write_byte(OLED_CMD, 0x3f); /* set com scan direction */oled_write_byte(OLED_CMD, 0xd3); /* set display offset */oled_write_byte(OLED_CMD, 0x00);oled_write_byte(OLED_CMD, 0xd5); /* set display clock divide/oscillator frequency */oled_write_byte(OLED_CMD, 0x80);oled_write_byte(OLED_CMD, 0xD9); /*set area color mode off */oled_write_byte(OLED_CMD, 0xf1);oled_write_byte(OLED_CMD, 0xDa); /* Set Pre-Charge Period */oled_write_byte(OLED_CMD, 0x12);oled_write_byte(OLED_CMD, 0xdb); /* set com pin configuartion */oled_write_byte(OLED_CMD, 0x30);oled_write_byte(OLED_CMD, 0x20); /* set Vcomh */oled_write_byte(OLED_CMD, 0x02);oled_write_byte(OLED_CMD, 0x8d); /* set Vcomh */oled_write_byte(OLED_CMD, 0x14);oled_clear();oled_write_byte(OLED_CMD, 0xAF); /* display ON */
}static int oled096_open(struct inode *inode, struct file *file)
{oled_init();return 0;
}static ssize_t oled096_write(struct file *file, char __user *buf, size_t cnt, loff_t *off)
{int ret;struct display_stru dis_format;//从应用层复制数据ret = copy_from_user(&dis_format, buf, cnt);//oled显示数据oled_showstring(dis_format.x, dis_format.y, dis_format.buf);return 0;
}int oled096_release(struct inode *inode, struct file *file)
{return 0;
}struct file_operations oled096_dev1_file_operations = {.owner = THIS_MODULE,.open = oled096_open,.write = oled096_write,.release = oled096_release,
};static int oled096_probe(struct i2c_client *client, const struct i2c_device_id *device_id)
{printk("i2c driver and device was matched!\r\n");//申请设备号if (oled096_dev1.major) //设置了主设备号{//根据主设备号,获取设备号oled096_dev1.devt = MKDEV(oled096_dev1.major, 0);//根据设备号,申请分配设备号register_chrdev_region(oled096_dev1.devt, DEV_CNT, DEV_NAME);}else //未设置主设备号{//系统自动分配设备号alloc_chrdev_region(&oled096_dev1.devt, 0, DEV_CNT, DEV_NAME);//根据分配到的设备号,获取主设备号oled096_dev1.major = MAJOR(oled096_dev1.devt);}//注册设备cdev_init(&oled096_dev1.cdev, &oled096_dev1_file_operations);//添加设备cdev_add(&oled096_dev1.cdev, oled096_dev1.devt, DEV_CNT);//创建类oled096_dev1.class = class_create(THIS_MODULE, DEV_NAME);if (IS_ERR(oled096_dev1.class)){return PTR_ERR(oled096_dev1.class);}//创建设备oled096_dev1.device = device_create(oled096_dev1.class, NULL, oled096_dev1.devt, NULL, DEV_NAME);if (IS_ERR(oled096_dev1.device)){return PTR_ERR(oled096_dev1.device);}//保存私有数据oled096_dev1.private_data = client;//初始化OLEDoled_init();printk("oled init finished!\r\n");return 0;
}static int oled096_remove(struct i2c_client *client)
{oled_clear();//删除字符设备cdev_del(&oled096_dev1.cdev);//释放设备号unregister_chrdev_region(oled096_dev1.devt, DEV_CNT);//删除设备device_destroy(oled096_dev1.class, oled096_dev1.devt);//删除类class_destroy(oled096_dev1.class);return 0;
}static const struct i2c_device_id oled096_device_id[] = {{"alientek,oled096", 0},{}};static const struct of_device_id oled096_driver_of_match_table[] = {{.compatible = "alientek,oled096"},{}};//i2c设备驱动
struct i2c_driver oled096_driver = {.probe = oled096_probe,.remove = oled096_remove,.driver = {.name = "oled096",.owner = THIS_MODULE,.of_match_table = oled096_driver_of_match_table,},.id_table = oled096_device_id,
};//入口函数
static int __init oled096_init(void)
{//加载驱动int ret = 0;ret = i2c_add_driver(&oled096_driver);return ret;
}//出口函数
static void __exit oled096_exit(void)
{//卸载驱动i2c_del_driver(&oled096_driver);
}module_init(oled096_init);
module_exit(oled096_exit);
MODULE_AUTHOR("chen");
MODULE_LICENSE("GPL");

i2c通信协议

#define OLED_CMD 0x00  //OLED写命令(0x00转换为二进制为0000 0000,将D/C#控制位设置为0)
#define OLED_DATA 0x40 //OLED写数据(0x40转换为二进制为0100 0000,将D/C#控制位设置为1)

常用寻址方式

  • 页寻址
  • 水平寻址
  • 垂直寻址

页寻址方式代码分析

void oled_set_pos(u8 x, u8 y)
{oled_write_byte(OLED_CMD, 0xb0 + y);oled_write_byte(OLED_CMD, ((x & 0xf0) >> 4) | 0x10);oled_write_byte(OLED_CMD, x & 0x0f);
}
  • 第一行代码
oled_write_byte(OLED_CMD, 0xb0 + y);
//
第一行代码设置页寻址方式页起始地址,从表格中可以看出,需要输入命令0,需要输入数据(10000 x2 x1 x0)=0xb0+x[2:0]。
0xb0+y(最终确定是PAGE0~PAGE7)。
  • 第二行代码
oled_write_byte(OLED_CMD, ((x & 0xf0) >> 4) | 0x10);
//
第二行代码设置高列起始地址,从表格中可以看出,需要输入命令0,需要输入数据(0001 x3 x2 x1 x0)=0x10。
将x & 0xf0 获取高四位数据,再将高四位数据右移,最后与上0x10,得到高列起始地址。
  • 第三行代码
oled_write_byte(OLED_CMD, x & 0x0f);
//
第三行代码设置低列起始地址,从表格中可以看出,需要输入命令0,需要输入数据(0000 x3 x2 x1 x0)。
将x & 0x0f获取低四位数据,得到低列起始地址。

显示代码分析

//
以下代码是基于16*8字号字符编写的显示函数
共需写入16字节数据,1字节8位(16*8)
void oled_showchar(u8 x, u8 y, u8 chr)
{u8 c = 0, i = 0;//得到当前字符偏移量c = chr - ' ';//超出范围,另起一页显示if (x > Max_Column - 1){//另起一行x = 0;//显示到下两页y = y + 2;}//设置坐标oled_set_pos(x, y);//依次写入每个字节for (i = 0; i < 8; i++){//前8字节数据oled_write_byte(OLED_DATA, asc2_1608[c * 16 + i]);}//设置坐标(页数加1),其实是下一页起始位置oled_set_pos(x, y + 1);for (i = 0; i < 8; i++){//后8字节数据oled_write_byte(OLED_DATA, asc2_1608[c * 16 + i + 8]);}
}

Linux-oled096驱动硬件分析相关推荐

  1. Linux USB驱动框架分析 【转】

    转自:http://blog.chinaunix.net/uid-11848011-id-96188.html 初次接触与OS相关的设备驱动编写,感觉还挺有意思的,为了不至于忘掉看过的东西,笔记跟总结 ...

  2. linux RTC 驱动模型分析

    linux RTC 驱动模型分析 RTC(real time clock)实时时钟,主要作用是给Linux系统提供时间.RTC因为是电池供电的,所以掉电后时间不丢失.Linux内核把RTC用作&quo ...

  3. Linux PCI驱动框架分析:(Peripheral Component Interconnect,外部设备互联)

    <DPDK 20.05 | rte_pci_bus思维导图 | 第一版> <linux系统下:IO端口,内存,PCI总线 的 读写(I/O)操作> <Linux指令:ls ...

  4. Linux PCIe驱动框架分析(第二章)

    目录 项目背景 1. 概述 2. 数据结构 3. 流程分析 3.1 设备驱动模型 3.2 初始化 3.2.1 pci_bus_match 3.2.2 pci_device_probe 3.3 枚举 项 ...

  5. 深入分析Linux PCI驱动框架分析(二)

    说明: Kernel版本:4.14 ARM64处理器 使用工具:Source Insight 3.5, Visio 1. 概述 本文将分析Linux PCI子系统的框架,主要围绕Linux PCI子系 ...

  6. Linux i2c驱动框架分析 (二)

    Linux i2c驱动框架分析 (一) Linux i2c驱动框架分析 (二) Linux i2c驱动框架分析 (三) 通用i2c设备驱动分析 i2c core i2c核心(drivers/i2c/i ...

  7. linux MISC 驱动模型分析

    linux MISC 驱动模型分析 阅读led驱动程序的代码的时候,没有发现ldd3中提到的各种字符设备注册函数,而是发现了一个misc_register函数,这说明led设备是作为杂项设备出现在内核 ...

  8. LINUX设备驱动模型分析之三 驱动(DRIVER)接口分析

    上一章我们分析了bus-driver-device模型中bus接口部分,本章我们将分析driver接口,在bus-driver-device模型中,driver接口是依附于bus上,而不像device ...

  9. linux驱动架构变化,Linux网卡驱动架构分析

    一.网卡驱动架构 由上到下层次依次为:应用程序→系统调用接口→协议无关接口→网络协议栈→设备无关接口→设备驱动. 二.重要数据结构 1.Linux内核中每一个网卡由一个net_device结构来描述. ...

最新文章

  1. tensorflow详解-tf.nn.conv2d(),tf.nn.max_pool()
  2. C语言二进制转换为八进制(附完整源码)
  3. CRM Interactive Report的UI设计
  4. 你的“不着急”,最后都是“来不及”
  5. plsql如何显示表结构图_产品经理需了解的架构图/结构图知识
  6. 帮你轻松理解Commonjs、AMD、CMD、ES6的区别
  7. RDD,DataFrame与DataSet区别
  8. 李昌镐究竟是不是神?
  9. 几种自动化功能测试的工具的认识
  10. 找不到本地计算机策略组,Win10家庭版找不到本地组策略gpedit.msc解决办法
  11. wps删除第二页页眉
  12. 响铃:云+峰会再召开,腾讯云的政企合作玩得怎么样了?
  13. 如何给PDF加密码保护?这3种方法总有一个能用上
  14. MFC 图标 icon 如何制作?
  15. 自媒体人不做广告怎么吃饭
  16. 桌面删除的文件如何找回
  17. pandas多列合并成一列
  18. CS很难发论文?这些技巧你都get了吗?
  19. HDU 4883 TIANKENG’s restaurant (贪心)
  20. 原生JavaScript实现 城市二级三级联动

热门文章

  1. 西安建筑科技大学安德学院计算机专业,【图片】【安德学院】身在建大,志在四方【西安建筑科技大学吧】_百度贴吧...
  2. Java 算法 最大体积
  3. matplotlib绘制平滑曲线
  4. Vmware fusion强制断电,关闭虚拟机
  5. mysql在线增加字段_MySQL在线加字段实现原理
  6. vuejs简单介绍特点
  7. Ubuntu 服务器设置软件多用户访问
  8. 软件需求和问题解决-转载
  9. undefined reference to libiconv_open'
  10. asp.net中验证控件的使用方法