Skip to main content
SomeGuyFromNH
Associate
December 1, 2019
Question

Executing HAL_I2C_Master_Transmit_IT function holds SCL low.

Hi,

I found in my search there is a similar question that went unanswered. This may be a newb question, but I'm stuck on it.

What I have found is that when executing HAL_I2C_Master_Transmit(), the data transfer happens as expected. (I happen to have green LEDs hanging on GPIO). When I execute HAL_I2C_Master_Transmit_IT(), only the 7-bit address is sent, and the Master (this program) continues to hold the SCL line low.

If someone could explain what I am doing wrong with the HAL_I2C_Master_Transmit_IT() program, that would be much appreciated!

	 //Turn on the two green LEDs on the LTC4306's GPIO
	 data[0] = 0x01;
	 data[1] = 0b00001111;
	 status = HAL_I2C_Master_Transmit(&hi2c1, ltc4306_Address, data, 2, 1 );
 
	 //Turn off the two green LEDs on the LTC4306's GPIO
	 data[0] = 0x01;
	 data[1] = 0b00111111;
	 status = HAL_I2C_Master_Transmit(&hi2c1, ltc4306_Address, data, 2, 1 );
 
	 //Turn on the two green LEDs on the LTC4306's GPIO
	 data[0] = 0x01;
	 data[1] = 0b00001111;
	 status = HAL_I2C_Master_Transmit_IT(&hi2c1, ltc4306_Address, data, 2 ); //This returns HAL_OK... but the master (this program) is holding SCL low after having transmitted the 7-bit address.
	 HAL_I2C_MasterTxCpltCallback(&hi2c1); // SCL still being held low after execution of this line. Doesn't seem to help. 

This topic has been closed for replies.

13 replies

SomeGuyFromNH
Associate
December 1, 2019

Executing this line after the HAL_I2C_Master_Transmit_IT() function results in an infinite loop. I thought this might be a problem stepping through the program.

while (HAL_I2C_GetState(&hi2c1) != HAL_I2C_STATE_READY){};
SomeGuyFromNH
Associate
December 8, 2019

Any help would be much appreciated!

Johnny1
Graduate II
December 9, 2019

Have you enabled the interrupt for I2C?

SomeGuyFromNH
Associate
December 10, 2019

Hi Johnny,

I appreciate the reply. I think I have interrupts enabled, but perhaps not properly.

I found an example in the STM32Cube installed files for IT functions here (this is where they are on my computer at least):

C:\Users\SomeGuyInNH\STM32Cube\Repository\STM32Cube_FW_G0_V1.3.0\Projects\NUCLEO-G071RB\Examples\I2C\I2C_TwoBoards_ComIT\Src

What I saw there were two functions in the HAL_I2C_MspInit() function

   /* I2C1 interrupt Init */

   HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0);

   HAL_NVIC_EnableIRQ(I2C1_IRQn);

I don't seem to have a HAL_I2C_MSPInit() but I'm wondering if this MX_I2C1_Init() is where to stick these functions. This is where the above functions are now, but the I2C bus is still hanging. It seems like it should be going to an ISR, but something is missing (or wrong).

SomeGuyFromNH
Associate
December 13, 2019

Hi,

Any help from the community on this would be greatly appreciated. I've been stuck on this for two weeks now. I'm at the point I'm going to ditch the STM32 and start with a different brand microcontroller.

I am trying to send a repeated start on I2C. It seems from the documentation that using the _IT functions to do this is the only way, but all code I have tried results in the STM32G071RB holding the SCL line low indefinitely after HAL_I2C_Master_Transmit_IT(). I simply do not understand why it is doing this.

If anyone that can point me towards example code, or explain why the SCL line just hangs, it would be much appreciated.

Thanks

Johnny1
Graduate II
December 16, 2019

I don't know an answer to your exact question because i never use HAL_I2C_Master_Transmit_x but instead HAL_I2C_Mem_Read_x to read something from an address or HAL_I2C_Mem_Write_x to write something to an address. If you don't want to do something very special, it should work easy with these functions.

For example:

// Read from a sensor

HAL_I2C_Mem_Read_DMA(&hi2c1, I2CADDRESS_AS5601, ReadAddress, I2C_MEMADD_SIZE_8BIT, data, size);

For your need maybe something like this:

register_address = 0x01;

size = 1;

data[0] = 0b00001111;

HAL_I2C_Mem_Write_IT(hi2c1, ltc4306_Address, register_address, I2C_MEMADD_SIZE_8BIT, data, size, 100);

fal.sch
Associate II
August 5, 2020

@SomeGuyFromNH​ Did you find a solution? I seem to have a similar problem.

Johnny1
Graduate II
August 5, 2020

@SomeGuyFromNH (Community Member), maybe it has something to do with the IRQ priorities. I think the SysTick should have a higher priority than the I2C, because HAL uses it for the timeout handling. So you could try to lower the I2C IRQ priority under the SysTick IRQ priority.

AOmel.242
Associate
February 7, 2021

I got similar infinite SCL low.

my situation:

STM32G070CB

multimaster I2C ( three CPU, every CPU sends as master, receives as slave)

if I set up addressed MCU to answer (to send packet as master) immediately after STOP interrupt (in the interrupt function) when it recieved and processed some packet as slave - it will hang forever with low SCL wire, cause no TXIS interrupt occurs.

(by the way, even the first byte, which was put into TXD register during send setup, was not sent out)

(I tried change I2C interrupt priority highest or lowest - no changes)

furthermore:

if i set up to answer in my general 1ms interrupt routine, it is ok unless it occurs in vicinity of next packet reception end - with very high probability,

about once per 100 packets (packets are ~2ms long, sent at random 2...20ms intervals).

my WORKAROUND:

  • not set up master to send right after reception,
  • in 1ms system tick interrupt check no BUSY and at least 1 ms after previous reception - then set master send.

first I tried after reception to reinit I2C by setting CR1=0 and then set it up from scratch - no success.

I did not try to reset I2C from RCC - may be could help.

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

for information:

chip marking:

STM32G070

CBT6

GQ267189R

CHN GQ 950

ST (e3) B

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

I2C2 used.

init and set to receive (very long timing used while seeking for problem source - does not change anything):

 I2C2->CR1 = 0;

 NVIC_ClearPendingIRQ(BOOT_I2C_IRQn);

 I2C2->CR1 = I2C_CR1_GCEN | I2C_CR1_STOPIE | I2C_CR1_ERRIE | I2C_CR1_TCIE | I2C_CR1_ADDRIE | (15UL << I2C_CR1_DNF_Pos);

 I2C2->TIMINGR = (0x5 << I2C_TIMINGR_PRESC_Pos) | (0x7f << I2C_TIMINGR_SCLL_Pos) | (0x7f << I2C_TIMINGR_SCLH_Pos) | (0xf << I2C_TIMINGR_SCLDEL_Pos) | (0xf << I2C_TIMINGR_SDADEL_Pos);

 I2C2->CR1 |= I2C_CR1_PE;

set to transmit:

 __disable_irq();

 I2C2->ICR = I2C_ICR_ARLOCF | I2C_ICR_BERRCF | I2C_ICR_STOPCF | I2C_ICR_NACKCF;

 I2C2->CR1 |= I2C_CR1_TXIE;

 I2C2->TXDR = buf[1];

 I2C2->CR2 = I2C_CR2_AUTOEND | buf[0] | (bufLength << I2C_CR2_NBYTES_Pos); // buf[0] == destinationAddress

 I2C2->CR2 |= I2C_CR2_START;

 __enable_irq();

GFedo.1
Visitor II
May 18, 2021

I had similar problem. If you had something like that:

uint8_t fn{

uint8_t data[2];

data[0] = 0x01;

data[1] = 0b00001111;

status = HAL_I2C_Master_Transmit(&hi2c1, ltc4306_Address, data, 2, 1 );

data[0] = 0x01;

data[1] = 0b00111111;

status = HAL_I2C_Master_Transmit(&hi2c1, ltc4306_Address, data, 2, 1 );

data[0] = 0x01;

data[1] = 0b00001111;

status = HAL_I2C_Master_Transmit_IT(&hi2c1, ltc4306_Address, data, 2 );

return 0;

}

In the moment, when you execute return line, you pop fn function pointer from stack. i2c takes data from different place in memory and NACK on SDA occurs -> transmitting is stopped.

txnghia
Visitor II
April 8, 2022

You probably missed the I2C1 interrupt handler function. I had a similar problem when executing this function HAL_I2C_Master_Transmit_IT(). After I added the interrupt handler function, the problem was fixed.

I added I2C1 interrupt handler in to the "stm32fxxx_it.c" file as below:

/* External variables --------------------------------------------------------*/

extern I2C_HandleTypeDef hi2c1;

void I2C1_IRQHandler(void)

{

 if (hi2c1.Instance->ISR & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR)) {

  HAL_I2C_ER_IRQHandler(&hi2c1);

 } else {

  HAL_I2C_EV_IRQHandler(&hi2c1);

 }

}

And don't forget to add I2C1 interrupt enable to this function HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)

  HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0);

  HAL_NVIC_EnableIRQ(I2C1_IRQn);

Hope it helps.