嵌入式LINUX驱动学习之15 i2c代码举例(三轴加速度传感器MMA8653)方式一


说明:
本例使用开发板为x6818,三星S5P6818 cpu

一、添加板级信息(硬件信息)

注: 1.1和1.2是原理相同,两种不同方式,二选一即可

1.1 插入到其它原文件中

本小节以在“arch/arm/plat-s5p6818/x6818/device.c” 文档中插入内容为例

//vim arch/arm/plat-s5p6818/x6818/device.c
#include <linux/i2c.h>
/*注:添加如下信息前,应先查检原代码中是否有相关的硬件信息注册,
  如果有,则可以不必添加,或注释后自行添加。
*/
static struct i2c_board_info mma8653_obj[] = {
    
    
    {
    
    
        I2C_BOARD_INFO("my_mma8653_test",0x1D)// "my_mma8653_test" 用于匹配,0x1D为i2c从设备地址
    }
};
/*
   2  : mma8653连接S5P6818芯片的I2C端口编号
   mma8653_obj : struct i2c_board_info 结构体对象地址
  ARRAY_SIZE(mma8653_obj) : 当 mma8653_obj为数组时,可以直接求组元素个数,即i2c从设备个数;
*/
i2c_register_board_info(2,mma8653_obj,ARRAY_SIZE(mma8653_obj));

1.2 利用arch_initcall()函数,新建一个源文件的方式添加i2c硬件

1.2.1 源文件

//vim mymma8653_dev.c
#include <linux/i2c.h>
#include <linux/init.h>
static struct i2c_board_info mma8653_obj[] = {
    
    
    {
    
    
        I2C_BOARD_INFO("my_mma8653_test",0x1D)
    }
};
static int __init mma8653_dev(void){
    
    
    i2c_register_board_info(2,mma8653_obj,1);
    return 0;
}
arch_initcall(mma8653_dev);

1.2.2 Makefile文件

//vim Makefile
obj-y                                   := board.o device.o x6818-lcds.o mymma8653_dev.o

二、软件驱动代码

功能:读取mma8653的x,y,z轴数值,并传递给用户空间

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
void mma8653_state(void);
void mma8653_action(void);
struct i2c_client *g_cli = NULL;
/* 定义x,y,z三轴*/
struct mma8653_state_struct {
    
    
    int x;
    int y;
    int z;
};
struct mma8653_state_struct *mma8653_state_obj = NULL;
/*当用户采用ioctl函数读取三轴加速度传感器信息时,调用此函数*/
static long my_ioctl(struct file * file,unsigned int ucmd,unsigned long ubuf){
    
    
    int copy_ret = 0;
    //池软件驱动没有匹配到硬件驱动时,不参获取信息,报错
    if(!g_cli){
    
    
        printk("设备打开失败!\n");
        return -EIO;
    }
    mma8653_state_obj =(struct mma8653_state_struct *) kmalloc(sizeof(mma8653_state_obj),GFP_KERNEL);
    mma8653_action();
    mma8653_state();
    copy_ret = copy_to_user((struct mma8653_state_struct *)ubuf,\
                  mma8653_state_obj,sizeof(struct mma8653_state_struct));
    kfree(mma8653_state_obj);
        return 0;
}
struct file_operations f_ops={
    
    
    .owner = THIS_MODULE,
    .unlocked_ioctl = my_ioctl
};
struct miscdevice misc_ops = {
    
    
    .minor = MISC_DYNAMIC_MINOR,
    .fops  = &f_ops,
    .name = "mma8653_ioctl"
};
void mma8653_state(void){
    
    
    int mma8653_x,mma8653_y,mma8653_z;
    mma8653_x = (i2c_smbus_read_byte_data(g_cli, 0x01) << 2 ) |\
                (i2c_smbus_read_byte_data(g_cli,0x2) >> 6 );
    mma8653_y = (i2c_smbus_read_byte_data(g_cli, 0x03) << 2 ) |\
                (i2c_smbus_read_byte_data(g_cli,0x4) >> 6 );
    mma8653_z = (i2c_smbus_read_byte_data(g_cli, 0x05) << 2 ) |\
                (i2c_smbus_read_byte_data(g_cli,0x6) >> 6 );
    /*判断第10位是否为1,如果为1,说明结果是负值
         0x3ff  =>   11 1111 1111   //确保有效值为低10位
    */
    if(mma8653_x & (0x1 << 9))
        mma8653_x = ((mma8653_x & 0x3ff) & ~(0x1 << 9)) - (0x1 << 9);
    if(mma8653_y & (0x1 << 9))
        mma8653_y = ((mma8653_y & 0x3ff) & ~(0x1 << 9)) - (0x1 << 9);
    if(mma8653_z & (0x1 << 9))
        mma8653_z = ((mma8653_z & 0x3ff) & ~(0x1 << 9)) - (0x1 << 9);
    mma8653_state_obj -> x = mma8653_x;
    mma8653_state_obj -> y = mma8653_y;
    mma8653_state_obj -> z = mma8653_z;
}
//激活mma8653
void mma8653_action(void){
    
    
    int data;
    data= i2c_smbus_read_byte_data(g_cli, 0x2a);
    data|= 1;
    i2c_smbus_write_byte_data(g_cli,0x2a,data);
}
/*当软件驱动和硬件驱动匹配成功时执行*/
static int mma8653_probe(struct i2c_client * client,\
                         const struct i2c_device_id *i2c_dev_id){
    
    
    g_cli = client;
    return 0;
}
/*当软件驱动卸载时执行*/
static int mma8653_remove(struct i2c_client *client){
    
    
    g_cli = NULL;
    return 0;
}
struct i2c_device_id i2c_dev_id_obj = {
    
    
    .name = "my_mma8653_test",
    .driver_data = 0
};
struct i2c_driver mma8653_dri_obj = {
    
    
    .probe    = mma8653_probe,
    .remove   = mma8653_remove,
    .id_table = &i2c_dev_id_obj,
    .driver   = {
    
    
        .name = "my_mma8653_dri"
    }
};

static int mma8653_test_init(void){
    
    
    misc_register(&misc_ops);
    i2c_add_driver(&mma8653_dri_obj);//向内核注册软件驱动
    printk("%s\n",__func__);

    return 0;
}

static void mma8653_test_exit(void){
    
    
    misc_deregister(&misc_ops);
    i2c_del_driver(&mma8653_dri_obj);//从内核卸载软件驱动 
    printk("%s\n",__func__);
}
module_init(mma8653_test_init);
module_exit(mma8653_test_exit);
MODULE_LICENSE("GPL");                   

三、用户空间代码举例

打印mma8653驱动传递过来的三轴数值

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#define RD 0X1111
/*定义三轴结构体*/
struct mma8653_state_struct {
    
    
    int x;
    int y;
    int z;
};
/*打印三轴的数值*/
struct mma8653_state_struct mma8653_obj;//保存三轴数值
void mma8653_print(void){
    
    
    printf("x:%*d,y:%*d,z:%*d\r",4,mma8653_obj.x,\
           4,mma8653_obj.y , 4,mma8653_obj.z);
    fflush(NULL);
}
int main(int argc , char * argv[]){
    
    
    int fp,ioctl_ret;
    if(argc != 2)
        goto comm_err;
    fp = open(argv[1],O_RDWR);
    if(fp < 0)
        goto fp_err;
    /*每隔1秒读取一次三轴的数值*/
    while(1){
    
    
        ioctl_ret = ioctl(fp,RD,&mma8653_obj);
        if(ioctl_ret)
            goto ioctl_err;
        mma8653_print();
        sleep(1);
    }
    return 0;
comm_err :
    printf("命令错误!\n");
    printf("          comm <cdev_file>\n");
fp_err :
    perror("open file error :");
    return -1;
ioctl_err:
    perror("ioctl error :");
    return -1;
}

猜你喜欢

转载自blog.csdn.net/weixin_47273317/article/details/108430086