cancel
Showing results for 
Search instead for 
Did you mean: 

Executing HAL_I2C_Master_Transmit_IT function holds SCL low.

SomeGuyFromNH
Associate II

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. 

13 REPLIES 13
SomeGuyFromNH
Associate II

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 II

Any help would be much appreciated!

Johnny1
Associate III

Have you enabled the interrupt for I2C?

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 II

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
Associate III

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

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

Johnny1
Associate III

@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 II

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();