gpio_i2c: gpio_i2c {
status = "okay";
compatible = "gpio_i2c";
gpio_sda = <&gpio2 RK_PA2 GPIO_ACTIVE_HIGH>;
gpio_scl = <&gpio2 RK_PA3 GPIO_ACTIVE_HIGH>;
};
分别用两个gpio模拟数据线与信号线
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DELAY_TIME_HXD 100 //设置i2c clk, hxd019大概要求10k左右
static int SDA; /*SDA的引脚号*/
static int SCL; /*SDL的引脚号*/
static int majorNumber;
static const char *CLASS_NAME = "i2c_class";
static const char *DEVICE_NAME = "i2c_device";
static struct cdev gpio_dev;
static dev_t ndev;
static int gpio_status;
static char recv_msg[2000];
static struct class *i2c_gpio_class;
static struct device *i2c_gpio_device;
struct i2c_gpio_info {
int i2c_gpio; /*gpio号*/
int gpio_value; /*电平*/
};
static int i2c_gpio_open(struct inode *node, struct file *file)
{
printk(KERN_INFO "GPIO init\n");
return 0;
}
static ssize_t i2c_gpio_read(struct file *file, char *buf, size_t len, loff_t *offset)
{
int cnt = 0;/*将内核空间的数据copy到用户空间*/
cnt = copy_to_user(buf, &gpio_status, 1);
if (cnt == 0) {
return 0;
} else {
printk(KERN_ALERT "ERROR occur when reading!!\n");
return -EFAULT;
}
return 1;
}
/* I2C起始条件 */
void i2c_start(void)
{
//初始化GPIO口
gpio_direction_output (SDA, 1); //设置SDA方向为输出,设置SDA为高电平
gpio_direction_output (SCL, 1); //设置SCL方向为输出,设置SCL为高电平
udelay(DELAY_TIME_HXD); //延时
//起始条件
gpio_set_value(SDA, 0); //SCL为高电平时,SDA由高变低
udelay(DELAY_TIME_HXD);
}
/* I2C终止条件 */
void i2c_stop(void)
{
gpio_set_value(SCL, 1);
gpio_direction_output (SDA, 0);
udelay(DELAY_TIME_HXD);
gpio_set_value(SDA, 1); //SCL高电平时,SDA由低变高
}
/*
I2C读取ACK信号(写数据时使用)
返回值 :0表示ACK信号有效;非0表示ACK信号无效
*/
unsigned char i2c_read_ack(void)
{
unsigned char r;
gpio_direction_input (SDA);//设置SDA方向为输入
gpio_set_value(SCL,0); // SCL变低
r = gpio_get_value(SDA); //读取ACK信号
udelay(DELAY_TIME_HXD);
gpio_set_value(SCL,1); // SCL变高
udelay(DELAY_TIME_HXD);
return r;
}
/* I2C发出ACK信号(读数据时使用) */
void i2c_send_ack(void)
{
gpio_set_value(SCL,0); // SCL变低
gpio_direction_output(SDA, 0); //设置SDA方向为输出,发出ACK信号
printk(KERN_INFO "ACK SDAlow\n");
udelay(DELAY_TIME_HXD);
gpio_set_value(SCL,1); // SCL变高
udelay(DELAY_TIME_HXD);
}
/* I2C字节写 */
void i2c_write_byte(unsigned char b)
{
int i;
gpio_direction_output(SDA, gpio_get_value(SDA)); //设置SDA方向为输出
for (i=7; i>=0; i--) {
gpio_set_value(SCL, 0); // SCL变低
udelay(DELAY_TIME_HXD);
gpio_set_value(SDA, b & (1<<i)); //从高位到低位依次准备数据进行发送
gpio_set_value(SCL, 1); // SCL变高
udelay(DELAY_TIME_HXD);
}
i2c_read_ack(); //检查目标设备的ACK信号
}
/* I2C字节读 */
unsigned char i2c_read_byte(void)
{
int i;
unsigned char r = 0;
gpio_direction_input(SDA); //设置SDA方向为输入
for (i=7; i>=0; i--) {
gpio_set_value(SCL, 0); // SCL变低
udelay(DELAY_TIME_HXD);
r = (r <<1) | gpio_get_value(SDA); //从高位到低位依次准备数据进行读取
gpio_set_value(SCL, 1); // SCL变高
udelay(DELAY_TIME_HXD);
}
i2c_send_ack(); //向目标设备发送ACK信号
return r;
}
/*
I2C读操作
addr:目标设备地址
buf:读缓冲区
len:读入字节的长度
*/
void i2c_read(unsigned char addr, unsigned char* buf, int len)
{
int i;
unsigned char t;
i2c_start(); //起始条件,开始数据通信
//发送地址和数据读写方向
t = (addr << 1) | 1; //低位为1,表示读数据
i2c_write_byte(t);
//读入数据
for (i=0; i<len; i++)
buf[i] = i2c_read_byte();
i2c_stop(); //终止条件,结束数据通信
}
/*
I2C写操作
addr:目标设备地址
buf:写缓冲区
len:写入字节的长度
*/
void i2c_write (unsigned char addr, unsigned char* buf, int len)
{
int i;
unsigned char t;
i2c_start(); //起始条件,开始数据通信
//发送地址和数据读写方向
t = (addr << 1) | 0; //低位为0,表示写数据
i2c_write_byte(t);
//写入数据
for (i=0; i<len; i++)
i2c_write_byte(buf[i]);
i2c_stop(); //终止条件,结束数据通信
}
static ssize_t i2c_gpio_write(struct file *file, const char *buf, size_t len, loff_t *offset)
{
/*将用户空间的数据copy到内核空间*/
unsigned char addr = 'h';
char real_msg[2000];
int cnt = copy_from_user(recv_msg, buf, len);
strncpy(real_msg, recv_msg + 1, strlen(recv_msg) - 1);
if (cnt == 0) {
/*首先对recv_msg拆分,分为目的和传输内容*/
if (recv_msg[0] == '1') {
//printk(KERN_INFO "I2C read! The length of recv_msg is %d\n", strlen(recv_msg));
i2c_read(addr, real_msg, strlen(real_msg));
} else if (recv_msg[0] == '0') {
printk(KERN_INFO "I2C write!\n");
i2c_write(addr, real_msg, strlen(real_msg));
}
} else {
printk(KERN_ALERT "ERROR occur when writing!!\n");
return -EFAULT;
}
return len;
}
static int i2c_gpio_release(struct inode *node, struct file *file)
{
printk(KERN_INFO "Release!!\n");
return 0;
}
static struct file_operations file_oprts = {
.open = i2c_gpio_open,
.read = i2c_gpio_read,
.write = i2c_gpio_write,
.release = i2c_gpio_release,
};
static int i2c_gpio_probe(struct platform_device *pdev)
{
/*先把两个引脚request到!*/
int gpio; /*gpio号*/
struct i2c_gpio_info i2c_info; /*结构体准备*/
struct device_node *i2c_gpio_node = pdev->dev.of_node; /*设备节点*/
printk(KERN_INFO "I2C GPIO Program Probe.\n");
/*先申请模拟的SDA线*/
gpio = of_get_named_gpio(i2c_gpio_node, "gpio_sda", 0);
if (!gpio_is_valid(gpio)) {
dev_err(&pdev->dev, "gpio_sda: %d is invalid\n", gpio);
return -ENODEV;
}
if(gpio_request(gpio, "gpio_sda")) {
dev_err(&pdev->dev, "gpio_sda: %d request failed!\n", gpio);
gpio_free(gpio);
return -ENODEV;
}
SDA = gpio;
i2c_info.i2c_gpio = gpio;
i2c_info.gpio_value = 1;
gpio_direction_output(i2c_info.i2c_gpio, i2c_info.gpio_value);
printk(KERN_INFO "I2C SDA request successfully.\n");
/*再申请模拟的SCL线*/
gpio = of_get_named_gpio(i2c_gpio_node, "gpio_scl", 0);
if (!gpio_is_valid(gpio)) {
dev_err(&pdev->dev, "gpio_scl: %d is invalid\n", gpio);
return -ENODEV;
}
if(gpio_request(gpio, "gpio_scl")) {
dev_err(&pdev->dev, "gpio_scl: %d request failed!\n", gpio);
gpio_free(gpio);
return -ENODEV;
}
SCL = gpio;
i2c_info.i2c_gpio = gpio;
i2c_info.gpio_value = 1;
gpio_direction_output(i2c_info.i2c_gpio, i2c_info.gpio_value);
printk(KERN_INFO "I2C SCL request successfully.\n");
return 0;
}
static struct of_device_id i2c_match_table[] = {
{ .compatible = "gpio_i2c",},
{},
};
static struct platform_driver i2c_gpio_driver = {
.driver = {
.name = "gpio_i2c",
.owner = THIS_MODULE,
.of_match_table = i2c_match_table,
},
.probe = i2c_gpio_probe,
};
static int cdev_create(void)
{
printk(KERN_INFO "chev adding-----\n");
cdev_init(&gpio_dev, &file_oprts);
if (alloc_chrdev_region(&ndev, 0, 1, DEVICE_NAME) < 0) {
printk(KERN_ALERT "Register failed!!\r\n");
return -1;
}
if (cdev_add(&gpio_dev, ndev, 1) < 0) {
printk("add wrong!\n");
return -1;
}
majorNumber = MAJOR(ndev);
printk(KERN_ALERT "Registe success,major number is %d\r\n", majorNumber);
/*以CLASS_NAME创建一个class结构,这个动作将会在/sys/class目录创建一个名为CLASS_NAME的目录*/
i2c_gpio_class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(i2c_gpio_class)) {
unregister_chrdev_region(ndev, 1);
return PTR_ERR(i2c_gpio_class);
}
/*以DEVICE_NAME为名,参考/sys/class/CLASS_NAME在/dev目录下创led建一个设备:/dev/DEVICE_NAME*/
i2c_gpio_device = device_create(i2c_gpio_class, NULL, MKDEV(majorNumber, 0), NULL, DEVICE_NAME);
if (IS_ERR(i2c_gpio_device)) {
class_destroy(i2c_gpio_device);
unregister_chrdev_region(ndev, 1);
return PTR_ERR(i2c_gpio_device);
}
printk(KERN_ALERT "i2c_gpio device init success!!\r\n");
return 0;
}
static int i2c_gpio_init(void)
{
platform_driver_register(&i2c_gpio_driver);
if (cdev_create() != 0)
{
printk(KERN_INFO "cdev create failed.\n");
return -1;
}
return 0;
}
module_init(i2c_gpio_init);
static void i2c_gpio_exit(void)
{
device_destroy(i2c_gpio_class, MKDEV(majorNumber, 0));
class_unregister(i2c_gpio_class);
class_destroy(i2c_gpio_class);
unregister_chrdev_region(ndev, 1);
platform_driver_unregister(&i2c_gpio_driver);
}
module_exit(i2c_gpio_exit);
MODULE_LICENSE("GPL");
#include
#include
#include
#include
#include
#include
static char buf[256] = {1};
int main(int argc, char *argv[])
{
int fd = open("/dev/i2c_device", O_RDWR);
if (fd < 0) {
perror("Open file failed!!!\r\n");
return -1;
}
printf("Please input:\n");
scanf("%s", buf);
int ret = write(fd, buf, strlen(buf));
if (ret < 0)
perror("Failed to write!!");
close(fd);
return 0;
}
分别让两个引脚连接到示波器上,然后采取边缘触发模式,运行应用层代码,输入你想传输的信息,观察得到的波形即可~
1、会在正常输入后还有其他波形,目前未找到原因
2、不支持从机发送信号,所以read部分,开始读取从机信号时,SDA会一直保持高电平