/* ---------------------------------------------------------------------------- * ATMEL Microcontroller Software Support * ---------------------------------------------------------------------------- * Copyright (c) 2008, Atmel Corporation * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the disclaimer below. * * Atmel's name may not be used to endorse or promote products derived from * this software without specific prior written permission. * * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ---------------------------------------------------------------------------- */ //------------------------------------------------------------------------------ /// \unit /// /// This file contains algorithms and drivers for tilt sensing. /// //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Headers //------------------------------------------------------------------------------ #include "dfm_accelerometer.h" #include "board.h" #include #include #include #include #include #include #include #include "dfm_config.h" #include "dfm_cmd.h" #include "dfm_lcd_tsd.h" #include "dfm_dispboxmgr.h" #include "dfm_it.h" #include "dfm_init.h" //------------------------------------------------------------------------------ // Macros //------------------------------------------------------------------------------ #define BOARD_ADC12_FREQ 5000000 //! ADC clock #define ADC12_VREF 3300 //! reference voltage 3.3 * 1000,make sure the jumper setting is right #define PINS_ACC_ADC PIN_ADC0_AD2,PIN_ADC0_AD6,PIN_ADC0_AD7 #define TAN30 (37) //! fixed point for tanget tan(45)*0x40 #define TAN15 17 //! fixed point for tangent tan(15)*0x40 #define DELAY 100 #define SAMPLES 1 #if defined(at91sam3u4) #define AT91C_ID_ADC_PRESENT AT91C_ID_ADC12B #define AT91C_BASE_ADC AT91C_BASE_ADC12B #endif //------------------------------------------------------------------------------ // External Variables //------------------------------------------------------------------------------ extern const char * gpActiveBinFile; extern unsigned int gLcdRefreshFlag; extern int rotation_axes_cpt; /// record measurement times static int count =0; //------------------------------------------------------------------------------ // Variables //------------------------------------------------------------------------------ unsigned char ADC12_channel_x = ADC12_CHANNEL_2; //!< X Channel For Accelerometer unsigned char ADC12_channel_y = ADC12_CHANNEL_6; //!< Y Channel For Accelerometer unsigned char ADC12_channel_z = ADC12_CHANNEL_7; //!< Z Channel For Accelerometer /// Indicates that the conversion is finished. static volatile unsigned char conversionDone; acc_t acc = { //!< Accelerometer Instance .m = { .x=0 , .y=0 , .z=0 } , .k = { .x=ACC_ZERO_X , .y=ACC_ZERO_Y , .z=ACC_ZERO_Z } , .ak = { .x=0 , .y=0 , .z=0 } , } ; static const Pin pinsADC[] = {PINS_ACC_ADC}; static xyz_t lastMeasure = {0}; int gDir = DIR_UNCHANGED; int gLastDir = DIR_UNCHANGED; ///push button to configure for the applicatino. static Pin pinBP4 = PIN_PUSHBUTTON_1; //------------------------------------------------------------------------------ // Functions //------------------------------------------------------------------------------ int DV_Check_AccStatus(); //------------------------------------------------------------------------------ /// add position //------------------------------------------------------------------------------ xyz_t xyz_add (xyz_t p, xyz_t q) { xyz_t r ; r.x = p.x + q.x ; r.y = p.y + q.y ; r.z = p.z + q.z ; return r ; } //------------------------------------------------------------------------------ /// sub position //------------------------------------------------------------------------------ xyz_t xyz_diff (xyz_t p, xyz_t q) { xyz_t r ; r.x = p.x - q.x ; r.y = p.y - q.y ; r.z = p.z - q.z ; return r ; } //------------------------------------------------------------------------------ /// Invoke platform api to get converted data /// \param pAdc address pointer for ADC12B controller /// \param ADC12_channel_x channel number for x axis /// \param ADC12_channel_y channel number for y axis /// \param ADC12_channel_z channel number for z axis /// \return converted data for three channels //------------------------------------------------------------------------------ xyz_t acc_get_value ( AT91S_ADC12B *pAdc , unsigned char ADC12_channel_x, unsigned char ADC12_channel_y, unsigned char ADC12_channel_z) { xyz_t val ; val.x = ADC12_GetConvertedData(pAdc, ADC12_channel_x); val.y = ADC12_GetConvertedData(pAdc, ADC12_channel_y); val.z = ADC12_GetConvertedData(pAdc, ADC12_channel_z); val.x = val.x>>ACC_SHIFT; val.y = val.y>>ACC_SHIFT; val.z = val.z>>ACC_SHIFT; return val ; } //------------------------------------------------------------------------------ /// get present acceleration value as 0-g value for x and y, 1-g value for z //------------------------------------------------------------------------------ void DoCalibration() { int i = 0,j; xyz_t temp ={0}; count = 0; acc.m.x = 0; acc.m.y = 0; acc.m.z = 0; for(i = 0; i < 16 ; i++) { if(DV_Check_AccStatus()){ temp = xyz_add(acc.m,temp); for(j=0;j (TAN15*TAN15)*(y*y+z*z) || (unsigned int)(y*y)<<12 > (TAN15*TAN15)*(x*x+z*z)) { if((unsigned int)(x*x)<<12 > (TAN15*TAN15)*(y*y+z*z)) { if((unsigned int)(y*y)<<12 > (TAN15*TAN15)*(x*x+z*z)) { if(x < 0) { if(y < 0) { dir = DV_Accelerometer_up_right; } else { dir =DV_Accelerometer_down_right; } } else { if(y < 0) { dir = DV_Accelerometer_up_left; } else { dir = DV_Accelerometer_down_left; } } } else { if(x < 0) { dir = DV_Accelerometer_right; } else { dir = DV_Accelerometer_left; } } } else { if(y < 0) { dir = DV_Accelerometer_up; } else { dir = DV_Accelerometer_down; } } } return dir; } //------------------------------------------------------------------------------ /// get the direction of the board /// \return direction //------------------------------------------------------------------------------ int DV_Accelerometer_Dir() { int dir = gDir; int x=0,y=0,z=0; xyz_t diff = {0}; ///measure the difference between the last one and the present one diff = xyz_diff(acc.m,lastMeasure); ///check the status,acc.m will be changed after called routine ///if conversion is done,otherwise,return immediately DV_Check_AccStatus(); ///no big change since last measurement if( diff.x*diff.x + diff.y*diff.y + diff.z*diff.z < ((ACC_1G*ACC_1G)>>11)) { ///keep the old direction return gDir; } ///update lastMeasure to the new one lastMeasure = acc.m; ///get acceleration offset acc.ak = xyz_diff(acc.m,acc.k); x = acc.ak.x; y = acc.ak.y; z = (acc.ak.z + ACC_1G); /// filter non-tilting operation if( (x*x + y*y+z*z > ACC_AMPLITUDE_UPPER) ||(x*x + y*y+z*z < ACC_AMPLITUDE_LOWER) ){ return gDir; } ///the board plane is angled with the horizontal surface if( (unsigned int)(x*x)<<12 > (TAN30*TAN30)*(y*y+z*z) || (unsigned int)(y*y)<<12 > (TAN30*TAN30)*(x*x+z*z)) { if(x*x > y*y + (y*y>>1)) { if(x > 0) { dir = DIR_HORIZIONTAL_UP; } else { dir = DIR_HORIZIONTAL_DOWN; } } else if(x*x + (x*x>>1) < y*y) { if(y > 0) { dir = DIR_VERTICAL_UP; } else { dir = DIR_VERTICAL_DOWN; } } //else dir = previous dir //leave gap enough for stabilization ///renew the direction gDir = dir; } return gDir; } //------------------------------------------------------------------------------ /// Check accelerometer is ready? /// if the direction is unchanged since last measurement,return "not ready" /// \return 0 not ready, other value means ready and command string length //------------------------------------------------------------------------------ unsigned int ACC_CommandIsReady() { int dir = DIR_UNCHANGED; unsigned int ret; dir = DV_Accelerometer_Dir(); //no change of direction since last measurement if(gLastDir == dir) { ret = 0; } else { ret = 1; } gLastDir = dir; return ret; } //------------------------------------------------------------------------------ // get flipped ppt page //------------------------------------------------------------------------------ const char * ACC_GetCommand() { if(gDir == DIR_HORIZIONTAL_UP || gDir == DIR_HORIZIONTAL_DOWN) { //update to portait image file gpActiveBinFile = LCDSLIDEVIMAGEFILE; gLcdRefreshFlag = 1; } else { gpActiveBinFile = LCDSLIDEIMAGEFILE; gLcdRefreshFlag = 1; } return NULL; } //an example of ShowPrompt int ACC_ShowPrompt() { // int i; // switch(gDir)//gDir // { // // case DIR_HORIZIONTAL_UP: // printf("Horizontal Up!\n"); // //LCDD_DrawRectangle((void *)BOARD_LCD_BASE, x,y,width,height,0xE0E0C0); // break; // case DIR_HORIZIONTAL_DOWN: // printf("Horizontal Down!\n"); // break; // case DIR_VERTICAL_UP: // printf("Vertical Up!\n"); // break; // case DIR_VERTICAL_DOWN: // printf("Vertical Down!\n"); // break; // default: // printf("Unchanged!\n"); // break; // } // for(i=0;i<5000;i++); return 0; } //global accelerometer entry variable TInputEntry gAccEntry = {0, {NULL,NULL},ACC_ShowPrompt, ACC_CommandIsReady, ACC_GetCommand, NULL}; //------------------------------------------------------------------------------ /// Check if conversion is done.If done,read the corresponding parameters and ///start new measurement //------------------------------------------------------------------------------ int DV_Check_AccStatus() { //check if conversation is done //if done, read and measure,and start new conversation //else, return directly if(conversionDone == ((1<