Sorry to ask another TWI question...

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

But I don't seem to be able to get this to work.  I'm helping someone port their Arduino code and I'm 99% of the way there.  I'm using the Fleury library.  It's just a simple reading of a IMU.  I get the yellow led's to start and it never gets past the first check read.

 

     i2c_start_wait(imu+I2C_WRITE);     // set device address and write mode
     i2c_write(0x00);                        // write address for x valuelow

 

between these two lines is where it locks up.

 

This is my first try in I2C

 

Note:  I'm sure there are tons of issues in this code, but right now my main priority is actually reading the IMU...

 

 

#define F_CPU 16000000UL
#include<avr/interrupt.h>
#include <util/delay.h>
#include <math.h>
#include <stdlib.h>
extern "C"
{
#include "lib/light_ws2812.h"
#include "lib\i2cmaster.h"
}
#define ledsize 4
int ledvalue = 50;
struct cRGB led[ledsize];
#define imu 0x53

volatile float delaysensevalue = 0;
volatile int sensoroffsetroutine = 1;
volatile float sensoroffset = 0;
#define filteredsensorvalue (xvalue - sensoroffset)
#define ledvalue ((xvalue + sensoroffset)*20) 
volatile int delayvalue (delaysensevalue);
volatile int pwmvalue=1;
volatile int patternselectorarray[5] = {1,2,3,4,5};  //was a good idea but not cleanly implemented.  maybe later
volatile float xvalue = 0;
volatile float yvalue = 0;
volatile char datareturn = 0;

////////////////////////////////////////////////////////////////////////////////////////////////////////
//Functions
////////////////////////////////////////////////////////////////////////////////////////////////////////
void delay(int delayvalue)
{
  for (int i = 0; i<=delayvalue; i++)
    {
    _delay_ms(1);
    }
}
void setupimuint()
{
        i2c_start(imu+I2C_WRITE);              //start write process
        i2c_write(0x24);                       //set thresh act
        i2c_write(0b00000001);                 // ret=0 -> Ok, ret=1 -> no ACK 
        i2c_stop();
        i2c_start(imu+I2C_WRITE);              //start write process
        i2c_write(0x27);                       //set act -z bit
        i2c_write(0b10000000);                 // ret=0 -> Ok, ret=1 -> no ACK
        i2c_stop();
        i2c_start(imu+I2C_WRITE);              //start write process
        i2c_write(0x2E);                       //set act z enable
        i2c_write(0b00010000);                 // ret=0 -> Ok, ret=1 -> no ACK     
        i2c_stop();
        i2c_start(imu+I2C_WRITE);              //start write process
        i2c_write(0x2F);                       //set map z to int1
        i2c_write(0b00010000);                 // ret=0 -> Ok, ret=1 -> no ACK           
        i2c_stop();                            // set stop conditon = release bus
        
}
//////////////////////////////////////////////////////////////////////////////////////
void interruptroutine()
{
  while (PIND & PIND2)
  {
  // pattern1();
 //pattern2();
 //pattern3();
 //pattern4();
 //pattern5();
  } 
}
///////////////////////////////////////////////////////////////////////////////////////
void setupAVRint()
{
  DDRD &= (~(1<<DD2));
  EICRA |= 1<<ISC20;
  EICRA |= 1<<ISC21;
  EIMSK |= 1<<INT2;
  sei();
}
///////////////////////////////////////////////////////////////////////////////////////
void setupimu()
{
  _delay_ms(500);
     i2c_start_wait(imu+I2C_WRITE);     // set device address and write mode
     i2c_write(0x00);                        // write address for x valuelow
     i2c_rep_start(imu+I2C_READ);       // set device address and read mode
     datareturn = i2c_readNak();                    // read one byte from EEPROM
     i2c_stop();
     if (!(datareturn = imu))
     {
      while(1)
      {
      //flashred();
      }
     }
}
//////////////////////////////////////////////////////////////////////////////////
void readimu()
{
     i2c_start_wait(imu+I2C_WRITE);     // set device address and write mode
     i2c_write(0x05);                        // write address for x valuelow
     i2c_rep_start(imu+I2C_READ);       // set device address and read mode
     datareturn = i2c_readNak();                    // read one byte from EEPROM
     i2c_stop();
     xvalue = datareturn;
     i2c_start_wait(imu+I2C_WRITE);     // set device address and write mode
     i2c_write(0x05);                        // write address for x valuehigh
     i2c_rep_start(imu+I2C_READ);       // set device address and read mode
     datareturn = i2c_readNak();                    // read one byte from EEPROM
     i2c_stop();
     xvalue = xvalue + datareturn;
     
     i2c_start_wait(imu+I2C_WRITE);     // set device address and write mode
     i2c_write(0x05);                        // write address for y valuelow
     i2c_rep_start(imu+I2C_READ);       // set device address and read mode
     datareturn = i2c_readNak();                    // read one byte from EEPROM
     i2c_stop();
     yvalue = datareturn;
     i2c_start_wait(imu+I2C_WRITE);     // set device address and write mode
     i2c_write(0x05);                        // write address for y valuehigh
     i2c_rep_start(imu+I2C_READ);       // set device address and read mode
     datareturn = i2c_readNak();                    // read one byte from EEPROM
     i2c_stop();
     yvalue = yvalue + datareturn;
}
/////////////////////////////////////////////////////////////////////////////



/////////////////////////////////////////////////////////////////////////////////////////////////////
//Flash patterns
////////////////////////////////////////////////////////////////////////////////////////////////////
void flashred()
{
    for (int i=0; i<ledsize; i++)
    {
    led[i].r=ledvalue;led[i].g=0;led[i].b=0;   
    ws2812_setleds(led,ledsize);
    }
    _delay_ms(200);
    for (int i=0; i<ledsize; i++)
    {
    led[i].r=0;led[i].g=0;led[i].b=0;   
    ws2812_setleds(led,ledsize);
    }
    _delay_ms(200);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
void nomovementpulse()
{
   for(double i=5; i<255; i=i*1.02)
   {
    _delay_ms(5);
    pwmvalue = i;
    for (int x = 0; x<ledsize; x++)
      {
       led[x].r=0;led[x].g=pwmvalue;led[x].b=0;   
       ws2812_setleds(led,ledsize); 
      }
    }
   
   for(double i=255; i>5; i=i/1.02)
   {
    _delay_ms(15);
    pwmvalue = i;
    for (int x = 0; x<ledsize; x++)
      {
        led[x].r=0;led[x].g=pwmvalue;led[x].b=0;
        ws2812_setleds(led,ledsize);
      } 
    }         
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
void pattern1()
{
  //  pattern 1
  readimu();
  for(int i = 0; i<ledsize; i++)
  {
   led[i].r= abs(ledvalue*2);led[i].g=0;led[i].b=abs(ledvalue/2);
  }
   ws2812_setleds(led,ledsize);
   delay(abs(delaysensevalue));
  for(int i = 0; i<ledsize; i++)
  {
  led[i].r=255;led[i].g=0;led[i].b=0;
  }
  ws2812_setleds(led,ledsize);
  delay(abs(delaysensevalue)); 
  
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void pattern2()
{
    
//  pattern 2
  for(int i = 0; i<ledsize; i++)
  {
    readimu();
   led[i].r=abs(ledvalue*2);led[i].g=0;led[i].b=abs(ledvalue/2);
   ws2812_setleds(led,ledsize);
   delay(abs(delaysensevalue));
  }
  
  for(int i = 0; i<ledsize; i++)
  {
    readimu();
   led[i].r=255;led[i].g=0;led[i].b=0;
   ws2812_setleds(led,ledsize);
   delay(abs(delaysensevalue)); 
  }
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void pattern3()
{
  //  pattern 3
  readimu();
  for(int i = 0; i<ledsize; i++)
  {
   led[i].r=abs(ledvalue*2);led[i].g=0;led[i].b=abs(ledvalue/2);
  }
   ws2812_setleds(led,ledsize);
   delay(10);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void pattern4()
{
  readimu();
  //  pattern 4
  for(int i = 0; i<ledsize; i++)
  {
   led[i].r=abs(ledvalue*2);led[i].g=0;led[i].b=abs(ledvalue/2);
   ws2812_setleds(led,ledsize);
   delay(abs(delaysensevalue));
  } 
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Sketch start
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int main(void)
{
i2c_init();

for(int i=0; i<ledsize; i++)    // sets leds yellow while the imu starts
      {
          led[i].r=pwmvalue;led[i].g=pwmvalue;led[i].b=0;
      }
       ws2812_setleds(led,ledsize);
       _delay_ms(200); 
setupimu();
setupimuint(); //sets up interrupt for activity on int1  If you have already run this specific IMU you can remove this to start faster
setupAVRint();
for(int i=0; i<ledsize; i++)    // sets leds green when IMU is all set up
{
    led[i].r=0;led[i].g=pwmvalue;led[i].b=0;
}
ws2812_setleds(led,ledsize);
_delay_ms(2000);
    while (1)
    {
      nomovementpulse();
    }
}


ISR (INT2_vect)
{
    while (PIND & PIND2)
    {
      for(int i=0; i<ledsize; i++)
      {
        led[i].r=0;led[i].g=0;led[i].b=pwmvalue;
      }
     ws2812_setleds(led,ledsize);
    }
} 

 

Last Edited: Sun. Apr 10, 2016 - 08:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Wire.h uses 7-bit Slave addresses e.g. 0x53
Fleury uses 8-bit Slave addresses e.g. 0xA6

Always check the return value from i2c_start()
Never use i2c_start_wait() unless you know that i2c_start() works.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tried eliminating the address bit and the (+write) part and just put the address with the calculated write bit in (it was in the datasheet) and that still didn't work.  Wouldn't that have gotten around the 8bit address problem?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You can use the wrong Slave address if you want. You will just hang in the start_wait() function.
If you use the correct address, you read the contents of register#0. Which you subsequently ignore.
However you test for imu being zero. Since imu is non-zero you will hang in the while().
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My thought was that 0x00 was the register that holds the slave address ,So If i write 0x00 and wait for the response, what I should get back is the slave address.

 

If the slave address is the same as what I defined it as we move on, otherwise it flashes red.  Neither happens.  It just stays at the yellow that was previously set and hangs after start_wait.

 

If I use just start I get the same result.

 

I never get to the while loop in any case...

 

it seems to lock up right after i2c_start_wait or if I do i2C_start.  It never writes to 0x00.

Last Edited: Sun. Apr 10, 2016 - 10:08 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

We do not know what device "imu" is. You do not even give a part number.

The first step is always to verify your Slave address. 0x53 is 7-bit 0x29 Read.
Hey-ho, the data sheet will tell you the Slave address. Some chips have external address pins. Others use an internal register.
If we knew which chip and your schematic, we could give you an accurate answer.
If you put an assignment into a conditional test, the condition depends on the assignment value. (which happens to be a constant)
You normally use a comparison as the conditional test.
David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's an ADXL345 with pin 12 low.  According to the datasheet it should be 0x53.

 

This translates to 0xA6 for a write and 0xA7 for a read.

 

again, I have tried

i2c_start_wait(imu+I2C_WRITE); 
i2c_start(imu+I2C_WRITE); 
i2c_start_wait(0xA6); 
i2c_start(0xA6); 

 

none of these get beyond that line.  I have also tried the other address from the datasheet and the same read/write translations.....

 

All I'm trying to do is read register 0x00 which should respond with the slave address.  if it matches we move on otherwise the light turns red.

 

Last Edited: Sun. Apr 10, 2016 - 10:32 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I suppose I2C_WRITE is defined as (0)

Formula :

imu+I2C_WRITE

leads to an adress of 0x53; if you think the write adress should be 0xA6, maybe the formula:

imu+imu+I2C_WRITE

might be a little better consistent

BTW defined macros suche as imu should be up-cased -making reading easier_ (this doesnot solve your problem, but hazving something easy to read seems a little more comfortable)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(imu<<1)+I2C_WRITE

Was the answer.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

(imu<<1) is equivalent to (imu *2) as imu has "only" 7 bits and therefore  equivalent to imu+imu...

(some people, used to computations, find easier to replace shifts by powers of 2  multiplications/divisions -optimizers cope with it since the early 80's in fortran : I bet they do the same thing with recent C ...- instead of shifts (their being right or left depend anyway on the way you look at the chip).

 

BTW  defining  two constants would make your code easier to read (and formula easier to change, at only one line) IMUWRITE and IMUREAD

#define IMUWRITE (imu+imu+I2C_WRITE)