I am trying to establish communication between TI BQ78350 FuelGauge and STM32F103C8T6 using I2C/SMBus. The following is the I2C configuration used for the standard HAL I2C library.

static void MX_I2C1_Init(void)

  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0;
  hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c1.Init.OwnAddress2 = 0;
  hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
    _Error_Handler(__FILE__, __LINE__);


When I try to transmit something to FuelGauge, using the following code there is no proper acknowledgement and response. Only the address byte is getting transmitted.

 HAL_I2C_Master_Transmit(&hi2c1,11<<1,0x09, 1, 100);

This is how the waveform looks in an oscilloscope.

I2C Waveform

On the hardware side, I am using BSS138 Mosfet to level shift between 5V fuel gauge and 3.3V STM32F103. Pull-up resistor value is 3.3k.

Any pointers to the cause of this issue would be helpful. Thank you.

  • 1
    \$\begingroup\$ "Pull-up resistor value is 3.3k.": I noticed that you say 'value' and not 'values'. Confirm that you have pull-ups on both SDA and SCL. Please add a schematic. \$\endgroup\$ Oct 23, 2018 at 11:56
  • \$\begingroup\$ Singaram - You said: "5V fuel gauge" but according to its datasheet the bq78350 is not a 5V device - Vcc is 2.4V to 2.6V. Although it appears to have different restrictions for its SMBus voltages, the fact that you refer to it as a "5V fuel gauge" makes it unclear how you are using it. Therefore, as just requested by Chris, please edit your question and add your schematic, and also explain what you mean by the term "5V fuel gauge". Thanks. \$\endgroup\$
    – SamGibson
    Oct 23, 2018 at 12:02
  • \$\begingroup\$ Schematic would be nice, a simple implementation of the BSS138 level shift would cause a signal inversion as well. \$\endgroup\$
    – isdi
    Oct 23, 2018 at 13:00

4 Answers 4


Aside from the voltage and level conversion issues already mentioned; there is no problem in the transaction itself.

The MCU performs exactly what the code tells it to do. It may not be what you want though.

It transfers one byte from MCU memory to the chip I2C address.

The data is sent from pointer that is set to point to MCU address 0x09. This address apparently holds a byte 0x00 that is sent over the bus. Most likely you want to point to a buffer or variable that holds the data to be sent - in this case you most likely want to send 0x09 which is a command to read voltage.


Your signal does't look clean and it's probably the reason you are having problem.

It is probably related to your mosfet drive, and maybe some capacitance on the line.

For I2C, you don't need level shift.

As for a 5V chip, the threshold for a logic "1" will be lower than the 3.3V, so you simply need to put your pull-up resistor to 3V3, as both IC controlling the I2C lines should be open drain control, your SDA/SCK line will never go above 3V3.

So remove all level shift mosfet, and connect your pullup to 3V3. You can also decrease the pullup to 1k to have quicker edge.


A lot of the STM32 pins are 5V tolerant. So you can probably skip the level shifting part, especially for an open drain architecture like I²C where the output level is determined by the voltage you pull up to.

The pins cannot output 5V, but tolerate an input up to 5V. Have a look in the datasheet where the I/O level is given. A "FT" denotes a pin which is 5 V tolerant.

pin description in datasheet


I don't see the problem you're talking about. The slave ACKed both bytes. You can tell when the slave is controlling the bus because, conveniently, its ground is shifted a bit from the master's ground. Here's my breakdown of your o-scope shot:

  • I assume there's a start that's not shown on your o-scope trace.
  • At the beginning of the o-scope trace, the slave is clock stretching for some reason.
  • The first byte comes in and is acknowledged by the slave.
  • The second byte comes in and the slave clock stretches again, at the end of the second byte but before the ACK.
  • The slave releases the clock stretch, and then ACKs.
  • Stop.

You might want to figure out what all the clock stretching is about.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.