微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > 嵌入式系统设计讨论 > 8.WaRP7开发板上传感器模块FXOS8700CQ和MPL3115A2简单使用。

8.WaRP7开发板上传感器模块FXOS8700CQ和MPL3115A2简单使用。

时间:10-02 整理:3721RD 点击:
  FXOS8700CQ模块是一款体积小,功耗低的6轴加速度和重力传感器。有i2c和spi接口,14位加速度数据输出,16位重力数据输出。   我总结对类似I2c接口的传感器可以从以下几个方面入手研究:
   1.明确传感器在SOC上的接线情况,确认接到i2c1上还是i2c2上,我们这里接到i2c3上,但是我没有找到接线原理图,只是从参考代码确定;
   2.从dts文件冲判断模块的一些参数设置,   

  1. &i2c4 {
  2.         clock-frequency = <100000>;
  3.         pinctrl-names = "default";
  4.         pinctrl-0 = <&pinctrl_i2c4>;
  5.         status = "okay";

  6.         fxas2100x@20 {
  7.                 compatible = "fsl,fxas2100x";
  8.                 reg = <0x20>;
  9.         };

  10.         fxos8700@1e {
  11.                 compatible = "fsl,fxos8700";
  12.                 reg = <0x1e>;
  13.         };

  14.         mpl3115@60 {
  15.                 compatible = "fsl,mpl3115";
  16.                 reg = <0x60>;
  17.         };

  18.         codec: sgtl5000@0a {
  19.                 #sound-dai-cells = <0>;
  20.                 reg = <0x0a>;
  21.                 compatible = "fsl,sgtl5000";
  22.                 clocks = <&clks IMX7D_AUDIO_MCLK_ROOT_CLK>;
  23.                 VDDA-supply = <&vgen4_reg>;
  24.                 VDDIO-supply = <&vgen4_reg>;
  25.         };
  26. };

复制代码


   3.找到相应的驱动程序(也许没有驱动程序)
   将近1000行的代码,这里就不在贴出,有兴趣去看看源代码,这里只列出关键点:
   3.1驱动入口函数:

  1. static const struct i2c_device_id fxos8700_id[] = {
  2.         {"fxos8700", 0},
  3.         { /* sentinel */ }
  4. };
  5. MODULE_DEVICE_TABLE(i2c, fxos8700_id);

  6. static SIMPLE_DEV_PM_OPS(fxos8700_pm_ops, fxos8700_suspend, fxos8700_resume);
  7. static struct i2c_driver fxos8700_driver = {
  8.         .driver = {
  9.                    .name = FXOS8700_DRIVER,
  10.                    .owner = THIS_MODULE,
  11.                    .pm = &fxos8700_pm_ops,
  12.                    },
  13.         .probe = fxos8700_probe,
  14.         .remove = fxos8700_remove,
  15.         .id_table = fxos8700_id,
  16. };

  17. module_i2c_driver(fxos8700_driver);

复制代码

  3.2驱动探针函数中注册两个misc类似的字符杂项设备。

  1. result = misc_register(&fxos8700_acc_device);
  2.         if (result != 0) {
  3.                 printk(KERN_ERR "register acc miscdevice error");
  4.                 goto err_regsiter_acc_misc;
  5.         }
  6.         pdata->acc_miscdev = &fxos8700_acc_device;

  7.         result = misc_register(&fxos8700_mag_device);
  8.         if (result != 0) {
  9.                 printk(KERN_ERR "register acc miscdevice error");
  10.                 goto err_regsiter_mag_misc;
  11.         }

复制代码

3.3加速度ioctl函数读取x,y,z的数值,详细实现必须结合传感器datasheet的内容0x1,0x2,0x3,如下图内容。

  1. case SENSOR_GET_RAW_DATA:
  2.                 position = atomic_read(&pdata->position);
  3.                 ret = fxos8700_read_data(pdata->client, &data, FXOS8700_TYPE_ACC);
  4.                 if (!ret) {
  5.                         fxos8700_data_convert(&data, position);
  6.                         sdata[0] = data.x;
  7.                         sdata[1] = data.y;
  8.                         sdata[2] = data.z;
  9.                         if (copy_to_user(argp, sdata, sizeof(sdata))) {
  10.                                 printk(KERN_ERR "SENSOR_GET_RAW_DATA copy_to_user failed.");
  11.                                 ret = -EFAULT;
  12.                         }
  13.                 }
  14.                 break;

复制代码



   3.4重力实现与加速度实现类似,只是传感器寄存器不同0x33,0x34,0x35,0x36,0x37,0x38,见下图:


   4.应用程序获取传感器输出结果
    4.1应用程序源代码如下:

  1. /* *************************************************************
  2. * File name:  
  3. * Function:   
  4. * Description:
  5. *
  6. * *************************************************************/
  7. #include "i2c_io.h"

  8. static int fd;
  9. char I2C_DevName_String[] = "/dev/i2c-3";
  10. char *I2C_DevName = I2C_DevName_String;
  11. unsigned int I2C_SLAVE_Address = 0x1E;

  12. #define        SENSOR_IOCTL_BASE                'S'
  13. #define        SENSOR_GET_MODEL_NAME                _IOR(SENSOR_IOCTL_BASE, 0, char *)
  14. #define        SENSOR_GET_POWER_STATUS                _IOR(SENSOR_IOCTL_BASE, 2, int)
  15. #define        SENSOR_SET_POWER_STATUS                _IOR(SENSOR_IOCTL_BASE, 3, int)
  16. #define        SENSOR_GET_DELAY_TIME                _IOR(SENSOR_IOCTL_BASE, 4, int)
  17. #define        SENSOR_SET_DELAY_TIME                _IOR(SENSOR_IOCTL_BASE, 5, int)
  18. #define        SENSOR_GET_RAW_DATA                _IOR(SENSOR_IOCTL_BASE, 6, short[3])

  19. #define FXOS8700CQ_SLAVE_ADRESS   0xC7

  20. #define FXOS8700CQ_OUT_X_MSB   0x1
  21. #define FXOS8700CQ_OUT_X_LSB   0x2
  22. #define FXOS8700CQ_OUT_Y_MSB   0x3
  23. #define FXOS8700CQ_OUT_Y_LSB   0x4
  24. #define FXOS8700CQ_OUT_Z_MSB   0x5
  25. #define FXOS8700CQ_OUT_Z_LSB   0x6
  26. #define FXOS8700CQ_WHO_AM_I    0x0D
  27. typedef struct _SRAWDATA {
  28.         int16_t x;
  29.         int16_t y;
  30.         int16_t z;
  31. } SRAWDATA;
  32. /*********************************************
  33. *fxos8700cq chip id
  34. *fxos8700cq_chipid
  35. *      
  36. *      
  37. * erro -> -1    sucess -> 0
  38. **********************************************/
  39. int fxos8700cq_read_chip_id(int fd,int* fxos8700cq_chipid)
  40. {
  41.         char buf;       
  42.         int ret;
  43.        
  44.         ret= iic_read(fd,&buf,FXOS8700CQ_WHO_AM_I,1);
  45.         if(ret < 0){
  46.                 printf(" <erro> fxos8700cq_chip_id failed \n");
  47.                 return ret;
  48.         }
  49.        
  50.         if(buf != FXOS8700CQ_SLAVE_ADRESS){
  51.                 *fxos8700cq_chipid = 0;
  52.                 return -1;
  53.         }       
  54.        
  55.         //return fxos8700cq_chipid value   
  56.         *fxos8700cq_chipid = buf;       
  57.         printf(" fxos8700cq_chip_id:0x%x\n", *fxos8700cq_chipid);
  58.         return 0;
  59. }
  60. static int read_register(int file, unsigned char address, unsigned char reg, unsigned char *data)
  61. {
  62.         unsigned char input_buffer, output_buffer;
  63.         struct i2c_rdwr_ioctl_data packets;
  64.         struct i2c_msg messages[2];

  65.         output_buffer = reg;
  66.         messages[0].addr= address;
  67.         messages[0].flags = 0;
  68.         messages[0].len = sizeof(output_buffer);
  69.         messages[0].buf = &output_buffer;

  70.         messages[1].addr= address;
  71.         messages[1].flags = I2C_M_RD;
  72.         messages[1].len = sizeof(input_buffer);
  73.         messages[1].buf = &input_buffer;

  74.         packets.msgs= messages;
  75.         packets.nmsgs = 2;
  76.         if(ioctl(file, I2C_RDWR, &packets) < 0) {
  77.                 perror("Error sending data");
  78.                 return 1;
  79.         }
  80.         *data = input_buffer;
  81.        
  82.         return 0;
  83. }
  84. int main(int argc, char* argv[])
  85. {
  86.         int i = 0;
  87.         int ret = 0;
  88.         int fd = 0;
  89.         int fd_mag = 0;
  90.         int file = 0;
  91.         unsigned char fxos8700cq_chipid;
  92.   char buf[8] = "";       
  93.         int tmp_msb = 0;
  94.         int tmp_lsb = 1;
  95.         int* nStatus = &tmp_lsb;
  96.         fxos8700_data_axis mfxos8700_data_axis;
  97.         fxos8700_data_axis* pfxos8700_acc_axis;
  98.         pfxos8700_acc_axis = &mfxos8700_data_axis;
  99.        
  100. //        printf("Test for FXOS8700CQ (3-axis linear accelerometer)\n");
  101.   printf("Please check the device ID (Should be 0xC7)\n");
  102.         if ((file = open("/dev/i2c-3", O_RDWR)) < 0)
  103.         {
  104.                 perror("Error openning file!");
  105.                 exit(1);
  106.         }
  107.         if(read_register(file, I2C_SLAVE_Address, FXOS8700CQ_WHO_AM_I, &fxos8700cq_chipid))
  108.                 exit(1);
  109.         else
  110.         {
  111.                 {
  112.                         printf("GET:Register[0x%02X]: whoami-deviceID=0x%02X\n" , 0x1e , fxos8700cq_chipid);
  113.                 }
  114.         }
  115.         close(file);       
  116.        
  117.         if ((fd = open("/dev/FreescaleAccelerometer", O_RDWR)) < 0)
  118.         {
  119.                 perror("Error openning /dev/FreescaleAccelerometer!");
  120.                 exit(1);
  121.         }

  122.         pfxos8700_acc_axis->x = 0;
  123.         pfxos8700_acc_axis->y = 0;
  124.         pfxos8700_acc_axis->z = 0;
  125.         printf("=1= pfxos8700_acc_axis->x=%d, pfxos8700_acc_axis->y=%d, pfxos8700_acc_axis->z=%d\n", pfxos8700_acc_axis->x, pfxos8700_acc_axis->y, pfxos8700_acc_axis->z);
  126.         for(i = 0; i < 5; i++)
  127.         {
  128.                 ret = ioctl(fd,SENSOR_GET_RAW_DATA,pfxos8700_acc_axis);   //I2C
  129.                 printf("=2= pfxos8700_acc_axis->x=%d, pfxos8700_acc_axis->y=%d, pfxos8700_acc_axis->z=%d\n", pfxos8700_acc_axis->x, pfxos8700_acc_axis->y, pfxos8700_acc_axis->z);
  130.         }
  131.         close(fd);
  132.         if ((fd_mag = open("/dev/FreescaleMagnetometer", O_RDWR)) < 0)
  133.         {
  134.                 perror("Error openning /dev/FreescaleMagnetometer!");
  135.                 exit(1);
  136.         }

  137.         pfxos8700_acc_axis->x = 0;
  138.         pfxos8700_acc_axis->y = 0;
  139.         pfxos8700_acc_axis->z = 0;
  140.         printf("=1= pfxos8700_mag_axis->x=%d, pfxos8700_mag_axis->y=%d, pfxos8700_mag_axis->z=%d\n", pfxos8700_acc_axis->x, pfxos8700_acc_axis->y, pfxos8700_acc_axis->z);
  141.         for(i = 0; i < 5; i++)
  142.         {
  143.                 ret = ioctl(fd_mag,SENSOR_GET_RAW_DATA,pfxos8700_acc_axis);   //I2C
  144.                 printf("=2= pfxos8700_mag_axis->x=%d, pfxos8700_mag_axis->y=%d, pfxos8700_mag_axis->z=%d\n", pfxos8700_acc_axis->x, pfxos8700_acc_axis->y, pfxos8700_acc_axis->z);
  145.         }
  146.         close(fd_mag);
  147.        


  148.         return 0;
  149. }

复制代码

  4.2测试结果:


   4.3测试结果每次都一样,但是前面测试的时候输出结果并不是每次都一样,还有其具体含义需要与业务联系。
   MPL3115A2使用一MEMS压力传感器, 带有I2C接口, 可提供精准的电压/高度和温度数据. 这一传感器为数字化输出, 使用一个高分辨率的24位模数转换器. 内部处理省去了主控MCU系统的补偿任务. 另有多个可用户编程, 电源节约, 中断和自治数据采集模式, 包括已编程的采集周期计时器和只轮询模式. 典型电源电流为40μA每测量-秒, 用于稳定的10cm输出分辨率。
  从读取传感器输出结果的角度来说,MPL3115A2和FXOS8700CQ是一样的,因为他们都使用IIC接口,只是传感器寄存器不同而已,但是因为MPL3115A2驱动没有FXOS8700CQ驱动那么强大,所以我们可以换一个方法来读取传感器输出结果。
   应用程序代码如下:

  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <linux/i2c.h>
  4. #include <linux/i2c-dev.h>
  5. #include <fcntl.h>
  6. #include <stdlib.h>
  7. #include <unistd.h>
  8. #include <sys/ioctl.h>
  9. #include <string.h>

  10. //#define FLAG_DBG_ENABLE 1

  11. static int write_register(int file,unsigned char address,unsigned char reg,unsigned char data)
  12. {
  13.         unsigned char output_buffer[2];
  14.         struct i2c_rdwr_ioctl_data packets;
  15.         struct i2c_msg messages[1];
  16.        
  17.         messages[0].addr= address;
  18.         messages[0].flags = 0;
  19.         messages[0].len = sizeof(output_buffer);
  20.         messages[0].buf = output_buffer;
  21.        
  22.         output_buffer[0] = reg;
  23.         output_buffer[1] = data;
  24.        
  25.         packets.msgs= messages;
  26.         packets.nmsgs = 1;
  27.        
  28.         if(ioctl(file, I2C_RDWR, &packets) < 0) {
  29.                 perror("Error sending data");
  30.                 return 1;
  31.         }
  32.         return 0;
  33. }




  34. static int read_register(int file, unsigned char address, unsigned char reg, unsigned char *data)
  35. {
  36.         unsigned char input_buffer, output_buffer;
  37.         struct i2c_rdwr_ioctl_data packets;
  38.         struct i2c_msg messages[2];

  39.         output_buffer = reg;
  40.         messages[0].addr= address;
  41.         messages[0].flags = 0;
  42.         messages[0].len = sizeof(output_buffer);
  43.         messages[0].buf = &output_buffer;

  44.         messages[1].addr= address;
  45.         messages[1].flags = I2C_M_RD;
  46.         messages[1].len = sizeof(input_buffer);
  47.         messages[1].buf = &input_buffer;

  48.         packets.msgs= messages;
  49.         packets.nmsgs = 2;
  50.         if(ioctl(file, I2C_RDWR, &packets) < 0) {
  51.                 perror("Error sending data");
  52.                 return 1;
  53.         }
  54.         *data = input_buffer;
  55.        
  56.         return 0;
  57. }

  58. int main() {
  59.         int file, i;
  60.         unsigned char data;
  61.         int val1;
  62.         int val2;
  63.         float t_m;
  64.         int choice;
  65.         int DBG_ENABLE = 1;
  66.         char string[200];
  67. #ifdef FLAG_DBG_ENABLE
  68.         printf("Enable Debugging [1-Enable/0-Disable] :");
  69.         scanf("%d",&choice);
  70.        
  71.        
  72.         if (choice == 1)
  73.                 DBG_ENABLE = 1;
  74.         else if (choice == 0)
  75.                 DBG_ENABLE = 0;
  76.         else
  77.         {
  78.                 printf("Unknown choice \n Exiting... \n");
  79.                 exit(1);
  80.         }
  81.         #endif
  82.        
  83.         if ((file = open("/dev/i2c-3", O_RDWR)) < 0)
  84.         {
  85.                 perror("Error openning file!");
  86.                 exit(1);
  87.         }

  88. #ifdef FLAG_DBG_ENABLE

  89.         if(DBG_ENABLE == 0)
  90.                 printf("Debugging Disabled \n");
  91.         else if(DBG_ENABLE == 1)
  92.                 printf("Debugging Enabled \n");
  93.         else
  94.                 printf("No idea");
  95.         #endif




  96.         //0x0C whoami verify
  97.         if(read_register(file, 0x60, 0x0C, &data))
  98.                 exit(1);
  99.         else
  100.         {
  101.                 if(DBG_ENABLE == 1)
  102.                 {
  103.                         printf("GET:Register[0x%02X]: whoami-deviceID=0x%02X\n" , 12 , data);
  104.                 }
  105.         }
  106.         //0x26 ctrlreg1 get/set ACTIVE
  107.         if(read_register(file, 0x60, 0x26, &data))
  108.                 exit(1);
  109.         else
  110.         {
  111.                 if(DBG_ENABLE == 1)
  112.                 {
  113.                         printf("GET:Register[0x%02X]: CTRL_REG1=0x%02X\n" , 38 , data);
  114.                 }
  115.         }




  116.         if(write_register(file, 0x60, 0x26, 0x03 | 0x80))
  117.                 exit(1);
  118.         else
  119.         {
  120.                 if(read_register(file, 0x60, 0x26, &data))
  121.                  exit(1);
  122.                 else
  123.                 {
  124.                         if(DBG_ENABLE == 1)
  125.                         {
  126.                                 printf("SET/GET:Register[0x%02X]: CTRL_REG1=0x%02X\n" , 38 , data);
  127.                         }
  128.                 }
  129.         }


  130.         int counter=0;
  131.         while(counter<5)
  132.         {
  133.                 //read temperature MSB/LSB
  134.                 if(read_register(file, 0x60, 0x04, &data))
  135.                 exit(1);
  136.                 /* else*/
  137.                 /*{ if(DBG_ENABLE == 1)*/
  138.                 /*{ printf("Register[0x%02X]: 0x%02X\n" , 4 , data);*/
  139.                 /*}*/
  140.                 /*}*/
  141.                
  142.                 val2 = (int)data;
  143.                 if(DBG_ENABLE == 1) printf("val2: initial :%d:\n",val2);
  144.                 val2 <<=4;
  145.                 //if(DBG_ENABLE == 1) printf("val2: shift :%d:\n",val2);
  146.                 if(read_register(file, 0x60, 0x05, &data))
  147.                 exit(1);
  148.                 else
  149.                 {
  150.                 if(DBG_ENABLE == 1)
  151.                 printf("Register[0x%02X]: 0x%02X\n" , 5 , data);
  152.                 }

  153.         //        val2 = val2+ (int)data;
  154.        
  155.         t_m = (float)data;
  156. //        printf("=1=t_m :%f:\n",t_m);
  157.         t_m = t_m / 1000;
  158.         printf("=2=t_m :%f:\n",t_m);
  159.                 if(DBG_ENABLE == 1)
  160.                 { //printf("val2 :%d:\n",val2);
  161.                 }

  162.                 t_m = t_m + (val2 >> 4);// & 0xff;

  163.                 printf("temperature :%.3f: \n",t_m);
  164.                 //printf("temperature string:%d: \n",string);
  165.         if(read_register(file, 0x60, 0x01, &data))
  166.                 exit(1);
  167.                 /* else*/
  168.                 /*{ if(DBG_ENABLE == 1)*/
  169.                 /*{ printf("Register[0x%02X]: 0x%02X\n" , 4 , data);*/
  170.                 /*}*/
  171.                 /*}*/
  172.                
  173.                 val2 = (int)data;
  174.                 if(DBG_ENABLE == 1) printf("val2: initial :%d:\n",val2);
  175.                 val2 <<=8;
  176.         if(read_register(file, 0x60, 0x02, &data))
  177.                 exit(1);
  178.                 /* else*/
  179.                 /*{ if(DBG_ENABLE == 1)*/
  180.                 /*{ printf("Register[0x%02X]: 0x%02X\n" , 4 , data);*/
  181.                 /*}*/
  182.                 /*}*/
  183.                
  184.                 val1 = (int)data;
  185.                 if(DBG_ENABLE == 1) printf("val1: initial :%d:\n",val1);
  186.                 val2 = val1 + val2;
  187.                 printf("altitude :%d: m\n", val2);
  188.                 //system(string);
  189.                 sleep(1);
  190.                 counter++;
  191.         }
  192.         close(file);
  193.         return 0;
  194. }

复制代码

   输出结果下:


  输出结果分析:
  1.虽然目前家里的温度大约是29左右,但是开发板的温度还是比较高,所以39度算是一个比较合理的数值,曾经对比电风扇吹一会的实验,电风扇开启前后温度输出有比较明显的变化,从44度可以下降到36度左右,我认为温度输出结果符合实际,当然真的做产品则需要更加准确和测试;
  2.关于高度的输出结果,目前的几个是80m,考虑北京的平均海拔40-50m,而我家是11楼,大概高度也有35-44m左右,这个高度输出也在合理的范围内,但是刚开始读取数值大约是136m左右,后面又测试是110m左右。这里可以认为是传感器测试需要一定时间来达到一个稳定数值。
   本来以为开发板没有集成陀螺仪传感器,后来才知道FXAS21002CQR1就是,不过这个传感器与前面的FXOS8700CQ模块很类似,驱动也基本一样,所以这里就不在研究,如果后面有时间则把这个三部分数据集成起来实现功能:“使能“多重感知”设备磁力-加速计,气压计,陀螺仪。并将数据简单处理然后通过wifi发送给固定PC。”。
  下面会看看电池和电源管理的功能实现。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top