2018-02-28 10:56 PM
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 byteitoa(
data
[0], buffer, 10);usart_puts(buffer);
usart_puts(''\r\nI2C finish'');
}
And my first call this function is OK:
But second read from device is wrong.
Any idea, what is wrong?
#i2c-sensor-read #nucleo-f767zi2018-03-01 12:41 AM
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
2018-03-01 01:51 AM
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?
2018-03-01 01:58 AM
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
2018-03-01 02:00 AM
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;
}
2018-03-01 02:05 AM
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
2018-03-01 02:10 AM
:)
I'm dissatisfied. I try find answer on my question.2018-03-01 02:20 AM
This function is wrong.
Because:
1. No return any data
:)
2. Read only one byte - timing is good
3. Read more than 1 byte
2018-03-01 02:38 AM
LL_I2C_Disable(I2Cx) set PE pin in I2C_CR1 register.
. This explains my question.