Why does this schematic send 3.3V with 10k resistors into the I2C bus?

yesterday I posted a post where I tried to explain that I was working on this sensor package for my rocket. It includes multiple sensors that runs as slaves on the I2C protocols. I managed to resolve the issue I had yesterday by myself but I find this one a bit trickier.

To setup the OV7670 in my schematic I used this project page.

In the schematic it shows that you’re supposed to have 2x 10kohm resistors going from 3.3V into the SIOC and SIOD respectively, otherwise known as the I2C communication. I dont understand why this is. If the camera is 3.3V shouldnt there just be a level shift device from from 5V → 3.3V on the I2C BUS and then I hook the device up directly to the SIOC and SIOD after the level shift?

Anyways all help is appreciated.

the confusing project page schematic.jpg

. . . I dont understand why this is. . .

Here's an over-simplified explanation:

When at rest the signal lines (SIOC and SIOD) are supposed to be at a (relatively) high level.

Communication is established when a device periodically brings the signal levels to a (relatively) low level.

So there is a power supply of some sort trying to make the signal levels high and there are devices that are periodically trying to make the signal levels low. If you do both at the same time you have what is commonly called a 'short-circuit'.

The pull-up resistors prevent this short-circuit condition. Their value must be low enough so that the high signal level is correct and high enough so the current isn't excessive when the low signal level is present.

Did you ever wonder why it takes so many years to get a degree in engineering?


Don is absolutely correct. I'm not one-upping the conversation. Personally, I enjoy the details and perhaps you do too since it's quite a simple concept -- as is true for everything once we understand it. You can also glean from the web that the 10-kohm resistors are used is because many, many devices (including most Arduinos and peripherals (sensors, etc), do not place a voltage onto the I2C bus (SDA / SCL ) pins. Rather, each device's SDA and SCL pins are connected to internal transistor switches referred to as "open collector architecture". It sounds more complicated that it is. For standardization, to preclude the conflicts Don mentioned, each I2C device connected to the 2-wire bus need only close it's internal open-collector switch to effectively "short" that bus wire (SDA / SCL ) to ground, thus "Pulling down" the buses voltage levels - creating the pulse trains (data) that are "seen" by all the I2C devices on the bus. (Only the one that's addressed reacts.) The two resistors which supply that voltage to the bus ("Pull-ups" as they are called) limit what would be a damaging "short circuit" current, as was mentioned. Without these pull-ups (thus no voltage on the bus except possible latent levels), there would be no I2C bus data or clock data pulses. Even if voltage is placed there by a pin's internal "PULLUP", the effective value is roughly 20k and the resulting bus pulses are often sloppy in shape, i.e., rounded edges and ill-defined. On a logic analyzer, the pulses are not "crisp", that is they have look rounded and ill-shaped and are difficult to process. It's worth noting that depending on the component designs, the open-collector switches used inside each I2C device vary in their switching abilities. This is why you'll see some applications using "STRONGER" pull-up resistors like 2.2k. Obviously, higher current flows when the open-collector switches close. Thus, the 2.2k is not as limiting as the 10k pull-ups. Personally, I find that 4.7k is a good all-around value that works for everything but even then, some devices I've seen lately (specifically SAMD51 dev boards) produce some pretty nasty looking I2C data/clock pulses when 10k pull-ups are used. In one case, I had to use 2.2k (VERY STRONG) pull-ups. I do prefer 10k pull-ups and always try that first. BTW, the standard use of the work "strong" people use as a general term to imply low resistance values is derived from the fact that (obviously) a 1-ohm resister would be so "strong" as a pull-up that damage is likely if not certain were it to be used. Reading the literature for each I2C device will alert you to the fact that there are exceptions and some manufactures of development boards will go ahead and place pull-up resistors on the board so you don't have to add them. The literature usually includes a note telling you where you can "disable" these pull-ups. It's rare but worth noting that large numbers of I2C devices connected to a common bus, each with it's own set of pull-ups, creates a progressively stronger and stronger net pull-up. For example, 2 devices - each with 10k pull-ups, form a net 5k pull-up strength and so on (per parallel resistor value calcs). This strength translates to more stress on all the I2C open-collector switches being connected.

It's kind of exciting and enjoyable to see a nice I2C bus setup with all the "players" performing as ordered.

Regards, GOV

If the camera is 3.3V shouldnt there just be a level shift device from from 5V --> 3.3V on the I2C BUS and then I hook the device up directly to the SIOC and SIOD after the level shift?

Yes, that would be a lot better. I strongly advise a level shifter in this situation.
The Wire library on the Arduino Uno enables the internal pullup resistors (to 5V) and the Uno requires 3.5V to detect a 'high' for the I2C bus (according to the datasheet). Using a 3.3V OV7670 with 10k pullup resistors to 3.3V is very cheesy. It might damage the OV7670 and might not work very well for the Arduino Uno.

A level shifter has often 10k pullup resistors for SDA and SCL on the "high side" and 10k on the "low side". Then probably no other pullup resistors are needed.

A level shifter makes the signal weaker, so the best solution is to use 5V I2C devices with a 5V Arduino board, and 3.3V I2C devices with a 3.3V Arduino board.

About the open-collector I2C bus:
The I2C bus was designed to be used with transistors and open-collectors. Then it would be no problem when two different voltages are used. Today, the outputs are open-drain mosfets and there are protection diodes, and pins can sometimes have multiple functions for a single pin. The microcontroller on the Arduino Uno has a input filter and reduces the output slewrate and needs 3.5V for a valid 'high' (even though it needs only 3.0V for normal digital pins) and the Wire library enables the internal pullup resistors to 5V.
All of that together makes it easy to create a mismatch that causes troubles. It is also easy to damage a sensor by the 5V via the internal pullup resistors pushing current into the SDA and SCL pins of the I2C chip. For example, the newer Bosch BMPxxx and BMExxx sensors are sensitive for that.