0
# Software Bit-banged Protocols
1
2
Software implementations of I2C and SPI communication protocols using bit-banging techniques. These implementations work on platforms without dedicated hardware communication peripherals or when hardware peripherals are already in use.
3
4
## Capabilities
5
6
### Software I2C
7
8
Bit-banged I2C implementation using GPIO pins for clock and data lines. Provides the same interface as hardware I2C but implemented in software.
9
10
```python { .api }
11
class I2C(Lockable):
12
def __init__(self, scl, sda, frequency: int = 400000):
13
"""
14
Initialize software I2C interface.
15
16
Parameters:
17
- scl: Pin to use for I2C clock line
18
- sda: Pin to use for I2C data line
19
- frequency: I2C frequency in Hz (default 400000)
20
21
Raises:
22
- NotImplementedError: On Pyboard or Linux platforms
23
"""
24
25
def scan(self) -> list[int]:
26
"""
27
Scan I2C bus for connected devices.
28
29
Returns:
30
List of device addresses found on the bus
31
"""
32
33
def readfrom_into(self, address: int, buffer: bytearray, start: int = 0, end: int = None) -> None:
34
"""
35
Read data from I2C device into existing buffer.
36
37
Parameters:
38
- address: 7-bit I2C device address
39
- buffer: Buffer to read data into
40
- start: Starting index in buffer (default 0)
41
- end: Ending index in buffer (default None for full buffer)
42
"""
43
44
def writeto(self, address: int, buffer: bytes, start: int = 0, end: int = None, stop: bool = True) -> int:
45
"""
46
Write data to I2C device from buffer.
47
48
Parameters:
49
- address: 7-bit I2C device address
50
- buffer: Data to write
51
- start: Starting index in buffer (default 0)
52
- end: Ending index in buffer (default None for full buffer)
53
- stop: Send I2C stop condition (default True)
54
55
Returns:
56
Number of bytes written
57
"""
58
```
59
60
### Software SPI
61
62
Bit-banged SPI implementation using GPIO pins for clock, MOSI, and MISO lines. Provides SPI communication when hardware SPI is unavailable.
63
64
```python { .api }
65
class SPI(Lockable):
66
def __init__(self, clock, MOSI=None, MISO=None):
67
"""
68
Initialize software SPI interface.
69
70
Parameters:
71
- clock: Pin to use for SPI clock
72
- MOSI: Pin to use for Master Out Slave In (optional)
73
- MISO: Pin to use for Master In Slave Out (optional)
74
75
Raises:
76
- NotImplementedError: On Linux platforms
77
"""
78
79
def configure(self, baudrate: int = 100000, polarity: int = 0, phase: int = 0, bits: int = 8) -> None:
80
"""
81
Configure SPI communication parameters.
82
83
Parameters:
84
- baudrate: SPI clock frequency in Hz (default 100000)
85
- polarity: Clock polarity (0 or 1, default 0)
86
- phase: Clock phase (0 or 1, default 0)
87
- bits: Bits per transfer (default 8)
88
89
Raises:
90
- RuntimeError: If try_lock() has not been called
91
"""
92
93
def write(self, buf: bytes) -> None:
94
"""
95
Write data to SPI device.
96
97
Parameters:
98
- buf: Data buffer to write
99
"""
100
101
def readinto(self, buf: bytearray) -> None:
102
"""
103
Read data from SPI device into buffer.
104
105
Parameters:
106
- buf: Buffer to read data into
107
"""
108
109
def write_readinto(self, buffer_out: bytes, buffer_in: bytearray) -> None:
110
"""
111
Simultaneously write and read data over SPI.
112
113
Parameters:
114
- buffer_out: Data to write
115
- buffer_in: Buffer to read data into
116
"""
117
```
118
119
## Usage Examples
120
121
### Software I2C Example
122
123
```python
124
import bitbangio
125
import board
126
127
# Initialize software I2C
128
i2c = bitbangio.I2C(board.SCL, board.SDA, frequency=100000)
129
130
# Scan for devices
131
devices = i2c.scan()
132
print(f"Found devices: {[hex(d) for d in devices]}")
133
134
# Read from device
135
if devices:
136
data = bytearray(4)
137
i2c.readfrom_into(devices[0], data)
138
print(f"Data: {list(data)}")
139
140
i2c.deinit()
141
```
142
143
### Software SPI Example
144
145
```python
146
import bitbangio
147
import board
148
149
# Initialize software SPI
150
spi = bitbangio.SPI(board.SCLK, MOSI=board.MOSI, MISO=board.MISO)
151
152
# Configure SPI parameters
153
if spi.try_lock():
154
try:
155
spi.configure(baudrate=1000000, polarity=0, phase=0)
156
157
# Write data
158
spi.write(b'\x01\x02\x03\x04')
159
160
# Read data
161
buffer = bytearray(4)
162
spi.readinto(buffer)
163
print(f"Read: {list(buffer)}")
164
165
finally:
166
spi.unlock()
167
168
spi.deinit()
169
```
170
171
## Platform Support
172
173
- **MicroPython platforms**: Full support using machine.I2C and machine.SPI
174
- **Linux platforms**: Not supported - use Adafruit_CircuitPython_BitbangIO instead
175
- **Pyboard**: I2C not supported
176
177
## Notes
178
179
- Software implementations are slower than hardware implementations
180
- CPU usage is higher during communication operations
181
- Timing precision depends on platform and system load
182
- On Linux, use the dedicated Adafruit_CircuitPython_BitbangIO library instead