【RV1126】IIC驱动--EEPROM

news2025/2/24 6:26:21

文章目录

  • 原理图查找空闲的I2C
  • EEPROM芯片
  • 改设备树
  • 编写驱动
    • 驱动端
    • 设备端
    • 驱动端和设备端编译成驱动模块
    • 应用层的测试代码

原理图查找空闲的I2C

在这里插入图片描述在这里插入图片描述

由上面可以知道,空闲了I2C4接口,然后也引出来了。
在这里插入图片描述

再找原理图找到具体引脚:

  • I2C4_SCL:GPIO3_A0
  • I2C4_SDA:GPIO3_A1

在这里插入图片描述

EEPROM芯片

我手上这款:

  • 第一行丝印:ATMLH825
  • 第二行丝印:2ECL Y

在这里插入图片描述
由上表可知是256KB的EEPROM。

该EEPROM的IIC地址是0x50

改设备树

kernel/arch/arm/boot/dts/rongpin/rv1126_1109_common.dtsi

&i2c4 {
	status = "okay";
	eeprom@50 {
		status = "okay";
		compatible = "atmel,at24c256B";
		reg = <0x50>;
	};
};

看看顶层设备树kernel/arch/arm/boot/dts/rv1126.dtsi关于I2C4的描述,这里不用改,贴出来看看:

	i2c4: i2c@ff530000 {
		compatible = "rockchip,rv1126-i2c", "rockchip,rk3399-i2c";
		reg = <0xff530000 0x1000>;
		interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
		#address-cells = <1>;
		#size-cells = <0>;
		clocks = <&cru CLK_I2C4>, <&cru PCLK_I2C4>;
		clock-names = "i2c", "pclk";
		pinctrl-names = "default";
		pinctrl-0 = <&i2c4m0_xfer>;
		status = "disabled";
	};

在这里插入图片描述

把EEPROM模块接上板子后,使用I2Cdetect测试工具进行测试:

[root@RV1126_RV1109:/mnt/nfs]# i2cdetect -y 4
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: 50 -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --

在地址0x50有响应。

编写驱动

下面使用IIC子系统框架编写EEPROM驱动。驱动端使用杂项设备字符驱动框架。

驱动端

iic_drv.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>

static struct i2c_client *eeprom_client;
 
#define MAX_SIZE 255  //EEPROM大小
#define EEPROM_PAGE  16 //页字节大小
 
static u8 eeprom_buff[255];
static int rv1126_open(struct inode *inode, struct file *file)
{
	printk("rv1126_open-->ok\n");
	return 0;
}
 
static ssize_t rv1126_read(struct file *file, char __user *buf, size_t size, loff_t *seek)
{	
	unsigned long err;
	//判断位置是否超出范围
	if(*seek+size>MAX_SIZE)
	{
		size=MAX_SIZE-*seek;
	}
	//读取数据
	i2c_smbus_read_i2c_block_data(eeprom_client,*seek,size,eeprom_buff);
	err=copy_to_user(buf,eeprom_buff,size);
	if(err!=0)return -1;
	*seek+=size;
	return size;
}
 
static ssize_t rv1126_write(struct file *file, const char __user *buf, size_t size, loff_t *seek)
{
	size_t write_ok_cnt=0;
	unsigned long err;
	int write_byte=0;
	u8 *write_p=eeprom_buff;
	err=copy_from_user(eeprom_buff,buf,size);
	if(err!=0)return -1;
	//判断位置是否超出范围
	if(*seek+size>MAX_SIZE)
	{
		size=MAX_SIZE-*seek;
	}
	
	while(1)
	{
		if(size>EEPROM_PAGE)
		{
			write_byte=EEPROM_PAGE;
			size-=EEPROM_PAGE;
		}
		else
		{
			write_byte=size;
		}
		
		//写数据
		i2c_smbus_write_i2c_block_data(eeprom_client,*seek,write_byte,write_p);
		*seek+=write_byte;
		write_p+=write_byte;
		write_ok_cnt+=write_byte;  //记录写成功的字节数
		//等待写完成
		msleep(10);
		if(write_byte==size)break; //写完毕
	}
	return write_ok_cnt;
}
 
/*
filp:待操作的设备文件file结构体指针
off:待操作的定位偏移值(可正可负)
whence:待操作的定位起始位置
返回:返回移位后的新文件读、写位置,并且新位置总为正值
定位起始位置
  SEEK_SET:0,表示文件开头
  SEEK_CUR:1,表示当前位置
  SEEK_END:2,表示文件尾
*/
static loff_t rv1126_llseek(struct file *filp, loff_t offset, int whence)
{
	loff_t newpos = 0;
	switch(whence)
	{
		case SEEK_SET:
			newpos = offset;
			break;
		case SEEK_CUR:
			newpos = filp->f_pos + offset;
			break;
		case SEEK_END:
			if(MAX_SIZE+offset>=MAX_SIZE)
			{
				newpos=MAX_SIZE;
			}
			else
			{
				newpos = MAX_SIZE + offset;
			}
			break;
		default:
			return -EINVAL;//无效的参数
	}
	filp->f_pos = newpos;
	return newpos;
}
 
static int rv1126_release(struct inode *inode, struct file *file)
{
	printk("rv1126_release-->ok\n");
	return 0;
}
 
static struct file_operations fops=
{
	.open=rv1126_open,
	.read=rv1126_read,
	.write=rv1126_write,
	.release=rv1126_release,
	.llseek=rv1126_llseek
};
 
/*
Linux内核管理驱动---设备号
设备号是一个unsigned int 的变量--32位。
设备号=主设备号+次设备号
*/
static struct miscdevice misc=
{
	.minor = MISC_DYNAMIC_MINOR,  /*次设备号填255表示自动分配     主设备号固定为10*/
	.name = "rv1126_eeprom",  /*/dev目录下文件名称*/
	.fops = &fops, /*文件操作接口*/
};
 
 
static int rv1126_probe(struct i2c_client *client, const struct i2c_device_id *device_id)
{
	printk("probe调用成功:%#X\n",client->addr);
	eeprom_client=client;
	
	/*1. 杂项设备的注册函数*/
	misc_register(&misc);
	
	return 0;
}
 
static int rv1126_remove(struct i2c_client *client)
{
	/*2. 杂项设备的注销函数*/
	misc_deregister(&misc);
	printk("remove调用成功.\n");
	return 0;
}
 
static struct i2c_device_id id_table[]=
{
	{"eeprom", 0},
	{}
};
MODULE_DEVICE_TABLE(i2c, id_table);

static const struct of_device_id eeprom_of_match[] = {
	{ .compatible = "atmel,at24c256B" },
	{ }
};
MODULE_DEVICE_TABLE(of, eeprom_of_match);

 
static struct i2c_driver drv=
{
	.probe=rv1126_probe,
	.remove=rv1126_remove,
	.driver=
	{
		.name="at24c256B",
		.of_match_table = of_match_ptr(eeprom_of_match),
	},
	.id_table=id_table
};
 
static int __init rv1126_drv_init(void)
{	
	/*注册IIC驱动端*/
	i2c_add_driver(&drv);
    printk("IIC驱动端: 驱动安装成功\n");
    return 0;
}
 
static void __exit rv1126_drv_cleanup(void)
{
	/*注销IIC驱动端*/
	i2c_del_driver(&drv);
    printk("IIC驱动端: 驱动卸载成功\n");
}
 
module_init(rv1126_drv_init);    /*驱动入口--安装驱动的时候执行*/
module_exit(rv1126_drv_cleanup); /*驱动出口--卸载驱动的时候执行*/
 
MODULE_LICENSE("GPL");  /*设置模块的许可证--GPL*/

设备端

iic_dev.c

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
 
static struct i2c_client *i2c_dev=NULL;
static struct i2c_adapter *adap=NULL;
static struct i2c_board_info info=
{
	.type="rv1126_eeprom",
	.addr=0x50, /*设备地址*/
};
 
static int __init rv1126_drv_init(void)
{	
	/*根据总线编号获取是适配器*/
	adap=i2c_get_adapter(0);
	/*注册IIC设备端*/
	i2c_dev=i2c_new_device(adap,&info);
    printk("IIC设备端: 驱动安装成功\n");
    return 0;
}
 
static void __exit rv1126_drv_cleanup(void)
{
	/*注销IIC设备*/
	i2c_unregister_device(i2c_dev);
	i2c_put_adapter(adap);
    printk("IIC设备端: 驱动卸载成功\n");
}
 
module_init(rv1126_drv_init);    /*驱动入口--安装驱动的时候执行*/
module_exit(rv1126_drv_cleanup); /*驱动出口--卸载驱动的时候执行*/
 
MODULE_LICENSE("GPL");  /*设置模块的许可证--GPL*/

驱动端和设备端编译成驱动模块

Makefile

KER_DRI:=/home/liefyuan/rv1126/rp_rv1126_sdk/kernel/

# 定义当前目录
PWD:=$(shell pwd)

all:
	make -C $(KER_DRI) M=$(PWD) modules

obj-m += iic_dev.o
obj-m += iic_drv.o

clean:
	rm -rf *.order *o *.symvers *.mod.c *.mod *.ko

会得到:

  • iic_drv.ko
  • iic_dev.ko

应用层的测试代码

app.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
 
#define EEPROM_DEV "/dev/rv1126_eeprom"
 
int main(int argc,char **argv)
{
    /*1. 打开设备文件*/
    int fd=open(EEPROM_DEV,O_RDWR);
    if(fd<0)
    {
        printf("%s 设备驱动打开失败.\n",EEPROM_DEV);
        return 0;
	}
    /*3.读写数据*/
	unsigned char buff[255];
	int cnt;
	int i;
	for(i=0;i<255;i++)buff[i]=i;
	cnt=write(fd,buff,255);
    printf("write成功:%d Byte\n",cnt);
	
	//偏移文件指针
	lseek(fd,SEEK_SET,0);
	
	unsigned char buff_r[255];
	cnt=read(fd,buff_r,255);
	printf("read成功:%d Byte\n",cnt);
	for(i=0;i<cnt;i++)
	{
		printf("%d ",buff_r[i]);
	}
	printf("\n");
    return 0;
}

编译:

arm-linux-gnueabihf-gcc app.c

测试记录:

[root@RV1126_RV1109:/mnt/nfs]# insmod iic_dev.ko
[ 6401.060250] IIC设备端: 驱动安装成功
[root@RV1126_RV1109:/mnt/nfs]# insmod iic_drv.ko
[ 6407.774268] probe调用成功:0X50
[root@RV1126_RV1109:/mnt/nfs]# [ 6407.776211] IIC驱动端: 驱动安装成功

[root@RV1126_RV1109:/mnt/nfs]# ls /dev/
block            media0              rfkill         v4l-subdev11    video26
bus              media1              rga            v4l-subdev2     video27
char             media2              rtc            v4l-subdev3     video28
console          media3              rtc0           v4l-subdev4     video29
cpu_dma_latency  media4              rv1126_eeprom  v4l-subdev5     video3
disk             mem                 serial         v4l-subdev6     video30
dri              memory_bandwidth    shm            v4l-subdev7     video31
fb0              mmcblk0             snd            v4l-subdev8     video32
fd               mmcblk0boot0        stderr         v4l-subdev9     video33
full             mmcblk0boot1        stdin          vendor_storage  video34
galcore          mmcblk0p1           stdout         video0          video35
gpiochip0        mmcblk0p2           tty            video1          video36
gpiochip1        mmcblk0p3           ttyFIQ0        video10         video37
gpiochip2        mmcblk0p4           ttyS0          video11         video38
gpiochip3        mmcblk0p5           ttyS4          video12         video39
gpiochip4        mmcblk0p6           ttyS5          video13         video4
gpiochip5        mmcblk0p7           ttyUSB0        video14         video40
hidraw0          mmcblk0p8           ttyUSB1        video15         video41
hidraw1          mmcblk0rpmb         ttyUSB2        video16         video42
hwrng            mpp_service         ttyUSB3        video17         video43
i2c-0            network_latency     ubi_ctrl       video18         video44
i2c-1            network_throughput  uhid           video19         video5
i2c-2            null                urandom        video2          video6
i2c-3            pmsg0               usb            video20         video7
i2c-4            ppp                 usb-ffs        video21         video8
iio:device0      ptmx                v4l            video22         video9
input            ptp0                v4l-subdev0    video23         zero
kmsg             pts                 v4l-subdev1    video24         zram0
log              random              v4l-subdev10   video25
[root@RV1126_RV1109:/mnt/nfs]# ./a.out
[ 6453.425909] rv1126_open-->ok
write成功:255 Byte
read成功:255 Byte
255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 255 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
[ 6453.77834] rv1126_release-->ok

[root@RV1126_RV1109:/mnt/nfs]#

OK!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/659852.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第 5 章 机器学习技术的应用(下)

全文目录 机器学习技术的实施方法 预测阶段效果监控 离线预测在线预测 监控点击率的稳定性 真实点击率的稳定性 计算相邻两个区间内点击率分布的 PSI(Population Stability Index, 群体稳定性指标), 小于 0.1 可认为数据相对稳定;预测点击率的稳定性 与系统本身和用户发生变…

Dice Loss

导读 ​ Dice Loss是由 Dice 系数而得名的&#xff0c;Dice系数是一种用于评估两个样本相似性的度量函数&#xff0c;其值越大意味着这两个样本越相似&#xff0c;Dice系数的数学表达式如下&#xff1a; Dice 2 ∣ X ∩ Y ∣ ∣ X ∣ ∣ Y ∣ \text { Dice }\frac{2|X \ca…

Windows10完全卸载oracle19c

Windows10完全卸载oracle19c 1.停止服务2.卸载产品3.清理注册表4.清理环境变量5.清理文件夹 1.停止服务 winR输入service.msc进入服务列表&#xff0c;停止所有的服务 2.卸载产品 点击开始菜找到Oracle&#xff0c;然后点击Oracle安装产品&#xff0c;再点击Universal Inst…

如何安装PHP框架

目录 什么是PHP框架 第一步 安装PHP依赖包 第二步 导入PHP相关包 第三步 解包并切换进指定目录 第四步 在PHP目录内编译安装 第五步 编译 第六步 拷贝配置文件进行编辑 第七步 修改时区 第八步 修改文件指定路径 第九步 将命令加入指定目录进行识别 第十步 进入配置…

【Flutter】Audioplayers 4.1.0 简要使用说明

文章目录 一、前言二、安装和设置三、基本使用1.创建 AudioPlayer 实例2.设置音频源3.控制播放 四、示例代码五、总结 一、前言 Audioplayers 是一个非常实用的 Flutter 插件&#xff0c;它可以帮助我们在 Flutter 应用中播放音频。无论你是想在你的应用中添加背景音乐&#x…

【Python】在同一图形中更加优雅地绘制多个子图

1. 引言 数据可视化非常重要&#xff0c;有一句俗语叫做一图顶千言&#xff0c;我相信好多小伙伴应该都听说过这句话&#xff1b;即使是有人第一次听到&#xff0c;我想应该也会觉得赞成&#xff0c;这足以说明数据可视化的重要性。我们在前一篇博客中&#xff0c;介绍了如何利…

C语言基础 位域

C语言基础&#xff1a;位域 主题&#xff1a;位域&#xff08;bit-field&#xff09; 关键字&#xff1a;位域 冒号 结构体 存储空间 参考链接&#xff1a;C语言中文网&#xff1a;位域 、C菜鸟工具&#xff08;在线编译器&#xff09;、位域知乎问答 注&#xff1a;以下内容中…

VM安装linux虚拟机宿主机连接不上虚拟机问题处理及静态ip设置

VM安装linux虚拟机宿主机连接不上虚拟机问题处理 用 vm安装linux虚拟机宿主机连不上虚拟机&#xff0c;ipconfig宿主机发现VMnet1以及VMnet8的Ip都变成了169.254开头的地址&#xff0c;网上各种方式都试了都不行&#xff0c;要么 是 虚拟机连不上网&#xff0c;要么 是宿主机连…

金融测试岗面试有多难?我有秘招……

最近发现好多人都喜欢往金融测试岗跑&#xff0c;看来是真的很香了&#xff0c;但是你们知不知道面试金融测试岗还是很难的&#xff0c;如果想去面试真的要多做些了解再去&#xff0c;我在这里总结了一份面试文档分享给大家&#xff0c;若有需要&#xff0c;【留言777】即可。 …

windows 系统加固

其实Windows和Linux加固的方法都差不多 1.防火墙 1.防火墙的开启 2.入站规则进行设置 对一些端口更改后可以使用telnet 进行检测端口是否开放 2.安装杀毒软件 3.扫描漏洞&#xff0c;打补丁 一般漏洞扫描可以借用第三方平台对系统漏洞进行扫描。 开启补丁的自动更新 4.用…

【css系列】八股2023/6/18

1.说说设备像素、css像素、设备独立像素、dpr、ppi 之间的区别&#xff1f; css 像素&#xff1a;长度单位&#xff0c;在css规范中&#xff0c;长度单位分为两类&#xff1a;绝对单位 和 相对单位。 设备像素&#xff1a;物理像素&#xff0c;指设备能控制显示的最小物理单位…

计算机视觉的应用8-基于ResNet50对童年数码宝贝的识别与分类

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用8-基于ResNet50对童年数码宝贝的识别与分类&#xff0c;想必做完90后的大家都看过数码宝贝吧&#xff0c;里面有好多类型的数码宝贝&#xff0c;今天就给大家简单实现一下&#xff0c;他们的分类任…

计网大题(6/18)

1.奈奎斯特定理和香农公式 1.奈奎斯特 B1/T ,T是波特 &#xff0c;B成为波特率 奎氏定理&#xff1a;R2Wlog2&#xff08;N&#xff09; &#xff08;W是理想信道带宽&#xff0c;单位是hz&#xff09; 香农公式 R是最大信道容量 信道带宽是W 信噪比是S/N ,(S是平均信号功率…

kotlin学习(二)泛型、函数、lambda、扩展、运算符重载

文章目录 泛型&#xff1a;in、out、where型变&#xff08;variance&#xff09;不变&#xff08;Invariant&#xff09;协变&#xff08;Covariant&#xff09;Java上界通配符<? extends T>Kotlin的关键词 outUnsafeVariance 逆变&#xff08;Contravariant&#xff09…

Portraiture4.1智能磨皮滤镜插件下载安装使用教程

ps磨皮插件portraiture是一款用于修饰人像照片的插件&#xff0c;可以在Photoshop中使用。它可以通过智能算法来自动识别照片中的肤色区域&#xff0c;然后对其进行磨皮处理&#xff0c;使得肌肤更加光滑细腻。不需要像曲线磨皮、中性灰磨皮那样需要复杂的操作&#xff0c;轻轻…

JavaScript之函数 (七):认识JavaScript函数、函数的声明和调用、函数的递归调用、局部和全局变量、函数表达式的写法、立即执行函数使用

1. 认识JavaScript函数 1.1 程序中的foo、bar、baz 在国外的一个问答网站stackover flow中&#xff0c;常常会使用这几个次进行变量&#xff0c;函数&#xff0c;对象等等声明&#xff0c;地位如同张三&#xff0c;李四&#xff0c;王五。foo、bar这些名词最早从什么时候、地…

【MySQL入门】-- 认识MySQL存储引擎

目录 1.MySQL存储引擎有什么用&#xff1f; 2.MySQL的存储引擎有哪些&#xff1f;分别有什么特点&#xff1f; 3.存储引擎的优缺点 4.关于存储引擎的操作 5. 存储引擎的选择&#xff1f; 6.InnoDB和MyISAM区别&#xff1f; 7.官方文档 1.MySQL存储引擎有什么用&#xff…

2022 年第十二届 MathorCup 高校数学建模挑战赛D题思路

目录 一、前言 二、问题背景 三、问题 四、解题思路 &#xff08;1&#xff09;针对问题1&#xff1a; &#xff08;2&#xff09;针对问题2&#xff1a; &#xff08;3&#xff09;针对问题3&#xff1a; 五、附上几个典型代码 &#xff08;1&#xff09;K-means算法…

文献阅读:Foundation Transformers

文献阅读&#xff1a;Foundation Transformers 1. 文章简介2. 模型结构 1. Sub-LN2. Initialization 3. 实验效果 1. NLP任务 1. 语言模型上效果2. MLM模型上效果3. 翻译模型上效果 2. Vision任务上效果3. Speech任务上效果4. 图文任务上效果 4. 结论 & 思考 文献链接&…

卡尔曼滤波器使用原理以及代码编写

注&#xff1a;要视频学习可以去B站搜索“DR_CAN”讲解的卡尔曼滤波器&#xff0c;深有体会&#xff01; 一、为啥需要卡尔曼滤波器 卡尔曼滤波器在生活中应用广泛&#xff0c;因为在我们生活中存在着不确定性&#xff0c;当我去描述一个系统&#xff0c;这个不确定性就包涵一…