Skip to main content
Associate II
August 14, 2024
Solved

Low Layer API for I2C Communication in Stm32L031

  • August 14, 2024
  • 12 replies
  • 4458 views

Hi,

I have created a code snippet to communicate with I2C using LL API instead of HAL. The code is given below

 

uint8_t temp[2]={0xF9,0x00};

while(LL_I2C_IsActiveFlag_BUSY(I2C1)); // Wait until the I2C bus is not busy



LL_I2C_HandleTransfer(I2C1, 0x94, LL_I2C_ADDRSLAVE_7BIT, 2, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_WRITE);

LL_mDelay(10);

for (int i = 0; i < 2; i++) {

while (!LL_I2C_IsActiveFlag_TXE(I2C1)); // Wait until the data register is empty



if (LL_I2C_IsActiveFlag_NACK(I2C1)) { // Check for NACK (Not Acknowledged)



return 1;

}



LL_I2C_TransmitData8(I2C1, temp[i]); // Transmit data byte

LL_mDelay(10);

LL_I2C_ClearFlag_TXE(I2C1);



}



LL_I2C_GenerateStopCondition(I2C1);

LL_mDelay(10);

LL_I2C_ClearFlag_STOP(I2C1); // Clear the stop flag





// Reception (Rx)

LL_I2C_HandleTransfer(I2C1, 0x94, LL_I2C_ADDRSLAVE_7BIT, 16, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_START_READ);



int i = 0;



// Wait for the stop condition or reception of 16 bytes

while (!LL_I2C_IsActiveFlag_STOP(I2C1)) {

if (LL_I2C_IsActiveFlag_RXNE(I2C1)) { // Check if data is received

Received[i++] = LL_I2C_ReceiveData8(I2C1); // Store received data

if (i >= 16) break; // Exit if 16 bytes have been received

}

}



// Ensure stop flag is cleared after reception is complete

if (LL_I2C_IsActiveFlag_STOP(I2C1)) {

LL_I2C_ClearFlag_STOP(I2C1);

}

 

 

 

i am able to transmit the data, but failed to read from the buffer. Anyone with prior experience in LL I2C can give me solution for this.

This topic has been closed for replies.
Best answer by Saket_Om

Hello @Sivakumarzcs128 

To transfer data exceeding 255 bytes, you need to enable the reload mode.

LL_I2C_HandleTransfer(I2C3, SLAVE_OWN_ADDRESS, LL_I2C_ADDRSLAVE_7BIT, ubNbDataToTransmit, LL_I2C_MODE_RELOAD, LL_I2C_GENERATE_START_WRITE);

 

This API should be called for each 255-byte transfer. The final call to this function should use the autoend mode.

In your case, you need to transfer 284 bytes, so you will call the API the first time with reload mode and the second time with autoend mode.

Here is the LL code for calling the function:

// First call with reload mode for the first 255 bytes
LL_I2C_HandleTransfer(I2C3, SLAVE_OWN_ADDRESS, LL_I2C_ADDRSLAVE_7BIT, 255, LL_I2C_MODE_RELOAD, LL_I2C_GENERATE_START_WRITE);

// ...

// Second call with autoend mode for the remaining 29 bytes
LL_I2C_HandleTransfer(I2C3, SLAVE_OWN_ADDRESS, LL_I2C_ADDRSLAVE_7BIT, 29, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_NOSTARTSTOP);

 

12 replies

ST Technical Moderator
August 14, 2024

Hello @Sivakumarzcs128 

 

Is the RXNE flag set? Or is the following if condition is true 

 

if (LL_I2C_IsActiveFlag_RXNE(I2C1))

 

Is the following instruction executed:

 

 

Received[i++] = LL_I2C_ReceiveData8(I2C1);

 

How the variable Received is declared? 

 

 

 

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
Associate II
August 14, 2024

The RXNE flag is set when the Handle transfer for read is completed and then reset when i check the stop flag condition. Also the variable received is declared as a buffer .

ST Technical Moderator
August 14, 2024

@Sivakumarzcs128 

Could you place a breakpoint on the following instruction and check if the data is being read from the SPI data register?

Received[i++] = LL_I2C_ReceiveData8(I2C1);

 

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
Associate II
August 14, 2024

i am always stuck here in this point 

while (!LL_I2C_IsActiveFlag_STOP(I2C1))

Also what are the things taken care during changing from HAL to LL in Stm32l031. 

Associate II
August 16, 2024

We have changed the code and now the I2C communication looks fine. Now we faces an issues of reading some data buffer ,where the buffer contains more than 255 data. 

LL_I2C_SetSlaveAddr(I2C1, (devAddr << 1) );

LL_I2C_SetTransferSize(I2C1, rxsize);

LL_I2C_SetTransferRequest(I2C1, LL_I2C_REQUEST_READ);

LL_I2C_GenerateStartCondition(I2C1);

 

The rxsize buffer is nearly 284, But the SetTransferSize parameter must be a value between Min_Data=0x00 and Max_Data=0xFF.

How can we read the remaing datas without losing any. given below is how we read the data

 

while(LL_I2C_IsActiveFlag_RXNE(I2C1))

{

*rxbyte = LL_I2C_ReceiveData8(I2C1);

LL_mDelay(5);

rxbyte++;

}

Saket_OmBest answer
ST Technical Moderator
August 16, 2024

Hello @Sivakumarzcs128 

To transfer data exceeding 255 bytes, you need to enable the reload mode.

LL_I2C_HandleTransfer(I2C3, SLAVE_OWN_ADDRESS, LL_I2C_ADDRSLAVE_7BIT, ubNbDataToTransmit, LL_I2C_MODE_RELOAD, LL_I2C_GENERATE_START_WRITE);

 

This API should be called for each 255-byte transfer. The final call to this function should use the autoend mode.

In your case, you need to transfer 284 bytes, so you will call the API the first time with reload mode and the second time with autoend mode.

Here is the LL code for calling the function:

// First call with reload mode for the first 255 bytes
LL_I2C_HandleTransfer(I2C3, SLAVE_OWN_ADDRESS, LL_I2C_ADDRSLAVE_7BIT, 255, LL_I2C_MODE_RELOAD, LL_I2C_GENERATE_START_WRITE);

// ...

// Second call with autoend mode for the remaining 29 bytes
LL_I2C_HandleTransfer(I2C3, SLAVE_OWN_ADDRESS, LL_I2C_ADDRSLAVE_7BIT, 29, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_NOSTARTSTOP);

 

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
ST Technical Moderator
August 23, 2024

Hello @Sivakumarzcs128 

 

Please find below the update of your code. 

int8_t LL_I2C_MasterRx(uint8_t devAddr, uint8_t* rxbyte, uint16_t rxsize)

{

// uint8_t cnt = 0;

uint16_t remaining = rxsize;

uint16_t StartIDX=0;

while (remaining > 0)

{

uint16_t currentTransferSize = (remaining > 255) ? 255 : remaining;


if(remaining > 255) & (StartIDX == 0)
{

LL_I2C_HandleTransfer(I2C1, devAddr, LL_I2C_ADDRSLAVE_7BIT, currentTransferSize, LL_I2C_MODE_RELOAD, LL_I2C_GENERATE_START_READ);

StartIDX = 1;

}
else if ((remaining > 255) & (StartIDX != 0))
{
LL_I2C_HandleTransfer(I2C1, devAddr, LL_I2C_ADDRSLAVE_7BIT, currentTransferSize, LL_I2C_MODE_RELOAD, LL_I2C_GENERATE_NOSTARTSTOP);	
}
else
{
LL_I2C_HandleTransfer(I2C1, devAddr, LL_I2C_ADDRSLAVE_7BIT, currentTransferSize, LL_I2C_MODE_AUTOEND, LL_I2C_GENERATE_NOSTARTSTOP);
}

for (uint16_t i = 0; i < currentTransferSize; i++)

{

while (!LL_I2C_IsActiveFlag_RXNE(I2C1));

*rxbyte = LL_I2C_ReceiveData8(I2C1);

LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_ACK);

rxbyte++;

}

remaining -= currentTransferSize;

if(remaining == 1)

{

LL_I2C_AcknowledgeNextData(I2C1, LL_I2C_NACK);

}

if (mode == LL_I2C_MODE_AUTOEND)

{

while (!LL_I2C_IsActiveFlag_STOP(I2C1));

LL_I2C_ClearFlag_STOP(I2C1);

}

 

}

 

LL_I2C_GenerateStopCondition(I2C1);

 

return 0; // Return success (or handle error cases as needed

}

 

To implement correctly your code with reload mode you need to implement the workaround in the Erratasheet (Section 2.12.5).

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Saket_Om
MOBEJ
ST Employee
August 22, 2024

hello @Sivakumarzcs128  , 

You can follow the examples provided in the STM32CubeL0 repository on GitHub. Specifically, you can refer to the  I2C LL examples for the NUCLEO-L073RZ board , it can help you to solve your issue : 

STM32CubeL0/Projects/NUCLEO-L073RZ/Examples_LL/I2C at master · STMicroelectronics/STM32CubeL0 · GitHub

 

BR

 

To give better visibility on the answered topics, please click on Accept as Solution on the reply which solved your issue or answered your question.