I2c woes!

Hi Guys,

I must be missing something very basic here:

int main(void)
{
	hw.Init();

	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;	
	
	i2c.Init(i2c_config);

	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?

Thanks

Andy

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.

https://electro-smith.github.io/libDaisy/md_doc_2md_2__a1___getting-_started-_g_p_i_o.html#autotoc_md8

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.