├── .gitignore ├── diff.sh ├── mpl3115a2.h ├── mma8491q.h ├── mag3110.h ├── Makefile ├── test.c ├── mma8491q.c ├── mpl3115a2.c ├── mag3110.c └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | test 2 | *.o 3 | *.so 4 | *.s 5 | -------------------------------------------------------------------------------- /diff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | (echo "struct p { int16_t x, y, z; };"; cproto $1.c) > $1.h 3 | gcc -shared $1.c -o /tmp/$1.so 4 | wdiff \ 5 | -n -w $'\e[31m' -x $'\e[0m' -y $'\e[32m' -z $'\e[0m' \ 6 | <(objdump -d ../rpi_sensor_board/sensor.so | awk "/<$2>/,/^$/" | cut -f2-) \ 7 | <(objdump -d /tmp/$1.so | awk "/<$2>/,/^$/" | cut -f2-) 8 | -------------------------------------------------------------------------------- /mpl3115a2.h: -------------------------------------------------------------------------------- 1 | /* mpl3115a2.c */ 2 | void MPL3115A2_WRITE_REGISTER(uint8_t reg, uint8_t value); 3 | uint8_t MPL3115A2_READ_REGISTER(uint8_t reg); 4 | void MPL3115A2_Active(void); 5 | void MPL3115A2_Standby(void); 6 | void MPL3115A2_Init_Alt(void); 7 | int MPL3115A2_Read_Alt(void); 8 | void MPL3115A2_Init_Bar(void); 9 | int MPL3115A2_Read_Temp(void); 10 | -------------------------------------------------------------------------------- /mma8491q.h: -------------------------------------------------------------------------------- 1 | struct p { int16_t x, y, z; }; 2 | /* mma8491q.c */ 3 | int MMA8491Q_Enable(void); 4 | int MMA8491Q_DisEnable(void); 5 | void MMA8491Q_WRITE_REGISTER(void); 6 | void MMA8491Q_READ_REGISTER(void); 7 | int MMA8491Q_BULK_READ(char a, char b, char *c); 8 | int MMA8491Q_Init(void); 9 | int MMA8491_ReadRaw(char *data); 10 | int MMA8491_Read(struct p *xyz); 11 | -------------------------------------------------------------------------------- /mag3110.h: -------------------------------------------------------------------------------- 1 | /* mag3110.c */ 2 | int MAG3110_WRITE_REGISTER(char reg, char val); 3 | char MAG3110_READ_REGISTER(char reg); 4 | int MAG3110_BULK_READ(char reg, char count, char *data); 5 | int MAG3110_Init(void); 6 | char MAG3110_ReadRawData(char *data); 7 | int MAG3110_ReadAsInt(void); 8 | int16_t MAG3110_ReadRawData_x(void); 9 | int16_t MAG3110_ReadRawData_y(void); 10 | int16_t MAG3110_ReadRawData_z(void); 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS = -Wall 2 | CC = gcc 3 | 4 | # Uncomment this for Raspberry V1 5 | # CFLAGS += -DI2C_V1 6 | 7 | SENSOR_SRC = mpl3115a2.c mma8491q.c mag3110.c 8 | SENSOR_OBJ = $(SENSOR_SRC:.c=.o) 9 | SENSOR_HDR = $(SENSOR_SRC:.c=.h) 10 | 11 | all: libmemssensor.a 12 | 13 | headers: $(SENSOR_HDR) 14 | 15 | %.o: %.c %.h 16 | $(CC) $(CFLAGS) -c $< 17 | 18 | %.h: %.c 19 | cproto $< > $@ 20 | 21 | libmemssensor.a: $(SENSOR_OBJ) 22 | ar r $@ $(SENSOR_OBJ) 23 | 24 | sensor.so: bcm2835.c $(SENSOR_SRC) Makefile 25 | $(CC) $(CFLAGS) -fpic -shared -o sensor.so $(SENSOR_SRC) bcm2835.c 26 | 27 | clean: 28 | rm -f $(SENSOR_OBJ) sensor.so libmemssensor.a test 29 | -------------------------------------------------------------------------------- /test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "mpl3115a2.h" 5 | #include 6 | 7 | double getAlt() { 8 | int v = MPL3115A2_Read_Alt(); 9 | printf("raw alt = %u\n", v); 10 | int alt_m = v >> 8; 11 | int alt_l = v & 0xff; 12 | if (alt_m & 0x8000) alt_m = alt_m - 65536; 13 | double frac = alt_l / 256.0; 14 | return alt_m + frac; 15 | } 16 | 17 | double getBar() { 18 | int v = MPL3115A2_Read_Alt(); 19 | int alt_m = v >> 6; 20 | int alt_l = v & 0x30; 21 | return alt_m + alt_l / 64.0; 22 | } 23 | 24 | double getTemp() { 25 | int t = MPL3115A2_Read_Temp(); 26 | int t_m = (t >> 8) & 0xFF; 27 | int t_l = t & 0xFF; 28 | if (t_m > 0x7f) t_m = t_m - 256; 29 | return t_m + t_l / 256.0; 30 | } 31 | 32 | int main() { 33 | bcm2835_init(); 34 | MPL3115A2_Init_Alt(); 35 | // MPL3115A2_Init_Bar(); 36 | MPL3115A2_Active(); 37 | sleep(1); 38 | for (;;) { 39 | printf("alt: %f, temp: %f\n", getAlt(), getTemp()); 40 | //printf("bar: %f Pa, temp: %f\n", getBar(), getTemp()); 41 | usleep(100000); 42 | } 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /mma8491q.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mma8491q.h" 3 | #include 4 | #include 5 | 6 | int MMA8491Q_Enable() { 7 | if (bcm2835_init() == 0) { 8 | return 1; 9 | } else { 10 | bcm2835_gpio_fsel(25, 1); 11 | bcm2835_gpio_write(25, 1); 12 | return 0; 13 | } 14 | } 15 | 16 | int MMA8491Q_DisEnable() { 17 | if (bcm2835_init() == 0) { 18 | return 1; 19 | } else { 20 | bcm2835_gpio_fsel(25, 1); 21 | bcm2835_gpio_write(25, 0); 22 | return 0; 23 | } 24 | } 25 | 26 | void MMA8491Q_WRITE_REGISTER() { 27 | /* tbd */ 28 | } 29 | 30 | void MMA8491Q_READ_REGISTER() { 31 | /* tbd */ 32 | } 33 | 34 | int MMA8491Q_BULK_READ(char a, char b, char* c) { 35 | if (!bcm2835_init()) { 36 | return 1; 37 | } else { 38 | bcm2835_i2c_begin(); 39 | bcm2835_i2c_setClockDivider(0x9c4); 40 | bcm2835_i2c_setSlaveAddress(0x55); 41 | bcm2835_i2c_read_register_rs(&a, c, b); 42 | return *c; 43 | } 44 | } 45 | 46 | int MMA8491Q_Init() { 47 | return 1; 48 | } 49 | 50 | int MMA8491_ReadRaw(char* data) { 51 | char r = 0; 52 | MMA8491Q_Enable(); 53 | MMA8491Q_BULK_READ(1, 6, data); 54 | MMA8491Q_DisEnable(); 55 | return 1; 56 | } 57 | 58 | int MMA8491_Read(struct p* xyz) { 59 | char a[8] = { 0 }; 60 | if (MMA8491_ReadRaw((char*)a) == 1) { 61 | xyz->x = a[0]; 62 | xyz->x <<= 8; 63 | xyz->x += a[1]; 64 | xyz->x >>= 2; 65 | 66 | xyz->y = a[2]; 67 | xyz->y <<= 8; 68 | xyz->y += a[3]; 69 | xyz->y >>= 2; 70 | 71 | xyz->z = a[4]; 72 | xyz->z <<= 8; 73 | xyz->z += a[5]; 74 | xyz->z >>= 2; 75 | } 76 | return 1; 77 | } 78 | -------------------------------------------------------------------------------- /mpl3115a2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void MPL3115A2_WRITE_REGISTER(uint8_t reg, uint8_t value) 4 | { 5 | char buf[2] = { reg, value }; 6 | bcm2835_i2c_setSlaveAddress(0x60); 7 | bcm2835_i2c_write(buf, 2); 8 | } 9 | 10 | uint8_t MPL3115A2_READ_REGISTER(uint8_t reg) 11 | { 12 | char buf[1]; 13 | char regaddr = reg; 14 | bcm2835_i2c_setSlaveAddress(0x60); 15 | bcm2835_i2c_read_register_rs(®addr, buf, 1); 16 | return buf[0]; 17 | } 18 | 19 | void MPL3115A2_Active() 20 | { 21 | uint8_t v = MPL3115A2_READ_REGISTER(0x26); 22 | v = v | 0x01; 23 | MPL3115A2_WRITE_REGISTER(0x26, v); 24 | } 25 | 26 | void MPL3115A2_Standby() 27 | { 28 | uint8_t v = MPL3115A2_READ_REGISTER(0x26); 29 | v = v & ~0x01; 30 | MPL3115A2_WRITE_REGISTER(0x26, v); 31 | } 32 | 33 | uint8_t MPL3115A2_Initialized = 0; 34 | 35 | void MPL3115A2_Init_Alt() 36 | { 37 | MPL3115A2_Initialized = 0; 38 | uint32_t b = 0x000009c4; 39 | bcm2835_i2c_begin(); 40 | bcm2835_i2c_setClockDivider(b); 41 | uint32_t c = MPL3115A2_READ_REGISTER(12); 42 | if (c == 0xc4) 43 | { 44 | MPL3115A2_Initialized = 1; 45 | MPL3115A2_WRITE_REGISTER(0x26, 0xb8); 46 | MPL3115A2_WRITE_REGISTER(0x27, 0x00); 47 | MPL3115A2_WRITE_REGISTER(0x28, 0x17); 48 | MPL3115A2_WRITE_REGISTER(0x29, 0x00); 49 | MPL3115A2_WRITE_REGISTER(0x2a, 0x00); 50 | MPL3115A2_WRITE_REGISTER(0x13, 0x07); 51 | } 52 | } 53 | 54 | int MPL3115A2_Read_Alt() 55 | { 56 | int a = 0; 57 | if (MPL3115A2_Initialized == 1) { 58 | a = MPL3115A2_READ_REGISTER(0x01); 59 | a <<= 8; 60 | int b = MPL3115A2_READ_REGISTER(0x02); 61 | a = a + b; 62 | a <<= 8; 63 | int c = MPL3115A2_READ_REGISTER(0x03); 64 | a = a + c; 65 | } 66 | return a; 67 | } 68 | 69 | void MPL3115A2_Init_Bar() 70 | { 71 | bcm2835_i2c_begin(); 72 | bcm2835_i2c_setClockDivider(0x9c4); 73 | uint8_t c = MPL3115A2_READ_REGISTER(12); 74 | if (c == 0xc4) { 75 | MPL3115A2_Initialized = 1; 76 | MPL3115A2_WRITE_REGISTER(0x26, 0x38); 77 | MPL3115A2_WRITE_REGISTER(0x27, 0x00); 78 | MPL3115A2_WRITE_REGISTER(0x28, 0x11); 79 | MPL3115A2_WRITE_REGISTER(0x29, 0x00); 80 | MPL3115A2_WRITE_REGISTER(0x2a, 0x00); 81 | MPL3115A2_WRITE_REGISTER(0x13, 0x07); 82 | } 83 | } 84 | 85 | int MPL3115A2_Read_Temp() { 86 | int a = 0; 87 | if (MPL3115A2_Initialized == 1) { 88 | a = (MPL3115A2_READ_REGISTER(0x04) << 8) + MPL3115A2_READ_REGISTER(0x05); 89 | } 90 | return a; 91 | } 92 | -------------------------------------------------------------------------------- /mag3110.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "mag3110.h" 4 | #include 5 | 6 | int MAG3110_WRITE_REGISTER(char reg, char val) { 7 | char x = reg; 8 | char c = val; 9 | bcm2835_i2c_setSlaveAddress(14); 10 | bcm2835_i2c_write(&x, 2); 11 | } 12 | 13 | char MAG3110_READ_REGISTER(char reg) { 14 | char* ch = malloc(1); 15 | bcm2835_i2c_setSlaveAddress(14); 16 | bcm2835_i2c_read_register_rs(®, ch, 1); 17 | return ch[0]; 18 | } 19 | 20 | int MAG3110_BULK_READ(char reg, char count, char* data) { 21 | bcm2835_i2c_setSlaveAddress(14); 22 | bcm2835_i2c_read_register_rs(®, data, count); 23 | return *data; 24 | } 25 | 26 | char MAG3110_Initialized = 0; 27 | 28 | int MAG3110_Init() { 29 | char v = 0; 30 | bcm2835_i2c_begin(); 31 | bcm2835_i2c_setClockDivider(2500); 32 | MAG3110_WRITE_REGISTER(16, 0); 33 | v = MAG3110_READ_REGISTER(7); 34 | if (v == 0xc4) { 35 | MAG3110_WRITE_REGISTER(17, 128); 36 | MAG3110_Initialized = 1; 37 | } 38 | return MAG3110_Initialized; 39 | } 40 | 41 | char MAG3110_ReadRawData(char* data) { 42 | char a = 0; 43 | short b = 0; 44 | if (MAG3110_Initialized == 1) { 45 | MAG3110_WRITE_REGISTER(17, 128); 46 | MAG3110_WRITE_REGISTER(16, 2); 47 | do { 48 | a = MAG3110_READ_REGISTER(0); 49 | } while ((a & 7) != 7); 50 | MAG3110_BULK_READ(1, 6, data); 51 | } 52 | return 1; 53 | } 54 | 55 | int MAG3110_ReadAsInt() { 56 | /* not used from Python script */ 57 | return 0; 58 | } 59 | 60 | int16_t MAG3110_ReadRawData_x() { 61 | char r = 0; 62 | int16_t a = 0; 63 | if (MAG3110_Initialized == 1) { 64 | a = MAG3110_READ_REGISTER(1); 65 | a = MAG3110_READ_REGISTER(2); 66 | MAG3110_WRITE_REGISTER(17, 128); 67 | MAG3110_WRITE_REGISTER(16, 2); 68 | do { 69 | r = MAG3110_READ_REGISTER(0); 70 | } while (!(r & 1)); 71 | a = MAG3110_READ_REGISTER(1); 72 | a = a << 8; 73 | a = a + MAG3110_READ_REGISTER(2); 74 | } 75 | return a; 76 | } 77 | 78 | int16_t MAG3110_ReadRawData_y() { 79 | char r = 0; 80 | int16_t a = 0; 81 | if (MAG3110_Initialized == 1) { 82 | a = MAG3110_READ_REGISTER(3); 83 | a = MAG3110_READ_REGISTER(4); 84 | MAG3110_WRITE_REGISTER(17, 128); 85 | MAG3110_WRITE_REGISTER(16, 2); 86 | do { 87 | r = MAG3110_READ_REGISTER(0); 88 | } while (!(r & 2)); 89 | a = MAG3110_READ_REGISTER(3); 90 | a = a << 8; 91 | a = a + MAG3110_READ_REGISTER(4); 92 | } 93 | return a; 94 | } 95 | 96 | int16_t MAG3110_ReadRawData_z() { 97 | char r = 0; 98 | int16_t a = 0; 99 | if (MAG3110_Initialized == 1) { 100 | a = MAG3110_READ_REGISTER(5); 101 | a = MAG3110_READ_REGISTER(6); 102 | MAG3110_WRITE_REGISTER(17, 128); 103 | MAG3110_WRITE_REGISTER(16, 2); 104 | do { 105 | r = MAG3110_READ_REGISTER(0); 106 | } while (!(r & 4)); 107 | a = MAG3110_READ_REGISTER(5); 108 | a = a << 8; 109 | a = a + MAG3110_READ_REGISTER(6); 110 | } 111 | return a; 112 | } 113 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MEMS Sensor Evaluation Board C Library 2 | 3 | This is a Raspberry Pi C library for the MEMS Sensor Board with the 3 Xtrinsic 4 | sensors: 5 | 6 | * High-Precision Pressure Sensor (MPL3115A2) 7 | * Low-power 3D Magnetometer (MAG3110) 8 | * 3-Axis, Digital Accelerometer (MMA8491Q) 9 | 10 | ## Links 11 | 12 | * [Element 14 Community Page for the MEMS Sensor Board](http://www.element14.com/community/community/designcenter/mems-sensor-board) 13 | * [Git Repo with script and binary-only sensor.so](http://git.oschina.net/embest/rpi_sensor_board.git) 14 | 15 | ## How to use from C 16 | 17 | 1. Run make to build `libmemssensor.a` 18 | 2. Link and use this library 19 | 20 | ## How to re-build sensor.so for use with Python scripts 21 | 22 | 1. Download and extract the [bcm2835 library](http://www.airspayce.com/mikem/bcm2835/). 23 | 2. Copy the bcm2835.c source file into the directory with this library 24 | 3. Run `make sensor.so`. 25 | 26 | ## Using with Raspberry Pi Version 1.0 27 | 28 | * `bcm2835.c` needs to be compiled with `-DI2C_V1`. 29 | * Either edit `bcm2835.c` or add the flags in `Makefile`. 30 | 31 | ## Background 32 | 33 | This is a reverse engineed binary-compatible version of `sensor.so` originally 34 | found on the Raspbian image for the sensor board. 35 | 36 | The download link to the Raspbian Image on element14.com has gone missing, but 37 | the `sensor.so` library can be found in [this 38 | git repository](http://git.oschina.net/embest/rpi_sensor_board.git). 39 | 40 | The sensor.so file is a binary blob, based on the 41 | [bcm2835](http://www.airspayce.com/mikem/bcm2835/), which is GPL licensed. So 42 | the binary blob is in full GPL violation. 43 | 44 | The original `sensor.so` is compiled for Raspberry V2.0 and does not work with 45 | V1.0 boards due to a number change on the GPIO pins for I2C. To use with a V1.0 46 | board, a define (`-DI2C_V1`) need to be set when compiling the bcm2835 library. 47 | This can done in `bcm2835.c` or in my Makefile. 48 | 49 | I disassembled `sensor.so` and reimplemented the functions in C, with 50 | practically exact result at the assembly level when compiled. I compare the 51 | disassembly output of the `sensor.so` with the output of my compiled C code for 52 | an exact match. I tested using the original Python scripts and everything seems 53 | to be working. 54 | 55 | I kept everything minimal and as accurate to the original binary `sensor.so` as 56 | possible, even with bugs and compiler warnings. 57 | 58 | ## License 59 | 60 | Copyright (c) 2014 Lars Christensen 61 | 62 | Permission is hereby granted, free of charge, to any person obtaining a copy 63 | of this software and associated documentation files (the "Software"), to deal 64 | in the Software without restriction, including without limitation the rights 65 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 66 | copies of the Software, and to permit persons to whom the Software is 67 | furnished to do so, subject to the following conditions: 68 | 69 | The above copyright notice and this permission notice shall be included in 70 | all copies or substantial portions of the Software. 71 | 72 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 73 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 74 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 75 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 76 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 77 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 78 | THE SOFTWARE. 79 | --------------------------------------------------------------------------------