cancel
Showing results for 
Search instead for 
Did you mean: 

Read from I2C - STM32F767

Pilous Droip
Senior
Posted on March 07, 2018 at 11:52

Helo friends.

Problem with write on I2C bus I solved. 

If anyone wanted to, I would provide a solution

.

Now I have problem with reading. 

I have got 1 stop bit more.

Here is good communication packet.

0690X00000609yOQAQ.png

I receive:

   S-Address-W-A-Command-A-

P

-S-Address-R-A-Data-nA-P

uint8_t I2C_read_brekeke(I2C_TypeDef *I2Cx, unsigned char Address, uint8_t reg, int nBytes, unsigned char *data)

{

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT); 

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_WRITE); /* Reguest write */

   LL_I2C_EnableAutoEndMode(I2Cx); /* Enable autoend mode*/

   LL_I2C_SetTransferSize(I2Cx, 1); /* Set transfer size register */

   while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} /* check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   

   while(!LL_I2C_IsActiveFlag_STOP(I2Cx)) /* check STOP bit */

   {

      if(LL_I2C_IsActiveFlag_TXE(I2Cx))

      {

         LL_I2C_TransmitData8(I2Cx, reg); /* send data out */

      }

   }

   

   LL_I2C_ClearFlag_STOP(I2Cx); /* Clear STOP flag */

   LL_I2C_ClearFlag_TXE(I2Cx); /* Clear Transmit data register empty flag */

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT); 

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_READ); /* Reguest write */

   LL_I2C_EnableAutoEndMode(I2Cx); /* Enable autoend mode*/

   LL_I2C_SetTransferSize(I2Cx, nBytes); /* Set transfer size register */

   while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} /* check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   while(!LL_I2C_IsActiveFlag_STOP(I2Cx)) /* check STOP bit */

   {

      if(LL_I2C_IsActiveFlag_RXNE(I2Cx))

      {

         *data++ = LL_I2C_ReceiveData8(I2Cx); /* send data out */

      }

   }

return 0;

}

My call function:

uint8_t ltc[] = {0, 0, 0, 0};

I2C_read_brekeke(I2C4, 0x6F, 0x14, 2, ltc);   //address 0x6F; Reg 0x14, receive to ltc

In position 6 I have stop bit. It is wrong.

0690X00000609vgQAA.png

Any idea, what is wrong?

=================================================================

I found this function: LL_I2C_EnableAuto10BitRead()

Where is wrote:

/**

* @brief Enable automatic RESTART Read request condition for 10bit address header (master mode).

* @note The master sends the complete 10bit slave address read sequence :

* Start + 2 bytes 10bit address in Write direction + Restart + first 7 bits of 10bit address in Read direction.

* @rmtoll CR2 HEAD10R LL_I2C_EnableAuto10BitRead

* @param I2Cx I2C Instance.

* @retval None

*/

And I try use it, but it doesn't work.

#stm32f767 #read-i2c #nucleo-f767zi
9 REPLIES 9
Posted on March 07, 2018 at 14:37

I'd suggest you become more familiar with what the LL_...() functions are actually doing, particularly

LL_I2C_EnableAutoEndMode

().
Pilous Droip
Senior
Posted on March 07, 2018 at 15:01

Here is function solution.....

uint8_t I2C_read_brekeke(I2C_TypeDef *I2Cx, unsigned char Address, uint8_t reg, int nBytes, unsigned char *data)

{

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT);

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_WRITE); /* Reguest write */

   LL_I2C_DisableAutoEndMode(I2Cx); /* Disable automatic STOP condition generation */

   LL_I2C_SetTransferSize(I2Cx, 1); /* Set transfer size register */

   while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} /* check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   while(!LL_I2C_IsActiveFlag_TC(I2Cx)) /* check STOP bit */

   {

      if(LL_I2C_IsActiveFlag_TXE(I2Cx))

      {   

         LL_I2C_TransmitData8(I2Cx, reg); /* send data out */

      }

   }

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT);

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_READ); /* Reguest write */

   LL_I2C_DisableAutoEndMode(I2Cx); /* Enable autoend mode*/

   LL_I2C_SetTransferSize(I2Cx, nBytes); /* Set transfer size register */

   /*while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   while(!LL_I2C_IsActiveFlag_TC(I2Cx)) /* check STOP bit */

   {

      if(LL_I2C_IsActiveFlag_RXNE(I2Cx))

      {

      *data++ = LL_I2C_ReceiveData8(I2Cx); /* send data out */

      }

   }

   LL_I2C_GenerateStopCondition(I2Cx);

   return 0;

}

0690X00000609mnQAA.png
Posted on March 07, 2018 at 14:42

I tried everything. But this code works best.

Posted on March 08, 2018 at 08:02

Hello friends.

This code working fine only for reading two byte.

0690X00000609udQAA.png

But when I read 3 bytes I have big problem. I don't send stop bit:

0690X00000609vBQAQ.png

uint8_t I2C_read_from_device(I2C_TypeDef *I2Cx, unsigned char Address, uint8_t reg, uint8_t nBytes, unsigned char *data)

{

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT);

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_WRITE); /* Reguest write */

   LL_I2C_DisableAutoEndMode(I2Cx); /* Disable automatic STOP condition generation */

   LL_I2C_SetTransferSize(I2Cx, 1); /* Set transfer size register */

   while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} /* check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   while(!LL_I2C_IsActiveFlag_TC(I2Cx)) /* check STOP bit */

   {

      if(LL_I2C_IsActiveFlag_TXE(I2Cx))

      {

         LL_I2C_TransmitData8(I2Cx, reg); /* send data out */

      }

   }

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT);

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_READ); /* Reguest write */

   LL_I2C_DisableAutoEndMode(I2Cx); /* Enable autoend mode*/

   LL_I2C_SetTransferSize(I2Cx, nBytes); /* Set transfer size register */

   /*while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   while(nBytes--)

   {

      while(!LL_I2C_IsActiveFlag_RXNE(I2Cx)){};

      *data++ = LL_I2C_ReceiveData8(I2Cx); /* send data out */

   }

   LL_I2C_GenerateStopCondition(I2Cx);

   LL_I2C_ClearFlag_TXE(I2Cx);

   LL_I2C_ClearFlag_STOP(I2Cx);

   return 0;

}

Any idea, what is wrong??

Posted on March 08, 2018 at 08:40

And now I try modificate the function, but the result is the same

uint8_t I2C_read_from_device(I2C_TypeDef *I2Cx, unsigned char Address, uint8_t reg, uint8_t nBytes, unsigned char *data)

{

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT);

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_WRITE); /* Reguest write */

   LL_I2C_DisableAutoEndMode(I2Cx); /* Disable automatic STOP condition generation */

   LL_I2C_SetTransferSize(I2Cx, 1); /* Set transfer size register */

   while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} /* check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   while(!LL_I2C_IsActiveFlag_TC(I2Cx)) /* check STOP bit */

   {

      if(LL_I2C_IsActiveFlag_TXE(I2Cx))

      {

         LL_I2C_TransmitData8(I2Cx, reg); /* send data out */

      }

   }

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT);

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_READ); /* Reguest write */

   LL_I2C_DisableAutoEndMode(I2Cx); /* Enable autoend mode*/

   LL_I2C_SetTransferSize(I2Cx, nBytes); /* Set transfer size register */

   /*while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   while(nBytes--)

   {

      if (!nBytes)

      {

         LL_I2C_AcknowledgeNextData(I2Cx, LL_I2C_NACK);

         LL_I2C_GenerateStopCondition(I2Cx);

         while (!LL_I2C_IsActiveFlag_RXNE(I2Cx)){};

         *data++ = LL_I2C_ReceiveData8(I2Cx);

      }

      else

      {

         LL_I2C_AcknowledgeNextData(I2Cx, LL_I2C_ACK);

         while (!LL_I2C_IsActiveFlag_RXNE(I2Cx)){};

         *data++ = LL_I2C_ReceiveData8(I2Cx);

      }

   }

   LL_I2C_ClearFlag_TXE(I2Cx);

   LL_I2C_ClearFlag_OVR(I2Cx);

   LL_I2C_ClearFlag_NACK(I2Cx);

   LL_I2C_ClearFlag_STOP(I2Cx);

   return 0;

}

READ 2 bytes is good:

0690X0000060A0jQAE.png

READ 3 bytes is bad:

0690X0000060A1IQAU.png
Posted on March 08, 2018 at 09:53

I'm looking in the registers. 

And:

When I receive 2 bytes (when all is good) register ISR is set:

  • ADDCODE - 0x00

  • ADDR - 0x00

  • ALERT - 0x00

  • ARLO - 0x00

  • BERR - 0x00

  • BUSY - 0x00

  • DIR - 0x00

  • NACKF - 0x01
  • OVR - 0x00

  • PECERR - 0x00

  • RXNE - 0x00

  • STOPF - 0x01
  • TC - 0x00

  • TCR - 0x00

  • TIMEOUT - 0x00

  • TXE - 0x00

  • TXIS - 0x00

When I receive 3 bytes (read is wrong) register ISR is set:

  • ADDCODE - 0x00

  • ADDR - 0x00

  • ALERT - 0x00

  • ARLO - 0x01

  • BERR - 0x00

  • BUSY - 0x01

  • DIR - 0x00

  • NACKF - 0x01

  • OVR - 0x00

  • PECERR - 0x00

  • RXNE - 0x00

  • STOPF - 0x00

  • TC - 0x00

  • TCR - 0x00

  • TIMEOUT - 0x00

  • TXE - 0x00

  • TXIS - 0x00

In datasheet is writing:

ARLO - This flag is set by hardware in case of arbitration loss. It is cleared by software by setting the ARLOCF bit.

BUSY - This flag indicates that a communication is in progress on the bus. It is set by hardware when a START bit is detected. It is cleared by PE=0 or when STOP bit is detected.

STOPF - Stop bit detection

Posted on March 08, 2018 at 11:14

Arbitration loss indicates that something is wrong with that last NAK (and the picture indecates the same).

Try decrease pullups on SDA, increase timing, and observe with oscilloscope.

JW

Posted on March 08, 2018 at 10:44

I try this function. It is working only, when I am going to receive 2 bytes.

When I am receiving 1, 3, 4 bytes it is not working.

uint8_t I2C_read_from_device(I2C_TypeDef *I2Cx, unsigned char Address, uint8_t reg, uint8_t nBytes, unsigned char *data)

{

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT);

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_WRITE); /* Reguest write */

   LL_I2C_DisableAutoEndMode(I2Cx); /* Disable automatic STOP condition generation */

   LL_I2C_SetTransferSize(I2Cx, 1); /* Set transfer size register */

   while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} /* check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   while(!LL_I2C_IsActiveFlag_TC(I2Cx)) /* check STOP bit */

   {

      if(LL_I2C_IsActiveFlag_TXE(I2Cx))

      {

         LL_I2C_TransmitData8(I2Cx, reg); /* send data out */

      }

   }

   LL_I2C_SetSlaveAddr(I2Cx, (Address<<1)); /* Prepare Address to send */

   LL_I2C_SetMasterAddressingMode(I2Cx, LL_I2C_ADDRSLAVE_7BIT);

   LL_I2C_SetTransferRequest(I2Cx, LL_I2C_REQUEST_READ); /* Reguest write */

   LL_I2C_DisableAutoEndMode(I2Cx); /* Enable autoend mode*/

   LL_I2C_SetTransferSize(I2Cx, nBytes); /* Set transfer size register */

   /*while(LL_I2C_IsActiveFlag_BUSY(I2Cx)){} check I2C bussy */

   LL_I2C_GenerateStartCondition(I2Cx); /* generate I2C Start address and send address*/

   while(nBytes--)

   {

      if (!nBytes)

      {

         LL_I2C_AcknowledgeNextData(I2Cx, LL_I2C_NACK);

         LL_I2C_GenerateStopCondition(I2Cx);

         while (!LL_I2C_IsActiveFlag_RXNE(I2Cx)){};

         *data++ = LL_I2C_ReceiveData8(I2Cx);

      }

      else

      {

         LL_I2C_AcknowledgeNextData(I2Cx, LL_I2C_ACK);

         while (!LL_I2C_IsActiveFlag_RXNE(I2Cx)){};

         *data++ = LL_I2C_ReceiveData8(I2Cx);

      }

   }

   LL_I2C_ClearFlag_TXE(I2Cx);

   LL_I2C_ClearFlag_OVR(I2Cx);

   LL_I2C_ClearFlag_NACK(I2Cx);

   LL_I2C_ClearFlag_STOP(I2Cx);

   return 0;

}
Posted on March 08, 2018 at 13:09

Yes of course. Problem is in HW.