Can SPI and I2C be implemented using GPIO pins?

Can SPI and I2C be implemented using digital GPIO pins? I.e. can the SDA and SCK pins of I2C and the MISO, MOSI, SCK, and SS pins of SPI be emulated by setting GPIO pins as input and output accordingly?

For example in the case of an Arduino/Atmega328p, certain pins have been dedicated for SPI and I2C use. Can the other digital GPIO pins perform the same function?1 Is there something fundamentally different in how they behave? Maybe an internal register or something to collect the incoming serial data?

In the diagram, one can see that the SPI pins are shared with digital GPIO pins. Inside the Atmega328p die, are the two distinct elements/submodules with something like a buffer determining which will drive the pin? Or are they the same thing...

1 For the SCK emulation, assume that somehow you are able to pass the clock pulse to a GPIO pin set in output mode.

Note: The Arduino is just an example. I am asking in a general sense.

• Many is the time I've had to implement SPI and I2C in software (obviously, the hardware has to also be compatible) on MCUs that didn't include an SPI peripheral or an I2C peripheral. (A 30-cent MCU is cheaper than a \$5 MCU, so what else can you do in those cases?) But if you already have an SPI/I2C peripheral in your MCU (or more) you should probably assign pin usage accordingly. Some MCUs include cross-bars so you can assign almost any peripheral function onto almost any I/O pin. But that's not the common case. So you may be stuck with the assignments. But yes, software can do it if slowly. – jonk Jul 3 '18 at 22:14

Sometimes you can bit-bang these interfaces but it will take more resources and may not work on all cases. For example, SPI master can easily be bit-banged but SPI slave at 10MHz is probably impossible on a slow micro, and even at much lower speeds you would likely have to block interrupts.

The specified pins are connected to dedicated hardware inside which makes it easier to use and it generally will work better, faster and will use less resources. For example, you can be off doing something else whilst the bus is sending or receiving data.

Read the MCU datasheet to see which pins are used and if there are an alternates available.

Yes, these protocols can be bit-banged, with two caveats: 1) I2C (or similar "two-wire" protocols) has to use open-drain GPIO pins to support clock-stretching, ACKs, and detect other conflicts that the protocol is designed around. I2C also 2) Your MCU must be running fast enough to support the speeds. As Sphero mentions, an SPI master is easily done in software ("bit banged"); as the micro is in full control of the clocking, it sets the pace for all transactions. To bit-bang a slave means that the software must be ready on time to the incoming clock. To fully implement I2C, the master also needs to monitor the SCL line for variable amounts of time to allow the slave to acknowledge transactions.

Yes, it is no problem.

It does not take much code space.

Since you often use I2C in a blocking fashion i.e. you are waiting for the byte to finish anyway, there is actually no time overhead at all.

Atmel has had some truly abysmal I2C hardware, and bit bashing has been necessary for correct function sometimes anyway.

You can also pin share, so multiple buses can have one shared SCL pin, and separate SDA's

What is very hard to do, is make a general purpose I2C slave in software. This requires hardware.

The dedicated I2C pins often have a different input threshold to match the I2c standard. You need to consider the input type (TTL vs CMOS vs Schmitt) for your job. For a long bus, going off board, the dedicated pins with I2C schmitt levels may give better noise immunity.

SPI usually runs faster, and the bit bashing is likely to be slower. Also the hardware operation of the chips is simple, clean and works properly - you don't have to work around bugs or badly thought out logic (unlike the I2C hardware). But if you need more SPI pins then bit bashing is fine. (using a cheap analog switch to mux the pin is also an option)