Skip to main content
Visitor II
December 1, 2019
Question

Executing HAL_I2C_Master_Transmit_IT function holds SCL low.

  • December 1, 2019
  • 12 replies
  • 5334 views

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.

    12 replies

    Visitor II
    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){};
    Visitor II
    December 8, 2019

    Any help would be much appreciated!

    Graduate II
    December 9, 2019

    Have you enabled the interrupt for I2C?

    Visitor II
    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).

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

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

    Visitor II
    August 5, 2020

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

    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.

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

    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.

    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.