/************************************************************************************************** * * LIS3LV02DQ * * Version: 1.0.1 - Mai 2009 * Author: Christoph Wartmann / chair for caad - ETH Zürich / wartmann[at].arch.ethz.ch * Etienne Ribeiro / tutorial assistant caad / eribeiro[at]ethz.ch * * Desc: Module to plug an LIS3LV02DQ Accelerator to your project. This Module makes it * easy to run a LIS3LV02DQ Accelerator in either +-2g or +- 6g mode. * * Protocol: SPI * * Pins: VCC: 3.3V * GND * SDO: Wiring: 27 Arduino Pro Mini: 12 MISO (SDO) * SDA: Wiring: 26 Arduino Pro Mini: 11 MOSI (SDA) * SCL: Wiring: 25 Arduino Pro Mini: 13 SCK (SCL) * CS: Wiring: 24 Arduino Pro Mini: 10 SS (CS) * * Not yet implemented: * - interrepts * - I2C Interface * - high pass filter * - 16 bit mode (Big Endian Mode) * - Self Test * * Methodes: boolean LIS3L_AppendSensor (int dataout, int datain, int spiclock, int slaveselect) * Append Sensor. Must be called in setup() * dataout, datain, spiclock, slaveselect: SPI-Pins (all digital pins) * Starts Sensor in +-2g Mode. * boolean LIS3L_AppendSensor (int dataout, int datain, int spiclock, int slaveselect, boolean use6g) * Append Sensor. Must be called in setup() * dataout, datain, spiclock, slaveselect: SPI-Pins (all digital pins) * use6g: true = +-6g Mode, false = +-2g Mode * void LIS3L_ConfigR1 (boolean turnOnDevice, byte datarate, boolean enableSelftest, boolean enableZ, boolean enableY, boolean enableX) * Configuration Register 1. See Datasheet if you want to change any settings. * void LIS3L_ConfigR2 (boolean use6g, boolean blockData, boolean bigEndian, boolean rebootMemory, boolean interruptEnable, boolean enableDataReadyGeneration, boolean Use3WireMode, boolean LeftJustified16bit) * Configuration Register 2. See Datasheet if you want to change any settings. * void LIS3L_ConfigR3 (boolean useExternalClock, boolean enableDirectionDetection, boolean enableFreeFallAndWakeUp, boolean enabledFilteredData, byte highPassFrequency) * Configuration Register 3. See Datasheet if you want to change any settings. * int LIS3L_Read(char which) * Read values * 'x', 'y', 'z': Acceleration * 's': Current state of Sensor * 'a', 'b', 'c': Get Configuration * 'w': Get whoAmI. should be 3A * int LIS3L_ParseToG (int val) * Parse value to G. Call val = LIS3L_Read('x') and LIS3L_ParseToG(val). * void LIS3L_PrintState (byte state) * Print current state of your sensor to command line. Call state = LIS3L_Read ('s') and LIS3L_PrintState(state) * ***************************************************************************************************/ // // Const #define whoAmI 15 // 0xF #define reg1 32 // 0x20 #define reg2 33 // 0x21 #define reg3 34 // 0x22 #define stateReg 39 // 0x27 #define outXlow 40 // 0x28 #define outXhigh 41 // 0x29 #define outYlow 42 // 0x2A #define outYhigh 43// 0x2B #define outZlow 44// 0x2C #define outZhigh 45// 0x2D // #define LIS3L_id 58// 0x3A #define LIS3L_2g_factor 1024 // Divide value from register with this value to get 'g' #define LIS3L_6g_factor 340 // Divide value from register with this value to get 'g' // // Var int lis3l_DATAIN; // Wiring: 27 Arduino Pro Mini: 12 MISO (SDO) int lis3l_DATAOUT; // Wiring: 26 Arduino Pro Mini: 11 MOSI (SDA) int lis3l_SPICLOCK; // Wiring: 25 Arduino Pro Mini: 13 SCK (SCL) int lis3l_SLAVESELECT; // Wiring: 24 Arduino Pro Mini: 10 SS (CS) boolean lis3l_2g_mode = true; // ************************* // // Functions // // // LIS3L_AppendSensor boolean LIS3L_AppendSensor (int dataout, int datain, int spiclock, int slaveselect) { LIS3L_AppendSensor (dataout, datain, spiclock, slaveselect, false); } boolean LIS3L_AppendSensor (int dataout, int datain, int spiclock, int slaveselect, boolean use6g) { // Variables lis3l_DATAOUT = dataout; lis3l_DATAIN = datain; lis3l_SPICLOCK = spiclock; lis3l_SLAVESELECT = slaveselect; // Pins pinMode (lis3l_DATAOUT, OUTPUT); pinMode (lis3l_DATAIN, INPUT); pinMode (lis3l_SPICLOCK,OUTPUT); pinMode (lis3l_SLAVESELECT,OUTPUT); digitalWrite (lis3l_SLAVESELECT,HIGH); //disable device // SPCR = 01010000 // Set the SPCR register to 01010000 //interrupt disabled,spi enabled,msb 1st,master,clk low when idle, //sample on leading edge of clk,system clock/4 rate SPCR = (1<<SPE)|(1<<MSTR)|(1<<CPOL)|(1<<CPHA); // Config Device delay (10); LIS3L_ConfigR1 (true, 0, false, true, true, true); LIS3L_ConfigR2 (use6g, false, false, false, false, false, false, false); LIS3L_ConfigR3 (false, false, false, false, 0); // query the WHO_AM_I register of the LIS3LV02DQ // this should return 0x3A, a factory setting byte in_byte = read_register(whoAmI); if (in_byte != LIS3L_id) return false; // Return return true; } // // LIS3L_ConfigR1 // default: false, 0, false, true, true, true void LIS3L_ConfigR1 (boolean turnOnDevice, byte datarate, boolean enableSelftest, boolean enableZ, boolean enableY, boolean enableX) { byte cmd = B00000000; if (turnOnDevice) // Turn on/off device cmd |= B11000000; if (datarate == 0) // 40 Hz (default) cmd |= B00000000; if (datarate == 1) // 160 Hz cmd |= B00010000; if (datarate == 2) // 640 Hz cmd |= B00100000; if (datarate == 3) // 2560 Hz cmd |= B00110000; if (enableSelftest) // Selftast on/off cmd |= B00001000; if (enableZ) // enable Z cmd |= B00000100; if (enableY) // enable Y cmd |= B00000010; if (enableX) // enable X cmd |= B00000001; // Write write_register(reg1, cmd); } // // LIS3L_ConfigR2 // default: false, false, false, false, false, false, false, false void LIS3L_ConfigR2 (boolean use6g, boolean blockData, boolean bigEndian, boolean rebootMemory, boolean interruptEnable, boolean enableDataReadyGeneration, boolean Use3WireMode, boolean LeftJustified16bit) { byte cmd = B00000000; if (use6g){ // +-2g or +-6g (+-2g is default) cmd |= B10000000; lis3l_2g_mode = false; } else { lis3l_2g_mode = true; } if (blockData) // if for any reason it is not sure to read faster than output data rate it is recommended to set this bit to '1' cmd |= B01000000; if (bigEndian) // Little Endian (12bit, default) or Big Endian mode (16bit) cmd |= B00100000; if (rebootMemory) // Reboot Memory (Reload Registers from flash memory, same is done at power up) cmd |= B00010000; if (interruptEnable) // DRDY now is used for Interrupts (enableDataReadyGeneration must be true) cmd |= B00001000; if (enableDataReadyGeneration) // DRDY ebabled. By default DRDY-Pins is HIGH when new data is available, or if interruptEnable is true, DRDY-Pin is used as interrupt cmd |= B00000100; if (Use3WireMode) // Use SPI 4-wire (default) or SPI 3-wire mode cmd |= B00000010; if (LeftJustified16bit) // cmd |= B00000001; // Write write_register(reg2, cmd); } // // LIS3L_ConfigR3 // default: false, false, false, false, 0 void LIS3L_ConfigR3 (boolean useExternalClock, boolean enableDirectionDetection, boolean enableFreeFallAndWakeUp, boolean enabledFilteredData, byte highPassFrequency) { byte cmd = B00001000; // leave the 1! if (useExternalClock) // Use External Clock cmd |= B10000000; if (enableDirectionDetection) // enable Direction Detection cmd |= B01000000; if (enableFreeFallAndWakeUp) // enalbe Free-Fall and Wake-Up cmd |= B00100000; if (enabledFilteredData) // enable Filtered Data Selection cmd |= B00010000; if (highPassFrequency == 0) // Hpc = 512 (default) Frequency for DirectionDetection and FreeFallAndWakeUp cmd |= B00000000; if (highPassFrequency == 1) // Hpc = 1024 cmd |= B00000001; if (highPassFrequency == 2) // Hpc = 2048 cmd |= B00000010; if (highPassFrequency == 3) // Hpc = 4096 cmd |= B00000011; // Write write_register(reg3, cmd); } // // LIS3L_Read // 'x', 'y', 'z', 's'->state, 'w'->whoAmI (8 Bit Dummie Identification for this Sensor), 'a'->config Reg1, 'b'->config Reg2, 'c'->config Reg3 int LIS3L_Read(char which) { // int val = 0; byte val_h; byte val_l; // switch(which) { case 'x': case 'X': val_h = read_register(outXhigh); val_l = read_register(outXlow); val = val_h; val <<= 8; val += val_l; break; case 'y': case 'Y': val_h = read_register(outYhigh); val_l = read_register(outYlow); val = val_h; val <<= 8; val += val_l; break; case 'z': case 'Z': val_h = read_register(outZhigh); val_l = read_register(outZlow); val = val_h; val <<= 8; val += val_l; break; case 's': // State case 'S': val_h = read_register(stateReg); val = val_h; break; case 'a': // Config Reg1 case 'A': val_h = read_register(reg1); val = val_h; break; case 'b': // Config Reg2 case 'B': val_h = read_register(reg2); val = val_h; break; case 'c': // Config Reg3 case 'C': val_h = read_register(reg3); val = val_h; break; case 'w': // whoAmI case 'W': val_h = read_register(whoAmI); val = val_h; break; default: return 0; // Exit Function break; } // return return val; } // // LIS3L_ParseToG // Parse Values from Register to mG int LIS3L_ParseToG (int val) { long tmpval = val; if (lis3l_2g_mode) return tmpval * 1000 / LIS3L_2g_factor; return tmpval * 1000 / LIS3L_6g_factor; } // // LIS3L_PrintState // Print state in natural language void LIS3L_PrintState (byte state) { Serial.print("Status: "); Serial.print(state, BIN); Serial.print(": "); if (int(1<<7 & state) != 0) // byte 1000 0000 Serial.print (" data overrun!"); if (int(1<<6 & state) != 0) // byte 0100 0000 Serial.print (" Z axis data overrun!"); if (int(1<<5 & state) != 0) // byte 0010 0000 Serial.print (" Y axis data overrun!"); if (int(1<<4 & state) != 0) // byte 0001 0000 Serial.print (" X axis data overrun!"); if (int(1<<3 & state) != 0) // byte 0000 1000 Serial.print (" new data available!"); if (int(1<<2 & state) != 0) // byte 0000 0100 Serial.print (" Z axis new data available!"); if (int(1<<1 & state) != 0) // byte 0000 0010 Serial.print (" X axis new data available!"); if (int(1<<0 & state) != 0) // byte 0000 0001 Serial.print (" Y axis new data available!"); } // ************************* // // SPI Functions // char spi_transfer(volatile char data) { /* Writing to the SPDR register begins an SPI transaction */ SPDR = data; /* Loop right here until the transaction is complete. the SPIF bit is the SPI Interrupt Flag. When interrupts are enabled, and the SPIE bit is set enabling SPI interrupts, this bit will set when the transaction is finished. */ while (!(SPSR & (1<<SPIF))) {}; // received data appears in the SPDR register return SPDR; } // reads a register char read_register(char register_name) { char in_byte; // need to set bit 7 to indicate a read register_name |= 128; // SS is active low digitalWrite(SLAVESELECT, LOW); // send the address of the register we want to read first spi_transfer(register_name); // send nothing, but here's when the device sends back the register's value as an 8 bit byte in_byte = spi_transfer(0); // deselect the device digitalWrite(SLAVESELECT, HIGH); return in_byte; } // write to a register void write_register(char register_name, byte data) { // char in_byte; // clear bit 7 to indicate we're doing a write register_name &= 127; // SS is active low digitalWrite(SLAVESELECT, LOW); // send the address of the register we want to write spi_transfer(register_name); // send the data we're writing spi_transfer(data); digitalWrite(SLAVESELECT, HIGH); //return in_byte; }