I2c woes!

Hi Guys,

I must be missing something very basic here:

int main(void)

	I2CHandle 		  i2c;
    I2CHandle::Config i2c_config;

	i2c_config.periph         = I2CHandle::Config::Peripheral::I2C_1;
	i2c_config.speed          = I2CHandle::Config::Speed::I2C_1MHZ;
	i2c_config.mode           = I2CHandle::Config::Mode::I2C_MASTER;
	i2c_config.pin_config.scl = {DSY_GPIOB, 8};
	i2c_config.pin_config.sda = {DSY_GPIOB, 9};
	i2c_config.address        = 0x3C;	

	uint8_t data;
	i2c.TransmitBlocking(i2c_config.address, &data, 1, 1000); 

I have a logic analyser attached to D11 and D12.

I see no data at all on these pins.

The TransmitBlocking() times out, in the following code in HAL_I2C_Master_Transmit()

/* No need to Check TC flag, with AUTOEND mode the stop is automatically generated */
    /* Wait until STOPF flag is set */
    if (I2C_WaitOnSTOPFlagUntilTimeout(hi2c, Timeout, tickstart) != HAL_OK)
      return HAL_ERROR;

Am I missing something very basic here?



And I was missing something basic, there are no pull-ups on the daisy, or they are not enabled by default?

With some pullup resisters it is now working.


dunno how it works with I2C, but they exist

Thanks, I’ll delve down into the i2c code and see if I can enable them…

Internal pull-up resistors in MCUs are typically for GPIO configured as an input, but I2C pins are meant to be bidirectional and configured as open-drain, which means they require external pull-up resistors. This is a standard requirement of an I2C circuit and I don’t believe you’ll be able to get around it by enabling internal pullups. They’ll simply be unused/disabled for open-drain pin configuration when using the pins for I2C. EDIT: this is incorrect, see below.

1 Like

Why would the internal pull-ups be different to an external pull-up, apart from the ohmage?

I have used i2c with a single device in the past using internal pull-ups on MCUs with no issue.

Anyway, I changed line 620 of i2c.cpp to 'GPIO_InitStruct.Pull = GPIO_PULLUP;` and now it is working fine without any external pull-ups.

Actually it’s not working fine :slight_smile:

Its ok at 100Khz but the internal pull-ups are not enough for 400khz,

My apologies, you are correct - according to the reference manual the open-drain GPIO modes can indeed work in tandem with pull-up/down resistors. However, libDaisy’s I2CHandle is hard coded to initialize the pins without any internal pull-ups, as you’ve discovered and changed.

I suppose the biggest difference is resistor value. The STM32H750 datasheet lists the weak pull-up resistor equivalent values as being anywhere from 30-50k Ohm (40k Ohm typical) which is an order of magnitude too large for most I2C circuits – 4.7k Ohm is often thrown out as a “safe” value for typical parasitic capacitance in short trace circuits running at ~100kHz. And the resistors will need to be even smaller for higher frequencies to meet the edge rise/fall time requirements.

I did some more testing and at 100Khz, even though it seemed to be working (as in the data seemed to be correct) the time taken was about 80% longer, so I looked on the analyser and acks were missing, there must be some kind of retry going on in the HAL.

At 400Khz it was totally dead.

So I guess we are both correct here :slight_smile:

I will check more at 400Khz, maybe there are also retries there as I am using only 4.7K resistors.

Thanks for the pointers and the info.