Microcontroller – I2C SCL Goes Low Using MCU GPIOs as Pull-Ups

i2cmicrocontrollerpulluptexas instrumentstm4c123g

I have an MCU (tm4c123gh6pm) in which I have configured an I2C slave device. At the moment I don't have resistors to wire the required pull-ups, so I want to use two of the MCU's GPIOs for this purpose.

I have configured two GPIOs as inputs with 'weak' pull-up resistors (not sure what 'weak' means):

static void init_pullup_resistors(void) {
    GPIOPinTypeGPIOInput(GPIO_PORTB_BASE, GPIO_PIN_6);
    GPIOPinTypeGPIOInput(GPIO_PORTB_BASE, GPIO_PIN_7);

    GPIOPadConfigSet(GPIO_PORTB_BASE,
                     GPIO_PIN_6 | GPIO_PIN_7,
                     GPIO_STRENGTH_8MA,
                     GPIO_PIN_TYPE_STD_WPU);
}

I have double checked that, before wiring anything, the two I2C pins are low and the 'pull-up' pins are high.

When I connect SDA to one of the 'pull-ups' it remains high, so fine. However, when I do the same with SCL, it goes low directly. If I try to send a frame from my I2C master dev. (which is a Basys 3), I can see a clock signal in SCL, but it only reaches a few millivolts (not the expected 3.3V).

Why is this happening?

More context: I have checked the tm4c123gh6pm datasheet and have found that its internal resistors are way bigger than what an I2C should use (4.7 kOhms):

enter image description here

I suspect this might be causing the problem, but I don't understand how. As you can see, those resistors are supposed to go from 13 to 35 kOhms. However, the header file documentation (TivaWare SDK) speaks about 'weak' pull-ups. I don't know what is this. See below:

#define GPIO_PIN_TYPE_STD       0x00000008  // Push-pull
#define GPIO_PIN_TYPE_STD_WPU   0x0000000A  // Push-pull with weak pull-up
#define GPIO_PIN_TYPE_STD_WPD   0x0000000C  // Push-pull with weak pull-down
#define GPIO_PIN_TYPE_OD        0x00000009  // Open-drain

Having that I2C requires ~4.7 kOhms pull-ups, ~13-35 don't seem weak, but rather the opposite.

Below is how I initialize the I2C slave dev.:

static void I2C1_Init(void) {
    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    GPIOPinConfigure(GPIO_PA6_I2C1SCL);
    GPIOPinConfigure(GPIO_PA7_I2C1SDA);

    GPIOPinTypeI2CSCL(GPIO_PORTA_BASE, GPIO_PIN_6);
    GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_7);

    I2CSlaveEnable(I2C1_BASE);
    I2CSlaveInit(I2C1_BASE, I2C_SLAVE_ADDRESS);
}

Best Answer

First of all "weak pull-up" means low current. Ohm law: higher the resistance, lower the current. It's a wide used term.

Next, I2C bus are open drain bus. Setting the I2C pins to push-pull can cause damage to the devices on the bus. Open drain devices only drives bus down to ground while communicating. If you have push-pull, it can cause short circuit while some device on the bus "connects" it to the ground and the other one drives it high.

Those weak pull-ups you've quoted are described in GPIO section. I.e. it's not supposed to work with the I2C. That's why it's weaker. I2C bus are usually supposed to have external pull-up resistors. Having 4.7K resistance on MCU die will consume much space which would be a waste if the user won't be using I2C Master.