CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

ADXL345 problem COMPILER v 5.078
Goto page 1, 2  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Cogitum



Joined: 22 Mar 2012
Posts: 70
Location: France (Paris)

View user's profile Send private message

ADXL345 problem COMPILER v 5.078
PostPosted: Sun Jan 19, 2020 11:18 am     Reply with quote

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: 19215

View user's profile Send private message

PostPosted: Sun Jan 19, 2020 11:41 am     Reply with quote

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)

View user's profile Send private message

PostPosted: Sun Jan 19, 2020 12:04 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Sun Jan 19, 2020 1:34 pm     Reply with quote

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: 19215

View user's profile Send private message

PostPosted: Sun Jan 19, 2020 2:02 pm     Reply with quote

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)

View user's profile Send private message

PostPosted: Sun Jan 19, 2020 2:06 pm     Reply with quote

On the pin 1 3.3Vdc (regulated)
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jan 19, 2020 3:00 pm     Reply with quote

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)

View user's profile Send private message

PostPosted: Sun Jan 19, 2020 3:10 pm     Reply with quote

Just a fluke multimètre in VDC mode
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Jan 19, 2020 10:07 pm     Reply with quote

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: 19215

View user's profile Send private message

PostPosted: Mon Jan 20, 2020 1:04 am     Reply with quote

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

View user's profile Send private message

PostPosted: Mon Jan 20, 2020 7:07 am     Reply with quote

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: 19215

View user's profile Send private message

PostPosted: Mon Jan 20, 2020 8:41 am     Reply with quote

Exactly the way I'm thinking. A burst of pulses, would typically read as
a voltage like this.
benoitstjean



Joined: 30 Oct 2007
Posts: 543
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Jan 22, 2020 6:02 am     Reply with quote

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: 543
Location: Ottawa, Ontario, Canada

View user's profile Send private message

PostPosted: Wed Jan 22, 2020 7:25 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Jan 22, 2020 8:59 am     Reply with quote

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?
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page 1, 2  Next
Page 1 of 2

 
Jump to:  
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