RK系列3588驱动开发:sensor注意点

工作记录与回顾:

移植过程:

        一般按照厂商提供的代码移植,注意以下框架 

1.添加设备树信息(对应总线下)

路径:arch-arm64-boot-dts-rochchip-rk3588-vehicle-s66-v10.dtsi

omi8658_acc@6a {
        status = "okay";
        reg = <0x6a>;
        compatible ="qmi8658_acc";
        type = <SENSOR_TYPE_ACCEL>;
        poll_delay_ms =<30>;
        power-off-in-suspend = <1>;

        layout = <4>;
    };

    qmi8658_gyro@6a {
        status ="okay";
        compatible ="qmi8658_gyro";
        reg = <0x6a>;
        type = <SENSOR_TYPE_GYROSCOPE>;
        power-off-in-suspend = <1>;
        poll_delay_ms = <30>;
    };

2。在include/linux/sensor-dev.h下进行设备的排号

enum sensor_id {

。。。

    COMPASS_ID_AK09918,
    ACCEL_ID_QMI8658,

。。。

    GYRO_ID_IAM20680,
    GYRO_ID_QMI8658,

。。。

}

这只需要把需要加的功能添加到相应的区域

3,。按照厂商给的驱动的.c文件进行注册

路径一般按照注册的sensor类型来决定

drivers-input-gyro

drivers-input-accle

驱动如下:

/* drivers/input/sensors/access/qmi8658_acc.c

 *

 * Copyright (C) 2012-2015 ROCKCHIP.

 * Author: oeh<oeh@rock-chips.com>

 *

 * This software is licensed under the terms of the GNU General Public

 * License version 2, as published by the Free Software Foundation, and

 * may be copied, distributed, and modified under those terms.

 *

 * This program is distributed in the hope that it will be useful,

 * but WITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

 * GNU General Public License for more details.

 *

 */

#include <linux/interrupt.h>

#include <linux/i2c.h>

#include <linux/slab.h>

#include <linux/irq.h>

#include <linux/miscdevice.h>

#include <linux/gpio.h>

#include <linux/uaccess.h>

#include <asm/atomic.h>

#include <linux/delay.h>

#include <linux/input.h>

#include <linux/workqueue.h>

#include <linux/freezer.h>

#include <linux/of_gpio.h>

#ifdef CONFIG_HAS_EARLYSUSPEND

#include <linux/earlysuspend.h>

#endif

#include <linux/sensor-dev.h>

#include <linux/qmi8658.h>





static int qmi8658_set_rate(struct i2c_client *client, int rate)

{

    const short hz[] = {448, 224, 112, 56, 28};

    const int   d[] = {0x24, 0x25,0x26, 0x27, 0x28};

    int i =0, data =0, result =0;



    /* always use poll mode, no need to set rate */

    return 0;



    if ((rate < 1) || (rate > 480))

        return -1;



    while ((rate > hz[i]) && (i < 5))

        i++;

    data = d[i];



    result = sensor_write_reg(client, QMI8658_REG_CTRL2, data);

    if (result)

        return -1;



    return 0;

}



static int sensor_active(struct i2c_client *client, int enable, int rate)

{

//  struct sensor_private_data *sensor =

//      (struct sensor_private_data *) i2c_get_clientdata(client);

    int result = 0;

    u8 databuf[2] = {0};



    databuf[0] = sensor_read_reg(client, QMI8658_REG_CTRL7);



    if (!enable) {

        databuf[0] = (databuf[0] & 0xFE) | 0x80; //accel disable;      

    } else {

        databuf[0] = (databuf[0] & 0xFE) | 0x81; //accel enable;        

        qmi8658_set_rate(client, rate);

    }



    result = sensor_write_reg(client, QMI8658_REG_CTRL7, databuf[0]);

    if (result) {

        dev_err(&client->dev, "%s:fail to set pwrm1\n", __func__);

        return -1;

    }

    dev_err(&client->dev, "zhoucs %s:activer OK, enable=%d, result=%d\n", __func__, enable, result);

    return result;

}



static int sensor_init(struct i2c_client *client)

{

    int res = 0;

    u8 read_data = 0,reg_value = 0;



    struct sensor_private_data *sensor =

        (struct sensor_private_data *) i2c_get_clientdata(client);



    read_data = sensor_read_reg(client, sensor->ops->id_reg);



    if (read_data != sensor->ops->id_data) {

        dev_err(&client->dev, "%s:check id err,read_data:%d,ops->id_data:%d\n",

                __func__, read_data, sensor->ops->id_data);

        return -1;

    }else{

        dev_err(&client->dev, "%s:check id success -->qmi8658\n", __func__);

    }



    res = sensor_write_reg(client, QMI8658_REG_RESET, QMI8658_SW_RESET);

    if (res) {

        dev_err(&client->dev, "set QMI8658_SW_RESET error,res: %d!\n", res);

        return res;

    }

    msleep(15);



    res = sensor_write_reg(client, QMI8658_REG_CTRL1, QMI8658_ADDR_AI_BE);

    if (res) {

        dev_err(&client->dev, "set QMI8658_REG_CTRL1 error,res: %d!\n", res);

        return res;

    }



    reg_value = QMI8658_ACC_RANGE_DEF|QMI8658_ODR_470HZ_REG_VALUE;// ±8g,odr=479hz

    res = sensor_write_reg(client, QMI8658_REG_CTRL2, reg_value);

    if (res) {

        dev_err(&client->dev, "set QMI8658_REG_CTRL2 error,res: %d!\n", res);

        return res;

    }



    reg_value = QMI8658_GYR_RANGE_2048DPS|QMI8658_ODR_470HZ_REG_VALUE;//2048dps,odr=479hz

    res = sensor_write_reg(client, QMI8658_REG_CTRL3, reg_value);

    if (res) {

        dev_err(&client->dev, "set QMI8658_REG_CTRL3 error,res: %d!\n", res);

        return res;

    }



    res = sensor->ops->active(client, 0, sensor->pdata->poll_delay_ms);

    if (res) {

        dev_err(&client->dev, "%s:line=%d,error\n", __func__, __LINE__);

        return res;

    }

    return res;

}



static int gsensor_report_value(struct i2c_client *client, struct sensor_axis *axis)

{

    struct sensor_private_data *sensor =

        (struct sensor_private_data *) i2c_get_clientdata(client);



    if (sensor->status_cur == SENSOR_ON) {

        /* Report acceleration sensor information */

        input_report_abs(sensor->input_dev, ABS_X, axis->x);

        input_report_abs(sensor->input_dev, ABS_Y, axis->y);

        input_report_abs(sensor->input_dev, ABS_Z, axis->z);

        input_sync(sensor->input_dev);

    }



    return 0;

}



static int sensor_report_value(struct i2c_client *client)

{

    struct sensor_private_data *sensor =

        (struct sensor_private_data *) i2c_get_clientdata(client);

    struct sensor_platform_data *pdata = sensor->pdata;

    int ret = 0;

    short x, y, z;

    struct sensor_axis axis;

    u8 buffer[6] = {0};

    // char value = 0, count = 0;

    if (sensor->ops->read_len < 6) {

        dev_err(&client->dev, "%s:lenth is error,len=%d\n", __func__, sensor->ops->read_len);

        return -1;

    }



    memset(buffer, 0, 6);



    /* Data bytes from hardware xL, xH, yL, yH, zL, zH */

    // while(((value & 0x03)!= 0x03)&&(count++ < 3)){

    //  value = sensor_read_reg(client, QMI8658_REG_STATUSINT);

    // }

    *buffer = QMI8658_REG_GYR_XOUT_LSB;

    ret = sensor_rx_data(client, buffer, sensor->ops->read_len);

    *buffer = sensor->ops->read_reg;

    ret = sensor_rx_data(client, buffer, sensor->ops->read_len);

    if (ret < 0)

        return ret;



    x = ((buffer[1] << 8) & 0xFF00) + (buffer[0] & 0xFF);

    y = ((buffer[3] << 8) & 0xFF00) + (buffer[2] & 0xFF);

    z = ((buffer[5] << 8) & 0xFF00) + (buffer[4] & 0xFF);

    //dev_err(&client->dev, "raw_acc=%4d,%4d,%4d\n", (signed short)x, (signed short)y, (signed short)z);



    axis.x = (pdata->orientation[0]) * x + (pdata->orientation[1]) * y + (pdata->orientation[2]) * z;

    axis.y = (pdata->orientation[3]) * x + (pdata->orientation[4]) * y + (pdata->orientation[5]) * z;

    axis.z = (pdata->orientation[6]) * x + (pdata->orientation[7]) * y + (pdata->orientation[8]) * z;

    gsensor_report_value(client, &axis);



    mutex_lock(&(sensor->data_mutex));

    sensor->axis = axis;

    mutex_unlock(&(sensor->data_mutex));



    //if ((sensor->pdata->irq_enable) && (sensor->ops->int_status_reg >= 0))

    //  value = sensor_read_reg(client, sensor->ops->int_status_reg);



    return ret;

}



struct sensor_operate gsensor_qmi8658_ops = {

    .name               = "qmi8658_acc",

    .type               = SENSOR_TYPE_ACCEL,

    .id_i2c             = ACCEL_ID_QMI8658,

    .read_reg           = QMI8658_REG_ACC_XOUT_LSB,

    .read_len           = 6,

    .id_reg             = QMI8658_REG_WHO_AM_I,

    .id_data            = SENSOR_CHIP_ID_QMI8658,

    .precision          = QMI8658_PRECISION,

    .ctrl_reg           = QMI8658_REG_CTRL7,

    .int_status_reg     = QMI8658_REG_STATUS0,

    .range              = {-32768, 32768},

    .trig               = IRQF_TRIGGER_HIGH | IRQF_ONESHOT,

    .active             = sensor_active,

    .init               = sensor_init,

    .report             = sensor_report_value,

};



/****************operate according to sensor chip:end************/

static int gsensor_qmi8658_probe(struct i2c_client *client,

                 const struct i2c_device_id *devid)

{

    return sensor_register_device(client, NULL, devid, &gsensor_qmi8658_ops);

}



static int gsensor_qmi8658_remove(struct i2c_client *client)

{

    return sensor_unregister_device(client, NULL, &gsensor_qmi8658_ops);

}



static const struct i2c_device_id gsensor_qmi8658_id[] = {

    {"qmi8658_acc", ACCEL_ID_QMI8658},

    {}

};



static struct i2c_driver gsensor_qmi8658_driver = {

    .probe = gsensor_qmi8658_probe,

    .remove = gsensor_qmi8658_remove,

    .shutdown = sensor_shutdown,

    .id_table = gsensor_qmi8658_id,

    .driver = {

        .name = "gsensor_qmi8658",

#ifdef CONFIG_PM

        .pm = &sensor_pm_ops,

#endif

    },

};



module_i2c_driver(gsensor_qmi8658_driver);



MODULE_AUTHOR("ouenhui <oeh@rock-chips.com");

MODULE_DESCRIPTION("qmi8658_acc 3-Axis accelerometer driver");

MODULE_LICENSE("GPL");

驱动中需要注意的点就是这个结构体中需要的值

struct sensor_operate gsensor_qmi8658_ops = {

    .name               = "qmi8658_acc",                        

    .type               = SENSOR_TYPE_ACCEL,           //sensor-dev.h定义,设备树部分也有定义类型

    .id_i2c             = ACCEL_ID_QMI8658,                //前面提到的标号的类型   

    .read_reg           = QMI8658_REG_ACC_XOUT_LSB,//第一个读取的寄存器地址

    .read_len           = 6,                                                //读取长度

    .id_reg             = QMI8658_REG_WHO_AM_I,        

    .id_data            = SENSOR_CHIP_ID_QMI8658,

    .precision          = QMI8658_PRECISION,

    .ctrl_reg           = QMI8658_REG_CTRL7,

    .int_status_reg     = QMI8658_REG_STATUS0,

    .range              = {-32768, 32768},

    .trig               = IRQF_TRIGGER_HIGH | IRQF_ONESHOT,

    .active             = sensor_active,                                //框架中需要给hal做控制

    .init               = sensor_init,                                        //初始化

    .report             = sensor_report_value,                //我这里使用的模式是轮询

};

开始我认为这个可以做中断触发和轮询上报的两种模式,但是后面发现rk平台不支持中断触发的方式去做,

因为是一个6轴加速器,加有温度传感器,实际是有3个驱动,另两个驱动大同小异,只是init部分是通过accle部分就已经初始化好,后面的就没有再次做初始化,然后就是读取的寄存器部分和注册的名称有一定的差异,还是比较简单的

驱动部分的测试:

我以前没怎么接触rk平台,不知道有对应工具去抓,就自己写啦测试程序来测试,这部分不想了解的可以直接用系统带的(getevent)测试,当时我测试的主要就是看是否能抓数据,模拟100ms轮询去读取数据,后面还会有一个读取时间戳等等的一些功能

test1.c

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/input.h>
#include <poll.h>
#include <errno.h>


#define GSENSOR_IOCTL_MAGIC 'a'
#define GSENSOR_IOCTL_START _IO(GSENSOR_IOCTL_MAGIC, 0x03)
#define GSENSOR_IOCTL_APP_SET_RATE			_IOW(GSENSOR_IOCTL_MAGIC, 0x10, short)
#define L3G4200D_IOCTL_BASE 77
#define L3G4200D_IOCTL_SET_DELAY _IOW(L3G4200D_IOCTL_BASE, 0, int)
#define L3G4200D_IOCTL_SET_ENABLE  _IOW(L3G4200D_IOCTL_BASE, 2, int)

#define TEMPERATURE_IOCTL_MAGIC			't'
#define TEMPERATURE_IOCTL_GET_ENABLED	_IOR(TEMPERATURE_IOCTL_MAGIC, 1, int *)
#define TEMPERATURE_IOCTL_ENABLE			_IOW(TEMPERATURE_IOCTL_MAGIC, 2, int *)
int main() 
{
    int fd = -1;
    int fd2 = -1;
    int ret = 0;

    int fd3 = -1;
    int fd4 = -1;
    int fd6 = -1;
    struct input_event ev;

    struct pollfd fds[1];
    nfds_t nfds = 1;
    int timeout_ms = 100; // 设置为-1表示无限等待,可以根据需要调整为超时时间
    int enable = 1;

   fd = open("/dev/mma8452_daemon", O_RDWR);
    if (fd == -1)
    {
        printf("can not open file mma8452_daemon\n");
        return -1;
    }
    ret = ioctl(fd,GSENSOR_IOCTL_START);
    if(ret == -1)
    {
        printf("ioctl1 fail\n");
    }
    

    fd2 = open("/dev/gyrosensor", O_RDWR);
    if (fd2 == -1)
    {
        printf("can not open file gyrosensor\n");
        return -1;
    }
    ret = ioctl(fd,GSENSOR_IOCTL_APP_SET_RATE,&timeout_ms);
    if(ret == -1)
    {
        printf("ioctl2.01 fail\n");
    }
    ret = ioctl(fd2,L3G4200D_IOCTL_SET_DELAY,&timeout_ms);
    if(ret == -1)
    {
        printf("ioctl2.1 fail\n");
    }
    ret = ioctl(fd2,L3G4200D_IOCTL_SET_ENABLE,&enable);
    if(ret == -1)
    {
        printf("ioctl2.2 fail\n");
    }
///

    
    fd6 = open("/dev/temperature", O_RDWR);
    if (fd6 == -1)
    {
        printf("can not open file temperature\n");
        return -1;
    }
    if (ioctl(fd6, TEMPERATURE_IOCTL_GET_ENABLED, &enable) == -1) {
        perror("Failed to get temperature enable status");
    }
    enable = 1;

     ret = ioctl(fd6,TEMPERATURE_IOCTL_ENABLE,&enable);
    if(ret == -1)
    {
        printf("ioctl2.2 tmp fail\n");
        fprintf(stderr, "Error number: %d\n", errno); // 输出错误号
    }
/
    close(fd);
    close(fd2);



    // 打开设备文件,这里以event1为例,请根据实际情况修改
    if ((fd3 = open("/dev/input/event1", O_RDONLY)) == -1) {
        perror("Failed to open /dev/input/event1");
        return EXIT_FAILURE;
    }
    // 打开设备文件,这里以event1为例,请根据实际情况修改
    if ((fd4 = open("/dev/input/event2", O_RDONLY)) == -1) {
        perror("Failed to open /dev/input/event2");
        return EXIT_FAILURE;
    }

    if (fcntl(fd3, F_SETFL, fcntl(fd3, F_GETFL, 0) | O_NONBLOCK) == -1) {
        perror("Failed to set non-blocking");
        close(fd3);
        return EXIT_FAILURE;
    }
    // 初始化pollfd结构
    fds[0].fd = fd3;
    fds[0].events = POLLIN;
    


    int fd5;
    char buffera[256];
    off_t offset = 0;

    // 打开设备文件,假设它是一个只读权限
    fd5 = open("/dev/input/event3", O_RDONLY);
    if (fd5 == -1) {
        perror("Failed to open temperature device");
        return EXIT_FAILURE;
    }

    // 读取设备文件内容
    while (offset < sizeof(buffera)) {
        ssize_t bytes_read = read(fd5, buffera + offset, sizeof(buffera) - offset);
        if (bytes_read == -1) {
            perror("Read error");
            break;
        } else if (bytes_read == 0) {
            // 文件结束
            break;
        }
        offset += bytes_read;
    }

    // 关闭合设备文件
    close(fd5);
    close(fd6);
    // 确单假设温度值为纯文本且在buffer中,打印出来
    buffera[offset] = '\0'; // 确保字符串结尾
    printf("Temperature Reading: %s\n", buffera);




    while (1) {
        // 读取一个输入事件

        int ret = poll(fds, nfds, timeout_ms);
        //int ret_2 = poll(fds_2, nfds_2, timeout_ms);

        if (ret == -1 ) {
            perror("Poll error");
            break;
        } else if (ret == 0 ) {
            // 超时
            printf("Poll timeout\n");
            continue;
        }


        if (fds[0].revents & POLLIN) {
            // 读取事件
            //event1
            ssize_t bytes_read = read(fd3, &ev, sizeof(struct input_event));
            if (bytes_read == -1) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    // 没有更多数据可读,继续下一轮循环
                    continue;
                } else {
                    perror("Read error");
                    break;
                }
            } else if (bytes_read != sizeof(struct input_event)) {
                fprintf(stderr, "Unexpected read size: %zd\n", bytes_read);
                continue;
            }

            printf("Time1: %ld.%06ld, Type: %d, Code: %u, Value: %d\n",
                   ev.time.tv_sec, ev.time.tv_usec,
                   ev.type, ev.code, ev.value);

            // //event2
            // ssize_t bytes_read_2 = read(fd4, &ev, sizeof(struct input_event));
            // if (bytes_read_2 == -1) {
            //     if (errno == EAGAIN || errno == EWOULDBLOCK) {
            //         // 没有更多数据可读,继续下一轮循环
            //         continue;
            //     } else {
            //         perror("Read error");
            //         break;
            //     }
            // } else if (bytes_read_2 != sizeof(struct input_event)) {
            //     fprintf(stderr, "Unexpected read size: %zd\n", bytes_read_2);
            //     continue;
            // }

            // printf("Time2: %ld.%06ld, Type: %d, Code: %u, Value: %d\n",
            //        ev.time.tv_sec, ev.time.tv_usec,
            //        ev.type, ev.code, ev.value);


            
        }
    }

    
    close(fd3);
    close(fd4);

    return 0;
}

test2.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/input.h>
#include <signal.h>
#include <time.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <errno.h>
#include <string.h>
static int timer_fd = -1; // 定时器文件描述符
static int event_fd1, event_fd2;

// 定时器到期处理函数
void timer_handler(int sig, siginfo_t *si, void *uc) {
    // 读取event1和event2的数据
    (void)sig; // 告诉编译器这个变量是被特意弃用的
    (void)si;
    (void)uc;
}
// long long getTimeInMilliseconds() {
//     struct timespec spec;
//     clock_gettime(CLOCK_REALTIME, &spec);
//     return spec.tv_sec * 1000 + spec.tv_nsec / 1000000;
// }
void printCurrentTime() {
    time_t rawtime;
    struct tm * timeinfo;

    // 获取当前时间(自1970年1月1日以来的秒数)
    time(&rawtime);
    
    // 将秒数转换为本地时间的tm结构体
    timeinfo = localtime(&rawtime);

    // 打印格式化的时间字符串
    // long long nesc = getTimeInMilliseconds();
    printf("当前系统时间: %d-%02d-%02d %02d:%02d:%02d,  %lld\n",
           timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday,
           timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
}
int main() {
    struct sigaction sa;
    struct itimerspec its;
    struct epoll_event ev;
    int epoll_fd;
    struct input_event ev2;

    // 打开设备文件
    if ((event_fd1 = open("/dev/input/event1", O_RDONLY)) == -1 ||
        (event_fd2 = open("/dev/input/event2", O_RDONLY)) == -1) {
        perror("Failed to open device files");
        return EXIT_FAILURE;
    }

    // 创建定时器
    timer_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
    if (timer_fd == -1) {
        perror("Failed to create timer");
        return EXIT_FAILURE;
    }

    // 设置信号处理函数
    memset(&sa, 0, sizeof(sa));
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = timer_handler;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGRTMIN, &sa, NULL) == -1) {
        perror("Failed to set signal handler");
        return EXIT_FAILURE;
    }

    // 初始化定时器
    its.it_value.tv_sec = 0;
    // its.it_value.tv_nsec = 100000000; // 100毫秒,纳秒
    // its.it_value.tv_nsec = 10000000; // 10毫秒,纳秒
    its.it_interval = its.it_value;      // 重复周期与初始值相同
    if (timerfd_settime(timer_fd, 0, &its, NULL) == -1) {
        perror("Failed to arm timer");
        return EXIT_FAILURE;
    }

    // 设置EPOLL以监控定时器事件
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1) {
        perror("Failed to create epoll");
        return EXIT_FAILURE;
    }

    ev.events = EPOLLIN;
    ev.data.fd = timer_fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, timer_fd, &ev) == -1) {
        perror("Failed to add timer to epoll");
        return EXIT_FAILURE;
    }

    // 主循环,使用epoll_wait等待事件
    while (1) {
        int ready = epoll_wait(epoll_fd, &ev, 1, -1);
        if (ready == -1 && errno != EINTR) {
            perror("epoll_wait");
            break;
        }
        // 定时器触发,处理事件
        if (ready > 0 && ev.events & EPOLLIN) {
            read(timer_fd, &its, sizeof(its)); // 清除到期事件
            printCurrentTime();
             ssize_t bytes_read = read(event_fd1, &ev2, sizeof(struct input_event));
            if (bytes_read == -1) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    // 没有更多数据可读,继续下一轮循环
                    continue;
                } else {
                    perror("Read error");
                    break;
                }
            } else if (bytes_read != sizeof(struct input_event)) {
                fprintf(stderr, "Unexpected read size: %zd\n", bytes_read);
                continue;
            }
            printf("Time1: %ld.%06ld, Type: %d, Code: %u, Value: %d\n",
                   ev2.time.tv_sec, ev2.time.tv_usec,
                   ev2.type, ev2.code, ev2.value);
            //event2
            read(timer_fd, &its, sizeof(its)); // 清除到期事件
            bytes_read = read(event_fd2, &ev2, sizeof(struct input_event));
            if (bytes_read == -1) {
                if (errno == EAGAIN || errno == EWOULDBLOCK) {
                    // 没有更多数据可读,继续下一轮循环
                    continue;
                } else {
                    perror("Read error");
                    break;
                }
            } else if (bytes_read != sizeof(struct input_event)) {
                fprintf(stderr, "Unexpected read size: %zd\n", bytes_read);
                continue;
            }
            printf("Time2: %ld.%06ld, Type: %d, Code: %u, Value: %d\n",
                   ev2.time.tv_sec, ev2.time.tv_usec,
                   ev2.type, ev2.code, ev2.value);
        }
    }

    close(event_fd1);
    close(event_fd2);
    if (timer_fd != -1) close(timer_fd);
    return 0;
}

后面的test2好像打印不出来微秒级别的,用getevent -t +event节点会好点,显示跟内核打印的时间戳精度一致

碰到的难题:

1.开始因为不熟悉框架,在/dev下注册成功啦还是不知道叫啥名,这部分可以看sensor-dev.c,因为是杂项设备的注册规则,这个就遵循啦多种相同功能设备都使用同一个名称,代码太多就不copy太多

static int sensor_misc_device_register(struct sensor_private_data *sensor, int type)
{
	int result = 0;

	switch (type) {
	case SENSOR_TYPE_ANGLE:
		if (!sensor->ops->misc_dev) {
			sensor->fops.owner = THIS_MODULE;
			sensor->fops.unlocked_ioctl = angle_dev_ioctl;
			sensor->fops.open = angle_dev_open;
			sensor->fops.release = angle_dev_release;

			sensor->miscdev.minor = MISC_DYNAMIC_MINOR;
			sensor->miscdev.name = "angle";
			sensor->miscdev.fops = &sensor->fops;
		} else {
			memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev));
		}
		break;

	case SENSOR_TYPE_ACCEL:
		if (!sensor->ops->misc_dev) {
			sensor->fops.owner = THIS_MODULE;
			sensor->fops.unlocked_ioctl = gsensor_dev_ioctl;
			#ifdef CONFIG_COMPAT
			sensor->fops.compat_ioctl = gsensor_dev_ioctl;
			#endif
			sensor->fops.open = gsensor_dev_open;
			sensor->fops.release = gsensor_dev_release;

			sensor->miscdev.minor = MISC_DYNAMIC_MINOR;
			sensor->miscdev.name = "mma8452_daemon";
			sensor->miscdev.fops = &sensor->fops;
		} else {
			memcpy(&sensor->miscdev, sensor->ops->misc_dev, sizeof(*sensor->ops->misc_dev));
		}
		break;

2.rk平台时间戳到微妙级时会出现一部分问题(本文重点)

在hal层测试过程中,抓到的数据有问题,时间戳会出现波动异常,100ms的轮询延时,会出现10ms左右的波动,

调试中发现,厂商给的驱动有一个重读机制会重新做retry,根据寄存器状态再次读取需要上传的值,保证值的正确性,然而在驱动上传数据到接口时,这个状态寄存器并不稳定,可能1次到10次的概率过这个case,所以我直接删掉啦retry的这个机制,

如果有做过这个的人就可能有疑问,那上传的值是不是就是上次上传的值,导致hal报错呢,这个我再补充一下机制,hal层是100ms采样,然而sensor的采样是可以设定的,驱动中设定的是5ms的采样,删除retry机制也不会影响到寄存器中已经更新的数据,这个部分就解决啦一部分时间戳的问题,

为啥说解决的是一部分你,因为后面测试还是有概率(大概hal采样几十次)出现一次到2次的不稳定现象,这个问题查啦2天,后面锁定在rk平台在做工作队列的唤醒时出现的问题,

假如打印的位置sensor-dev.c

实际测试:

异常100ms是因为rk平台有补偿值可以修改,一个轮询的时间我已经补偿到92-93是属于正常,100ms就是突然出现的一次,这个目前还不知道怎么修改,只能暂时先用着,

做完总结,sensor驱动只是移植还是挺简单的,主要是写测试,了解平台以及调整时间戳有点恶心

最终版本在这个链接:rk平台sensor驱动开发结束篇_rk1106 sensor slave id-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值