Contents
3 Warp7 Sensors demo mpl3115a2 <-- You are here
4. Warp7 Sensors demo - fxos8700cq
The warp7 comes with mutiple MEMS sensors.
One of the highly popular sensors is the mpl3115 sensor.
For mpl3115 sensor there is i2c driver support in kernel, but I was interested in the temperature part and thought to write a userspace driver myself. Honestly the i2c interface isn't that difficult. I will write about other warp7 drivers in subsequent blogs. The mpl3115 can operate in either altimeter or barometer mode depending on config register settings. In this blog we will be exploring the temperature part of the sensor. The high precision mpl3115 with the small form factor warp7 is a prefect fit for IoT and smartwatch like devices.
enough praising the sensor, lets write a simple bare-metal application to access the sensor.
We will use the linux header files i2c-dev.h and i2c.h to perform read/write on i2c bus.
We need to define the register write function.
static int write_register(int file,unsigned char address,unsigned char reg,unsigned char data) { unsigned char output_buffer[2]; struct i2c_rdwr_ioctl_data packets; struct i2c_msg messages[1]; messages[0].addr = address; messages[0].flags = 0; messages[0].len = sizeof(output_buffer); messages[0].buf = output_buffer; output_buffer[0] = reg; output_buffer[1] = data; packets.msgs = messages; packets.nmsgs = 1; if(ioctl(file, I2C_RDWR, &packets) < 0) { perror("Error sending data"); return 1; } return 0; }
Similarly the register read function.
static int read_register(int file, unsigned char address, unsigned char reg, unsigned char *data) { unsigned char input_buffer, output_buffer; struct i2c_rdwr_ioctl_data packets; struct i2c_msg messages[2]; output_buffer = reg; messages[0].addr = address; messages[0].flags = 0; messages[0].len = sizeof(output_buffer); messages[0].buf = &output_buffer; messages[1].addr = address; messages[1].flags = I2C_M_RD; messages[1].len = sizeof(input_buffer); messages[1].buf = &input_buffer; packets.msgs = messages; packets.nmsgs = 2; if(ioctl(file, I2C_RDWR, &packets) < 0) { perror("Error sending data"); return 1; } *data = input_buffer; return 0; }
Probing...
probe the 0C(WHO_AM_I) register at i2c address 0x60.
Its should give a value hex value C4.
i2ctools package comes handy here, install it sudo apt-get install i2c-tools
$ i2cget -y 3 0x60 0x0C
0xc4
reading WHO_AMI_I register programatically using above function:
read_register(file, 0x60, 0x0C, <BUFFER_ADDRESS>)
For temperature calculation we are interested in three registers of the sensor:
26 – The Control register to put module in active mode and start measurement immediately.
05 – read temperature LSB data (4 bits 0:3)
04 – read temperature MSB data (4 bits 4:11)
Now we will set the mpl3115 to active mode, this is done by switching the bit0(SYSB) in CTRL_REG1 from standby to active, i.e set the bit to 1.
To start getting the temp values set the bit1(OST) in CTRL_REG1 to 1.
write_register(file, 0x60, 0x26, 0x03)
with settings done, lets read data from 0x04 and 0x03 to a buffer using read_register function.
read_register(file, 0x60, 0x04, <BUFFER_ADDRESS>)
read_register(file, 0x60, 0x04, <BUFFER_ADDRESS>)
once data read we have to apply the shift operator couple of times to get the correct reading value .
The complete source code:
#include <stdio.h> #include <stdint.h> #include <linux/i2c.h> #include <linux/i2c-dev.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <string.h> static int write_register(int file,unsigned char address,unsigned char reg,unsigned char data) { unsigned char output_buffer[2]; struct i2c_rdwr_ioctl_data packets; struct i2c_msg messages[1]; messages[0].addr = address; messages[0].flags = 0; messages[0].len = sizeof(output_buffer); messages[0].buf = output_buffer; output_buffer[0] = reg; output_buffer[1] = data; packets.msgs = messages; packets.nmsgs = 1; if(ioctl(file, I2C_RDWR, &packets) < 0) { perror("Error sending data"); return 1; } return 0; } static int read_register(int file, unsigned char address, unsigned char reg, unsigned char *data) { unsigned char input_buffer, output_buffer; struct i2c_rdwr_ioctl_data packets; struct i2c_msg messages[2]; output_buffer = reg; messages[0].addr = address; messages[0].flags = 0; messages[0].len = sizeof(output_buffer); messages[0].buf = &output_buffer; messages[1].addr = address; messages[1].flags = I2C_M_RD; messages[1].len = sizeof(input_buffer); messages[1].buf = &input_buffer; packets.msgs = messages; packets.nmsgs = 2; if(ioctl(file, I2C_RDWR, &packets) < 0) { perror("Error sending data"); return 1; } *data = input_buffer; return 0; } int main() { int file, i; unsigned char data; int val1; int val2; int t_m; int choice; int DBG_ENABLE = 0; char string[200]; printf("Enable Debugging [1-Enable/0-Disable] :"); scanf("%d",&choice); if (choice == 1) DBG_ENABLE = 1; else if (choice == 0) DBG_ENABLE = 0; else { printf("Unknown choice \n Exiting... \n"); exit(1); } if ((file = open("/dev/i2c-3", O_RDWR)) < 0) { perror("Error openning file!"); exit(1); } if(DBG_ENABLE == 0) printf("Debugging Disabled \n"); else if(DBG_ENABLE == 1) printf("Debugging Enabled \n"); else printf("No idea"); //0x0C whoami verify if(read_register(file, 0x60, 0x0C, &data)) exit(1); else { if(DBG_ENABLE == 1) { printf("GET:Register[0x%02X]: 0x%02X\n" , 12 , data); } } //0x26 ctrlreg1 get/set ACTIVE if(read_register(file, 0x60, 0x26, &data)) exit(1); else { if(DBG_ENABLE == 1) { printf("GET:Register[0x%02X]: 0x%02X\n" , 38 , data); } } if(write_register(file, 0x60, 0x26, 0x03)) exit(1); else { if(read_register(file, 0x60, 0x26, &data)) exit(1); else { if(DBG_ENABLE == 1) { printf("SET/GET:Register[0x%02X]: 0x%02X\n" , 38 , data); } } } int counter=0; while(counter<5) { //read temperature MSB/LSB if(read_register(file, 0x60, 0x04, &data)) exit(1); /* else*/ /* { if(DBG_ENABLE == 1) */ /* { printf("Register[0x%02X]: 0x%02X\n" , 4 , data);*/ /* }*/ /* }*/ val2 = (int)data; if(DBG_ENABLE == 1) printf("val2: initial :%d:\n",val2); val2 <<=8; if(DBG_ENABLE == 1) printf("val2: shift :%d:\n",val2); if(read_register(file, 0x60, 0x05, &data)) exit(1); else { if(DBG_ENABLE == 1) printf("Register[0x%02X]: 0x%02X\n" , 5 , data); } val2 = val2+ (int)data; if(DBG_ENABLE == 1) { printf("val2 :%d:\n",val2); } t_m = (val2 >> 8) & 0xff; printf("temperature :%d: \n",t_m); system(string); sleep(1); counter++; } close(file); return 0; }
you will get result as below (with debug enabled):
$ ./mpl3115_temperature
The above code can be used in android/yocto platforms also.
NOTE: the above code access the /dev/i2c-3 interface, if MPL3115A2MPL3115A2 driver enabled in kernel, the code will fail due to device blocking by driver.
To enable supported drivers in kernel, change the values to "y" in .config (as show below) or edit in "menuconfig".
# CONFIG_SENSORS_FXOS8700 is not set
# CONFIG_SENSORS_FXAS2100X is not set
# CONFIG_INPUT_MPL3115 is not set
to
CONFIG_SENSORS_FXOS8700=y
CONFIG_SENSORS_FXAS2100X=y
CONFIG_INPUT_MPL3115=y
Happy Sensing.
Top Comments