cancel
Showing results for 
Search instead for 
Did you mean: 

STM32L412 doesn't transmit anything via I2C with LL

AKise
Associate III

Hello, I try to transmit data via I2C bus using LL drivers, but it doesn't work properly. No data is transfered properly.

Here is my I2C initialisation generated with CubeMX:

 

 

  LL_I2C_InitTypeDef I2C_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
  /**I2C1 GPIO Configuration
  PB6   ------> I2C1_SCL
  PB7   ------> I2C1_SDA
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_6|LL_GPIO_PIN_7;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C1);

  /* USER CODE BEGIN I2C1_Init 1 */

  /* USER CODE END I2C1_Init 1 */

  /** I2C Initialization
  */
  LL_I2C_EnableAutoEndMode(I2C1);
  LL_I2C_DisableOwnAddress2(I2C1);
  LL_I2C_DisableGeneralCall(I2C1);
  LL_I2C_EnableClockStretching(I2C1);
  I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;
  I2C_InitStruct.Timing = 0x00702991;
  I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
  I2C_InitStruct.DigitalFilter = 0;
  I2C_InitStruct.OwnAddress1 = 0;
  I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;
  I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
  LL_I2C_Init(I2C1, &I2C_InitStruct);
  LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);

 

 

And here is data transmission, only the beginning, because I can't even transmit an address:

 

 

    // 1. Set ACK configuration
    LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_ACK);

    // 2. start condition
    LL_I2C_GenerateStartCondition(I2C1);

    // 3. check start bit flag
    while (!LL_I2C_IsActiveFlag_BUSY(I2C1))
    {
      osDelay(1);
      if (cnt++ > ms) return -1;
    }

    // 3. write device address (WRITE)
    LL_I2C_TransmitData8(I2C1, (slaveAddr << 1) | 0x00);

    // 4. wait address sent
    while (!LL_I2C_IsActiveFlag_ADDR(I2C1))
    {
      osDelay(1);
      if (cnt++ > ms) return -1;
    }

    // 5. clear ADDR flag
    LL_I2C_ClearFlag_ADDR(I2C1_I2C);
...

 

 

It hangs at position 4, because wrong address was transmitted.

Here is a diagram from the logic analyzer:

image.png

As you can see, empty byte was transmitted, but slaveAddr was not 0.

I have already checked everything, tried different variants of I2C commands, but without any success.

Does LL actualy work with I2C?

1 ACCEPTED SOLUTION

Accepted Solutions
Saket_Om
ST Employee

Hello @AKise 

The slave address cannot be transmitted using the API LL_I2C_TransmitData8. 

it is handled using the API LL_I2C_HandleTransfer. 

You can refer to the I2C LL example available on Github.

The snipped code below is a simplified function (taken from the mentioned example) that can manage I2C transmit using LL API.

void Handle_I2C_Master(void)
{
  /* (1) Initiate a Start condition to the Slave device ***********************/

  /* Master Generate Start condition for a write request :              */
  /*    - to the Slave with a 7-Bit SLAVE_OWN_ADDRESS                   */
  /*    - with a auto stop condition generation when transmit all bytes */
  LL_I2C_HandleTransfer(I2C1, SLAVE_OWN_ADDRESS, LL_I2C_ADDRSLAVE_7BIT, ubNbDataToTransmit, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);

  /* (2) Loop until end of transfer received (STOP flag raised) ***************/


  /* Loop until STOP flag is raised  */
  while (!LL_I2C_IsActiveFlag_STOP(I2C1))
  {
    /* (2.1) Transmit data (TXIS flag raised) *********************************/

    /* Check TXIS flag value in ISR register */
    if (LL_I2C_IsActiveFlag_TXIS(I2C1))
    {
      /* Write data in Transmit Data register.
      TXIS flag is cleared by writing data in TXDR register */
      LL_I2C_TransmitData8(I2C1, (*pTransmitBuffer++));
    }


  }

  /* (3) Clear pending flags, Data consistency are checking into Slave process */

  /* End of I2C_SlaveReceiver_MasterTransmitter Process */
  LL_I2C_ClearFlag_STOP(I2C1);


}

 

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar

View solution in original post

2 REPLIES 2
TDK
Guru

> LL_I2C_TransmitData8(I2C1, (slaveAddr << 1) | 0x00)

The slave address is not sent to DR, but to CR2. Look at HAL_I2C_Master_Transmit or the reference manual for inspiration.

TDK_0-1723674273733.png

 

Consider using direct register access rather than LL. It needlessly obfuscates the code.

If you feel a post has answered your question, please click "Accept as Solution".
Saket_Om
ST Employee

Hello @AKise 

The slave address cannot be transmitted using the API LL_I2C_TransmitData8. 

it is handled using the API LL_I2C_HandleTransfer. 

You can refer to the I2C LL example available on Github.

The snipped code below is a simplified function (taken from the mentioned example) that can manage I2C transmit using LL API.

void Handle_I2C_Master(void)
{
  /* (1) Initiate a Start condition to the Slave device ***********************/

  /* Master Generate Start condition for a write request :              */
  /*    - to the Slave with a 7-Bit SLAVE_OWN_ADDRESS                   */
  /*    - with a auto stop condition generation when transmit all bytes */
  LL_I2C_HandleTransfer(I2C1, SLAVE_OWN_ADDRESS, LL_I2C_ADDRSLAVE_7BIT, ubNbDataToTransmit, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);

  /* (2) Loop until end of transfer received (STOP flag raised) ***************/


  /* Loop until STOP flag is raised  */
  while (!LL_I2C_IsActiveFlag_STOP(I2C1))
  {
    /* (2.1) Transmit data (TXIS flag raised) *********************************/

    /* Check TXIS flag value in ISR register */
    if (LL_I2C_IsActiveFlag_TXIS(I2C1))
    {
      /* Write data in Transmit Data register.
      TXIS flag is cleared by writing data in TXDR register */
      LL_I2C_TransmitData8(I2C1, (*pTransmitBuffer++));
    }


  }

  /* (3) Clear pending flags, Data consistency are checking into Slave process */

  /* End of I2C_SlaveReceiver_MasterTransmitter Process */
  LL_I2C_ClearFlag_STOP(I2C1);


}

 

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar