15 i2c code examples of embedded LINUX driving learning (three-axis acceleration sensor MMA8653) method one


Description:
This example uses the development board x6818, Samsung S5P6818 cpu

1. Add board level information (hardware information)

Note: 1.1 and 1.2 have the same principle, two different methods, choose one of the two

1.1 Insert into other original files

This section takes the example of inserting content in the "arch/arm/plat-s5p6818/x6818/device.c" document

//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 Use arch_initcall() function to add i2c hardware by creating a new source file

1.2.1 Source files

//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

Second, the software driver code

Function: Read the x, y, z axis values ​​of mma8653 and pass them to user space

#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");                   

Three, user space code example

Print the three-axis value passed by the mma8653 driver

#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;
}

Guess you like

Origin blog.csdn.net/weixin_47273317/article/details/108430086