I2C Bus

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

I am writing a program in ASF for the sensor LPS33HW to read the pressure through I2C bus. can someone help me with this because the program does not work and I do not know where the problem is. 

 

void twi_init_master()
{
    twi_options_t m_options = {
        .speed     = TWI_SPEED,
        .chip      = TWI_MASTER_ADDR,
        .speed_reg = TWI_BAUD(sysclk_get_cpu_hz(), TWI_SPEED)
    };
    
    TWI_MASTER_PORT.PIN0CTRL = PORT_OPC_WIREDANDPULL_gc;
    TWI_MASTER_PORT.PIN1CTRL = PORT_OPC_WIREDANDPULL_gc;

    irq_initialize_vectors();

    sysclk_enable_peripheral_clock(&TWI_MASTER);
    twi_master_init(&TWI_MASTER, &m_options);
    twi_master_enable(&TWI_MASTER);
        
    cpu_irq_enable();
}

void twi_init_slave()
{
       sysclk_enable_peripheral_clock(&TWI_SLAVE);
       TWI_SlaveInitializeModule(&slave, LPS33HW_ADDR,TWI_SLAVE_INTLVL_MED_gc);
       twi_slave_enable(&TWI_SLAVE);
}

uint8_t i2c_master_read (uint8_t SensorRegister,uint8_t *value)
{
    twi_package_t packet = {
        .addr_length = 1,
        .chip        = LPS33HW_ADDR,
        .buffer      = (void *) value,
        .addr [0]     = SensorRegister,
        .length      = DATA_LENGTH,
        .no_wait     = false
    };
    
   uint8_t ecode = twi_master_read (&TWI_MASTER,&packet);
   

    *value = &packet.buffer;
    
    
    return (ecode);
}

float readpress ()
     {
         uint32_t press;
         uint8_t value1;
         uint8_t value2;
         uint8_t value3;
         float  pressData;
         uint16_t pressLSBw;
         i2c_master_read (LPS33HW_P_OUT_XL,&value1);
         i2c_master_read (LPS33HW_P_OUT_L,&value2);
         i2c_master_read (LPS33HW_P_OUT_H,&value3);
          press = (value3 << 16) | (value2 << 8)  | (value1) ;        
         pressData = ((float)press/(4096.0f));
         return pressData;
 }

 

int main (void)
{
    /* Insert system clock initialization code here (sysclk_init()). */

    board_init();
    twi_init_master();

while (1)
    {
    luftdruck = readpress ();

    }

}

 

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

What AVR/SAM device are you targeting?  If an AVR its a waste to use Start when there are so many TWI/I2C libraries out there.

 

Jim

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"Step N is required before you can do step N+1!" - ka7ehk

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB, RSLogix user

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

moago wrote:
because the program does not work

Is a poor description of the problem, what does not work? 

So what status does your i2c_read function return?

What bus speed are you running, have you tried running it slower (1/2 speed?)

What bus vcc voltage is it, 3.3v, or 5.0v? 

What bus pull up resistors are you using?  

Have you looked at the pulse shapes with a scope?

Is this the first time you have interfaced with an I2C device?

 

Jim

 

 

(Possum Lodge oath) Quando omni flunkus, moritati.

"I thought growing old would take longer"

 

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

I use the ATxmega 32A4U  

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

the problem is I get 236 as return from the function i2c_master_rad. that means the three variable Value1, Value2,Value3 have the same values 236 and the values does not correspond to the correct pressure. 

I use the Voltage 3.3V and the hardware or pullup resistors I have checked and there is no problem. 

I actually have problem because this is my first program with IC bus and I don't have much experience with the bus.  

 

Last Edited: Wed. Jul 21, 2021 - 07:08 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

ZIP up your AS7.0 project and attach the ZIP file.

 

ASF is incredibly complicated.   And I don't want to guess all the values like DATA_LENGTH  or LPS33HW_ADDR

 

Quite honestly,  every TWI transaction comes down to writing X bytes to the Slave and reading Y bytes back.    Often with X or Y being zero bytes.

 

I bet that ASF provides functions for doing these operations.   And you just need to read the documentation to see how to call the functions correctly,  check for success.

 

Different I2C Slaves will have different behaviour.    e.g. writing X bytes in one block will be different to writing X blocks that are each one byte long.

Which is probably why the twi_master_read() function requires all the packet fields to be filled correctly.

 

David.

Last Edited: Wed. Jul 21, 2021 - 07:35 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is pure speculation.   ASF makes my head hurt.    However,  looking at the packet structure I bet that you should say:

uint8_t i2c_master_read_uint24(uint8_t SensorRegister, uint24_t *value)
{
    twi_package_t packet = {
        .addr_length = 1,
        .chip        = LPS33HW_ADDR,
        .buffer      = (void*)value,
        .addr[0]     = SensorRegister,
        .length      = sizeof(*value),
        .no_wait     = false
    };
    
    uint8_t ecode = twi_master_read (&TWI_MASTER,&packet);
   
    return (ecode);
}

Of course this will depend on the endian-ness of your LP833 and the endian-ness of your target compiler.

I would feel much happier with using regular uint8_t buffer[ ] and processing the resulting bytes myself.  e.g.

 

uint8_t i2c_master_read_sensor(uint8_t SensorRegister, uint8_t *buf, uint8_t size)
{
    twi_package_t packet = {
        .addr_length = 1,
        .chip        = LPS33HW_ADDR,
        .buffer      = buf,
        .addr[0]     = SensorRegister,
        .length      = size,
        .no_wait     = false
    };
    
    uint8_t ecode = twi_master_read (&TWI_MASTER,&packet);
   
    return (ecode);
}

float readpress(void)
{
    uint8_t buf[3];
    uint8_t ecode = i2c_master_read_sensor(LP833HW_P_OUT_XL, buf, sizeof(buf));
    uint24_t press = (buf[0] << 16)|(buf[1] << 8)|(buf[2] << 0);
    return press / 4096.0;
}

Please note that this is complete guesswork.   Based purely on the field names of the packet structure.

I have made NO attempt to find or read the ASF documentation.   And have assumed that the Sensor Register has adjacent addresses and that your I2C device auto-increments.

 

David.

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

You are likely reading the sensor too fast.  Your main() has its loop be a constantly repeating call to readpress().  Which, as far as I can tell, is calling the sensor using I2C immediately after the previous I2C process finished its STOP.

 

  Try putting a delay of about one second inside your while(1) loop after readpress().   Also, I don't see 'luftdruct'  [atmospheric pressure] defined anywhere.

 

Your code for doing the I2C read from the sensor appears to be missing a few lines.  The function receives two addresses, one to a peripheral-control register (?) and the other to a structure.  The function does nothing but copy a buffer's address to an undefined pointer.  There doesn't seem to be any actual reading of the I2C bus, which means that there is no real data coming from the sensor.

 

 

        uint8_t ecode = twi_master_read (&TWI_MASTER,&packet);
   

               *value = &packet.buffer;
    
    
              return (ecode);
          }

Last Edited: Fri. Jul 23, 2021 - 03:44 PM