首页 > 其他分享 >用OLED屏幕播放视频(2): 为OLED屏幕开发I2C驱动

用OLED屏幕播放视频(2): 为OLED屏幕开发I2C驱动

时间:2023-09-10 12:00:34浏览次数:47  
标签:i2c driver ssd130x OLED 屏幕 I2C 设备

下面的系列文章记录了如何使用一块linux开发扳和一块OLED屏幕实现视频的播放:

  1. 项目介绍
  2. 为OLED屏幕开发I2C驱动
  3. 使用cuda编程加速视频处理

这是此系列文章的第2篇, 主要总结和记录一个I2C从设备的驱动, 在linux内核中如何实现, 如何给用户态的程序暴露合适的接口, 让用户态有机会操作真实的硬件设备. 可以通过下面的视频快速了解最终达到的效果和实现的总体思路.

跳转到6:48, 直接观看演示

<iframe allowfullscreen="true" border="0" frameborder="no" framespacing="0" height="600" scrolling="no" src="//player.bilibili.com/player.html?aid=788149070&bvid=BV1d14y1k7YR&cid=1260923220&p=1" width="100%"> </iframe>

1). I2C驱动架构

I2C总线是一种主从, 同步, 半双工的低速通信总线, 硬件标准可以参考这里. 这篇文章只讨论I2C总线上从设备的驱动在linux平台下如何实现, 下图是linux中I2C总线相关的软件模块, 其中i2c core提供给驱动开发人员重要的数据结构和接口函数:

image

  • i2c_adapter: 表示总线上的主设备, 或者说总线控制器
  • i2c_algorithm: 当主设备想要通信时, 它负责具体硬件时序的实现, 比如, 在总线上产生开始/结束条件, 发送/接收数据
  • i2c_client: 表示总线上的从设备
  • i2c_driver: 表示从设备对应的驱动, 需要实现其中的接口函数之后, 把驱动注册到i2c core之中
  • i2c_add_driver: 注册i2c_driver到i2c core, 一般在模块初始化函数中调用
  • i2c_del_driver: 删除i2c_driver, 一般在模块退出函数中调用
  • i2c_master_send/recv: 主设备发送/接收数据, 实际上为了驱动从设备, 需要让主设备向从设备发送合适的命令, 或者读取从设备的状态, 具体发送或者接收什么, 参考从设备的datasheet即可

2). 实现ssd1306屏幕的I2C驱动

  1. 注册i2c_driver
    使用module_i2c_driver宏, 并传递我们实现的i2c_driver, 该宏能够为我们生成模块的init和exit函数, 在函数中自动注册和删除传递进来的i2c_driver. 如果需要在init和exit中做一些其他工作, 则需要自己实现, 不能使用这个宏.
module_i2c_driver(ssd130x_driver);
  1. 实现i2c_driver中的接口
static struct i2c_driver ssd130x_driver = {
    .driver = {
        .owner = THIS_MODULE,
        .name = "ssd130x_driver",
    },
    .probe = ssd130x_probe,
    .remove = ssd130x_remove,
    .id_table = ssd130x_id_table,
};

这里只实现了i2c_driver中的probe和remove. 当驱动和设备匹配成功时, probe函数被调用, 在probe函数中, 完成了字符设备的相关的操作, 包括:

  • 分配设备号
  • 初始化字符设备结构体
  • 添加字符设备到内核
  • 创建设备文件
  1. 实现字符设备接口, 暴露给用户态程序
static struct file_operations ssd130x_fops = {
	.owner = THIS_MODULE,
	.open = ssd130x_open,
	.release = ssd130x_close,
	.write = ssd130x_write,
};

用户态程序可以对设备文件进行打开, 关闭, 写入3种操作. 当打开设备文件时, ssd130x_open被调用, 完成OLED屏幕的初始化; 关闭设备文件时, ssd130x_close被调用, 屏幕被关闭; 当向设备文件写入数据时, ssd130x_write被调用, 一帧数据被发送到ssd1306的RAM上, 屏幕显示的内容被更新. 以上3种操作, 底层都是通过i2c_master_send向从设备发送特定的命令或者数据实现的.

2.1). 阅读数据手册

ssd1306的数据手册参考这里, 手册内容较多, 不宜通读, 主要关注以下几点:

  • 基本硬件参数: 屏幕分辨率, 支持的通信接口, 支持哪些显示相关的功能(比如滚动, 反转等) ...
  • 基本工作原理: 通过向RAM中写入数据, 控制屏幕像素点的亮灭
  • 基本使用方法: 支持哪些命令? 分别能控制它的什么功能?
  • Application Note: 典型硬件电路, 示例代码

2.2). 设备的初始化

在数据手册的Application Note中包含使用ssd1306时的初始化流程, 如下图所示. 在此基础上, 可以做一些调整, 比如我在驱动中关闭了屏幕滚动.

image

2.3). 调整I2C的频率

我在beaglebone black板子上刷入的debian系统, 其设备树中的i2c时钟频率是100kbits/s, 内核中的i2c_algorithm会根据这个频率计算在i2c总线上发送数据时使用的延时. 实际测试之后发现按照这个频率播放视频存在一些卡顿, 因此需要对i2c时钟频率做修改, 有两种方式:

  • 在uboot启动时, 进入uboot的shell, 使用fdt相关的命令修改始终频率
  • 备份原来的设备树文件, 使用dtc编译器从dtb得到dts, 在dts中修改始终频率, 再编译得到新的dtb, 替换原来的设备树文件

我这里采用的是dtc的方式, 这样就不需要每次系统启动都手动修改了, 修改之后的时钟频率为400kbits/s, 播放视频流畅很多.

3). 测试驱动功能

驱动代码编写完成之后, 需要实际测试一下功能, 下面代码首先打开OLED屏幕的设备文件, 写入一帧数据, 每个字节都填充为0x88, 这样屏幕上会显示出预期的条纹, sleep两秒之后, 关闭设备文件, 屏幕熄灭.

#define FRAME_SIZE (128 * 8)

int main(int argc, char **argv)
{
	int device_fd = open("/dev/ssd130x0", O_WRONLY);
	if (device_fd < 0) {
		return -1;
	}

	char *frame = malloc(FRAME_SIZE);
	memset(frame, 0x88, FRAME_SIZE);
	write(device_fd, frame, FRAME_SIZE);
	sleep(2);

	free(frame);
	close(device_fd);
	return 0;
}

4). 文末推广

欢迎关注我的B站账号, 或者加入QQ群838923389, 一起研究计算机底层技术, 一起搞事情:P

其实还有很多实现的细节没有在博客中写出来, 只有自己在做的时候遇到了才能够体会的到, 需要完整代码的老铁直接在qq群中问一下.

标签:i2c,driver,ssd130x,OLED,屏幕,I2C,设备
From: https://www.cnblogs.com/kfggww/p/17672942.html

相关文章

  • C#获取屏幕大小的“简单整理”。
    Console.WriteLine("主显示器完整尺寸:");Console.WriteLine("宽:"+Screen.PrimaryScreen.Bounds.Width);Console.WriteLine("高:"+Screen.PrimaryScreen.Bounds.Height);Console.WriteLine("主显示器工作尺寸(排除任务栏、工具栏):");Console.WriteLine(......
  • 用OLED屏幕播放视频(3): 使用cuda编程加速视频处理
    下面的系列文章记录了如何使用一块linux开发扳和一块OLED屏幕实现视频的播放:项目介绍为OLED屏幕开发I2C驱动使用cuda编程加速视频处理这是此系列文章的第3篇,主要总结和记录了如何使用cuda编程释放GPU的算力.在此之前尝试过使用python调用opencv直接处理视频数据,但使用......
  • Android全面屏下,默认不会全屏显示,屏幕底部会留黑问题
    公司以前的老项目,便出现了这种情况,网上搜索了各种资料,用了各种库,依然无法解决这个问题。如图所示:最终功夫不负有心人,在Application中看到了,这样一个属性android:resizeableActivity=“false”这个属性设置为了false,我们新建的项目,是没有这个属性的,然后我把这个属性设置为了true......
  • Linux驱动-I2C子系统基本分析
    第一:Linux中I2C驱动框架分析I2C核心(i2c_core)I2C核心维护了i2c_bus结构体,提供了I2C总线驱动和设备驱动的注册、注销方法,维护了I2C总线的驱动、设备链表,实现了设备、驱动的匹配探测。此部分代码由Linux内核提供。I2C总线驱动I2C总线驱动维护了I2C适配器数据结构(i2c_adapter)和适配器的......
  • 【ROS2机器人入门到实战】I2C通信实验-点亮OLED
    6.I2C通信实验-点亮OLED写在前面当前平台文章汇总地址:ROS2机器人从入门到实战获取完整教程及配套资料代码,请关注公众号<鱼香ROS>获取教程配套机器人开发平台:两驱版|四驱版为方便交流,搭建了机器人技术问答社区:地址fishros.org.cn你好,我是爱吃鱼香ROS的小鱼。本节我们就尝试直接使......
  • 【ROS2机器人入门到实战】控制OLED-自定义消息接口
    1.控制OLED-自定义消息接口写在前面当前平台文章汇总地址:ROS2机器人从入门到实战获取完整教程及配套资料代码,请关注公众号<鱼香ROS>获取教程配套机器人开发平台:两驱版|四驱版为方便交流,搭建了机器人技术问答社区:地址fishros.org.cn你好,我是爱吃鱼香ROS的小鱼。前面章节中我们使用......
  • IU5200集成30V的OVP功能,支持I2C接口,3A充电电流,1~4节锂电池升降压充电芯片
    IU5200D是一款自动申请快充输入,开关模式升降压充电管理IC,用于1~4节锂离子电池和锂聚合物电池,以及1~5节磷酸铁锂电池。芯片集成包括4开关MOSFET、输入和充电电流感应电路、电池以及升降压转换器的环路补偿。芯片具有3A的充电电流能力,充电电流可以通过外部电阻灵活可调。IU5200D内置......
  • I2C 接 MPU6050
    MPU6050量化范围-32768~32767  量程3轴加速度计 测量加速度±2/4/8/16(G)3轴陀螺仪传感器 测量角速度±250/500/1000/2000(°/SEC)从机地址AD0=0:1101000AD0=1:1101001MPU6050初始化&获取加速度角速度数据#include"main.h"#include"MPU6050.h"#i......
  • SPI接OLED
    7脚OLED显示屏接线GND电源地 VCC电源正 D0SPISCKPB10D1SPIMOSIPC3RESGPIOPA6DCGPIOPA7CSGPIOPC4RESDCCS的GPIO初始化查看代码#defineOLED_RST_PinGPIO_PIN_6#defineOLED_RST_GPIO_PortGPIOA#defineOLED_DC_PinGPIO_......
  • 协议I2C
    SCL  SDA  同步,半双工 开漏+弱上拉,谁用这跟线,就下拉成低电平想输出,去拉杆子或放手,操作杆子变化想输入,直接放手,看电平高低就行线与,一个低电平,全部低电平,可以利用这个执行多主机下的时钟同步和总线仲裁 时序 主机发出起始信号(SCL高,SDA下拉),从机捕获这个状态时,就复......