|
|
View previous topic :: View next topic |
Author |
Message |
respected
Joined: 16 May 2006 Posts: 95
|
18F26J50 and MMA8452 accelerometer reading FF |
Posted: Wed Apr 25, 2012 4:55 am |
|
|
hi,
I wrote 18f26j50 and mma8452 accelerometer code. But seen FF on screen.
I changed i2c_RegRead(SlaveAddressIIC, MMA8452_OFF_X) result is same. where is mistake?
Thanks..
Code: |
#include <18F26J50.h>
#fuses INTRC_IO,NOPROTECT,NODEBUG,NOCPUDIV
#use delay(clock=8000000)
#include <lcdaccess.c>
#use i2c(master, sda=PIN_B5, scl=PIN_B4, force_hw)
#define SlaveAddressIIC 0x38
#define CTRL_REG1 0x2A
#define CTRL_REG2 0x2B
#define CTRL_REG3 0x2C
#define CTRL_REG4 0x2D
#define CTRL_REG5 0x2E
#define MMA8452_OFF_X 0x2F
#define MMA8452_OFF_Y 0x30
#define MMA8452_OFF_Z 0x31
///////////////////////////////////
#define ASLP_RATE1_MASK 0x80
#define ASLP_RATE0_MASK 0x40
#define DR2_MASK 0x20
#define DR1_MASK 0x10
#define DR0_MASK 0x08
#define LNOISE_MASK 0x04
#define FREAD_MASK 0x02
#define ACTIVE_MASK 0x01
#define ASLP_RATE_MASK 0xC0
#define DR_MASK 0x38
//
#define ASLP_RATE_20MS 0x00
#define ASLP_RATE_80MS ASLP_RATE0_MASK
#define ASLP_RATE_160MS ASLP_RATE1_MASK
#define ASLP_RATE_640MS ASLP_RATE1_MASK+ASLP_RATE0_MASK
//
#define DATA_RATE_1250US 0x00
#define DATA_RATE_2500US DR0_MASK
#define DATA_RATE_5MS DR1_MASK
#define DATA_RATE_10MS DR1_MASK+DR0_MASK
#define DATA_RATE_20MS DR2_MASK
#define DATA_RATE_80MS DR2_MASK+DR0_MASK
#define DATA_RATE_160MS DR2_MASK+DR1_MASK
#define DATA_RATE_640MS DR2_MASK+DR1_MASK+DR0_MASK
/*
** XYZ_DATA_CFG Sensor Data Configuration Register
*/
#define XYZ_DATA_CFG_REG 0x0E
//
#define HPF_OUT_BIT Bit._4
#define FS1_BIT Bit._1
#define FS0_BIT Bit._0
//
#define HPF_OUT_MASK 0x10
#define FS1_MASK 0x02
#define FS0_MASK 0x01
#define FS_MASK 0x03
#define FULL_SCALE_8G FS1_MASK
#define FULL_SCALE_4G FS0_MASK
#define FULL_SCALE_2G 0x00
byte value[6]; // working value result scratchpad
byte full_scale; // current accelerometer full scale setting
void i2c_RegWrite(byte address, byte reg,byte val)
{
i2c_start();
i2c_write(address);
i2c_write(reg);
i2c_write(val);
i2c_stop();
}
/////////////////////////////
byte i2c_RegRead(byte address, byte reg)
{
byte b;
i2c_start(); // Send Start
i2c_write(address); // Send IIC "Write" Address
i2c_write(reg); // Send Register
i2c_start(); // Send Repeat Start
i2c_write(address+1); // Send IIC "Read" Address
b = i2c_read(1); // *** Dummy read: reads "IIC_ReadAddress" value ***
b = i2c_read(1); // Read Register Value
i2c_stop(); // Send Stop
return b;
}
////////////////////////////
void MMA8452_Active ()
{
i2c_RegWrite(SlaveAddressIIC, CTRL_REG1, (i2c_RegRead(SlaveAddressIIC, CTRL_REG1) | ACTIVE_MASK));
}
///////////////////////////
void MMA8452_Standby (void)
{
byte n;
/*
** Read current value of System Control 1 Register.
** Put sensor into Standby Mode.
** Return with previous value of System Control 1 Register.
*/
n = i2c_RegRead(SlaveAddressIIC, CTRL_REG1);
i2c_RegWrite(SlaveAddressIIC, CTRL_REG1, n & ~ACTIVE_MASK);
}
////////////////////////////////////
void MMA8452_Init (void)
{
MMA8452_Standby();
/*
** Configure sensor for:
** - Sleep Mode Poll Rate of 50Hz (20ms)
** - System Output Data Rate of 200Hz (5ms)
** - Full Scale of +/-2g
*/
i2c_RegWrite(SlaveAddressIIC, CTRL_REG1, ASLP_RATE_20MS+DATA_RATE_5MS);
i2c_RegWrite(SlaveAddressIIC, XYZ_DATA_CFG_REG, FULL_SCALE_2G);
}
/////////////////////////////
void main(void)
{
lcd_init();
output_high(PIN_A3);
MMA8452_Init();
MMA8452_Active();
full_scale= FULL_SCALE_2G;
while(true)
{
printf(lcd_putc,"\fivme:%x",i2c_RegRead(SlaveAddressIIC, MMA8452_OFF_X));
delay_ms(100);
}
}//main
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9224 Location: Greensville,Ontario
|
|
Posted: Wed Apr 25, 2012 5:04 am |
|
|
1) you don't specify the speed of the I2C bus..so can the device accept the default speed ??
2) do you have the correct pullup resistors on the I2C bus? Val;ue depends upon Vcc,distance and of course speed(which we don't know).
Ttemah(sp) has a nice I2C 'sniffer' program here, you should download it to verify your hardware. |
|
|
respected
Joined: 16 May 2006 Posts: 95
|
|
Posted: Wed Apr 25, 2012 5:13 am |
|
|
it have pull up registor because this is module. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19503
|
|
Posted: Wed Apr 25, 2012 7:29 am |
|
|
Just because it is a 'module', does not automatically imply it has the pull up resistors. You need to check the data for the specific 'module'. Some are built to connect to ports that already have the resistors, so do not have them on the board, or they are optional....
How have you got the supply connected?. There are two supply pins to the chip (and presumably the module). You need both to be present.
Do you know how the module has the SA0 pin connected?. The chip has two different slave addresses possible. 0x38 - if SA0 is low, and 0x3A, if SA0 is high.
Then your read code appears faulty. You send the register address, and then read twice, saying "Dummy read: reads "IIC_ReadAddress" value" for the first read. This is not the case. The value you read after sending the address is the data on the very next transaction. A dummy read like this is necessary with SSP, where the master receives 'back' a dummy byte when sending, but not with I2C.
Best Wishes |
|
|
respected
Joined: 16 May 2006 Posts: 95
|
|
Posted: Thu Apr 26, 2012 3:53 pm |
|
|
Code: |
#include <18F26J50.h>
#fuses INTRC_IO,NOPROTECT,NODEBUG,NOCPUDIV
#use delay(clock=8000000)
#include <lcdaccess.c>
#use i2c(master, sda=PIN_B5, scl=PIN_B4, force_hw)
//#define MMA8452_ADDRESS 0x1C //SA0=0
#define MMA8452_ADDRESS 0x1D //SA0=1
int accelCount[3]; // Stores the 12-bit signed value
float accelG[3]; // Stores the real accel value in g's
/* Set the scale below either 2, 4 or 8*/
const byte SCALE = 2; // Sets full-scale range to +/-2, 4, or 8g. Used to calc real g values.
/* Set the output data rate below. Value should be between 0 and 7*/
const byte dataRate = 0; // 0=800Hz, 1=400, 2=200, 3=100, 4=50, 5=12.5, 6=6.25, 7=1.56
byte readRegister(unsigned int8 address)
{
byte data;
i2c_Start();
i2c_write((MMA8452_ADDRESS<<1)); // write 0xB4
i2c_write(address); // write register address
i2c_Start();
i2c_write((MMA8452_ADDRESS<<1)|0x01); // write 0xB5
i2c_read(TRUE);
delay_cycles(5);
data = i2c_read(); // Get MSB result
i2c_stop();
return data;
}
void writeRegister(unsigned char address, unsigned char data)
{
i2c_Start();
i2c_write((MMA8452_ADDRESS<<1));// write 0xB4
i2c_write(address); // write register address
i2c_write(data);
i2c_stop();
}
void MMA8452Standby()
{
byte c = readRegister(0x2A);
writeRegister(0x2A, c & ~(0x01));
}
void MMA8452Active()
{
byte c = readRegister(0x2A);
writeRegister(0x2A, c | 0x01);
}
void initMMA8452(byte fsr, byte dataRate)
{
MMA8452Standby(); // Must be in standby to change registers
/* Set up the full scale range to 2, 4, or 8g. */
if ((fsr==2)||(fsr==4)||(fsr==8))
writeRegister(0x0E, fsr >> 2);
else
writeRegister(0x0E, 0);
/* Setup the 3 data rate bits, from 0 to 7 */
writeRegister(0x2A, readRegister(0x2A) & ~(0x38));
if (dataRate <= 7)
writeRegister(0x2A, readRegister(0x2A) | (dataRate << 3));
/* Set up portrait/landscap registers - 4 steps:
1. Enable P/L
2. Set the back/front angle trigger points (z-lock)
3. Set the threshold/hysteresis angle
4. Set the debouce rate
// For more info check out this app note: http://cache.freescale.com/files/sensors/doc/app_note/AN4068.pdf */
writeRegister(0x11, 0x40); // 1. Enable P/L
writeRegister(0x13, 0x44); // 2. 29deg z-lock (don't think this register is actually writable)
writeRegister(0x14, 0x84); // 3. 45deg thresh, 14deg hyst (don't think this register is writable either)
writeRegister(0x12, 0x50); // 4. debounce counter at 100ms (at 800 hz)
/* Set up single and double tap - 5 steps:
1. Set up single and/or double tap detection on each axis individually.
2. Set the threshold - minimum required acceleration to cause a tap.
3. Set the time limit - the maximum time that a tap can be above the threshold
4. Set the pulse latency - the minimum required time between one pulse and the next
5. Set the second pulse window - maximum allowed time between end of latency and start of second pulse
for more info check out this app note: http://cache.freescale.com/files/sensors/doc/app_note/AN4072.pdf */
writeRegister(0x21, 0x7F); // 1. enable single/double taps on all axes
// writeRegister(0x21, 0x55); // 1. single taps only on all axes
// writeRegister(0x21, 0x6A); // 1. double taps only on all axes
writeRegister(0x23, 0x20); // 2. x thresh at 2g, multiply the value by 0.0625g/LSB to get the threshold
writeRegister(0x24, 0x20); // 2. y thresh at 2g, multiply the value by 0.0625g/LSB to get the threshold
writeRegister(0x25, 0x08); // 2. z thresh at .5g, multiply the value by 0.0625g/LSB to get the threshold
writeRegister(0x26, 0x30); // 3. 30ms time limit at 800Hz odr, this is very dependent on data rate, see the app note
writeRegister(0x27, 0xA0); // 4. 200ms (at 800Hz odr) between taps min, this also depends on the data rate
writeRegister(0x28, 0xFF); // 5. 318ms (max value) between taps max
/* Set up interrupt 1 and 2 */
writeRegister(0x2C, 0x02); // Active high, push-pull interrupts
writeRegister(0x2D, 0x19); // DRDY, P/L and tap ints enabled
writeRegister(0x2E, 0x01); // DRDY on INT1, P/L and taps on INT2
MMA8452Active(); // Set to active to start reading
}
void readreg(byte address, int i, byte * dest)
{
int j;
i2c_start();
i2c_write((MMA8452_ADDRESS<<1)); // write 0xB4
i2c_write(address); // write register address
i2c_start();
i2c_write((MMA8452_ADDRESS<<1)|0x01); // write 0xB5
for ( j=0; j<i; j++)
{
i2c_read(TRUE);
dest[j] = i2c_read(); // Get MSB result
}
i2c_stop();
}
void readAccelData(int * destination)
{ int i;
byte rawData[6]; // x/y/z accel register data stored here
readreg(0x01, 6, &rawData[0]); // Read the six raw data registers into data array
/* loop to calculate 12-bit ADC and g value for each axis */
for ( i=0; i<6; i+=2)
{
destination[i/2] = ((rawData[i] << 8) | rawData[i+1]) >> 4; // Turn the MSB and LSB into a 12-bit value
if (rawData[i] > 0x7F)
{ // If the number is negative, we have to make it so manually (no 12-bit data type)
destination[i/2] = ~destination[i/2] + 1;
destination[i/2] *= -1; // Transform into negative 2's complement #
}
}
}
void main(void)
{
int c=0;
int i;
lcd_init();
start:
output_high(PIN_A3);
c=readRegister(0x0D);
if(c==0x2a) printf(lcd_putc,"\fMMA8452");
else {printf(lcd_putc,"\f not connect MMA8");goto start;}
/* Set up the Full Scale Range to 2, 4, or 8g. (fsr,datarate)*/
/* Setup the 3 data rate bits, from 0 to 7 */
initMMA8452(2,3);
while(true)
{
// printf(lcd_putc,"\nACCEL:%x",c);
////////////////////////////////////////////////////
/* If int1 goes high, all data registers have new data */
if (input(PIN_A2)==0) // Interrupt pin, should probably attach to interrupt function
{
readAccelData(accelCount); // Read the x/y/z adc values
/* Now we'll calculate the accleration value into actual g's */
for (i=0; i<3; i++)
{
accelG[i] = (float) accelCount[i]/((1<<12)/(2*SCALE)); // get actual g value, this depends on scale being set
}
for (i=0; i<3; i++)
{
printf(lcd_putc,"\nACCEL:%f",accelG[i]);
}
}
delay_ms(100);
///////////////////////////////////////////////////
} //while
}//main
|
This is my new code. I read "who am i" register. But I didn't data yet. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Apr 26, 2012 5:32 pm |
|
|
Quote: |
readRegister()
readreg()
|
The two routines above are not doing a NACK on the last call to
i2c_read() in an i2c transaction. You need to fix the code so they
do that. If there is only one call to i2c_read() in a function, then it
counts as the "last" one, and it must do a NACK. Do a NACK by
giving it a 0 parameter. Example:
Code: |
result = i2c_read(0);
|
The NACK tells the i2c slave that you are done reading data, and it's
part of the i2c specification and it's essential. Look at the diagrams on
page 17 of the MMA8452Q data sheet, for Single Byte Read and Mulitiple
Byte Read. Look at the end of each transaction for a block labeled "NAK":
http://cache.freescale.com/files/sensors/doc/data_sheet/MMA8452Q.pdf |
|
|
respected
Joined: 16 May 2006 Posts: 95
|
|
Posted: Fri Apr 27, 2012 1:13 am |
|
|
data = i2c_read(); // Get MSB result
and
dest[j] = i2c_read(); // Get MSB result
lcd screen:
first line MMA8452 (this is mean = device is connect)
second line 1.573 and 52.288
but value is not changing |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Apr 27, 2012 7:11 pm |
|
|
You didn't make the changes that I suggested. You didn't add the 0x00
parameter on the last call of i2c_read() in each function.
Fix the code in these two functions, and then post edited functions see I can see your changes:
Code: |
readRegister()
readreg()
|
Also, I'm not sure if your PIC even sees the MMA8452 chip on the i2c bus.
Here is an i2c bus scanner program that will report the addresses of any
i2c slave devices that it finds on the bus. Modify the #include, #fuses,
and the #use statements so it will work with your board. Then run it
and see what devices it finds:
http://www.ccsinfo.com/forum/viewtopic.php?t=47707&start=21 |
|
|
respected
Joined: 16 May 2006 Posts: 95
|
|
Posted: Sat Apr 28, 2012 3:18 pm |
|
|
Code: | int8 readRegister(unsigned int8 address)
{
byte data;
i2c_Start();
i2c_write((MMA8452_ADDRESS<<1)); // write 0xB4
i2c_write(address); // write register address
i2c_Start();
i2c_write((MMA8452_ADDRESS<<1)|0x01); // write 0xB5
i2c_read(0);
delay_cycles(5);
data = i2c_read(); // Get MSB result
i2c_stop();
return data;
} |
what do you want to say? |
|
|
dyeatman
Joined: 06 Sep 2003 Posts: 1933 Location: Norman, OK
|
|
Posted: Sat Apr 28, 2012 3:59 pm |
|
|
Did you run PCMs bus scanner program? If so, what results did you get? _________________ Google and Forum Search are some of your best tools!!!! |
|
|
respected
Joined: 16 May 2006 Posts: 95
|
|
Posted: Sat Apr 28, 2012 4:32 pm |
|
|
yes. I tried it. chip founds:1 ack:3a |
|
|
respected
Joined: 16 May 2006 Posts: 95
|
|
Posted: Sat Apr 28, 2012 4:46 pm |
|
|
Code: |
#define I2C_WRITE_ADDR 0x3A
#define I2C_READ_ADDR 0x3B
int8 readreg(int8 address)
{
int8 data;
i2c_start(); // initiate start condition
i2c_write(I2C_WRITE_ADDR); // device address
i2c_write(address); // register address
i2c_start();
i2c_write(I2C_READ_ADDR); // device address
data = i2c_read(0);
i2c_stop();
return data;
}
|
I guess this is my code. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Apr 29, 2012 7:46 pm |
|
|
Quote: | yes. I tried it. chip founds:1 ack:3a
|
That means the i2c bus scanner program found the i2c slave chip at the
correct address. That's good.
Quote: |
I guess this is my code.
#define I2C_WRITE_ADDR 0x3A
#define I2C_READ_ADDR 0x3B
int8 readreg(int8 address)
{
int8 data;
i2c_start(); // initiate start condition
i2c_write(I2C_WRITE_ADDR); // device address
i2c_write(address); // register address
i2c_start();
i2c_write(I2C_READ_ADDR); // device address
data = i2c_read(0);
i2c_stop();
return data;
}
|
OK, that's correct. But what about the other routine, called readreg().
Did you fix that one ? |
|
|
respected
Joined: 16 May 2006 Posts: 95
|
|
Posted: Mon Apr 30, 2012 12:38 am |
|
|
Code: | #include <18F26J50.h>
#fuses INTRC_IO,NOPROTECT,NODEBUG,NOCPUDIV
#use delay(clock=8000000)
#include <lcdaccess.c>
#include <accel.h>
#use i2c(master, sda=PIN_B5, scl=PIN_B4)
#define I2C_WRITE_ADDR 0x3A
#define I2C_READ_ADDR 0x3B
int8 readreg(int8 address)
{
int8 data;
i2c_start(); // initiate start condition
i2c_write(I2C_WRITE_ADDR); // device address
i2c_write(address); // register address
i2c_start();
i2c_write(I2C_READ_ADDR); // device address
data = i2c_read(0);
i2c_stop();
return data;
}
void writeReg(unsigned char address, unsigned char data)
{
i2c_Start();
i2c_write(I2C_WRITE_ADDR);//
i2c_write(address); //
i2c_write(data);
i2c_stop();
}
void MMA8452_Standby (void)
{
byte n;
n = readreg(CTRL_REG1);
writeReg(CTRL_REG1, n & ~ACTIVE_MASK);
}
void MMA8452_Active ()
{
writeReg(CTRL_REG1, (readreg(CTRL_REG1) | ACTIVE_MASK));
}
void main()
{
long x;
int hix,lox;
lcd_init();
int8 data;
start:
data=readreg(0x0d);
printf(lcd_putc,"\n\data: %0u", data);
if(data!=42) goto start;
MMA8452_Standby();
writeReg(CTRL_REG1,(readreg(CTRL_REG1)& ~FREAD_MASK));
MMA8452_Active();
delay_ms(100);
while(true)
{
hix=readreg(OUT_X_MSB_REG);
lox=readreg(OUT_X_LSB_REG);
x = make16(hix,lox);
printf(lcd_putc,"\fx: %0Lu",x);
delay_ms(100);
}
}
|
accel.h
Code: | /******************************************************************************
*
* M M A 8 4 5 2 Q A C C E L E R O M E T E R H E A D E R
*
*/
#ifndef ACCEL_H
#define ACCEL_H
// Accelerometer registers
#define HP_FILTER_CUTOFF 0x0f
#define CTRL_REG1 0x2a
#define CTRL_REG2 0x2b
#define CTRL_REG3 0x2c
#define CTRL_REG4 0x2d
#define CTRL_REG5 0x2e
#define XYZ_DATA_CFG 0x0e
#define F_SETUP 0x09
#define OUTPUT_REGS 0x01
#define INT_SRC_REG 0x0c
#define PULSE_CFG 0x21
#define PULSE_SRC 0x22
#define PULSE_THS_X 0x23
#define PULSE_THS_Y 0x24
#define PULSE_THS_Z 0x25
#define PULSE_TMLT 0x26
#define PULSE_LTCY 0x27
#define PULSE_WIND 0x28
#define FF_MT_CFG 0x15
#define FF_MT_THS 0x17
#define FF_MT_COUNT 0x18
#define ASLP_COUNT 0x29
#define SYSMOD 0x0b
#define TRANS_CFG 0x1d
#define TRANS_THS 0x1f
#define TRANS_COUNT 0x20
////////////////////
#define ASLP_RATE1_MASK 0x80
#define ASLP_RATE0_MASK 0x40
#define DR2_MASK 0x20
#define DR1_MASK 0x10
#define DR0_MASK 0x08
#define LNOISE_MASK 0x04
#define FREAD_MASK 0x02
#define ACTIVE_MASK 0x01
#define ASLP_RATE_MASK 0xC0
#define DR_MASK 0x38
#define OUT_X_MSB_REG 0x01
#define OUT_X_LSB_REG 0x02
#define OUT_Y_MSB_REG 0x03
#define OUT_Y_LSB_REG 0x04
#define OUT_Z_MSB_REG 0x05
#define OUT_Z_LSB_REG 0x06
// Acceleromenet events
#define NEW_DATA_EVT 0x01
#define ACC_SLEEP_EVT 0x02
#define CAL_PRESS_EVT 0x04
#define CAL_RELEASE_EVT 0x08
#endif |
|
|
|
|
|
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
|