0
# SPI Master Communication
1
2
SPI master controller implementation enabling communication with SPI devices. Supports multiple chip selects, simultaneous GPIO access, variable clock speeds up to 30MHz, and advanced features like non-byte-aligned transfers.
3
4
## Capabilities
5
6
### SPI Controller Setup
7
8
Configure and manage SPI controller with multiple device support.
9
10
```python { .api }
11
class SpiController:
12
def configure(self, url, **kwargs):
13
"""
14
Configure SPI controller with FTDI device.
15
16
Parameters:
17
- url: FTDI device URL (e.g., 'ftdi:///1')
18
- frequency: Default SPI clock frequency in Hz (default: 6MHz)
19
- cs_count: Number of chip select lines (1-8)
20
- turbo: Enable turbo mode for higher performance
21
- debug: Enable debug output
22
23
Raises:
24
- SpiIOError: Configuration failed
25
- FtdiError: Device access error
26
"""
27
28
def terminate(self):
29
"""Terminate SPI controller and release device."""
30
31
def get_frequency(self) -> float:
32
"""Get actual configured frequency."""
33
34
def get_gpio(self):
35
"""
36
Get GPIO controller for unused pins.
37
38
Returns:
39
GpioMpsseController: GPIO controller for remaining pins
40
"""
41
```
42
43
### SPI Port Access
44
45
Get SPI port instances for communication with specific devices.
46
47
```python { .api }
48
def get_port(self, cs: int, freq: float = 6000000, mode: int = 0) -> 'SpiPort':
49
"""
50
Get SPI port for specific chip select.
51
52
Parameters:
53
- cs: Chip select number (0-7)
54
- freq: SPI clock frequency in Hz
55
- mode: SPI mode (0-3)
56
- Mode 0: CPOL=0, CPHA=0 (clock idle low, sample on rising edge)
57
- Mode 1: CPOL=0, CPHA=1 (clock idle low, sample on falling edge)
58
- Mode 2: CPOL=1, CPHA=0 (clock idle high, sample on falling edge)
59
- Mode 3: CPOL=1, CPHA=1 (clock idle high, sample on rising edge)
60
61
Returns:
62
SpiPort: Port instance for device communication
63
"""
64
```
65
66
### SPI Data Transfer
67
68
Perform SPI transactions with various transfer patterns.
69
70
```python { .api }
71
class SpiPort:
72
def exchange(self, out: bytes, readlen: int = 0, start: bool = True,
73
stop: bool = True, duplex: bool = False) -> bytes:
74
"""
75
Perform full-duplex SPI transaction.
76
77
Parameters:
78
- out: Data bytes to transmit
79
- readlen: Number of additional bytes to read after transmission
80
- start: Assert chip select at start
81
- stop: Deassert chip select at end
82
- duplex: True for simultaneous read/write, False for write-then-read
83
84
Returns:
85
bytes: Data received during transaction
86
"""
87
88
def read(self, readlen: int, start: bool = True, stop: bool = True) -> bytes:
89
"""
90
Read data from SPI device.
91
92
Parameters:
93
- readlen: Number of bytes to read
94
- start: Assert chip select at start
95
- stop: Deassert chip select at end
96
97
Returns:
98
bytes: Data read from device
99
"""
100
101
def write(self, out: bytes, start: bool = True, stop: bool = True):
102
"""
103
Write data to SPI device.
104
105
Parameters:
106
- out: Data bytes to write
107
- start: Assert chip select at start
108
- stop: Deassert chip select at end
109
"""
110
```
111
112
### Advanced SPI Features
113
114
Non-standard SPI operations and advanced transfer modes.
115
116
```python { .api }
117
def write_readinto(self, out: bytes, read_buf: bytearray, start: bool = True,
118
stop: bool = True):
119
"""Write data and read response into existing buffer."""
120
121
def flush(self):
122
"""Flush any pending SPI operations."""
123
124
def set_frequency(self, frequency: float) -> float:
125
"""
126
Set SPI clock frequency for this port.
127
128
Parameters:
129
- frequency: Desired frequency in Hz
130
131
Returns:
132
float: Actual configured frequency
133
"""
134
135
def get_frequency(self) -> float:
136
"""Get current SPI clock frequency."""
137
```
138
139
### SPI with GPIO Support
140
141
SPI port with additional GPIO control for device management.
142
143
```python { .api }
144
class SpiGpioPort(SpiPort):
145
"""SPI port with GPIO capabilities for control signals."""
146
147
def set_gpio_direction(self, pins: int, direction: int):
148
"""Set GPIO pin directions (0=input, 1=output)."""
149
150
def read_gpio(self) -> int:
151
"""Read current GPIO pin states."""
152
153
def write_gpio(self, value: int):
154
"""Write GPIO pin states."""
155
156
def exchange_gpio(self, out: bytes, readlen: int, gpio_dir: int,
157
gpio_out: int) -> tuple:
158
"""
159
Perform SPI exchange with simultaneous GPIO control.
160
161
Returns:
162
tuple: (spi_data, gpio_state)
163
"""
164
```
165
166
## Device Support
167
168
### Pin Assignments
169
170
Standard FTDI SPI pin assignments:
171
172
**FT232H (8 pins available):**
173
- SCK: AD0 (SPI Clock)
174
- MOSI: AD1 (Master Out, Slave In)
175
- MISO: AD2 (Master In, Slave Out)
176
- CS0: AD3 (Chip Select 0)
177
- CS1: AD4 (Chip Select 1)
178
- CS2-CS7: AD5-AD7, AC0-AC2 (Additional chip selects)
179
180
**FT2232H/FT4232H:**
181
- Similar pin assignments per interface
182
- Multiple interfaces allow independent SPI controllers
183
184
### Clock Speeds
185
186
Supported SPI clock frequencies:
187
- **FT232H**: Up to 30 MHz
188
- **FT2232H**: Up to 30 MHz
189
- **FT2232C/D**: Up to 6 MHz
190
- **Actual speeds**: Depend on FTDI device oscillator and divider limitations
191
192
## Usage Examples
193
194
### Basic SPI Communication
195
196
```python
197
from pyftdi.spi import SpiController
198
199
# Configure SPI controller
200
spi = SpiController()
201
spi.configure('ftdi:///1')
202
203
# Get SPI port for device on CS0
204
device = spi.get_port(cs=0, freq=1E6, mode=0)
205
206
# Read device ID (common SPI flash operation)
207
device_id = device.exchange([0x9F], 3) # JEDEC ID command
208
print(f"Device ID: {device_id.hex()}")
209
210
# Write enable command
211
device.write([0x06])
212
213
# Read status register
214
status = device.exchange([0x05], 1)[0]
215
print(f"Status: 0x{status:02x}")
216
217
# Clean up
218
spi.terminate()
219
```
220
221
### Multiple Device Management
222
223
```python
224
from pyftdi.spi import SpiController
225
226
spi = SpiController()
227
spi.configure('ftdi:///1', cs_count=3)
228
229
# Different devices on different chip selects
230
flash = spi.get_port(cs=0, freq=10E6, mode=0) # SPI Flash
231
adc = spi.get_port(cs=1, freq=1E6, mode=1) # ADC
232
dac = spi.get_port(cs=2, freq=5E6, mode=2) # DAC
233
234
# Independent communication with each device
235
flash_id = flash.exchange([0x9F], 3)
236
adc_value = adc.exchange([0x00, 0x00], 2)
237
dac.write([0x30, 0xFF, 0x00]) # Set DAC output
238
239
spi.terminate()
240
```
241
242
### SPI with GPIO Control
243
244
```python
245
from pyftdi.spi import SpiController
246
247
spi = SpiController()
248
spi.configure('ftdi:///1')
249
250
# Get SPI port and GPIO controller
251
device = spi.get_port(cs=0, freq=6E6, mode=0)
252
gpio = spi.get_gpio()
253
254
# Configure additional pins as GPIO
255
gpio.set_direction(0xF0, 0xF0) # Upper 4 bits as outputs
256
257
# Control reset line while doing SPI
258
gpio.write(0x10) # Assert reset
259
device.write([0x01, 0x02, 0x03]) # Send data
260
gpio.write(0x00) # Release reset
261
262
spi.terminate()
263
```
264
265
### High-Performance Transfers
266
267
```python
268
from pyftdi.spi import SpiController
269
270
spi = SpiController()
271
spi.configure('ftdi:///1', turbo=True) # Enable turbo mode
272
273
device = spi.get_port(cs=0, freq=30E6, mode=0) # Max speed
274
275
# Large data transfer
276
data_out = bytes(range(256)) # 256 bytes of test data
277
response = device.exchange(data_out, len(data_out), duplex=True)
278
279
# Continuous operations without CS toggling
280
device.write([0x02, 0x00, 0x00], start=True, stop=False) # Write command
281
device.write(data_out, start=False, stop=False) # Data
282
device.write([0x00], start=False, stop=True) # End transfer
283
284
spi.terminate()
285
```
286
287
## Exception Handling
288
289
```python
290
from pyftdi.spi import SpiController, SpiIOError
291
from pyftdi.ftdi import FtdiError
292
293
try:
294
spi = SpiController()
295
spi.configure('ftdi:///1')
296
297
device = spi.get_port(cs=0)
298
data = device.exchange([0x9F], 3)
299
300
except SpiIOError as e:
301
print(f"SPI communication error: {e}")
302
except FtdiError as e:
303
print(f"FTDI device error: {e}")
304
finally:
305
if 'spi' in locals():
306
spi.terminate()
307
```
308
309
## Types
310
311
```python { .api }
312
# Exception types
313
class SpiIOError(FtdiError):
314
"""SPI communication error"""
315
316
# SPI mode constants
317
SPI_MODE_0 = 0 # CPOL=0, CPHA=0
318
SPI_MODE_1 = 1 # CPOL=0, CPHA=1
319
SPI_MODE_2 = 2 # CPOL=1, CPHA=0
320
SPI_MODE_3 = 3 # CPOL=1, CPHA=1
321
```