| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| Cogitum 
 
 
 Joined: 22 Mar 2012
 Posts: 70
 Location: France (Paris)
 
 
			    
 
 | 
			
				| ADXL345  problem  COMPILER v 5.078 |  
				|  Posted: Sun Jan 19, 2020 11:18 am |   |  
				| 
 |  
				| Hi everybody.  My goal is to order ON / OFF a small module. I have a good command of the hardware but less of the software.
 My goal is as follows: wake up the 18F66K22 with an interrupt from an ADXL345.
 The attached program does not work properly.
 I use the INT1 ADXL to INT0 output from 18F. The Adxl INT1
 output is connected to a DC Voltmeter without pull up.
 From time to time by moving ADXL the level goes up to 1.7V!
 Then goes back down to 0V. All suggestions are welcome.
 Thank you in advance.
 Note : I can see ON/OFF using LED pin_G0 and accel Value
 on Hyperterminal.
 
  	  | Code: |  	  | #include <18F66K22.h>
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
 #FUSES  SOSC_HIGH   // 2 x Osci OK 20MHZ and 32K
 #use delay(crystal=20MHz)
 #use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=Valid)
 #use rs232(baud=115200,parity=N,xmit=PIN_G1,rcv=PIN_G2,bits=8,stream=debug)
 #use i2c(Master,Fast=200000,sda=PIN_D5,scl=PIN_D6)  //  18F66K22
 
 //  altern Test
 #include "ACCEL_ADXL345_new.h"  // en debug
 //#include "ACCEL_ADXL345.h" // 100% basic OK
 
 
 unsigned long cmd_adc(char cmd);
 unsigned int cmd_prom(char coef_num);
 float32 mesure_accel();
 
 
 void main()
 {
 fprintf(Valid,"+----------------------+\r\n");
 fprintf(Valid,"| ADXL345_NEW 19/01/20 |\r\n");
 fprintf(Valid,"+----------------------+\r\n");
 delay_ms(1000);
 
 float32 accel;
 
 fprintf (Valid,"Start Processus ADXL345 2020 \r\n");//OK
 
 // Main loop
 while(true)
 {
 //  output_high(pin_G0); // test
 accel = mesure_accel();     //
 
 }
 
 }
 
 | 
 ACCEL_ADXL345_new.h
 
  	  | Code: |  	  | // DEFINE ACCEL ADXL
 #define ACCEL_WRITE_ADDR   0XA6  // suivant cablage !
 #define ACCEL_READ_ADDR    0XA7
 #define ACCEL_DATA_ADDR    0x32
 #define ACCEL_PWRCTRL_ADDR 0x2d
 #define ACCEL_MEASURE_MODE 0x08
 #define ACCEL_INT_ENABLE   0x2E    // R/W   Interrupt enable control
 #define ACCEL_INT_MAP      0x2F    // R/W   Interrupt mapping control
 #define ACCEL_INT_SOURCE   0x30    // R     Source of interrupts
 #define ACCEL_THRESH_ACT   0x24    // R/W   Activity threshold
 #define ACCEL_THRESH_INACT 0x25    // R/W   Inactivity threshold
 #define ACCEL_TIME_INACT   0x26    // R/W   Inactivity time
 #define ACCEL_BW_RATE      0x25    // R/W   Data Rate and power mode control
 
 //#define BP PIN_B0
 //_____ M A C R O S
 #define ADDR_W       0xEE // Module address write mode     suivant cablage
 #define ADDR_R       0xEF // Module address read mode
 #define CMD_RESET    0x1E // ADC reset command
 #define CMD_ADC_READ 0x00 // ADC read command
 #define CMD_ADC_CONV 0x40 // ADC conversion command
 #define CMD_ADC_D1   0x00 // ADC D1 conversion Pression
 #define CMD_ADC_D2   0x10 // ADC D2 conversion TEMPERATURE
 #define CMD_ADC_256  0x00 // ADC OSR=256
 #define CMD_ADC_512  0x02 // ADC OSR=512
 #define CMD_ADC_1024 0x04 // ADC OSR=1024
 #define CMD_ADC_2048 0x06 // ADC OSR=2048
 #define CMD_ADC_4096 0x08 // ADC OSR=4096
 #define CMD_PROM_RD  0xA0 // Prom read command
 
 
 signed int accel_data[6];
 signed int x,y,z;
 float32 xg,yg,zg;
 
 //********************************************************
 //! @brief preform adc conversion
 //! @return 24bit result
 //********************************************************
 
 unsigned long cmd_adc(char cmd)
 {
 unsigned  int ret;
 unsigned  long temp;
 
 i2c_start();
 i2c_write(ADDR_W);
 i2c_write(CMD_ADC_CONV+cmd); // send conversion command
 i2c_stop();
 switch (cmd & 0x0f)          // wait necessary conversion time
 {
 case CMD_ADC_256 :  delay_us(900); break;
 case CMD_ADC_512 :  delay_ms(3);   break;
 case CMD_ADC_1024:  delay_ms(4);   break;
 case CMD_ADC_2048:  delay_ms(6);   break;
 case CMD_ADC_4096:  delay_ms(10);  break;
 }
 i2c_start();
 i2C_write(ADDR_W);
 i2c_write(CMD_ADC_READ);
 i2c_stop();
 
 i2c_start();
 i2C_write(ADDR_R);
 ret = i2c_read();  //  read MSB and acknowledge
 temp= 65536*ret;
 ret = i2c_read();  // read byte and acknowledge
 temp=temp+256*ret;
 ret = i2c_read(0); // read LSB and not acknowledge
 temp= temp+ret;
 i2c_stop();        // send stop condition
 return temp;
 }
 
 //********************************************************
 //! @brief Read calibration coefficients
 //! @return coefficient
 //********************************************************
 unsigned int cmd_prom(char coef_num)
 {
 unsigned int ret;
 unsigned int rC=0;
 i2c_start();
 i2C_write(ADDR_W);
 i2c_write(CMD_PROM_RD+coef_num*2); // send PROM READ command
 i2c_stop();
 
 i2c_start();
 i2c_write(ADDR_R);
 ret = i2c_read();   // read MSB and acknowledge
 rC=256*ret;
 ret = i2c_read(0);  // read LSB and Not acknowledge
 rC=rC+ret;
 i2c_stop();
 
 return (rC); //
 
 }
 
 
 float32 mesure_accel()
 {
 float32 result;
 
 //
 //======================================================
 //  POWER_CTL  0x2D
 i2c_start();
 i2c_write(ACCEL_WRITE_ADDR);//
 i2c_write(0X2D); // register adress
 i2c_write(0X08); //0x1B  0x1C setup du register
 i2c_stop();
 //======================================================
 //!//  BW_RATE  0x2C
 i2c_start();
 i2c_write(ACCEL_WRITE_ADDR);//
 i2c_write(0X2C); //
 i2c_write(0X1A); // 0x1A
 i2c_stop();
 //======================================================
 // DATA FORMAT
 i2c_start();
 i2c_write(ACCEL_WRITE_ADDR);
 i2c_write(0X31);
 i2c_write(0X01);//0x25 0x01 = +-4g(scale) //0x83 with self test
 i2c_stop();
 //======================================================
 //!// INT_MAP
 i2c_start();
 i2c_write(ACCEL_WRITE_ADDR);
 i2c_write(0X2F);
 i2c_write(0XD0);//0x00 0x10
 i2c_stop();
 //!//=====================================================
 //!// INT_ENABLE
 i2c_start();
 i2c_write(ACCEL_WRITE_ADDR);
 i2c_write(0X2E);
 i2c_write(0X10);// 0x10
 i2c_stop();
 //=====================================================
 // Activity threshold
 //!i2c_start();
 //!i2c_write(ACCEL_WRITE_ADDR);
 //!i2c_write(0X24);
 //!i2c_write(0X01);// 0x10
 //!i2c_stop();
 //!//=====================================================
 //!// Inactivity threshold
 //!i2c_start();
 //!i2c_write(ACCEL_WRITE_ADDR);
 //!i2c_write(0X25);
 //!i2c_write(0X01);// 0x10
 //!i2c_stop();
 //=====================================================
 //!// Inactivity time
 //!i2c_start();
 //!i2c_write(ACCEL_WRITE_ADDR);
 //!i2c_write(0X26);
 //!i2c_write(0X01);// 0x50
 //!i2c_stop();
 //=====================================================
 
 I2C_start();
 i2c_write(ACCEL_WRITE_ADDR);    // OK
 i2c_write(ACCEL_PWRCTRL_ADDR);  // Ok
 i2c_write(ACCEL_MEASURE_MODE);
 i2c_write(ACCEL_INT_MAP);
 i2c_write(ACCEL_INT_ENABLE);   //
 
 //!i2c_write(ACCEL_THRESH_ACT);
 //!i2c_write(ACCEL_THRESH_INACT);
 //!i2c_write(ACCEL_TIME_INACT);
 //!i2c_write(ACCEL_BW_RATE);
 
 I2C_stop();
 
 // Read data from the accel
 i2c_start();
 i2c_write(ACCEL_WRITE_ADDR);
 i2c_write(ACCEL_DATA_ADDR);
 i2c_start();
 i2c_write(ACCEL_READ_ADDR);
 accel_data[0] = i2c_read(); //x0
 accel_data[1] = i2c_read(); //x1
 accel_data[2] = i2c_read(); //y0
 accel_data[3] = i2c_read(); //y1
 accel_data[4] = i2c_read(); //z0
 accel_data[5] = i2c_read(0); // z1, NACK on last read
 i2c_stop();
 
 //////////concatenation adxl345/////////////
 
 x=MAKE16(accel_data[1],accel_data[0]);
 y=MAKE16(accel_data[3],accel_data[2]);
 z=MAKE16(accel_data[5],accel_data[4]);
 //// mise à l'echelle //////
 xg  = x*0.0078;    // 13 bits > 32/8192
 yg  = y*0.0078;
 zg  = z*0.0078;
 result = sqrt(xg*xg+yg*yg+zg*zg);
 //output_high(pin_G0); // test
 
 If (result >=0.9 )// 1.2 1.1 1.0 0.9
 {
 fprintf(valid,"result = %f\n\r",result);
 fprintf(valid," xg  = %f\n\r",xg );
 fprintf(valid," yg  = %f\n\r",yg );
 fprintf(valid," zg  = %f\n\r",zg );
 output_high(pin_G0);
 //output_high(pin_E1);
 delay_ms(2000);//500
 }
 else
 {
 output_low(pin_G0);
 delay_ms(1000);
 
 }
 
 return result;
 }
 | 
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Jan 19, 2020 11:41 am |   |  
				| 
 |  
				| The ADXL INT1 pin defaults to active high. It'll go high when it is signalling.
 What is VddIO connected to?.
 It is this that the I/O should go up to. It should be connected to the same
 3.3v supply as Vs. It sounds as if it is actually connected to a lower
 supply.
 |  |  
		|  |  
		| Cogitum 
 
 
 Joined: 22 Mar 2012
 Posts: 70
 Location: France (Paris)
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Jan 19, 2020 12:04 pm |   |  
				| 
 |  
				| Hello Ttelmah Thanks for your reactivity.
 
 The power supply (3.3V) is the same for 18F and ADXL.
 Probably the problem is the wrong  ADXL register set up.
 Using another one "h" file on/off checked by LED on pin_G0 and
 hyperterminal working well. "H" file is with few adxl setup register like :
 
  	  | Code: |  	  | float32 resultat;
 //output_high(pin_G0);
 
 i2c_start();
 i2c_write(ACCEL_WRITE_ADDR);
 i2c_write(0X31);
 /////i2c_write(0X0B);////+-16      init des registres (scale)
 i2c_write(0X01);///+-4g
 i2c_stop();
 
 I2C_start();
 i2c_write(ACCEL_WRITE_ADDR);
 i2c_write(ACCEL_PWRCTRL_ADDR);
 i2c_write(ACCEL_MEASURE_MODE);
 I2C_stop();
 
 | 
 Moving ADXL in this case (of course no INT1 output) the result is fine.
 But not right for me.
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Jan 19, 2020 1:34 pm |   |  
				| 
 |  
				| Ttelmah asked you this question: 
  	  | Ttelmah wrote: |  	  | What is Vddio connected to ?
 
 | 
 What do you have connected to the Vdd I/O pin ?
 This is pin 1 on the ADXL345 chip.
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Jan 19, 2020 2:02 pm |   |  
				| 
 |  
				| Exactly. The ADXL has two power pins. One feeds the internal controller, the other
 the I/O.
 I'm suspicious the I/O voltage is not correctly supplied.
 |  |  
		|  |  
		| Cogitum 
 
 
 Joined: 22 Mar 2012
 Posts: 70
 Location: France (Paris)
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Jan 19, 2020 2:06 pm |   |  
				| 
 |  
				| On the pin 1  3.3Vdc (regulated) |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Jan 19, 2020 3:00 pm |   |  
				| 
 |  
				| Do you have an LED connected to the INT1 pin ? Or is anything connected to it ?
 |  |  
		|  |  
		| Cogitum 
 
 
 Joined: 22 Mar 2012
 Posts: 70
 Location: France (Paris)
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Jan 19, 2020 3:10 pm |   |  
				| 
 |  
				| Just a fluke multimètre in VDC mode |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Sun Jan 19, 2020 10:07 pm |   |  
				| 
 |  
				| Here is newguy's code for the ADXL345.  It uses the INT1 pin for interrupts. http://www.ccsinfo.com/forum/viewtopic.php?t=51309&start=1
 You should copy his setup data for the registers.  His code uses SPI
 and you're using i2C.  But that doesn't matter.  Just copy the setup data.
 
 For example, he's writing 0x7F do the INT_MAP register.  This sets the
 ADXL345 to use INT1 for Data Ready.
 He is also writing 0x80 to the INT_ENABLE register.   This sets INT1 high
 if data is available to be read from the ADXL345.
 
 You are trying to use "Activity" as the interrupt cause.  But that depends
 upon the Threshold register.  Why not do it more simply, and just do it
 for Data Ready like newguy does it ?
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Jan 20, 2020 1:04 am |   |  
				| 
 |  
				| Also, honestly, a 'voltmeter' is not going to actually 'see' the level of an interrupt on this pin. Voltmeters are slow. Logic signals are fast....
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Jan 20, 2020 7:07 am |   |  
				| 
 |  
				| Ttelmah, it's occurred to me - suppose his INT1 output is at a 50% duty cycle.  With his 3.3v Vdd, that signal would be averaged to about 1.7v on
 his voltmeter, which is what he reports.
 |  |  
		|  |  
		| Ttelmah 
 
 
 Joined: 11 Mar 2010
 Posts: 19966
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Mon Jan 20, 2020 8:41 am |   |  
				| 
 |  
				| Exactly the way I'm thinking. A burst of pulses, would typically read as a voltage like this.
 |  |  
		|  |  
		| benoitstjean 
 
 
 Joined: 30 Oct 2007
 Posts: 590
 Location: Ottawa, Ontario, Canada
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Jan 22, 2020 6:02 am |   |  
				| 
 |  
				| Bonjour @Cogitum, 
 I am using the same accelerometer. I am not at the office (should be there soon) then I can check.
 
 Don't forget also that the sensitivity will also impact how the interrupts work. You have the ACTIVITY THRESHOLD and INACTIVITY THRESHOLD that you must configure.
 
 I set the ACT_TH to 8 and INACT_TH to 5.
 
 Too high of an ACT_TH will take a harder tap to trigger it but too high of an INACT_TH will also require the IC to be very stable before it is triggered.
 
 Let me get back to you once I get to the office.
 
 A bientôt,
 
 Benoit
 |  |  
		|  |  
		| benoitstjean 
 
 
 Joined: 30 Oct 2007
 Posts: 590
 Location: Ottawa, Ontario, Canada
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Jan 22, 2020 7:25 am |   |  
				| 
 |  
				| Hi again @Cogitum, 
 I didn't go through your code because it's long. But I re-read your explanation and I'm not sure if I understand what is not working based on your description of what seems to be the problem:
 
 
  	  | Quote: |  	  | From time to time by moving ADXL the level goes up to 1.7V! Then goes back down to 0V.
 
 | 
 To me this is normal behaviour. INT1 goes high then back low to tell you that motion was detected. But you also have to monitor the second interrupt INT2 to tell you that the motion has stopped when no more motion is detected.
 
 There are a few things also that you need to understand that will impact the behaviour such as:
 
 A) The sensitivity thresholds (ACT_THRESH and INACT_THRESH) as explained in my previous post.
 
 B) The configuration of the motion reporting: I don't remember what the name is but with this setting, you can make the accelerometer work two ways:
 
 B.1) In the first mode, it can trigger the INT1 interrupt everytime you tap the ADXL and when you stop tapping it and no motion is detected for the amount of time you specify, then INT2 will trigger. So if you were to "tap" the ADXL 3 times, I believe you will see the following (I don't use this mode so I'm not 100% sure if the "no tap" occurs only once or if it occurs after every "tap"):
 
 "tap" --> INT1..."tap" --> INT1..."tap" --> INT1.....(3 seconds without tapping)...... "no tap" INT2
 
 B.2) In the second mode, as soon as the first tap is detected, you will get the motion interrupt and will not get anymore interrupts until the motion stops for a certain amount of time:
 
 "tap" --> INT1..."tap"..."tap"..."tap"..."tap"..."tap".......(3 seconds without tapping)...... "no tap" INT2
 
 C) You must clear the registers when the interrupt is detected by reading register 0x30 to reset the interrupts.
 
 As explained in my previous post, I used ACT_TH of 8 and INACT_TH of 5.
 
 Here's my configuration code which triggers a single interrupt when motion is detected, not matter how many times you tap it and will trigger the second interrupt when motion stops:
 
 CONFIGURE ACCELEROMETER:
 
  	  | Code: |  	  | ADXL345_SetRegister( ADXL345_DATA_FORMAT   /*0x31*/, 0x03 );
 ADXL345_SetRegister( ADXL345_POWER_CTL     /*0x2D*/, 0x28 );
 ADXL345_SetRegister( ADXL345_BW_RATE       /*0x2C*/, 0x0B );
 
 // R/W Activity threshold
 ADXL345_SetRegister( ADXL345_THRESH_ACT    /*0x24*/, ADXL.ActivityThreshold );
 
 // R/W Inactivity threshold
 ADXL345_SetRegister( ADXL345_THRESH_INACT  /*0x25*/, ADXL.InactivityThreshold );
 
 // R/W Inactivity time
 ADXL345_SetRegister( ADXL345_TIME_INACT    /*0x26*/, ADXL_DEFAULT_TIMEOUT );
 
 // R/W Axis enable control for activity and inactivity detection
 ADXL345_SetRegister( ADXL345_ACT_INACT_CTL /*0x27*/, 0xFF );
 
 // Set which interrupts get enabled
 ADXL345_SetRegister( ADXL345_INT_ENABLE    /*0x2E*/, 0x18 );
 
 // Map interrupt pins to correct interrupt
 ADXL345_SetRegister( ADXL345_INT_MAP       /*0x2F*/, 0xEF );
 
 | 
 
 START ACCELEROMETER:
 
  	  | Code: |  	  | // Motion interrupt edge trigger
 ext_int_edge( 3, L_TO_H );
 ext_int_edge( 4, L_TO_H);
 
 // Enable interrupt pins on MCU
 enable_interrupts( INT_EXT3 );
 enable_interrupts( INT_EXT4 );
 
 // Clear any interrupts that might have been triggered after the setup
 ADXL345_GetRegister( 0x30, 1, &ADXL.Data );
 
 | 
 
 INTERRUPTS:
 
  	  | Code: |  	  | #INT_EXT3 // Motion detected
 void INT_EXT_INPUT3( void )
 {
 // Get interrupt source to clear the register
 ADXL345_GetRegister( 0x30, 1, &ADXL.Data );
 }
 
 #INT_EXT4 // Motion stopped
 void INT_EXT_INPUT4( void )
 {
 // Get interrupt source to clear the register
 ADXL345_GetRegister( 0x30, 1, &ADXL.Data );
 }
 
 | 
 Don't forget also that when you read the registers, it's from 1 - 4 bytes depending on the register you read.
 
 
 Hope this sheds a bit of light.
 
 Bonne journée et bonne chance.
 
 Benoit
 |  |  
		|  |  
		| PCM programmer 
 
 
 Joined: 06 Sep 2003
 Posts: 21708
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Jan 22, 2020 8:59 am |   |  
				| 
 |  
				|  	  | benoitstjean wrote: |  	  | : 
  	  | Quote: |  	  | From time to time by moving ADXL the level goes up to 1.7V! Then goes back down to 0V.
 
 | 
 To me this is normal behaviour. INT1 goes high then back low to tell you that motion was detected. But you also have to monitor the second interrupt INT2 to tell you that the motion has stopped when no more motion is detected.
 
 | 
 Benoit, this is not even remotely normal.  Here is the data sheet:
 https://www.analog.com/media/en/technical-documentation/data-sheets/ADXL345.pdf
 Look at Table 13 on page 21.  It shows that minimum Voh = 0.8 x Vddio.
 He has stated earlier in this thread that Vddio is connected to +3.3v.
 So 0.8 x 3.3v =2.64v minimum.   In reality it will be closer to 3.3v.
 So 1.7v as the high level is wrong.  It is not normal.
 
 We have already figured out that because he's using a voltmeter, it is
 averaging the output pulses on INT1, and that's why he gets 1.7v.
 He needs to get a scope.  He can buy a new digital scope on Amazon
 for less than $200 USD.  Example:
 https://www.amazon.com/Hantek-DSO5072P-Digital-Oscilloscope-Bandwidth/dp/B00RJPXB6Y/ref=sr_1_4?
 |  |  
		|  |  
		|  |  
  
	| 
 
 | You cannot post new topics in this forum You cannot reply to topics in this forum
 You cannot edit your posts in this forum
 You cannot delete your posts in this forum
 You cannot vote in polls in this forum
 
 |  
 Powered by phpBB © 2001, 2005 phpBB Group
 
 |