What Is Bit Banging?
Last updated 28 June 2026 · 5 min read
Direct Answer
Bit banging is a technique for implementing a serial communication protocol entirely in software by directly toggling GPIO pins in the correct sequence and timing, rather than relying on a dedicated hardware peripheral (such as a UART, SPI, or I2C controller). The firmware manually generates each clock pulse, data bit, and control signal, making it possible to run protocols on any GPIO pin but at the cost of CPU time and timing accuracy.
Detailed Explanation
Hardware UART, SPI, and I2C peripherals handle the timing and bit sequencing of their respective protocols in dedicated silicon, freeing the CPU from cycle-by-cycle involvement. Bit banging reverses this: the firmware itself generates every bit transition and timing delay.
How it works
A bit-banged UART transmit, for example, looks like this in pseudocode:
void uart_tx_byte(uint8_t byte) {
// Start bit
gpio_write(TX_PIN, 0);
delay_us(bit_period);
// 8 data bits, LSB first
for (int i = 0; i < 8; i++) {
gpio_write(TX_PIN, (byte >> i) & 1);
delay_us(bit_period);
}
// Stop bit
gpio_write(TX_PIN, 1);
delay_us(bit_period);
}
The bit period (in microseconds) is determined by the target baud rate: bit_period = 1 000 000 / baud_rate. At 9600 baud, each bit lasts approximately 104 µs; at 115200 baud, approximately 8.7 µs.
Timing accuracy requirements
The accuracy of the software delays is critical. UART, for example, requires that the receiver samples each bit roughly at its midpoint. A typical UART receiver tolerates up to ±3–5% deviation in bit timing before errors occur. At 9600 baud, each bit is 104 µs, so a ±3% error allows only about ±3 µs of timing jitter. At 115200 baud, the entire bit is only 8.7 µs, leaving no room for timing errors introduced by interrupt latency or cache misses.
This is why bit banging is primarily reliable only:
- At slow bit rates (below approximately 100 kHz for most MCUs)
- On MCUs with deterministic single-cycle GPIO and delay instructions
- With interrupts disabled during the transmission window
Software overhead
Hardware peripherals offload bit transmission entirely — the CPU writes to a transmit register and the peripheral clocks out each bit autonomously while the CPU does other work. With bit banging, the CPU is fully occupied for the entire transmission duration. At 9600 baud, transmitting a single byte takes roughly 9 bit periods = approximately 940 µs of CPU time. At 115200 baud, that same byte takes approximately 78 µs — still substantial on a heavily loaded RTOS with many tasks competing for CPU time.
Common use cases
- Protocol not available in hardware: some microcontrollers lack a hardware I2S peripheral; bit-banged audio output at low sample rates (8 kHz, µ-law encoded) is feasible.
- All hardware peripherals occupied: a design might have three SPI devices but only two hardware SPI controllers; the third can use bit-banged SPI.
- Pin routing constraints: hardware peripherals are only available on specific pins. If pin assignment is locked by PCB layout, bit banging can implement the protocol on whatever GPIO pins are available.
- One-wire protocol: many one-wire protocols (Dallas 1-Wire, DHT22 temperature sensor) are commonly implemented via bit banging because hardware support is rare.
Practical Examples
The Arduino platform's SoftwareSerial library provides a bit-banged UART implementation that works on any two GPIO pins. It is widely used for debugging on boards that have only one hardware UART (used for programming), or for communicating with GPS modules or Bluetooth serial adapters on a second serial port. At 9600 baud, SoftwareSerial is reliable on 8 MHz and faster AVR-based Arduinos; at 115200 baud, timing becomes marginal and data corruption is common without careful interrupt management.
Bit-banged I2C (software I2C) is common on Linux-based single-board computers like the Raspberry Pi when additional I2C buses are needed beyond the hardware-provided two. The Linux kernel's i2c-gpio driver implements I2C entirely via GPIO bit banging and is production-quality at standard 100 kHz and 400 kHz speeds.
Design Considerations
- Prefer hardware peripherals: whenever a hardware peripheral supports the required protocol, use it. Hardware peripherals operate with far better timing accuracy, require no CPU time during transmission, and are tested and validated by the MCU vendor. Reserve bit banging for cases where hardware genuinely is not available.
- Disable interrupts carefully: for bit-bang implementations that require tight timing, disable interrupts for the critical transmission window. On a FreeRTOS system, use
taskENTER_CRITICAL()/taskEXIT_CRITICAL()to suspend the scheduler and block interrupts below the FreeRTOS priority ceiling. - Validate timing: use an oscilloscope or logic analyser to measure the actual bit periods produced by your bit-bang implementation. Timing errors are often invisible in bench testing (where the receiver is tolerant) but cause failures with stricter receivers in production.
- DMA is not available: hardware peripherals can use DMA to stream many bytes without CPU involvement. Bit banging cannot — every byte requires active CPU time. This is a hard limitation that makes bit banging unsuitable for sustained high-throughput communication.
Common Mistakes
- Assuming bit banging will work at hardware peripheral speeds: a bit-banged SPI at 10 MHz is impractical on most MCUs. Software delays at this frequency would require single-instruction timing precision with no interrupt tolerance. High-speed protocols require hardware peripherals.
- Not accounting for interrupt latency in timing: a 50 µs interrupt service routine that fires mid-byte corrupts the bit timing for that byte and often the entire subsequent framing. Always profile the worst-case interrupt latency and ensure it fits within the bit period tolerance.
- Using bit banging with DMA buffer flush patterns: DMA cache-coherency operations introduce variable latency in Cortex-M7 systems. If bit banging is used in the same code path, the variable DMA latency can add jitter to GPIO transitions.
Frequently Asked Questions
- When should you use bit banging instead of a hardware peripheral?
- Use bit banging when the required protocol is not available as a hardware peripheral on your MCU, when all hardware peripherals of the required type are already in use, when pin assignment constraints mean the hardware peripheral cannot be routed to the required pins, or when you need to run a very simple, very slow protocol and cannot justify the peripheral's overhead. Hardware peripherals should always be preferred for high-speed or timing-critical protocols — bit banging at speeds above roughly 100 kHz becomes increasingly unreliable on a general-purpose RTOS or interrupt-driven system.
- Can you bit bang I2C or SPI?
- Yes, and it is done routinely. Bit-banged I2C (software I2C) is common when all hardware I2C peripherals are occupied or unavailable on a given pin. Arduino's Wire library uses hardware I2C, but the SoftwareWire library provides bit-banged I2C on any GPIO pair. Bit-banged SPI is similarly feasible and common. The limitations are lower speed and higher CPU occupancy compared to hardware-peripheral implementations.
- Does bit banging affect interrupt latency?
- Yes. Bit banging often requires precise timing between GPIO transitions. If an interrupt fires during a bit-bang transmission, the timing of that bit's GPIO transition will be delayed, potentially violating the protocol's timing requirements and corrupting the transmission. This is why bit banging is typically done with interrupts disabled during the critical transmission window, which blocks other real-time processing for the duration.
Related Questions
What Is UART (Universal Asynchronous Receiver-Transmitter)?
UART sends serial data asynchronously over TX and RX with no shared clock. Learn how framing, baud rate, RS-232 voltage levels, and common UART pitfalls work.
What Is SPI (Serial Peripheral Interface)?
SPI is a synchronous full-duplex serial bus for connecting microcontrollers to peripherals at high speed. Learn how SCLK, MOSI, MISO, and CS work.
What Is I2C (Inter-Integrated Circuit)?
I2C is a two-wire serial bus for addressing multiple peripherals over shared SDA/SCL lines. Learn how addressing, speed grades, and pull-up resistors work.
How Do GPIO Pins Work on a Microcontroller?
GPIO (General Purpose Input/Output) pins let a microcontroller read digital signals and drive outputs. Learn how push-pull, open-drain, and pull resistors work.
What Is a Microcontroller (MCU)?
A microcontroller (MCU) combines a CPU, flash, RAM, and peripherals on one chip. Learn how MCUs work and how they differ from microprocessors and FPGAs.
SPI vs I2C vs UART: Which Protocol Should You Use?
SPI suits high-speed transfers, I2C minimises pins for multi-device buses, and UART suits point-to-point links. Learn which to choose for your embedded design.
Related Forum Discussions
STM32F401 UART printing garbage after switching to 84 MHz PLL — same 115200 baud in CubeMX and PuTTY
Got a WeAct Black Pill (STM32F401CCU6) project that's been running happily on the default HSI clock at 16 MHz. Using USART1 on PA9/PA10 thro
SPI reads all returning 0xFF — logic analyser shows MISO activity, W25Q32 not responding to commands
Been staring at this one for a day and a half. I'm trying to read the JEDEC ID from a W25Q32JV SPI flash chip on a custom STM32L432 board. T
I2C bus scan finding nothing — NACK on every address despite pull-ups
Working through my first proper I2C project — hooking up a BME280 temp/humidity sensor to an ESP32 devkit. Wired SDA to GPIO21 and SCL to GP
STM32 GPIO interrupt configured but ISR never fires — what am I missing?
Trying to use a button on PA0 to trigger an interrupt on an STM32F411 Nucleo board. Using HAL, generated the init code with CubeMX. The GPIO