리눅스 기반의 개발 프레임 워크

드라이버 모델

최근에 드라이버를 개발하기 시작, 일반 모델 기반 개발은 다음과 같이 요약된다
: 글로벌 모델을 운전
여기에 그림 삽입 설명
장치를 추가를 필요의 대부분은 사용자의 명령 공간 작업을 보낼 수 있습니다. 그래서 두 가지 문제가 있습니다 :

  1. 어떻게 커널 제어 장치
  2. 의 사용자 공간과 커널 사이의 상호 작용을 유도하는 방법

문제 1 :.
버스의 다양한 커널이 장치는 버스, 인터페이스 버스를 통하여 구동 제어 장치는 커널 초기화 마운트를 제공.
질문 2 :
커널 파일이 디바이스 드라이버에서 제공되고, 이러한 문자 장치, PROC, SYS 장비 및 기타 문서로 장치 드라이버에 파일을 추가합니다.

위의 두 문제에 기초하여, 두 부분으로 포함
여기에 그림 삽입 설명

장치 드라이버 개발

운전 시스템 개발 단계의 끝

도 1을 참조하면, 판독 장치와 관련된 사양 데모
2 버스 로딩 결정 장치, 파일 상호 작용 장치
(3), 기준 데모, 코드의 두 부분으로 구성 드라이버 코드 쓰기 장치 트리 로직 코드 노드를 추가

주 : 필드 장치 트리 노드가 표준 (기존 커널 코드 분석) 일, 또한 포함 할 수있다 (논리 디바이스 드라이버 코드 분석) 정의된다.

마이크로 프로세서 기반의 클라이언트 장치 개발

정상적인 상황에서는, 코드의 일부, 장비 제조업체는 개발 종료에 대한 책임을 어떤 시스템을 제공 없었다.

시나리오

아키텍처 모델 기반 개발은 디바이스 드라이버는 개발해야 컨트롤러 I2C, SPI 버스 컨트롤러, 프레임 층, 같은 컨트롤러의 몇 가지 유형의 일반적으로 필요하지 커널 파일 시스템 장치가 일반적으로 애플리케이션 레벨의 드라이버 개발을 사용하여, 상기 한 바와 그것은 할 수 있습니다.

현상에서는, 실제의 필요에 따라 결정될 수있다.

데모

요구 사항에 대한 설명

구동 사용자 공간 일부 사용을 제공하기 위해 I2C, I2C 인터페이스를 작성하는

장치 트리 노드 추가
// SoC上的i2c控制器的地址
i2c@138B0000 {
	#address-cells = <1>;
    #size-cells = <0>;
    samsung,i2c-sda-delay = <100>;
    samsung,i2c-max-bus-freq = <20000>;
    pinctrl-0 =<&i2c5_bus>;
    pinctrl-names="default";
    // 这个一定要okay,其实是对"./arch/arm/boot/dts/exynos4.dtsi +387"处的status = "disabled"的重写,
    // 相同的节点的不同属性信息都会被合并,相同节点的相同的属性会被重写
    status="okay";
    // 设备子节点,/表示板子,它的子节点node1表示SoC上的某个控制器,
    // 控制器中的子节点node2表示挂接在这个控制器上的设备(们)。68即是设备地址。
    // 父结点是一个i2c总线,在此处定义i2c设备,设备i2c客户端自动和总线关联;
    // 否则,多个总线,设备i2c客户端驱动如何和总线关联?(待学习了解)
    mpu6050@68{
    	// 这个属性就是我们和驱动匹配的钥匙,一个字符都不能错
        compatible="invensense,mpu6050";
        // 这个属性是从设备的地址,我们可以通过查阅手册"MPU-6050_DataSheet_V3_4"得到
        reg=<0x68>;
    };
};
의 드라이버
//mpu6050_common.h
#define MPU6050_MAGIC 'K'

union mpu6050_data
{
    struct {
        short x;
        short y;
        short z;
    }accel;
    struct {
        short x;
        short y;
        short z;
    }gyro;
    unsigned short temp;
};

#define GET_ACCEL _IOR(MPU6050_MAGIC, 0, union mpu6050_data)
#define GET_GYRO  _IOR(MPU6050_MAGIC, 1, union mpu6050_data) 
#define GET_TEMP  _IOR(MPU6050_MAGIC, 2, union mpu6050_data)
//mpu6050_drv.h

#define SMPLRT_DIV      0x19    //陀螺仪采样率,典型值:0x07(125Hz)
#define CONFIG          0x1A    //低通滤波频率,典型值:0x06(5Hz)
#define GYRO_CONFIG     0x1B    //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s)
#define ACCEL_CONFIG        0x1C    //加速计自检、测量范围及高通滤波,典型值:0x18(不自检,2G,5Hz)
#define ACCEL_XOUT_H        0x3B
#define ACCEL_XOUT_L        0x3C
#define ACCEL_YOUT_H        0x3D
#define ACCEL_YOUT_L        0x3E
#define ACCEL_ZOUT_H        0x3F
#define ACCEL_ZOUT_L        0x40
#define TEMP_OUT_H      0x41
#define TEMP_OUT_L      0x42
#define GYRO_XOUT_H     0x43
#define GYRO_XOUT_L     0x44
#define GYRO_YOUT_H     0x45
#define GYRO_YOUT_L     0x46
#define GYRO_ZOUT_H     0x47    //陀螺仪z轴角速度数据寄存器(高位)
#define GYRO_ZOUT_L     0x48    //陀螺仪z轴角速度数据寄存器(低位)
#define PWR_MGMT_1      0x6B    //电源管理,典型值:0x00(正常启用)
#define WHO_AM_I        0x75    //IIC地址寄存器(默认数值0x68,只读)
#define SlaveAddress        0x68    //MPU6050-I2C地址寄存器
#define W_FLG           0
#define R_FLG           1
//mpu6050.c
struct mpu6050_pri {
    struct cdev dev;
    struct i2c_client *client;
};
struct mpu6050_pri dev;
static void mpu6050_write_byte(struct i2c_client *client,const unsigned char reg,const unsigned char val)
{ 
    char txbuf[2] = {reg,val};
    struct i2c_msg msg[2] = {
        [0] = {
            .addr = client->addr,
            .flags= W_FLG,
            .len = sizeof(txbuf),
            .buf = txbuf,
        },
    };
    i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
}
static char mpu6050_read_byte(struct i2c_client *client,const unsigned char reg)
{
    char txbuf[1] = {reg};
    char rxbuf[1] = {0};
    struct i2c_msg msg[2] = {
        [0] = {
            .addr = client->addr,
            .flags = W_FLG,
            .len = sizeof(txbuf),
            .buf = txbuf,
        },
        [1] = {
            .addr = client->addr,
            .flags = I2C_M_RD,
            .len = sizeof(rxbuf),
            .buf = rxbuf,
        },
    };

    i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
    return rxbuf[0];
}
static int dev_open(struct inode *ip, struct file *fp)
{
    return 0;
}
static int dev_release(struct inode *ip, struct file *fp)
{
    return 0;
}
static long dev_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
    int res = 0;
    union mpu6050_data data = {{0}};
    switch(cmd){
    case GET_ACCEL:
        data.accel.x = mpu6050_read_byte(dev.client,ACCEL_XOUT_L);
        data.accel.x|= mpu6050_read_byte(dev.client,ACCEL_XOUT_H)<<8;
        data.accel.y = mpu6050_read_byte(dev.client,ACCEL_YOUT_L);
        data.accel.y|= mpu6050_read_byte(dev.client,ACCEL_YOUT_H)<<8;
        data.accel.z = mpu6050_read_byte(dev.client,ACCEL_ZOUT_L);
        data.accel.z|= mpu6050_read_byte(dev.client,ACCEL_ZOUT_H)<<8;
        break;
    case GET_GYRO:
        data.gyro.x = mpu6050_read_byte(dev.client,GYRO_XOUT_L);
        data.gyro.x|= mpu6050_read_byte(dev.client,GYRO_XOUT_H)<<8;
        data.gyro.y = mpu6050_read_byte(dev.client,GYRO_YOUT_L);
        data.gyro.y|= mpu6050_read_byte(dev.client,GYRO_YOUT_H)<<8;
        data.gyro.z = mpu6050_read_byte(dev.client,GYRO_ZOUT_L);
        data.gyro.z|= mpu6050_read_byte(dev.client,GYRO_ZOUT_H)<<8;
        printk("gyro:x %d, y:%d, z:%d\n",data.gyro.x,data.gyro.y,data.gyro.z);
        break;
    case GET_TEMP:
        data.temp = mpu6050_read_byte(dev.client,TEMP_OUT_L);
        data.temp|= mpu6050_read_byte(dev.client,TEMP_OUT_H)<<8;
        printk("temp: %d\n",data.temp);
        break;
    default:
        printk(KERN_INFO "invalid cmd");
        break;
    }
    printk("acc:x %d, y:%d, z:%d\n",data.accel.x,data.accel.y,data.accel.z);
    res = copy_to_user((void *)arg,&data,sizeof(data));
    return sizeof(data);
}

// 初始化文件系统设备操作接口
struct file_operations fops = {
    .open = dev_open,
    .release = dev_release,
    .unlocked_ioctl = dev_ioctl, 
};

#define DEV_CNT 1
#define DEV_MI 0
#define DEV_MAME "mpu6050"

struct class *cls;
dev_t dev_no ;

static void mpu6050_init(struct i2c_client *client)
{
    mpu6050_write_byte(client, PWR_MGMT_1, 0x00);
    mpu6050_write_byte(client, SMPLRT_DIV, 0x07);
    mpu6050_write_byte(client, CONFIG, 0x06);
    mpu6050_write_byte(client, GYRO_CONFIG, 0x18);
    mpu6050_write_byte(client, ACCEL_CONFIG, 0x0);
}
static int mpu6050_probe(struct i2c_client * client, const struct i2c_device_id * id)
{
    dev.client = client;
    printk(KERN_INFO "xj_match ok\n");
    // 初始化设备文件系统
    cdev_init(&dev.dev,&fops);    
    alloc_chrdev_region(&dev_no,DEV_MI,DEV_CNT,DEV_MAME);    
    cdev_add(&dev.dev,dev_no,DEV_CNT);
    
    // 设备初始化
    mpu6050_init(client);

    /*自动创建设备文件*/
    cls = class_create(THIS_MODULE,DEV_MAME);
    device_create(cls,NULL,dev_no,NULL,"%s%d",DEV_MAME,DEV_MI);
    
    printk(KERN_INFO "probe\n");
    
    return 0;
}

static int mpu6050_remove(struct i2c_client * client)
{
    device_destroy(cls,dev_no);
    class_destroy(cls);
    unregister_chrdev_region(dev_no,DEV_CNT);
    return 0;
}

struct of_device_id mpu6050_dt_match[] = {
    {.compatible = "invensense,mpu6050"},
    {},
};

// 设备驱动注册到总线
struct i2c_device_id mpu6050_dev_match[] = {};
struct i2c_driver mpu6050_driver = {
    .probe = mpu6050_probe,
    .remove = mpu6050_remove,
    .driver = {
        .owner = THIS_MODULE,
        .name = "mpu6050drv",
        .of_match_table = of_match_ptr(mpu6050_dt_match), 
    },
    .id_table = mpu6050_dev_match,
};
module_i2c_driver(mpu6050_driver);
MODULE_LICENSE("GPL");

함께 혼합 달성하기 위해 구현 된 디바이스와 디바이스 드라이버의 파일 시스템을 구현 코드에서, 각각 별개로 구현 한 장치 드라이버의 코드 재사용은 여분 및 다중 프로그램 스위칭을 용이하게한다.

확인

다음으로, 상기 구동함으로써, 애플리케이션 계층 애플리케이션 계층을 mpu6050 레지스터 파일 조작 장치로부터 원래의 데이터를 읽을 수있다

int main(int argc, char * const argv[])
{
    int fd = open(argv[1],O_RDWR);
    if(-1== fd){
        perror("open");
        return -1;
    }
    union mpu6050_data data = {{0}};
    while(1){
        ioctl(fd,GET_ACCEL,&data);
        printf("acc:x %d, y:%d, z:%d\n",data.accel.x,data.accel.y,data.accel.z);
        ioctl(fd,GET_GYRO,&data);
        printf("gyro:x %d, y:%d, z:%d\n",data.gyro.x,data.gyro.y,data.gyro.z);
        ioctl(fd,GET_TEMP,&data);
        printf("temp: %d\n",data.temp);
        sleep(1);
    }
    return 0;
}

다음과 같이 최종 센서 원시 데이터를 얻을 수
여기에 그림 삽입 설명
설명 : 위의 데모는 배우는 것입니다 https://www.cnblogs.com/xiaojiang1025/p/6500540.html을 개인의 실제 개발도 실현해야 할 코드는이 문서 블로그 컴퓨터를 쓰지 않습니다 위대한 하나님 코드를 빌려.

추천

출처blog.csdn.net/mcsbary/article/details/90696849