cancel
Showing results for 
Search instead for 
Did you mean: 

i2c - No Slave Address Acknowledgement - Standard Peripheral Library - STM32L1xx

paulr
Associate II
Posted on December 27, 2014 at 21:09

The original post was too long to process during our migration. Please click on the attachment to read the original post.
2 REPLIES 2
paulr
Associate II
Posted on December 30, 2014 at 19:38

Hi Folks:

I modified I2C_CheckEvent(), as illustrated below, to prevent

the I2C SR1 register from being read twice in the case of

overly anxious compilers and optimizers. The solution is

not elegant or sophisticated but works.  Basically, it

involves using the volatile qualifier and computing the

register address before accessing the register. A potential

drawback is the use of a hardcoded register offset.

Best Regards,

Paul R.

ErrorStatus I2C_CheckEvent(I2C_TypeDef* I2Cx, uint32_t I2C_EVENT)

{

  uint32_t lastevent = 0;

  volatile uint32_t flag1 = 0, flag2 = 0;

  volatile uint32_t *p_sr1;

  ErrorStatus status = ERROR;

  /* Check the parameters */

  assert_param(IS_I2C_ALL_PERIPH(I2Cx));

  assert_param(IS_I2C_EVENT(I2C_EVENT));

  /* Read the I2Cx status register */

  p_sr1 = (volatile uint32_t *) ((void *) I2Cx + I2C_Register_SR1);

  flag1 = *p_sr1;

  flag2 = I2Cx->SR2;

  flag2 = flag2 << 16;

  /* Get the last event value from I2C status register */

  lastevent = (flag1 | flag2) & FLAG_MASK;

/* Check whether the last event contains the I2C_EVENT */

  if ((lastevent & I2C_EVENT) == I2C_EVENT)

  {

    /* SUCCESS: last event is equal to I2C_EVENT */

    status = SUCCESS;

  }

  else

  {

    /* ERROR: last event is different from I2C_EVENT */

    status = ERROR;

  }

  /* Return status */

  return status;

}

paulr
Associate II
Posted on December 31, 2014 at 03:20

Hi Folks:

I know the exact cause of the I2C problem and have solved it.

The cause is that in an OS environment with preemptive scheduling

it is likely that data in read sensitive registers will be lost

during task switches--due to the fact that you need to read

registers in order to save them. For example, if the I2C SR1 register

is saved during a task switch, the value of bit 1 may be

cleared.

The solution is to make the all the I2C operation code between

the point the bus is acquired and the routine exits a critical section

in the P_I2C_Rx_Byte() and P_I2C_Tx_Byte() routines. Since these

routines only transfer a one byte register, it is safe to do this.

The details of entering a critical section are OS dependent and

and versions of these routines configured for FreeRTOS are attached.

Also, I strongly advise adopting the changes in I2C_CheckEvent()

which I previously described.

Best Regards,

Paul R.

________________

Attachments :

code.c : https://st--c.eu10.content.force.com/sfc/dist/version/download/?oid=00Db0000000YtG6&ids=0680X000006HzVA&d=%2Fa%2F0X0000000bMm%2FqT_Jv7BxqOxXBNmKcv.RA_qGB8xniQ4.4sdFq5kqlrM&asPdf=false