![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
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;
} |
|
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
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. |
|
![](templates/subSilver/images/spacer.gif) |
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
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) |
|
![](templates/subSilver/images/spacer.gif) |
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 ? |
|
![](templates/subSilver/images/spacer.gif) |
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 |
|
![](templates/subSilver/images/spacer.gif) |
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 ? |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
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.... |
|
![](templates/subSilver/images/spacer.gif) |
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. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19378
|
|
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. |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 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 |
|
![](templates/subSilver/images/spacer.gif) |
benoitstjean
Joined: 30 Oct 2007 Posts: 553 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 |
|
![](templates/subSilver/images/spacer.gif) |
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? |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|