如何做繁体字网站,珠海网站设计多少钱,wordpress国内优化,北京手机网站建设公司哪家好目录
一、 IIC基础知识
二、Linux中的IIC#xff08;韦东山老师的学习笔记#xff09;
1. I2C驱动程序的层次
2. I2C总线-设备-驱动模型
2.1 i2c_driver
2.2 i2c_client
三、 AT24C02 介绍
四、 AT24C02驱动开发
实验
驱动程序
应用程序 一、 IIC基础知识
总线类…目录
一、 IIC基础知识
二、Linux中的IIC韦东山老师的学习笔记
1. I2C驱动程序的层次
2. I2C总线-设备-驱动模型
2.1 i2c_driver
2.2 i2c_client
三、 AT24C02 介绍
四、 AT24C02驱动开发
实验
驱动程序
应用程序 一、 IIC基础知识
总线类设备驱动——IIC_iic设备驱动-CSDN博客
Exynos_4412——IIC总线概述_.若使用iic总线让从机给主机发送一个字节的数据0xa2,画出scl和sda上的时序图-CSDN博客
STM32——IIC总线MPU6050应用_mpu6050例程-CSDN博客
写过好多次啦不打算重复写了。
二、Linux中的IIC韦东山老师的学习笔记
参考资料 Linux内核文档: Documentation\i2c\instantiating-devices.rst Documentation\i2c\writing-clients.rst Linux内核驱动程序示例: drivers/eeprom/at24.c 1. I2C驱动程序的层次 I2C Core就是I2C核心层它的作用 提供统一的访问函数比如i2c_transfer、i2c_smbus_xfer等 实现I2C总线-设备-驱动模型管理I2C设备(i2c_client)、I2C设备驱动(i2c_driver)、I2C控制器(i2c_adapter)
2. I2C总线-设备-驱动模型 2.1 i2c_driver
i2c_driver表明能支持哪些设备 使用of_match_table来判断 设备树中某个I2C控制器节点下可以创建I2C设备的节点 如果I2C设备节点的compatible属性跟of_match_table的某项兼容则匹配成功 i2c_client.name跟某个of_match_table[i].compatible值相同则匹配成功 使用id_table来判断 i2c_client.name跟某个id_table[i].name值相同则匹配成功
i2c_driver跟i2c_client匹配成功后就调用i2c_driver.probe函数。 2.2 i2c_client
i2c_client表示一个I2C设备创建i2c_client的方法有4种
方法1 通过I2C bus number来创建 int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned len); 通过设备树来创建 i2c1: i2c400a0000 {/* ... master properties skipped ... */clock-frequency 100000;flash50 {compatible atmel,24c256;reg 0x50;};pca9532: gpio60 {compatible nxp,pca9532;gpio-controller;#gpio-cells 2;reg 0x60;};};
方法2 有时候无法知道该设备挂载哪个I2C bus下无法知道它对应的I2C bus number。 但是可以通过其他方法知道对应的i2c_adapter结构体。 可以使用下面两个函数来创建i2c_client i2c_new_device static struct i2c_board_info sfe4001_hwmon_info {I2C_BOARD_INFO(max6647, 0x4e),};int sfe4001_init(struct efx_nic *efx){(...)efx-board_info.hwmon_client i2c_new_device(efx-i2c_adap, sfe4001_hwmon_info);(...)}
i2c_new_probed_device static const unsigned short normal_i2c[] { 0x2c, 0x2d, I2C_CLIENT_END };static int usb_hcd_nxp_probe(struct platform_device *pdev){(...)struct i2c_adapter *i2c_adap;struct i2c_board_info i2c_info;(...)i2c_adap i2c_get_adapter(2);memset(i2c_info, 0, sizeof(struct i2c_board_info));strscpy(i2c_info.type, isp1301_nxp, sizeof(i2c_info.type));isp1301_i2c_client i2c_new_probed_device(i2c_adap, i2c_info,normal_i2c, NULL);i2c_put_adapter(i2c_adap);(...)}
差别 i2c_new_device会创建i2c_client即使该设备并不存在 i2c_new_probed_device 它成功的话会创建i2c_client并且表示这个设备肯定存在 I2C设备的地址可能发生变化比如AT24C02的引脚A2A1A0电平不一样时设备地址就不一样 可以罗列出可能的地址 i2c_new_probed_device使用这些地址判断设备是否存在 方法3(不推荐)由i2c_driver.detect函数来判断是否有对应的I2C设备并生成i2c_client 方法4通过用户空间(user-space)生成 调试时、或者不方便通过代码明确地生成i2c_client时可以通过用户空间来生成。 // 创建一个i2c_client, .name eeprom, .addr0x50, .adapter是i2c-3# echo eeprom 0x50 /sys/bus/i2c/devices/i2c-3/new_device// 删除一个i2c_client# echo 0x50 /sys/bus/i2c/devices/i2c-3/delete_device
三、 AT24C02 介绍 AT24C02 是基于 I2C 总线的存储器件由于接口方便体积小数据掉电不丢失等特点在仪器仪表及工业自动化控制中得到大量的应用。百问网提供的 EEPROM 模块使用的就是 AT24C02使用 8 位地址存储容量为 2K bit即 2048bit 256*8bit 256 Byte, 其中它被分为 32 页每页 8Byte。 基于 I2C 接口的设备操作我们主要关心的是 I2C 数据格式。 AT24C02 作为 EEPROM 存储设备显然我们关心的是怎么读写某个地址即怎么发地址、怎么读写数据。 查阅《AT24CXX.pdf》手册要写入一个字节可如下操作先发出设备地址 再发出 WORD 地址(即存储地址)再发出数据。 反之要读 AT24C02如下图涉及 2 次 I2C 传输。 先发出设备地址 WORD地址再次发出设备地址读到数据。 四、 AT24C02驱动开发
实验 先添加设备树 这是我们的设备树目录 可以用find找到我们刚添加的设备目录 咱们用的这个小工具有个配置项可以设置一下很方便 reg这个可能是特殊的加密文件需要用hexdump去看 虽然我们是iic-1但是内核是从0开始的所以这个就是我们的设备目录 插入模块后我们的驱动就出来了没写的时候读出来是一堆乱码 验证一下它的非易失性 没毛病
驱动程序
#include asm/uaccess.h
#include linux/delay.h
#include linux/i2c.h
#include linux/module.h
#include linux/poll.h#include linux/fs.h
#include linux/errno.h
#include linux/miscdevice.h
#include linux/kernel.h
#include linux/major.h
#include linux/mutex.h
#include linux/proc_fs.h
#include linux/seq_file.h
#include linux/stat.h
#include linux/init.h
#include linux/device.h
#include linux/tty.h
#include linux/kmod.h
#include linux/gfp.h
#include linux/gpio/consumer.h
#include linux/platform_device.h
#include linux/of_gpio.h
#include linux/of_irq.h
#include linux/interrupt.h
#include linux/irq.h
#include linux/slab.h
#include linux/fcntl.h
#include linux/timer.h/* 主设备号 */
static int major 0;
static struct class *my_i2c_class;static struct i2c_client *g_client;static DECLARE_WAIT_QUEUE_HEAD(gpio_wait);
struct fasync_struct *i2c_fasync;/* 实现对应的open/read/write等函数填入file_operations结构体 */
static ssize_t i2c_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{int err;unsigned char *kern_buf;struct i2c_msg msgs[2];/* 从0读取size字节 */kern_buf kmalloc(size, GFP_KERNEL);/* 初始化i2c_msg * 1. 发起一次写操作: 把0发给AT24C02, 表示要从0地址读数据* 2. 发起一次读操作: 得到数据*/msgs[0].addr g_client-addr;msgs[0].flags 0; /* 写操作 */msgs[0].buf kern_buf;kern_buf[0] 0; /* 把数据0发给设备 */msgs[0].len 1;msgs[1].addr g_client-addr;msgs[1].flags I2C_M_RD; /* 写操作 */msgs[1].buf kern_buf;msgs[1].len size;err i2c_transfer(g_client-adapter, msgs, 2);/* copy_to_user */err copy_to_user(buf, kern_buf, size);kfree(kern_buf);return size;
}static ssize_t i2c_drv_write(struct file *file, const char __user *buf, size_t size, loff_t *offset)
{int err;unsigned char kern_buf[9];struct i2c_msg msgs[1];int len;unsigned char addr 0;/* 把size字节的数据写入地址0 *///kern_buf kmalloc(size1, GFP_KERNEL);while (size 0){if (size 8)len 8;elselen size;size - len;/* copy_from_user */err copy_from_user(kern_buf1, buf, len);buf len;/* 初始化i2c_msg * 1. 发起一次写操作: 把0发给AT24C02, 表示要从0地址读数据* 2. 发起一次读操作: 得到数据*/msgs[0].addr g_client-addr;msgs[0].flags 0; /* 写操作 */msgs[0].buf kern_buf;kern_buf[0] addr; /* 写AT24C02的地址 */msgs[0].len len1;addr len;err i2c_transfer(g_client-adapter, msgs, 1);mdelay(20);}//kfree(kern_buf);return size;
}static unsigned int i2c_drv_poll(struct file *fp, poll_table * wait)
{//printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);poll_wait(fp, gpio_wait, wait);//return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;return 0;
}static int i2c_drv_fasync(int fd, struct file *file, int on)
{if (fasync_helper(fd, file, on, i2c_fasync) 0)return 0;elsereturn -EIO;
}/* 定义自己的file_operations结构体 */
static struct file_operations i2c_drv_fops {.owner THIS_MODULE,.read i2c_drv_read,.write i2c_drv_write,.poll i2c_drv_poll,.fasync i2c_drv_fasync,
};static int i2c_drv_probe(struct i2c_client *client,const struct i2c_device_id *id)
{// struct device_node *np client-dev.of_node;// struct i2c_adapter *adapter client-adapter;/* 记录client */g_client client;/* 注册字符设备 *//* 注册file_operations */major register_chrdev(0, 100ask_i2c, i2c_drv_fops); /* /dev/gpio_desc */my_i2c_class class_create(THIS_MODULE, 100ask_i2c_class);if (IS_ERR(my_i2c_class)) {printk(%s %s line %d\n, __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, 100ask_i2c);return PTR_ERR(my_i2c_class);}device_create(my_i2c_class, NULL, MKDEV(major, 0), NULL, myi2c); /* /dev/myi2c */return 0;
}static int i2c_drv_remove(struct i2c_client *client)
{/* 反注册字符设备 */device_destroy(my_i2c_class, MKDEV(major, 0));class_destroy(my_i2c_class);unregister_chrdev(major, 100ask_i2c);return 0;
}static const struct of_device_id myi2c_dt_match[] {{ .compatible 100ask,i2cdev },{},
};static const struct i2c_device_id at24c02_ids[] {{ xxxxyyy, (kernel_ulong_t)NULL },{ /* END OF LIST */ }
};
static struct i2c_driver my_i2c_driver {.driver {.name 100ask_i2c_drv,.owner THIS_MODULE,.of_match_table myi2c_dt_match,},.probe i2c_drv_probe,.remove i2c_drv_remove,.id_table at24c02_ids,
};static int __init i2c_drv_init(void)
{/* 注册i2c_driver */return i2c_add_driver(my_i2c_driver);
}static void __exit i2c_drv_exit(void)
{/* 反注册i2c_driver */i2c_del_driver(my_i2c_driver);
}/* 7. 其他完善提供设备信息自动创建设备节点 */module_init(i2c_drv_init);
module_exit(i2c_drv_exit);MODULE_LICENSE(GPL);
应用程序 #include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h
#include stdio.h
#include string.h
#include poll.h
#include signal.hstatic int fd;/** ./i2c_test /dev/myi2c string * ./i2c_test /dev/myi2c**/
int main(int argc, char **argv)
{int ret;char buf[100];/* 1. 判断参数 */if (argc 2) {printf(Usage:\n, argv[0]);printf( %s dev, read at24c02\n, argv[0]);printf( %s dev string, write at24c02\n, argv[0]);return -1;}/* 2. 打开文件 */fd open(argv[1], O_RDWR | O_NONBLOCK);if (fd -1){printf(can not open file %s\n, argv[1]);return -1;}if (argc 3){ret write(fd, argv[2], strlen(argv[2]) 1);}else{ret read(fd, buf, 100);printf(read: %s\n, buf);}close(fd);return 0;
}