g-sensor bmc156数据传输流程(compass部分)

刚入门的小白第一次写博客,望各路大神指点
一、硬件电路
g-sensor bmc156数据传输流程(compass部分)_第1张图片
连接到主芯片的管脚

二、设备树

Msm8909.dtsi     Master
i2c_1: i2c@78b5000 { /* BLSP1 QUP1 */
        compatible = "qcom,i2c-msm-v2";
        #address-cells = <1>;
        #size-cells = <0>;
        reg-names = "qup_phys_addr";
        reg = <0x78b5000 0x1000>;
        interrupt-names = "qup_irq";
        interrupts = <0 95 0>;
        clocks = <&clock_gcc clk_gcc_blsp1_ahb_clk>,
                 <&clock_gcc clk_gcc_blsp1_qup1_i2c_apps_clk>;
        clock-names = "iface_clk", "core_clk";
        qcom,clk-freq-out = <100000>;
        qcom,clk-freq-in  = <19200000>;
        pinctrl-names = "i2c_active", "i2c_sleep";
        pinctrl-0 = <&i2c_1_active>;
        pinctrl-1 = <&i2c_1_sleep>;
        qcom,noise-rjct-scl = <0>;
        qcom,noise-rjct-sda = <0>;
        dmas = <&dma_blsp1 4 64 0x20000020 0x20>,
            <&dma_blsp1 5  32 0x20000020 0x20>;
        dma-names = "tx", "rx";
        qcom,master-id = <86>;
    };
Msm8909-pinctrl.dtsi
pmx_i2c_1 {  /* CLK, DATA */
            qcom,pins = <&gp 6>, <&gp 7>;
            qcom,num-grp-pins = <2>;
            qcom,pin-func = <3>;
            label = "pmx_i2c_1";
            i2c_1_active: i2c_1_active {
                drive-strength = <2>; /* 2 MA */
                bias-disable = <0>; /* No PULL */
            };
            i2c_1_sleep: i2c_1_sleep {
                drive-strength = <2>; /* 2 MA */
                bias-pull-down; /* PULL DOWN */
            };
        };
Msm8909-Q9-mtp.dtsi client
    bosch@10 { /* Accelerometer sensor */
        compatible = "bosch,bma2x2";
        reg = <0x10>;
        vdd-supply = <&pm8909_l17>;
        vio-supply = <&pm8909_l6>;
    };
    bosch@12 { /* Magnetic field sensor */
        compatible = "bosch,bmm050";
        reg = <0x12>;
        vdd-supply = <&pm8909_l17>;
        vio-supply = <&pm8909_l6>;
    };

三、 Makefile 文件
确保所有添加的驱动文件都包含在Makefile中,会被编译进去

obj-$(CONFIG_SENSORS_BMA2X2)   += bma2x2_driver.o
ccflags-y += -DBMA2X2_SENSOR_IDENTIFICATION_ENABLE
obj-$(CONFIG_SENSORS_BMM050)    += bmm050_driver.o bmm050.o
ccflags-y += -DBMM_USE_BASIC_I2C_FUNC -DCONFIG_BMM_USE_PLATFORM_DATA

四、 Config文件

config SENSORS_BMA2X2
    tristate "BMA255/BMA250E/BMA222E/BMA280 acceleration sensor support"
    depends on I2C
    help
      If you say yes here you get support for Bosch Sensortec's
      acceleration sensors BMA255/BMA250E/BMA222E/BMA280.

config SENSORS_BMA2X2_ENABLE_INT1
    tristate "BMA2X2 acceleration sensor interrupt INT1 support"
    depends on SENSORS_BMA2X2 && !SENSORS_BMA2X2_ENABLE_INT2
    help
     If you say yes here you get INT1 support for Bosch Sensortec
     acceleration sensors BMA255/BMA250E/BMA222E/BMA280.
     Select it will disable interrupt INT2 support

config BOSCH_BMA2X2_ENABLE_INT2
    tristate "BMA2X2 acceleration sensor interrupt INT2 support"
    depends on SENSORS_BMA2X2 && !SENSORS_BMA2X2_ENABLE_INT1
    help
     If you say yes here you get INT2 support for Bosch Sensortec
     acceleration sensors BMA255/BMA250E/BMA222E/BMA280.
     Can only open if you do NOT open interrupt INT1 support

config SIG_MOTION
    tristate "support significant motion sensor function"
    depends on SENSORS_BMA2X2  && ( SENSORS_BMA2X2_ENABLE_INT1 || BOSCH_BMA2X2_ENABLE_INT2)
    help
     Say Y here if you want to support Bosch significant motion sensor function

config DOUBLE_TAP
    tristate "support double tap sensor function"
    depends on SENSORS_BMA2X2  && ( SENSORS_BMA2X2_ENABLE_INT1 || BOSCH_BMA2X2_ENABLE_INT2)
    help
     Say Y here if you want to support Bosch double tap sensor function

config SENSORS_BMM050
    tristate "BMM050 Magnetic Sensor Driver"
    depends on I2C
    help
     BMM050 Magnetic Sensor Driver implemented by Bosch-Sensortec.

五、 数据流程分析(kernel ->framework)
1、kernel部分
BMC156是acceleration和compass的结合,但是我们还是需要将它看作两个单独的sensor,但是软件原理相差不大,所以我们以compass为例进行叙述。(##此处I2C读出数据(无论对错)代表硬件没有问题且初始化成功)

1) Kernel/driver/bmm050.c bmm050_read_mdataXYZ_s32
这里是最初I2C从寄存器中读取xyz值的地方。XYZ的值存储在两个寄存器中(LSB、MSB),所以在读取寄存器中的值之后会进行位运算得出真正的XYZ值

BMM050_RETURN_FUNCTION_TYPE bmm050_read_mdataXYZ_s32(
    struct bmm050_mdata_s32 *mdata)
{
    BMM050_RETURN_FUNCTION_TYPE comres;

    unsigned char a_data_u8r[8] = "";

    struct {
        BMM050_S16 raw_dataX;
        BMM050_S16 raw_dataY;
        BMM050_S16 raw_dataZ;
        BMM050_U16 raw_dataR;
    } raw_dataXYZ;

    if (p_bmm050 == BMM050_NULL) {
        comres = E_BMM050_NULL_PTR;
    } else {
        comres = p_bmm050->BMM050_BUS_READ_FUNC(p_bmm050->dev_addr,
                BMM050_DATAX_LSB, a_data_u8r, 8);

        /* Reading data for X axis */
        a_data_u8r[0] = BMM050_GET_BITSLICE(a_data_u8r[0],
                BMM050_DATAX_LSB_VALUEX);
        raw_dataXYZ.raw_dataX = (BMM050_S16)((((BMM050_S16)
                        ((signed char)a_data_u8r[1])) <<
                    SHIFT_LEFT_5_POSITION) | a_data_u8r[0]);

        /* Reading data for Y axis */
        a_data_u8r[2] = BMM050_GET_BITSLICE(a_data_u8r[2],
                BMM050_DATAY_LSB_VALUEY);
        raw_dataXYZ.raw_dataY = (BMM050_S16)((((BMM050_S16)
                        ((signed char)a_data_u8r[3])) <<
                    SHIFT_LEFT_5_POSITION) | a_data_u8r[2]);

        /* Reading data for Z axis */
        a_data_u8r[4] = BMM050_GET_BITSLICE(a_data_u8r[4],
                BMM050_DATAZ_LSB_VALUEZ);
        raw_dataXYZ.raw_dataZ = (BMM050_S16)((((BMM050_S16)
                        ((signed char)a_data_u8r[5])) <<
                    SHIFT_LEFT_7_POSITION) | a_data_u8r[4]);
PINFO("x = %d , y = %d ,z = %d \n",raw_dataXYZ.raw_dataX,raw_dataXYZ.raw_dataY,raw_dataXYZ.raw_dataZ);  // 1、此处是寄存器中的xyz值
        /* Reading data for Resistance*/
        if (!comres)
            mdata->drdy = BMM050_GET_BITSLICE(a_data_u8r[6],
                    BMM050_DATA_RDYSTAT);

        a_data_u8r[6] = BMM050_GET_BITSLICE(a_data_u8r[6],
                BMM050_R_LSB_VALUE);
        raw_dataXYZ.raw_dataR = (BMM050_U16)((((BMM050_U16)
                        a_data_u8r[7]) <<
                    SHIFT_LEFT_6_POSITION) | a_data_u8r[6]);

        /* Compensation for X axis */
        mdata->datax = bmm050_compensate_X_s32(raw_dataXYZ.raw_dataX,
                raw_dataXYZ.raw_dataR);

        /* Compensation for Y axis */
        mdata->datay = bmm050_compensate_Y_s32(raw_dataXYZ.raw_dataY,
                raw_dataXYZ.raw_dataR);

        /* Compensation for Z axis */
        mdata->dataz = bmm050_compensate_Z_s32(raw_dataXYZ.raw_dataZ,
                raw_dataXYZ.raw_dataR);
            // 2、在观察到磁力值(x/y/z)正负不对称的时候,可以用excel将下方的log打出的xyz值制成散点图(x-y,x-z),观察图中偏差值,以校正xyz,保证圆心在圆点(文档最后会介绍)
        /* Output raw resistance value */
        mdata->resistance = raw_dataXYZ.raw_dataR;
        PINFO("x = %d , y = %d ,z = %d \n",mdata->datax,mdata->datay,mdata->dataz);
        // 3、此处读出的是对寄存器中的值进行校正、补偿之后的值
    }
    return comres;
}

2) Kernel/driver/bmm050_driver.c bmm_work_func
compass kernel对hardware的接口

static void bmm_work_func(struct work_struct *work)
{
    struct bmm_client_data *client_data =
        container_of((struct delayed_work *)work,
            struct bmm_client_data, work);
    struct i2c_client *client = client_data->client;
    unsigned long delay =
        msecs_to_jiffies(atomic_read(&client_data->delay));

    mutex_lock(&client_data->mutex_value);

    //使用FORCED_MODE,因为相较于NORMAL_MODE准确度更高,但一般使用NORMAL_MODE就够了
    mutex_lock(&client_data->mutex_op_mode);
    if (BMM_VAL_NAME(NORMAL_MODE) != client_data->op_mode)
        bmm_set_forced_mode(client);

    mutex_unlock(&client_data->mutex_op_mode);

    //这里调用了上文中的函数,读取硬件数据
    BMM_CALL_API(read_mdataXYZ_s32)(&client_data->value);
    bmm_remap_sensor_data(&client_data->value, client_data);

    //input_report_abs将kernel读到的数据都传输到hardware中
    input_report_abs(client_data->input, ABS_X, client_data->value.datax);
    input_report_abs(client_data->input, ABS_Y, client_data->value.datay);
    input_report_abs(client_data->input, ABS_Z, client_data->value.dataz);
    mutex_unlock(&client_data->mutex_value);
    /*printk("=============x=%d y=%d z=%d\n",client_data->value.datax,
    client_data->value.datay, client_data->value.dataz);*/
    input_sync(client_data->input);

    schedule_delayed_work(&client_data->work, delay);
}

2、 hardware 部分
1)hardware/sensors/CompassSensor.cpp CompassSensor::readEvents
这个文件是比较重要的,可以根据标志点调整xyz的方向(在kernel完成这部分调整比较好,层次清楚)。readEvents函数的作用是读取kernel上报的数据,并经过计算传递到上层。
打LOG:在打出时会发现data的log值会出现其他Sensor的值,例如Acceleration,这是正常的,因为几个Sensor是个union共用一个存储空间,这个可以看定义。data打出Compass的数据时会发现与result的值相同而可能与mPendingEvent有差异,这就需要看一下,这个差异是不是必要的。

int CompassSensor::readEvents(sensors_event_t* data, int count)
{
    if (count < 1)
        return -EINVAL;

    if (mHasPendingEvent) {
        mHasPendingEvent = false;
        mPendingEvent.timestamp = getTimestamp();
        *data = mPendingEvent;
        return mEnabled ? 1 : 0;
    }

    if (mHasPendingMetadata) {
        mHasPendingMetadata--;
        meta_data.timestamp = getTimestamp();
        *data = meta_data;
        return mEnabled ? 1 : 0;
    }

    ssize_t n = mInputReader.fill(data_fd);
    if (n < 0)
        return n;

    int numEventReceived = 0;
    input_event const* event;
    sensors_event_t raw, result;

#if FETCH_FULL_EVENT_BEFORE_RETURN
again:
#endif
    while (count && mInputReader.readEvent(&event)) {
        int type = event->type;
        //Type == EV_ABS会循环3次,旨在将底层值赋给mPendingEvent.magnetic的x y z,在填充满之后type就会变成EV_SYN
        if (type == EV_ABS) {
            float value = event->value;
            if (event->code == EVENT_TYPE_MAG_X) {
                mPendingEvent.magnetic.x = value * res;// 此处的res一般为CONVERT_MAG ( 1/16 )
            } else if (event->code == EVENT_TYPE_MAG_Y) {
                mPendingEvent.magnetic.y = value * res;
            } else if (event->code == EVENT_TYPE_MAG_Z) {
                mPendingEvent.magnetic.z = value * res;
            }
        } else if (type == EV_SYN) {
            switch (event->code) {
                case SYN_TIME_SEC:
                    mUseAbsTimeStamp = true;
                    report_time = event->value*1000000000LL;
                    break;
                case SYN_TIME_NSEC:
                    mUseAbsTimeStamp = true;
                    mPendingEvent.timestamp = report_time+event->value;
                    break;
//在SYN_REPORTraw接了mPendingEvent的值,之后经过计算并赋给了result,最后传递给了data
                case SYN_REPORT:
                    if (mUseAbsTimeStamp != true) {
                        mPendingEvent.timestamp = timevalToNano(event->time);
                    }
                    if (mEnabled) {
                        raw = mPendingEvent;

                        if (algo != NULL) {
                            if (algo->methods->convert(&raw, &result, NULL)) {
                                ALOGE("Calibration failed.");
                                result.magnetic.x = CALIBRATE_ERROR_MAGIC;
                                result.magnetic.y = CALIBRATE_ERROR_MAGIC;
                                result.magnetic.z = CALIBRATE_ERROR_MAGIC;
                                result.magnetic.status = 0;
                            }
                        } else {
                            result = raw;
                        }
//这里可添加ALOGE (”Compass x = %f , y = %f , z = %f  celine\n ”, result.magnetic.x, result.magnetic.y, result.magnetic.z);
                        *data = result;
                        data->version = sizeof(sensors_event_t);
                        data->sensor = mPendingEvent.sensor;
                        data->type = SENSOR_TYPE_MAGNETIC_FIELD;
                        data->timestamp = mPendingEvent.timestamp;

                        /* The raw data is stored inside sensors_event_t.data after
                         * sensors_event_t.magnetic. Notice that the raw data is
                         * required to composite the virtual sensor uncalibrated
                         * magnetic field sensor.
                         *
                         * data[0~2]: calibrated magnetic field data.
                         * data[3]: magnetic field data accuracy.
                         * data[4~6]: uncalibrated magnetic field data.
                         */
                        data->data[4] = mPendingEvent.data[0];
                        data->data[5] = mPendingEvent.data[1];
                        data->data[6] = mPendingEvent.data[2];

                        data++;
                        numEventReceived++;
                        count--;
                    }
                    break;
            }
        } else {
            ALOGE("CompassSensor: unknown event (type=%d, code=%d)",
                    type, event->code);
        }
        ALOGE("Compass x = %f , y = %f , z = %f  celine\n",mPendingEvent.magnetic.x,mPendingEvent.magnetic.y,mPendingEvent.magnetic.z);
        ALOGE (”Compass x = %f , y = %f , z = %f  celine\n ”, data.magnetic.x, data.magnetic.y, data.magnetic.z);
        mInputReader.next();
    }

#if FETCH_FULL_EVENT_BEFORE_RETURN
    /* if we didn't read a complete event, see if we can fill and
       try again instead of returning with nothing and redoing poll. */
    if (numEventReceived == 0 && mEnabled == 1) {
        n = mInputReader.fill(data_fd);
        if (n)
            goto again;
    }
#endif

    return numEventReceived;
}

(3) hardware/sensors/NativeSensorManager.cpp NativeSensorManager::readEvents
相当于将所有Sensor的readEvents或injectEvents做了一个汇总(例如CompassSensor::readEvents和AccelSensor::readEvents),在这可以对所有Sensor的数据进行遍历,但一次只能一个Sensor

int NativeSensorManager::readEvents(int handle, sensors_event_t* data, int count)
{
    const SensorContext *list;
    int i, j;
    int number = getSensorCount();
    int nb;
    struct listnode *node;
    struct SensorRefMap *item;

    list = getInfoByHandle(handle);//根据handle确定Sensor,得到Sensor的list
    if (list == NULL) {
        ALOGE("Invalid handle(%d)", handle);
        return -EINVAL;
    }
    do {
        nb = list->driver->readEvents(data, count); //调用每个Sensor的readevents,获取数据存在data中
    } while ((nb == -EAGAIN) || (nb == -EINTR));

    for (j = 0; j < nb; j++) {
        list_for_each(node, &list->listener) {
            item = node_to_item(node, struct SensorRefMap, list);
            if (item->ctx->enable && (item->ctx != list)) {
                item->ctx->driver->injectEvents(&data[j], 1); //方向传感器之类的Sensor
            }
        }
    }

    if (list->enable)
        return nb;

    /* No need to report the events if the sensor is not enabled */
    return 0;
}

(4)harware/sensors/sensors.cpp Sensors_poll_context_t::pollEvents

int sensors_poll_context_t::pollEvents(sensors_event_t* data, int count)
{
    int nbEvents = 0;
    int n = 0;
    NativeSensorManager& sm(NativeSensorManager::getInstance());
    const sensor_t *slist;
    int number = sm.getSensorList(&slist);

    do {
        // 这是在根据Sensor设备的个数进行循环,相当于这个函数是在不停的对所有的Sensor进行轮询 poll()
        for (int i = 0 ; count && i < number ; i++) {
            if ((mPollFds[i].revents & POLLIN) || (sm.hasPendingEvents(slist[i].handle))) {
                Mutex::Autolock _l(mLock);
                int nb = sm.readEvents(slist[i].handle, data, count);
                //ALOGE("x : %f , y = %f , z =%f celine compass\n",data->magnetic.x,data->magnetic.y,data->magnetic.z);
                //ALOGE("azimuth : %f , pitch = %f , roll =%f celine compass\n",data->orientation.azimuth,data->orientation.pitch,data->orientation.roll);
                //调用到NativeSensorManager的readevents,读取Sensor数据,下面的两个log打出的x y z值会发现是一样的,所以导致每次上报的值只能根据handle来确定,无法像结构体一样读取固定的存储地址。
                if (nb < 0) {
                    ALOGE("readEvents failed.(%d)", errno);
                    return nb;
                }
                if (nb <= count) {
                    // no more data for this sensor
                    mPollFds[i].revents = 0;
                }
                count -= nb;
                nbEvents += nb;
                data += nb;
            }
        }

        if (count) {
            // we still have some room, so try to see if we can get
            // some events immediately or just wait if we don't have
            // anything to return
            do {
                n = poll(mPollFds, number + 1, nbEvents ? 0 : -1);
            } while (n < 0 && errno == EINTR);
            if (n<0) {
                ALOGE("poll() failed (%s)", strerror(errno));
                return -errno;
            }
            if (mPollFds[number].revents & POLLIN) {
                char msg;
                int result = read(mPollFds[number].fd, &msg, 1);
                ALOGE_IF(result<0, "error reading from wake pipe (%s)", strerror(errno));
                ALOGE_IF(msg != WAKE_MESSAGE, "unknown message on wake queue (0x%02x)", int(msg));
                mPollFds[number].revents = 0;
            }
        }
        // if we have events and space, go read them
    } while (n && count);

    return nbEvents;
}

(5)harware/sensors/sensors.cpp poll_poll

static int poll__poll(struct sensors_poll_device_t *dev,
        sensors_event_t* data, int count) {
    sensors_poll_context_t *ctx = (sensors_poll_context_t *)dev;
    return ctx->pollEvents(data, count);  //**
}

(6)harware/sensors/sensors.cpp open_sensors

static int open_sensors(const struct hw_module_t* module, const char*,
                        struct hw_device_t** device)
{
        int status = -EINVAL;
        sensors_poll_context_t *dev = new sensors_poll_context_t();
        NativeSensorManager& sm(NativeSensorManager::getInstance());

        memset(&dev->device, 0, sizeof(sensors_poll_device_1_ext_t));

        dev->device.common.tag = HARDWARE_DEVICE_TAG;
#if defined(SENSORS_DEVICE_API_VERSION_1_3)
        ALOGI("Sensors device API version 1.3 supported\n");
        dev->device.common.version = SENSORS_DEVICE_API_VERSION_1_3;
#else
        dev->device.common.version = SENSORS_DEVICE_API_VERSION_0_1;
#endif
        dev->device.common.module   = const_cast(module);
        dev->device.common.close    = poll__close;
        dev->device.activate        = poll__activate;
        dev->device.setDelay        = poll__setDelay;
        dev->device.poll        = poll__poll;  //**
        dev->device.calibrate       = poll_calibrate;
#if defined(SENSORS_DEVICE_API_VERSION_1_3)
        dev->device.batch       = poll__batch;
        dev->device.flush       = poll__flush;
#endif

        *device = &dev->device.common;
        status = 0;

        return status;
}

(7)harware/sensors/sensors.cpp

static struct hw_module_methods_t sensors_module_methods = {
            open: open_sensors  //**
};

这就是hardware对framework的接口HAL_MOUDLE_SYM,framework层根据id来选择模块

struct sensors_module_t HAL_MODULE_INFO_SYM = {
        common: {
                tag: HARDWARE_MODULE_TAG,
                version_major: 1,
                version_minor: 0,
                id: SENSORS_HARDWARE_MODULE_ID,
                name: "Quic Sensor module",
                author: "Quic",
                methods: &sensors_module_methods,   //**
                dso: NULL,
                reserved: {0},
        },
        get_sensors_list: sensors__get_sensors_list,
};

3、 framework 部分
(1)framework/native/services/sensorServices/SensorDevices.cpp SensorDevices::SensorDevice()

SensorDevice::SensorDevice()
    :  mSensorDevice(0),
       mSensorModule(0)
{
    status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
            (hw_module_t const**)&mSensorModule);   //获取sensor模块

    ALOGE_IF(err, "couldn't load %s module (%s)",
            SENSORS_HARDWARE_MODULE_ID, strerror(-err));

    if (mSensorModule) {
        err = sensors_open_1(&mSensorModule->common, &mSensorDevice);   //打开sensor设备

        ALOGE_IF(err, "couldn't open device for module %s (%s)",
                SENSORS_HARDWARE_MODULE_ID, strerror(-err));

        if (mSensorDevice) {
            if (mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_1 ||
                mSensorDevice->common.version == SENSORS_DEVICE_API_VERSION_1_2) {
                ALOGE(">>>> WARNING <<< Upgrade sensor HAL to version 1_3");
            }

            sensor_t const* list;
            ssize_t count = mSensorModule->get_sensors_list(mSensorModule, &list);  //获取sensor 列表 
            mActivationCount.setCapacity(count);
            Info model;//Sensor<->handle<->info model,都是一一对应的关系,所以SensorDevices去读hal层的数据后根据handle放在对应的info中以便上层使用,在这里的时候每个Sensor才有独立的存储空间存放自己的数据,好处:类似acc、compass这类的传感器会产生大量的数据导致占用大量的存储空间,但可能我们并不需要那么频繁的刷新,那么高的精确度,这样就会造成资源的浪费
            for (size_t i=0 ; ilist[i].handle, model);
                mSensorDevice->activate(
                        reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice),
                        list[i].handle, 0);
            }
        }
    }
}

1.通过SENSORS_HARDWARE_MODULE_ID获取Sensor模块,&mSensorModule
2.将该模块下的sensor设备公共部分打开,&mSensorDevice
3.获取该模块下的sensor list,&list(所有sensor),并记录下了sensor的个数count
4.for循环中,handle是用来识别sensor的,每一个sensor都会有一个独一无二的handle,这样用handle来标识 Info Model,相当于,每个sensor都有一个独立的Info,hal层传上来的数据就是放在这
5.对sensorDevice,根据handle逐个激活

六、 调试方法
1.Excel画图
上文中提到,在需要校准acceleration或者compass的数值时,我们可以使用excel制作散点图来观察数据是不是在以原点为圆心的圆上均匀分布的。校准x y z三个值的时候需要画两个散点图校准。
x – y
1) 在需要校准的地方(一般为kernel)加上打出 x y z的log,需有特殊词(如:picture)以便挑出log,在数据前后留出较大空格,以便之后导入数据( 如 x = %d , )。
2) 手机以x y 轴组成的面为平面旋转1~3周,确保在每个角度都打出了值,这一步可能需要重复多次(确认数据完整方法,观察数据例如从北顺时针转动手机时 x 值变化顺序是否为 正最大 –> 0 –> 负增大 -> 负减小 0 ->正增大)
3) 将以特殊词选出的log保存为txt格式,以便之后使用
4) 打开excel –> 数据 ->自文本 -> 选择 之前的txt文本 -> 按提示导入文本 ->选中列 x y –> 插入 ->散点图 down
5) 最终结果
g-sensor bmc156数据传输流程(compass部分)_第2张图片

2.打log
Kernel :#define DEBUG 打开PINFO
PINFO定义:#define PINFO( fmt , args…)
Printk (KERN_INFO “ \n ” “ [ I ] ” KERN_INFO MODULE_TAG “ < %s > < %d >” fmt “ \n ”,func , LINE ,##args) ;
< %s >:函数名
< %d >:行号
“##”的作用:如果可变参数部分(args …)被忽略或为空 , 那么 “##” 操作会使预处理器去掉它前面的逗号,使宏结束展开(补充完右边的括号)若在调用宏的时候确实提供了一些可变参数,GNU C 也会正常工作,它会把这些可变参数放在逗号后。
adb pull data/logger/kernel.log kernel.log

hardware : ALOGE
adb shell logcat –v time –b system –b event –b main –b radio > logcat_xxx.txt
kernel、hardware….都是单独编译,那么每个模块的log的定义必然都在该模块下,其中有些宏开关不是在代码中出现,而是在Makefile文件中,用来控制大量代码(可以编译出不同的版本),视情况改 (例如ALOGE)

3.调试顺序
1) 初始化是否正确,底层kernel是否可以读到数据,是否向hal层上报数据
2) Hal层是否可以从kernel读到数据(一致性),hal的数据是否上报给了framework
3) Framework是否接收到hal的数据(一致性)

你可能感兴趣的:(sensor)