NetBurner 3.5.8
PDF Version
Bit Bang I2C (GPIO)

Software I2C master driven directly from a pair of GPIO pins. More...

Classes

class  BBI2C
 Software (bit-banged) I2C master driver. More...

Detailed Description

Software I2C master driven directly from a pair of GPIO pins.

#include< bb_i2c.h>


The BBI2C class implements an I2C master entirely in software, by toggling two general purpose I/O pins. It does not use any I2C peripheral hardware, so it can put an I2C bus on any pair of GPIO capable pins.

Choosing between BBI2C and TwoWire

Most applications should use the TwoWire class in Wire.h, which drives the processor's I2C peripheral modules. Reach for BBI2C when:

  • the pins you need are not routed to a hardware I2C module,
  • every hardware module is already committed to another bus, or
  • you need a register address wider than one byte, which TwoWire does not currently offer. See Register address width below.
BBI2C TwoWire
Implementation Software, GPIO toggling I2C peripheral hardware
Pins Any two GPIO capable pins Fixed sets per platform
Controller (master) Yes Yes
Target (slave) No Yes
Register address 0 to 3 bytes 1 byte
Thread safe No, see below Yes
CPU cost Busy waits for the whole transaction Interrupt driven

Basic usage

Construct the object with the SCL and SDA pins, call setup() once with the bus speed, then use the register level calls. As with any I2C bus, both lines need pull up resistors; the driver configures the pins as open drain and never drives them high.

#include <bb_i2c.h>
BBI2C bb(Pins[9], Pins[10]); // SCL, SDA
void UserMain(void *pd)
{
init();
bb.setup(100000); // 100 kHz, call before the first transaction
uint8_t id;
if (bb.readReg8(0x51, 0x00, id) == BBI2C::I2C_RES_ACK)
{
iprintf("register 0x00 = 0x%02X\r\n", id);
}
}
Software (bit-banged) I2C master driver.
Definition bb_i2c.h:153
@ I2C_RES_ACK
Acknowledged.
Definition bb_i2c.h:157
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...

Register address width

Devices differ in how many bytes of register address they expect before the data phase. setNumAddressBytes() selects that width, and it applies to every transaction until changed. Address bytes are sent most significant first.

Call Bytes sent Typical device
setNumAddressBytes(0) none Parts with no register pointer, read straight from the device
setNumAddressBytes(1) 1, the default Most sensors and real time clocks, 8-bit registers
setNumAddressBytes(2) 2 EEPROMs and switches with 16-bit registers
setNumAddressBytes(3) 3 Large EEPROMs with 24-bit addressing

If every device on the bus uses the same width, call it once after setup(). With a mix of devices, set it before each transaction:

uint8_t buf[4];
bb.setNumAddressBytes(2); // 16-bit register address
bb.readRegN(0x50, 0x1234, buf, 4);
bb.setNumAddressBytes(1); // back to an 8-bit register address
bb.readRegN(0x68, 0x75, buf, 1);
bb.setNumAddressBytes(0); // no register phase at all
bb.readRegN(0x5A, 0, buf, 2);

Probing and recovery

ping() reports whether a device acknowledges an address, which is all a bus scan needs. resetBus() clocks SCL until a target that is holding SDA low releases it, then issues a stop, and is the way to recover a hung bus.

for (uint8_t addr = 1; addr < 127; addr++)
{
if (bb.ping(addr) == BBI2C::I2C_RES_ACK)
iprintf("device at 0x%02X\r\n", addr);
}

Things to know

  • Controller only. There is no target (slave) mode. Use TwoWire if this device has to respond to another controller.
  • Not thread safe. The class holds no lock. If more than one task uses the same BBI2C object, serialize access yourself.
  • Transactions busy wait. Bit timing comes from a spin loop, so a transaction occupies the calling task for its full duration. Lower bus speeds cost proportionally more CPU time.
  • The bus speed is approximate. setup() sets the delay between clock edges, but the time spent toggling the pins is added on top, so the rate on the wire is lower than requested. GetBusSpeed() reports the configured timing, not measured throughput.
  • **Every call returns a BBI2C::Result_t.** Check for I2C_RES_ACK rather than assuming success; I2C_RES_NACK usually means nothing responded at that address.