用OLED屏幕播放视频(2): 为OLED屏幕开发I2C驱动
下面的系列文章记录了如何使用一块linux开发扳和一块OLED屏幕实现视频的播放:
这是此系列文章的第2篇, 主要总结和记录一个I2C从设备的驱动, 在linux内核中如何实现, 如何给用户态的程序暴露合适的接口, 让用户态有机会操作真实的硬件设备. 可以通过下面的视频快速了解最终达到的效果和实现的总体思路.
跳转到6:48, 直接观看演示
1). I2C驱动架构
I2C总线是一种主从, 同步, 半双工的低速通信总线, 硬件标准可以参考这里. 这篇文章只讨论I2C总线上从设备的驱动在linux平台下如何实现, 下图是linux中I2C总线相关的软件模块, 其中i2c core提供给驱动开发人员重要的数据结构和接口函数:

- 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驱动
- 注册i2c_driver
使用module_i2c_driver宏, 并传递我们实现的i2c_driver, 该宏能够为我们生成模块的init和exit函数, 在函数中自动注册和删除传递进来的i2c_driver. 如果需要在init和exit中做一些其他工作, 则需要自己实现, 不能使用这个宏.
module_i2c_driver(ssd130x_driver);
- 实现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函数中, 完成了字符设备的相关的操作, 包括:
- 分配设备号
- 初始化字符设备结构体
- 添加字符设备到内核
- 创建设备文件
- 实现字符设备接口, 暴露给用户态程序
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时的初始化流程, 如下图所示. 在此基础上, 可以做一些调整, 比如我在驱动中关闭了屏幕滚动.

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群中问一下.
用OLED屏幕播放视频(2): 为OLED屏幕开发I2C驱动的更多相关文章
- android SurfaceView中播放视频 按视频的原始比例播放
OnPreparedListener mediaPlayerOnPreparedListener = new OnPreparedListener() { @Override public void ...
- Android三种播放视频的方式
在Android中,我们有三种方式来实现视频的播放: 1.使用其自带的播放器.指定Action为ACTION_VIEW,Data为Uri,Type为其MIME类型. 2.使用VideoView来播放. ...
- Android MediaPlayer和SurfaceView播放视频
昨天介绍了VideoView播放视频,今天再介绍一种播放视频的方法MediaPlayer和SurfaceView,MediaPlayer播放音频,SurfaceView来显示图像,具体步骤如下: 1. ...
- 3D立体显示大屏幕拼接视频墙系统解决方案【转】
http://shop.souvr.com/thread-123416-1-1.html 随着3D立体视像.全息影像等技术不断取得突破性进展,国内外越来越多的公司投身3D显示领域,产品层出不穷.3D技 ...
- Windows Phone 7 播放视频
在Windows Phone 7中播放视频有两种方式,一种是使用MediaElement 控件来播放,一种是使用启动器MediaPlayerLanucher来实现视频的播放.用MediaElement ...
- [转]Android WebView播放视频(包括全屏播放),androidwebview
Android WebView播放视频(包括全屏播放),androidwebview 最近项目开发中用到了WebView播放视频的功能,总结了开发中犯过的错误,这些错误在开发是及容易遇到的,所以我这里 ...
- 使用MediaPlayer和SurfaceView播放视频
使用VideoView播放视频简单.方便,丹有些早期的开发者更喜欢使用MediaPlayer来播放视频,但由于MediaPlayer主要用于播放音频,因此它没有提供图像输出界面,此时 需要借助于Sur ...
- 运用surfaceView与MediaPlayer实现播放视频的功能
该程序运用了surfaceView与MediaPlayer结合,实现播放视频,surfaceView详情请见 SurfaceView的使用 使用了第三方包Volly里面的方法StringQueue下载 ...
- android 98 MediaPlayer+SurfaceView播放视频
package com.itheima.videoplayer; import java.io.IOException; import android.media.MediaPlayer; impor ...
- Windows Phone 之播放视频
在Windows Phone 7中播放视频有两种方式, (1)使用MediaElement 控件来播放:用MediaElement 控件来播放视频比较灵活,你需要自己去实现播放暂停进度条等等的功能,播 ...
随机推荐
- 你以为搞个流水线每天跑,团队就在使用CI/CD实践了?
在实践中,很多团队对于DevOps 流水线没有很透彻的理解,要不就创建一大堆流水线,要不就一个流水线通吃.实际上,流水线的设计和写代码一样,需要基于"业务场景"进行一定的设计编排, ...
- 【python基础】类-初识类
1.面向对象思想 在认识类之前,我们需要理解面向对象思想和面向过程思想. 面向过程思想:要拥有一间房屋,面向过程像是自己来修盖房屋,如果需要经过选址.购买材料.砌墙.装修等步骤,面向过程编程,就相当于 ...
- SpringBoot 2 种方式快速实现分库分表,轻松拿捏!
大家好,我是小富- (一)好好的系统,为什么要分库分表? (二)分库分表的 21 条法则,hold 住! 本文是<分库分表ShardingSphere5.x原理与实战>系列的第三篇文章,本 ...
- Selenium:设置元素等待、上传文件、下载文件
前言:在工作和学习selenium自动化过程中记录学习知识点,深化知识点 1. 设置元素等待 元素定位之元素等待-- WebDriver提供了两种类型的等待:显示等待和隐式等待. 1.1 显示等待 显 ...
- MODBUS RTU转 EtherNet/IP 网关连接森兰变频器与欧姆龙系统通讯
捷米特JM-EIP-RTU(Modbus转Ethernet/Ip)网关,用于将多个 MODBUS 从站设备接入 ETHERNET/IP 主站网络,实现 MODBUS 转 ETHERNET/IP 功 ...
- 即构微信小程序直播组件是什么?有哪些功能?哪些小程序类目可以使用?
即构直播助手是微信官方认证的微信小程序插件,为开发者提供便捷.强大的微信小程序音视频直播服务. 即构直播助手除了包含微信小程序下的音视频推拉流能力,还支持iOS.Android.Windows.Web ...
- [TSG开发日志4]算法组件、个人编写的库文件如何封装成DLL,如何更好地对接软件开发?
写在前面 这个内容确实是我有点疏忽了,我以为做算法的同事应该多少对这方面会有点了解的.但是我想了一下我刚毕业的时候,确实对这方面的理解不深,查了很多资料才勉强搞懂什么意思,也是后来随着工程学习的愈加深 ...
- 三级缓存---解决 Spring 循环依赖
1. 循环依赖 1.1 什么是循环依赖 首先,什么是循环依赖?这个其实好理解,就是两个 Bean 互相依赖,类似下面这样: """ @Service public cla ...
- CMU15-445 Project4 Concurrency Control心得
一.概述 过瘾!过瘾!过瘾!P4 真过瘾!写 P3 的博客时我说过"感觉自己在数据库方面真正成长了",但写完 P4 之后最大的感受就是,我终于理解了 andy 在第一课说过的&qu ...
- jdbc-plus是一款基于JdbcTemplate增强工具包,基于JdbcTemplate已实现分页、多租户、动态表名等插件,可与mybatis、mybatis-plus等混合使用
jdbc-plus简介 jdbc-plus是一款基于JdbcTemplate增强工具包,基于JdbcTemplate已实现分页.多租户.动态表名等插件,可与mybatis.mybatis-plus等混 ...