This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

BQ27421-G1: BQ27421-G1: i2c communication problems

Part Number: BQ27421-G1

Tool/software:

Hello,

we are mounting the BQ27421-G1 on a wearable device, running on a STM32F7 processor.

Approximately on 1 device out of 10, the communication with the chip is not working.

What happens is that the call

 HAL_I2C_IsDeviceReady(&_hi2c, (ADDRESS << 1), 3, timeout)

returns HAL_ERROR.

Suspecting an invalid state of the inner state machine of the chip, we also implemented a manual recovery routine, which essentially outputs a series of pulses on the clock pin of the i2c: alas, it didn't work.

Sometimes (but not always) leaving the device without battery for a while solves the problem, but I am worried that the problem might rise again, when the device is on the field.

Any hint or suggestion?

Thanks a lot to anyone providing any help on the matter.

Alessandro

  • Hello Alessandro,

    What is HAL_ERROR, I am not familiar with this.

    Does the device communication work originally and then stops working after some use?

    Can you send me a digital logic capture of the communication that is happening between the STM and the gauge.

    Regards,

    Adrian

  • Hi Adrian,
    thanks for your answer.
    I'll provide to you some information about the matter.


    1. When the error occurs
    The error occurs approximatively on the 10% of the devices.
    The devices are brand new, so I would say that the error happened from the beginning of their use.


    2. Connections
    The I2C pins used by BQ27421-G1 are shared with another chip (a pressure sensor). This pressure sensor is not used in any way by the firmware.
    However, I tested the communication with the pressure sensor on a "faulty device", and it works correctly, while BQ27421-G1 does not: this (I think) excludes problems on the STM32 side.


    3. HAL_ERROR
    The HAL_ERROR is a generic error used by the Hardware Abstraction Layer of STM32 libraries.
    The problem arises while calling the HAL_I2C_IsDeviceReady function.
    Find attached the code for HAL_I2C_IsDeviceReady at the bottom of this comment.

    The part of code which fails is this one:

          /* Check if the NACKF flag has not been set */
          if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == RESET) {...}

    The I2C_FLAG_AF is always SET for the BQ27421-G1; on the contrary, for the pressure sensor the flag is RESET and the peripheral is detected correctly.



    Thanks again for your time, let me know if you need further information.

    /**
      * @brief  Checks if target device is ready for communication.
      * @note   This function is used with Memory devices
      * @param  hi2c Pointer to a I2C_HandleTypeDef structure that contains
      *                the configuration information for the specified I2C.
      * @param  DevAddress Target device address: The device 7 bits address value
      *         in datasheet must be shifted to the left before calling the interface
      * @param  Trials Number of trials
      * @param  Timeout Timeout duration
      * @retval HAL status
      */
    HAL_StatusTypeDef HAL_I2C_IsDeviceReady(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint32_t Trials,
                                            uint32_t Timeout)
    {
      uint32_t tickstart;

      __IO uint32_t I2C_Trials = 0UL;

      FlagStatus tmp1;
      FlagStatus tmp2;

      if (hi2c->State == HAL_I2C_STATE_READY)
      {
        if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_BUSY) == SET)
        {
          return HAL_BUSY;
        }

        /* Process Locked */
        __HAL_LOCK(hi2c);

        hi2c->State = HAL_I2C_STATE_BUSY;
        hi2c->ErrorCode = HAL_I2C_ERROR_NONE;

        do
        {
          /* Generate Start */
          hi2c->Instance->CR2 = I2C_GENERATE_START(hi2c->Init.AddressingMode, DevAddress);

          /* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */
          /* Wait until STOPF flag is set or a NACK flag is set*/
          tickstart = HAL_GetTick();

          tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF);
          tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF);

          while ((tmp1 == RESET) && (tmp2 == RESET))
          {
            if (Timeout != HAL_MAX_DELAY)
            {
              if (((HAL_GetTick() - tickstart) > Timeout) || (Timeout == 0U))
              {
                /* Update I2C state */
                hi2c->State = HAL_I2C_STATE_READY;

                /* Update I2C error code */
                hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;

                /* Process Unlocked */
                __HAL_UNLOCK(hi2c);

                return HAL_ERROR;
              }
            }

            tmp1 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_STOPF);
            tmp2 = __HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF);
          }

          /* Check if the NACKF flag has not been set */
          if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_AF) == RESET)
          {
            /* Wait until STOPF flag is reset */
            if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_STOPF, RESET, Timeout, tickstart) != HAL_OK)
            {
              return HAL_ERROR;
            }

            /* Clear STOP Flag */
            __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);

            /* Device is ready */
            hi2c->State = HAL_I2C_STATE_READY;

            /* Process Unlocked */
            __HAL_UNLOCK(hi2c);

            return HAL_OK;
          }
          else
          {
            /* Wait until STOPF flag is reset */
            if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_STOPF, RESET, Timeout, tickstart) != HAL_OK)
            {
              return HAL_ERROR;
            }

            /* Clear NACK Flag */
            __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF);

            /* Clear STOP Flag, auto generated with autoend*/
            __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
          }

          /* Check if the maximum allowed number of trials has been reached */
          if (I2C_Trials == Trials)
          {
            /* Generate Stop */
            hi2c->Instance->CR2 |= I2C_CR2_STOP;

            /* Wait until STOPF flag is reset */
            if (I2C_WaitOnFlagUntilTimeout(hi2c, I2C_FLAG_STOPF, RESET, Timeout, tickstart) != HAL_OK)
            {
              return HAL_ERROR;
            }

            /* Clear STOP Flag */
            __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);
          }

          /* Increment Trials */
          I2C_Trials++;
        } while (I2C_Trials < Trials);

        /* Update I2C state */
        hi2c->State = HAL_I2C_STATE_READY;

        /* Update I2C error code */
        hi2c->ErrorCode |= HAL_I2C_ERROR_TIMEOUT;

        /* Process Unlocked */
        __HAL_UNLOCK(hi2c);

        return HAL_ERROR;
      }
      else
      {
        return HAL_BUSY;
      }
    }

  • Hello Alessandro,

    Thank you for sending the additional information. Maybe this is an issue with the gauge clock stretching? Are you able to send a digital logic capture of the communication between the gauge and MCU when this error occurs?

    Regards,

    Adrian

  • Hi Adrian,

    thanks again for your suggestion, we did as requested.

    We measured the signal for a not-working device and for a working one.

    The CLOCK signal is essentially the same for both.

    However, the SDA is quite different:

    WORKING DEVICE

    Working device

    NOT-WORKING DEVICE

    NOT WORKING

    As you can see, the latter has a rising curve much slower (rise time approx 1000ns).

    Furthermore, the working one has anyway a rise time of 500ns, which is over the maximum allowed by specifications (300ns).

    So I guess this is it.

    Still, I don't understand why, in some cases, removing the battery and putting it back again solves the problem.

    If you have any other remarks I'll be glad to read it.

    Thanks again for your support.

  • Hello Alessandro,

    Removing the battery pack from the gauge will cause a hardware power on reset to occur, this essentially resets the entire gauge which is why the behavior from the gauge can be different afterwards.

    Regards,

    Adrian