mma8451q driver

Dependents:   nRF51822_DataLogger_PowerImpulseCounter scpi_sx127x NAMote72_Utility scpi_sx127x_firstTest

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mma8451q.cpp Source File

mma8451q.cpp

00001 #include "mma8451q.h"
00002 /* turn on: CTRL_REG1 active_bit = 1
00003  * back to standby: CTRL_REG1 active_bit = 0
00004  */
00005 
00006 /* STANDBY: SYSMOD = 00 */
00007 
00008 /*
00009  * MMA8451 I2C address
00010  */ 
00011 #define MMA8451_I2C_ADDRESS                          0x38 //0x1C
00012 
00013 
00014 MMA8451Q::MMA8451Q(I2C& r, DigitalIn& int_pin) : m_i2c(r), m_int_pin(int_pin)
00015 {
00016     /* INT pins on this chip default to push-pull output */
00017     write(MMA8451_CTRL_REG3, 0x01);    // set PP_OD
00018     /* INT1 and INT2 are tied together */
00019     
00020 }
00021 
00022 MMA8451Q::~MMA8451Q()
00023 {
00024 }
00025 
00026 void MMA8451Q::read(uint8_t addr, uint8_t *dst_buf, int length)
00027 {
00028     char cmd[2];
00029 
00030     cmd[0] = addr;
00031     if (m_i2c.write(MMA8451_I2C_ADDRESS, cmd, 1, true))
00032         printf("MMA write-fail %02x\n", addr);
00033     if (m_i2c.read(MMA8451_I2C_ADDRESS, (char *)dst_buf, length))
00034         printf("MMA read-fail\n");
00035 }
00036 
00037 uint8_t MMA8451Q::read_single(uint8_t addr)
00038 {
00039     char cmd[2];
00040 
00041     cmd[0] = addr;
00042     if (m_i2c.write(MMA8451_I2C_ADDRESS, cmd, 1, true))
00043         printf("MMA write-fail %02x\n", addr);
00044     if (m_i2c.read(MMA8451_I2C_ADDRESS, cmd, 1))
00045         printf("MMA read-fail\n");
00046 
00047     return cmd[0];
00048 }
00049 
00050 void MMA8451Q::print_regs()
00051 {
00052     printf("ID: %02x\n", read_single(MMA8451_ID));
00053     printf("sysmod:%02x\n", read_single(MMA8451_SYSMOD));
00054     ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
00055     printf("ctrl_reg1:%02x\n", ctrl_reg1.octet);
00056     printf("ctrl_reg2:%02x\n", read_single(MMA8451_CTRL_REG2));
00057     printf("ctrl_reg3:%02x\n", read_single(MMA8451_CTRL_REG3)); /* TODO: PP_OD is bit 0 (1=open drain) */
00058     printf("(int en) ctrl_reg4:%02x\n", read_single(MMA8451_CTRL_REG4));
00059     printf("(int cfg) ctrl_reg5:%02x\n", read_single(MMA8451_CTRL_REG5));
00060     printf("status:%02x\n", read_single(MMA8451_STATUS)); 
00061     /* (interrupt status) int src at 0x0c (MMA8451_INT_SOURCE): data ready, motion/freefall, pulse, orientation, transient, auto sleep */
00062     printf("INT_SOURCE:%02x\n", read_single(MMA8451_INT_SOURCE)); 
00063 }
00064 
00065 void MMA8451Q::write(uint8_t addr, uint8_t data)
00066 {
00067     uint8_t cmd[2];
00068     
00069     cmd[0] = addr;
00070     cmd[1] = data;
00071 
00072     if (m_i2c.write(MMA8451_I2C_ADDRESS, (char *)cmd, 2))
00073         printf("MMA write-fail %02x\n", addr);
00074 }
00075 
00076 void MMA8451Q::set_active(char arg)
00077 {
00078     char cmd[2];
00079     
00080     cmd[0] = MMA8451_CTRL_REG1;
00081     cmd[1] = arg;
00082 
00083     if (m_i2c.write(MMA8451_I2C_ADDRESS, cmd, 2))
00084         printf("MMA write-fail %02x\n", cmd[0]);
00085 }
00086 
00087 bool MMA8451Q::get_active(void)
00088 {
00089     uint8_t ret = read_single(MMA8451_CTRL_REG1);
00090     //printf("CTRL_REG1: %x\n", ret);
00091     if (ret & 1)
00092         return true;
00093     else
00094         return false;
00095 }
00096 
00097 void MMA8451Q::orient_detect()
00098 {
00099     uint8_t v;
00100     
00101     ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
00102     /* AN4068 Sensors Freescale Semiconductor, Inc.    
00103      * 4.1 Example Steps for Implementing the Embedded Orientation Detection */
00104      
00105      /* Step 1: Put the part into Standby Mode */
00106     ctrl_reg1.bits.ACTIVE = 0;
00107     write(MMA8451_CTRL_REG1, ctrl_reg1.octet);     
00108      
00109     /* Step 2: Set the data rate to 50 Hz (for example, but can choose any sample rate). */
00110     ctrl_reg1.bits.DR = 4;
00111     write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
00112     
00113     /* Step 3: Set the PL_EN bit in Register 0x11 PL_CFG. This will enable the orientation detection. */
00114     v = read_single(MMA8451_PL_CFG);
00115     v |= 0x40;
00116     write(MMA8451_PL_CFG, v);
00117     
00118     /* Step 4: Set the Back/Front Angle trip points in register 0x13 following the table in the data sheet. */
00119     v = read_single(MMA8451_PL_BF_ZCOMP);
00120     /*v &= 0x3f;
00121     v |= 0xX0;
00122     write(MMA8451_PL_BF_ZCOMP, v);*/
00123     
00124     /* Step 5: Set the Z-Lockout angle trip point in register 0x13 following the table in the data sheet. */
00125     /* v &= 0xf8;
00126     v |= 0x0X;
00127     */
00128     
00129     /* Step 6: Set the Trip Threshold Angle */
00130     v = read_single(MMA8451_PL_THS_REG);
00131     /*v &= 0x07;
00132     v |= 0x0X << 3;
00133     write(MMA8451_PL_THS_REG. v);*/
00134     
00135     /* Step 7: Set the Hysteresis Angle */
00136     v = read_single(MMA8451_PL_THS_REG);
00137     /*v &= 0xf8;
00138     v |= 0x0X;
00139     write(MMA8451_PL_THS_REG. v);*/    
00140     
00141     /* Step 8: Register 0x2D, Control Register 4 configures all embedded features for interrupt */
00142     ctrl_reg4.octet = 0;
00143     ctrl_reg4.bits.INT_EN_LNDPRT = 1;
00144     write(MMA8451_CTRL_REG4, ctrl_reg4.octet);
00145     
00146     /* Step 9: Register 0x2E is Control Register 5 which gives the option of routing the interrupt to either INT1 or INT2 */
00147     ctrl_reg5.octet = 0;
00148     ctrl_reg5.bits.INT_CFG_LNDPRT = 1;
00149     write(MMA8451_CTRL_REG5, ctrl_reg5.octet);
00150         
00151     /* Step 10: Set the debounce counter in register 0x12 */
00152     write(MMA8451_PL_COUNT, 5); // 5: debounce to 100ms at 50hz
00153     
00154     /* Step 11: Put the device in Active Mode */
00155     ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
00156     ctrl_reg1.bits.ACTIVE = 1;
00157     write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
00158         
00159     /* Step 12: in service() function */
00160 }
00161 
00162 
00163 void MMA8451Q::transient_detect()
00164 {
00165     ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
00166     /* AN4071 Sensors Freescale Semiconductor, Inc.
00167      * 7.1 Example Steps for Configuring Transient Detection
00168      * Change in X or Y > 0.5g for 50 ms at 100 Hz ODR, Normal mode */
00169 
00170     /* Step 1: Put the device in Standby Mode: Register 0x2A CTRL_REG1 */
00171     ctrl_reg1.bits.ACTIVE = 0;
00172     write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
00173     ctrl_reg1.bits.DR = 3; //Set device in 100 Hz ODR, Standby
00174     write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
00175 
00176     /* Step 2: Enable X and Y Axes and enable the latch: Register 0x1D Configuration Register */
00177     transient_cfg.octet = 0;
00178     transient_cfg.bits.ELE = 1; // enable latch
00179     transient_cfg.bits.YTEFE = 1;   // enable Y
00180     transient_cfg.bits.XTEFE = 1;   // enable X
00181     transient_cfg.bits.ZTEFE = 1;   // enable Z
00182     write(MMA8451_TRANSIENT_CFG, transient_cfg.octet);
00183 
00184     /* Step 3: Set the Threshold: Register 0x1F 
00185      * Note: Step count is 0.063g per count, 0.5g / 0.063g = 7.93.
00186      * Therefore set the threshold to 8 counts */
00187     write(MMA8451_TRANSIENT_THS, 8);
00188 
00189     /* Step 4: Set the Debounce Counter for 50 ms: Register 0x20
00190      * Note: 100 Hz ODR, therefore 10 ms step sizes */
00191     write(MMA8451_TRANSIENT_COUNT, 5);
00192 
00193     /* Step 5: Enable Transient Detection Interrupt in the System (CTRL_REG4) */
00194     ctrl_reg4.octet = 0;
00195     ctrl_reg4.bits.INT_EN_TRANS = 1;
00196     write(MMA8451_CTRL_REG4, ctrl_reg4.octet);
00197 
00198     /* Step 6: Route the Transient Interrupt to INT 1 hardware pin (CTRL_REG5) */
00199     ctrl_reg5.octet = 0;
00200     ctrl_reg5.bits.INT_CFG_TRANS = 1;
00201     write(MMA8451_CTRL_REG5, ctrl_reg5.octet);
00202 
00203     /* Step 7: Put the device in Active Mode: Register 0x2A CTRL_REG1 */
00204     ctrl_reg1.octet = read_single(MMA8451_CTRL_REG1);
00205     ctrl_reg1.bits.ACTIVE = 1;
00206     write(MMA8451_CTRL_REG1, ctrl_reg1.octet);
00207 
00208     /* Step 8: Write Interrupt Service Routine Reading the
00209      * System Interrupt Status and the Transient Status */
00210 }
00211 
00212 uint8_t MMA8451Q::service()
00213 {
00214     mma_int_source_t int_src;
00215     if (m_int_pin)
00216         return 0; // no interrupt
00217         
00218     int_src.octet = read_single(MMA8451_INT_SOURCE);
00219     
00220     if (int_src.bits.SRC_DRDY) {
00221         read(MMA8451_OUT_X_MSB, out.octets, 6);
00222     }
00223     if (int_src.bits.SRC_FF_MT) {
00224         read_single(MMA8451_FF_MT_SRC);
00225     }
00226     if (int_src.bits.SRC_PULSE) {
00227         read_single(MMA8451_PULSE_SRC);
00228     }
00229     if (int_src.bits.SRC_LNDPRT) {
00230         mma_pl_status_t pl_status;
00231         /*AN4068 Step 12: Write a Service Routine to Service the Interrupt */
00232         pl_status.octet = read_single(MMA8451_PL_STATUS);
00233         if (verbose) {
00234             printf("PL_STATUS: ");
00235             if (pl_status.bits.NEWLP) {
00236                 if (pl_status.bits.LO)
00237                     printf("Z-tilt-LO ");
00238                     
00239                 if (pl_status.bits.LAPO == 0)
00240                     printf("up ");
00241                 else if (pl_status.bits.LAPO == 1)
00242                     printf("down ");
00243                 else if (pl_status.bits.LAPO == 2)
00244                     printf("left ");
00245                 else if (pl_status.bits.LAPO == 3)
00246                     printf("right ");
00247                 
00248                 if (pl_status.bits.BAFRO)
00249                     printf("back ");
00250                 else
00251                     printf("front ");
00252             }
00253             printf("\r\n");
00254         }
00255     } // ...int_src.bits.SRC_LNDPRT
00256                          
00257     if (int_src.bits.SRC_TRANS) {
00258         transient_src_t t_src;
00259         t_src.octet = read_single(MMA8451_TRANSIENT_SRC);
00260         if (verbose) {
00261             printf("transient src:%x ", t_src.octet);
00262             if (t_src.bits.XTRANSE)
00263                 printf("X_Pol:%d ", t_src.bits.X_Trans_Pol);
00264             if (t_src.bits.YTRANSE)
00265                 printf("Y_Pol:%d ", t_src.bits.Y_Trans_Pol);
00266             if (t_src.bits.ZTRANSE)
00267                 printf("Z_Pol:%d ", t_src.bits.Z_Trans_Pol);
00268             printf("\r\n");        
00269         }
00270     } // ...int_src.bits.SRC_TRANS
00271     
00272     if (int_src.bits.SRC_ASLP) {
00273         read_single(MMA8451_SYSMOD);
00274     }
00275     
00276     return int_src.octet;
00277 }