Introduction to Bit Banging: SPI communication via Bit Banging

Published  August 28, 2018   0
Introduction to Bit Banging: SPI communication in Arduino via Bit Banging

Communication Interfaces are one of the factors that are considered when selecting a microcontroller to be used for a project. The designer ensures that the microcontroller being selected has all the interfaces required to communicate with all the other components to be used for the product. The existence of some of these interfaces, like SPI and I2C on microcontrollers, invariably increases the cost of such microcontrollers, and depending on the BOM budget, it may make a desired microcontroller not affordable. In situations like these, techniques like bit banging come into play. This method implements serial communication via bit banging i2c whenever other hardware interfaces are not available or too expensive. This exhaustive guide gives stepwise instructions: from bit banging Arduino for general purposes up to SPI communication in Arduino via bit banging

 

What is Bit Banging? Understanding Software-Based Communication

Bit banging is a technique for serial communication in which the whole communication process is handled via software instead of dedicated hardware. To transmit data, the technique involves the use of software to encode the data into signals and pulses, which are used to manipulate the state of an I/O pin of a microcontroller, which serves as the Tx pin to send data to the target device. To receive data, the technique involves sampling the state of the Rx pin after certain intervals, which are determined by the communication baud rate. The software sets all the parameters needed to achieve this communication, including synchronisation, timing, levels, etc., which are usually decided by dedicated hardware when bit banging is not used. The bit banging provides an elegant software-based solution.

Clock Levels

 

When to use Bit Banging

Bit banging is usually used in situations where a microcontroller with the required interface is not available or when switching to a microcontroller with the required interface might be too expensive. It thus provides a cheap way of enabling the same device to communicate using several protocols. A microcontroller which is previously enabled for UART communication only can be equipped to communicate using SPI and 12C via bit banging.  Bit banging Arduino projects benefit from enhanced flexibility, allowing any digital pin to serve as a communication interface. 

Primary Use Cases for Bit Banging

  • Budget: Microcontrollers with required interfaces exceed the project budget
  • Pin Allocation: Attempting to use specific GPIO pins in communications
  • Protocols: Implementing a series of different communications methods on simple MCUs
  • Legacy Devices: Interfacing with old devices with no standard protocol
  • Education: at a bit-level understanding of the communication protocols

Bit Banging vs Hardware Communication: Quick Comparison

AspectHardware CommunicationBit Banging
CostHigher (dedicated peripherals)Lower (GPIO pins only)
SpeedHigh (hardware optimized)Moderate (software limited)
CPU UsageLowHigh
FlexibilityLimited to available portsAny GPIO pin
ReliabilityHighModerate

SPI Communication in Arduino via Bit Banging: Complete Implementation

While the code to implement bit banging may differ across diverse microcontrollers and may also vary for different serial protocols, the procedure/algorithm for implementing bit banging is the same across all platforms.

To send data, for instance, the pseudo-code below is used;

  1. Start
  2. Send start bit
  3. Wait for the timing to correspond with the baud rate of the receiver
  4. Send data bit
  5. Wait for the duration to correspond with the baud rate of the receiver again
  6. Check if all data bits have been sent. If no, go to 4. If yes, go to 7
  7. Send stop bit
  8. Stop

 

Receiving data tends to be a little bit more complex; usually, an interrupt is used to determine when data is available on the receiver pin. This helps ensure the microcontroller doesn’t waste too much processing power. Although certain implementations use any of the microcontroller's I/O pins, the chances of noise and errors, if not properly handled, are higher. The algorithm to receive data using interrupts is explained below.

  1. Start
  2. Enable an interrupt on the Rx pin
  3. When an interrupt is triggered, obtain the start bit
  4. Wait for timing according to the baud rate
  5. Read the Rx pin
  6. Repeat from 4 till all data has been received
  7. Wait for timing according to the baud rate
  8. Check for the stop bit
  9. Stop

 

Understanding SPI Protocol for Bit Banging

As mentioned above, bit banging for different protocols works differently, and it’s thus important to read about each protocol to understand data framing and clocking before attempting to implement. Taking the SPI mode 1 as an example, the base value of the clock is always 0 and data is always sent or received on the rising edge of the clock. Bit banging SPI communication via Arduino requires knowledge of a four-wire protocol: MOSI (Master Out Slave In), MISO (Master In Slave Out), SCK (Serial Clock) and SS (Slave Select). SPI Mode 1 has a base clock value of 0, with data being sent on rising clock edges.  Bit banging I2C implementation involves managing the two-wire interface. The timing diagram for the SPI Mode 1 communication protocol is shown below.

Bit Banging over SPI

 

To implement this, the following algorithm can be used;

  1. Start
  2. Set the SS pin low to begin communication
  3. Set the pin for Master Out Slave In (MOSI) to the first bit of the data to be sent
  4. Set the clock pin (SCK) high so data is transmitted by the master and received by the slave
  5. Read the state of the Master in Slave Out (MISO) to receive the first bit of data from the slave
  6. Set SCK Low, so data can be sent on the next rising edge
  7. Go to 2 till all data bits have been transmitted.
  8. Set the SS pin High to stop transmission.
  9. Stop

 

Bit Banging SPI Example in C: Advanced Implementation

As an example, let’s implement the algorithm for SPI communication via bit banging in Arduino to show how data can be bit-banged over SPI using the code below. This bit banging SPI example in C demonstrates a professional-grade implementation suitable for various microcontroller platforms beyond Arduino.

We start by declaring the pins of the Arduino to be used.

const int SSPin = 11;
const int SCKPin = 10;
const int MISOPin = 9;
const int MOSIPin = 8;
byte sendData = 64;   // Value to be sent
byte slaveData = 0;  // for storing the  value sent by the slave

 

Next, we move to the void setup() function, where the state of the pins is declared. Only the Master in Slave out (MISO) pin is declared as an input since it is the only pin that receives data. All other pins are declared as output. After declaring the pin modes, the SS pin is set to HIGH. The reason for this is to ensure the process is error-free and communication only starts when it’s set to low.

void setup()
{
pinMode(MISOPin, INPUT);
 pinMode(SSPin, OUTPUT);
 pinMode(SCKPin, OUTPUT);
 pinMode(MOSIPin, OUTPUT);
digitalWrite(SSPin, HIGH);
}

 

Next, we start the loop to send data. Note that this loop will keep sending the data repeatedly.

We start the loop by writing the SS pin low to initiate the beginning of communication, and call on the bitbangdata function, which breaks the predefined data into bits and sends. With this done, we then write the SS pin HIGH to indicate the end of data transmission.

void loop()
{
  digitalWrite(SSPin, LOW);        // SS low
  slaveData = bitBangData(sendData); // data transmission
  digitalWrite(SSPin, HIGH);       // SS high again 
}

 

The bitbangdata() function is written below. The function takes in the data to be sent, breaks it down into bits, and sends it over by looping over the code for the transmission as indicated in step 7 of the algorithm.

byte bitBangData(byte _send)  // This function transmit the data via bitbanging
{
  byte _receive = 0;
  for(int i=0; i<8; i++)  // 8 bits in a byte
  {
    digitalWrite(MOSIPin, bitRead(_send, i));    // Set MOSI
    digitalWrite(SCKPin, HIGH);                  // SCK high
    bitWrite(_receive, i, digitalRead(MISOPin)); // Capture MISO
    digitalWrite(SCKPin, LOW);                   // SCK low
  } 
  return _receive;        // Return the received data
}

 

Disadvantages of Bit Banging

Adopting bit banging should, however, be a well-thought-out decision, as several downsides to bit banging may make it not reliable for implementation in certain solutions. Bit banging increases the power consumed by the microcontroller due to the high processing power required by the process. Compared to dedicated hardware, more communication errors, like glitches and jitters, occur when bit banging is used, especially when data communication is being performed by the microcontroller at the same time as other tasks. Communication via bit banging happens at a fraction of the speed with which it occurs when dedicated hardware is used. This may be important in certain applications and may make bit banging a “not so good” choice.

Bit banging is used for all kinds of serial communications, including RS-232, Asynchronous Serial Communication, UART, SPI, and I2C.

 

UART via Bit Banging in Arduino

One of the popular implementations of bit banging is the Arduino Software Serial library, which enables the Arduino to communicate over UART without using the dedicated hardware UART pins (D0 and D1). This gives a lot of flexibility, as users can connect as many serial devices as the number of pins on the Arduino board can support. Bit banging UART C code implementation requires precise timing control for asynchronous communication. One popular implementation of bit banging UART C code is Arduino's SoftwareSerial library.

 

Conclusion: Understanding Bit Banging for Embedded Systems

With cost-effective options for serial communication via bit banging with standard bus implementations. Bit banging is an important technique for developers of embedded systems. SPI communication in Arduino via bit banging, developing UART C code using bit banging, or simply implementing, is one way to expand your design space using these software-based communication options.

Of course, bit banging Arduino implementations will always have the important factors of timing and CPU overhead, but they provide the maximum possible performance with some flexibility for connecting numerous devices with any leftover GPIO pins you have available. The information in this guide provides a solid basis for developing your own communication systems in time- or resource-constrained embedded applications.

Frequently Asked Questions on Bit Banging Arduino

⇥ Q1: What exactly is bit banging, and when should you use bit banging?
A: Bit banging has often been called software-based serial communication since there is no special hardware required for it. It is often employed when: a microcontroller has limited interfaces, the peripheral hardware is expensive, or one is forced to use GPIO pins not dedicated to the protocol.

⇥ Q2: What differences exist between bit-banged SPI communication and hardware SPI?
A: Hardware SPI utilises (dedicated) hardware peripherals for timing and data transfer, whereas bit-banging controls or toggles GPIO pins by way of a software intervention. Hence, it is slower and uses CPU power to manage data; however, it can be executed on any microcontroller, and one therefore has the freedom to select the pin for implementation.

⇥ Q3: Is there a potential for UART-bit-bang on Arduino, without waiting for SoftwareSerial?
A: Yes, if you want to directly time and set states for the GPIO, you can simply invent your own UART bit-bang implementation. But, as SoftwareSerial has a very optimised and well-tested implementation around timing, interrupts, and buffering that is better than any home-grown solution, the preferred solution is SoftwareSerial in most cases.

⇥ Q4: What are the main challenges in I2C bit banging implementation?
A: I2C bit banging involves working with open-drain outputs, pull-up resistors, start/stop conditions, clock stretching, and acknowledge bits. Precision in timing is essential, and you have to deal with bus arbitration in multi-master situations as well as with proper signal levels during the course of communication.

⇥ Q5: What is the best way to optimise the performance of bit banging for real-time applications?
A: The most significant improvement will be made during critical phases of the communication if you turn off the interrupts. Use direct port access rather than digitalWrite() and have pre-computed timing numbers. You can improve your performance by using simpler bit manipulation methods and using delays based on timer values. For large volumes of data, you should implement buffering like DMA to keep the CPU costs low. They should also use larger buffers for bulk transactions.

⇥ Q6: What baud rates can I achieve with bit banging on Arduino?
A: With bit banging, Arduino typically achieves a stable UART at 9600-38400 baud, and for SPI communication, you can achieve several hundred kHz, depending on your design. Floating above the 38400 baud, could have problems, the data transmission speed can at times not be consistent due to timing constraints and the 16MHz clock speed of the Arduino.

Explore Serial Communication Based Projects

You can find various projects where we applied Serial Communication, browse the links below to discover them.

 How to use SPI (Serial Peripheral Interface) in Arduino to Communication between two Arduino Boards

How to use SPI (Serial Peripheral Interface) in Arduino to Communication between two Arduino Boards

This complete guide explains Arduino SPI communication between two Arduino boards, including Arduino SPI pinout diagrams, wiring examples, and complete code examples.

Serial UART Communication on STM8 using Cosmic C and STVD - Print / Read Characters and Strings

Serial UART Communication on STM8 using Cosmic C and STVD - Print / Read Characters and Strings

The tutorial also provides a header file called stm8s103 serial.h using which you can perform simple UART commands like Serial begin, Serial read, serial print, etc. Basically, you will be able to print char, int, and string to the serial monitor and also read char from the serial monitor. 

RS232 Serial Communication Protocol: Basics, Working & Specifications

RS232 Serial Communication Protocol: Basics, Working & Specifications

This comprehensive guide covers everything from basic RS232 principles to advanced implementation techniques, helping both beginners and experienced engineers master this essential communication protocol.

Have any question related to this Article?

Add New Comment

Login to Comment Sign in with Google Log in with Facebook Sign in with GitHub