1

I am trying to communicate with an SMBus battery. That has 2 sections so I am using 2 I2C modules. After the first I2C module makes a successful communication second module gets stuck. And it gets stuck in Busy. In that case I thought I need to reset that I2C module. However, I could not do it.

I tried following ways:

1) By using HAL library deiniting and then initing the module again:

HAL_I2C_DeInit(&hi2c1);
HAL_I2C_Init(&hi2c1);

2) Adding Swrst lines to first method:

//Set Swrst bit
        I2C2->CR1 |= I2C_CR1_SWRST;
//Clear Swrst bit
    I2C2->CR1 &= ~(I2C_CR1_SWRST);
    HAL_I2C_DeInit(&hi2c1);
    HAL_I2C_Init(&hi2c1);

3)

 __HAL_RCC_I2C1_CLK_ENABLE();
 __HAL_RCC_I2C1_FORCE_RESET();
 __HAL_RCC_I2C1_RELEASE_RESET();

4) Using the errata document and this line of codes:

void I2C_Errate_Workaround(int module){

    if(module==1){
        //Disable The I2C's
        I2C1 -> CR1 &= ~(I2C_CR1_PE);
        //Pins are general purpose output open-drain
        GPIOB->CRL |= 0b01<<24; //I2C1 SCL Open Drain
        GPIOB->CRL |= 0b01<<28; //I2C1 SDA Open Drain
        //Make SCL/SDA High
        GPIOB-> ODR |= GPIO_ODR_ODR6;
        GPIOB -> ODR |= GPIO_ODR_ODR7;
        //Check whether pins are high
        if((GPIOB->IDR & GPIO_PIN_6) == GPIO_PIN_RESET || (GPIOB ->IDR & GPIO_PIN_7) == GPIO_PIN_RESET)
        {
            for(;;){}
        }
        //SDA Low Level
        GPIOB->ODR &= ~(GPIO_ODR_ODR7);
        // Check if SDA pins are really low
        if((GPIOB->IDR & GPIO_PIN_7)== GPIO_PIN_SET){
            for(;;){}
        }
        // SCL Pin to Low
        GPIOB -> ODR &= ~(GPIO_ODR_ODR6);
        // Check whether SCL pins are cleared
        if((GPIOB->IDR & GPIO_PIN_6)== GPIO_PIN_SET){
            for(;;){}
        }
        //Configure SCL to High
        GPIOB->ODR |= GPIO_ODR_ODR6;
        //Check if SCL High
        if((GPIOB->IDR & GPIO_PIN_6)== GPIO_PIN_RESET)
        {
            for(;;){}
        }
        //Set SDA High
        GPIOB->ODR |=GPIO_ODR_ODR7;
        //Check if SDA high
        if((GPIOB->IDR & GPIO_PIN_7)== GPIO_PIN_RESET)
        {
            for(;;){}
        }
        //Set all to alternate function open drain
        GPIOB->CRL |= 0b11<<24; //I2C1 SCL Open Drain
        GPIOB->CRL |= 0b11<<28; //I2C1 SDA Open Drain
        //Set Swrst bit
        I2C1->CR1 |= I2C_CR1_SWRST;
        //Clear Swrst bit
        I2C1->CR1 &= ~(I2C_CR1_SWRST);
        //Enable I2C modules
        I2C1->CR1 |= I2C_CR1_PE;
    } else if (module ==2){
        //Disable The I2C's
        I2C2 -> CR1 &= ~( I2C_CR1_PE);
        // Pins are general purpose output open-drain
        GPIOB->CRH |= 0b01<<8;
        GPIOB->CRH |= 0b01<<10;
        //Set pins as outputs
        GPIOB -> ODR |= GPIO_ODR_ODR10;
        GPIOB -> ODR |= GPIO_ODR_ODR11;
        //Check whether pins are high
        if((GPIOB ->IDR & GPIO_PIN_11) == GPIO_PIN_RESET || (GPIOB -> IDR & GPIO_PIN_10)== GPIO_PIN_RESET)
        {
            for(;;){}
        }
        //SDA Low Level
        GPIOB ->ODR &= ~(GPIO_ODR_ODR11);
        // Check if SDA pins are really low
        if((GPIOB->IDR & GPIO_PIN_11)== GPIO_PIN_SET)
        {
            for(;;){}
        }
        // SCL Pins to Low
        GPIOB -> ODR &= ~(GPIO_ODR_ODR10);
        // Check whether SCL pins are cleared
        if((GPIOB->IDR & GPIO_PIN_10)== GPIO_PIN_SET)
        {
            for(;;){}
        }
        //Configure SCL to High
        GPIOB->ODR |= GPIO_ODR_ODR10;
        //Check if SCL High
        if((GPIOB-> IDR & GPIO_PIN_10)== GPIO_PIN_RESET)
        {
            for(;;){}
        }
        //Set SDA High
        GPIOB->ODR |= GPIO_ODR_ODR11;

        //Check if SDA high
        if((GPIOB->IDR & GPIO_PIN_11)== GPIO_PIN_RESET)
        {
            for(;;){}
        }
        //Set all to alternate function open drain
        GPIOB->CRH |= 0b11<<8; // I2C2 SCL Open Drain
        GPIOB->CRH |= 0b11<<10; //I2C2 SDA Open Drain
        //Set Swrst bit
        I2C2->CR1 |= I2C_CR1_SWRST;
        //Clear Swrst bit
        I2C2->CR1 &= ~(I2C_CR1_SWRST);
        //Enable I2C modules
        I2C2->CR1 |= I2C_CR1_PE;
    }
}

Is there a proper way to reset the I2C module in STM32? How can I recover from a lockup?

Edit: I am using STM32F103C8. Now I added MX_GPIO_Init function and I can reset the modules :

        HAL_I2C_DeInit(&hi2c2);
        osDelay(50);
        MX_GPIO_Init();
        HAL_I2C_Init(&hi2c2);

But second module in the transmission always fails. If I use hi2c1 first then hi2c2 then hi2c2 fails. If I use hi2c2 first then vice versa. I tried to disable first module then try to communicate with second one but that did not work neither.

0 Answers0