cancel
Showing results for 
Search instead for 
Did you mean: 

I2C read from device with STM32F767

Pilous Droip
Senior
Posted on March 01, 2018 at 07:56

Heelo friends.

I have STM32F767. And need to read from I2C device. 

I2C device has address 0x4C. Speed is set to 100kHz.

This is my INIT I2C peripheral:

uint8_t I2C1_Init(void)

{

   // declare and initialize pins to be used for I2C

   LL_AHB1_GRP1_EnableClock (LL_AHB1_GRP1_PERIPH_GPIOB);

   /* Configure SCL Pin as : Alternate function, High Speed, Open drain, Pull up */

   LL_GPIO_SetPinMode (GPIOB, LL_GPIO_PIN_8, LL_GPIO_MODE_ALTERNATE);

   LL_GPIO_SetAFPin_8_15 (GPIOB, LL_GPIO_PIN_8, LL_GPIO_AF_4);

   LL_GPIO_SetPinSpeed (GPIOB, LL_GPIO_PIN_8, LL_GPIO_SPEED_FREQ_HIGH);

   LL_GPIO_SetPinOutputType (GPIOB, LL_GPIO_PIN_8, LL_GPIO_OUTPUT_OPENDRAIN);

   LL_GPIO_SetPinPull (GPIOB, LL_GPIO_PIN_8, LL_GPIO_PULL_UP);

   /* Configure SDA Pin as : Alternate function, High Speed, Open drain, Pull up */

   LL_GPIO_SetPinMode (I2C1_PORT_SDA, LL_GPIO_PIN_9, LL_GPIO_MODE_ALTERNATE);

   LL_GPIO_SetAFPin_8_15 (I2C1_PORT_SDA, LL_GPIO_PIN_9, LL_GPIO_AF_4);

   LL_GPIO_SetPinSpeed (I2C1_PORT_SDA, LL_GPIO_PIN_9, LL_GPIO_SPEED_FREQ_HIGH);

   LL_GPIO_SetPinOutputType (I2C1_PORT_SDA, LL_GPIO_PIN_9, LL_GPIO_OUTPUT_OPENDRAIN);

   LL_GPIO_SetPinPull (I2C1_PORT_SDA, LL_GPIO_PIN_9, LL_GPIO_PULL_UP);

   // initialize I2C block

   LL_I2C_Disable(I2C1);

   LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);

   LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1); // Enable clock for I2C2

   LL_I2C_Disable(I2C1);

   LL_I2C_SetTiming(I2C1,0x60201E2B);   //from CubeMX

   LL_I2C_SetOwnAddress2(I2C1, 0x00, LL_I2C_OWNADDRESS2_NOMASK); // Default

   LL_I2C_Enable(I2C1);

   return 0;

}

And my Read function:

uint8_t I2C_ReadChar(I2C_TypeDef *I2Cx, uint8_t Addr, uint8_t Reg, uint8_t *Value, uint8_t size)

{

   LL_I2C_HandleTransfer(I2Cx, (Addr<<1), LL_I2C_ADDRSLAVE_7BIT, 1, LL_I2C_MODE_AUTOEND,    LL_I2C_GENERATE_START_WRITE);

   while(!LL_I2C_IsActiveFlag_STOP(I2Cx)) // Loop until end of transfer received

   {

      /* Indicate the status of Transmit data register empty flag */

      if(LL_I2C_IsActiveFlag_TXE(I2Cx))

      {

         /* Write data in Transmit Data register. */

         LL_I2C_TransmitData8(I2Cx, Reg);

      }

   }

   LL_I2C_HandleTransfer(I2Cx, (Addr<<1), LL_I2C_ADDRSLAVE_7BIT, size,    LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ);

   while(!LL_I2C_IsActiveFlag_STOP(I2Cx)) // Loop until end of transfer received 

   {

      /*Check RXNE flag value in ISR register*/

      if(LL_I2C_IsActiveFlag_RXNE(I2Cx))

      {

         /*Read character in Receive Data register.*/

         *Value = LL_I2C_ReceiveData8(I2Cx);

      }

   }

   LL_I2C_ClearFlag_STOP(I2Cx);

   /* all is good, return 0 */

   return 0;

}

And my first call this function is OK:

Here is my call function

if(strcmp((char *)uart_reads, ''i2c'') == 0)

{

   uint8_t data[2];

   I2C_ReadChar(I2C1, 0x4C, 0x00,

data

, 1);   //i2C addr: 0x4C, reg 0x00, ret. val data, size 1 byte

   itoa(

data

[0], buffer, 10);

   usart_puts(buffer);

   usart_puts(''\r\nI2C finish'');

}

And my first call this function is OK:

0690X00000609rcQAA.png

But second read from device is wrong.

0690X00000609rXQAQ.png

Any idea, what is wrong? 

#i2c-sensor-read #nucleo-f767zi
8 REPLIES 8
Posted on March 01, 2018 at 09:41

What are the symptoms when debugging? Where does the program hang - if at all, what is the value of registers (careful, status registers may be affected by reading, so you don't want to observe them in debugger, rather, store them when read in the program).

JW

Posted on March 01, 2018 at 09:51

I'm looking for registers now. And I found, that I sent first good command to device, register ISR->STOPF is set to 0. After this sent  register ISR->STOPF is set to 1.

But after sent message I clear this register, but it is still in 1. And I don't know, why.

LL_I2C_ClearFlag_STOP(I2Cx);

How to clear ISR->STOPF bit register?

Posted on March 01, 2018 at 09:58

The device can't perform stop while SCK is held down (see your waveform for case 2).

As the status register is read during communication, store its changing value into an array, so that you have the whole history; then compare 'good' with 'bad'.

JW

Posted on March 01, 2018 at 10:00

Ok, I found way, to clear register, but I don't know, if this is good way.

uint8_t I2C_ReadChar(I2C_TypeDef *I2Cx, uint8_t Addr, uint8_t Reg, uint8_t *Value, uint8_t size)

{

   /* Clear register */

   LL_I2C_Disable(I2Cx);

   LL_I2C_ClearFlag_STOP(I2Cx);

   LL_I2C_Enable(I2Cx);

   LL_I2C_HandleTransfer(I2Cx, (Addr<<1), LL_I2C_ADDRSLAVE_7BIT, 1, LL_I2C_MODE_AUTOEND,    LL_I2C_GENERATE_START_WRITE);

   while(!LL_I2C_IsActiveFlag_STOP(I2Cx)) // Loop until end of transfer received

   {   

      /* Indicate the status of Transmit data register empty flag */

      if(LL_I2C_IsActiveFlag_TXIS(I2Cx))

      {

         /* Write data in Transmit Data register. */

         LL_I2C_TransmitData8(I2Cx, Reg);

      }   

   }

   LL_I2C_HandleTransfer(I2Cx, (Addr<<1), LL_I2C_ADDRSLAVE_7BIT, size, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ);

   while(!LL_I2C_IsActiveFlag_STOP(I2Cx)) // Loop until end of transfer received 

   {

      /*Check RXNE flag value in ISR register*/

      if(LL_I2C_IsActiveFlag_RXNE(I2Cx))

      {

         /*Read character in Receive Data register.*/

         *Value = LL_I2C_ReceiveData8(I2Cx);

      }

   }

   /* all is good, return 0 */

   return 0;

}

Posted on March 01, 2018 at 10:05

While it may be functional, by resetting the interface after each transfer you probably cover up some other fault.

I personally would not be satisfied by 'it works but I don't know why'.

JW

Posted on March 01, 2018 at 10:10

🙂

I'm dissatisfied. I try find answer on my question.
Posted on March 01, 2018 at 10:20

This function is wrong.

Because:

1. No return any data

🙂

 

2. Read only one byte - timing is good

   0690X00000609rmQAA.png

3. Read more than 1 byte

  • missing NACK, STOP bit

   0690X00000609p8QAA.png