Skip to content

Commit 3beb0d9

Browse files
nkpro2000srbessman
authored andcommitted
Add busio.SPI
1 parent 391a40e commit 3beb0d9

File tree

1 file changed

+195
-0
lines changed

1 file changed

+195
-0
lines changed

pslab/bus/busio.py

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from typing import List, Union
3232

3333
from pslab.bus.i2c import _I2CPrimitive
34+
from pslab.bus.spi import _SPIPrimitive
3435
from pslab.serial_handler import SerialHandler
3536

3637
__all__ = "I2C"
@@ -178,3 +179,197 @@ def writeto_then_readfrom(
178179
self._restart(address, 1)
179180
buffer_in[in_start:in_end] = self._read(bytes_to_read)
180181
self._stop()
182+
183+
184+
class SPI(_SPIPrimitive):
185+
"""Busio SPI Class for CircuitPython Compatibility.
186+
187+
Parameters
188+
----------
189+
device : :class:`SerialHandler`, optional
190+
Serial connection to PSLab device. If not provided, a new one will be
191+
created.
192+
"""
193+
194+
def __init__(self, device: SerialHandler = None, frequency: int = 125e3):
195+
super().__init__(device)
196+
ppre, spre = self._get_prescaler(25e4)
197+
self._set_parameters(ppre, spre, 1, 0, 1)
198+
self._bits = 8
199+
200+
@property
201+
def frequency(self) -> int:
202+
"""Get the actual SPI bus frequency (rounded).
203+
204+
This may not match the frequency requested due to internal limitations.
205+
"""
206+
return round(self._frequency)
207+
208+
def deinit(self) -> None:
209+
"""Just a dummy method."""
210+
pass
211+
212+
def __enter__(self):
213+
"""Just a dummy context manager."""
214+
return self
215+
216+
def __exit__(self, exc_type, exc_val, exc_tb) -> None:
217+
"""Call :meth:`deinit` on context exit."""
218+
self.deinit()
219+
220+
def configure(
221+
self,
222+
*,
223+
baudrate: int = 100000,
224+
polarity: int = 0,
225+
phase: int = 0,
226+
bits: int = 8,
227+
) -> None:
228+
"""Configure the SPI bus.
229+
230+
Parameters
231+
----------
232+
baudrate : int
233+
The desired clock rate in Hertz. The actual clock rate may be
234+
higher or lower due to the granularity of available clock settings.
235+
Check the frequency attribute for the actual clock rate.
236+
polarity : int
237+
The base state of the clock line (0 or 1)
238+
phase : int
239+
The edge of the clock that data is captured. First (0) or second (1).
240+
Rising or falling depends on clock polarity.
241+
bits : int
242+
The number of bits per word.
243+
"""
244+
if polarity not in (0, 1):
245+
raise ValueError("Invalid polarity")
246+
if phase not in (0, 1):
247+
raise ValueError("Invalid phase")
248+
if bits not in self._INTEGER_TYPE_MAP:
249+
raise ValueError("Invalid number of bits")
250+
251+
ppre, spre = self._get_prescaler(baudrate)
252+
cke = (phase ^ 1) & 1
253+
self._set_parameters(ppre, spre, cke, polarity, 1)
254+
self._bits = bits
255+
256+
def try_lock(self) -> bool: # pylint: disable=no-self-use
257+
"""Just a dummy method."""
258+
return True
259+
260+
def unlock(self) -> None:
261+
"""Just a dummy method."""
262+
pass
263+
264+
def write(
265+
self,
266+
buffer: Union[ReadableBuffer, List[int]],
267+
*,
268+
start: int = 0,
269+
end: int = None,
270+
) -> None:
271+
"""Write the data contained in buffer. If the buffer is empty, nothing happens.
272+
273+
Parameters
274+
----------
275+
buffer : bytes or bytearray or memoryview or list_of_int (for bits >8)
276+
Write out the data in this buffer.
277+
start : int
278+
Start of the slice of `buffer` to write out: `buffer[start:end]`.
279+
end : int
280+
End of the slice; this index is not included. Defaults to `len(buffer)`.
281+
"""
282+
end = len(buffer) if end is None else end
283+
buffer = buffer[start:end]
284+
285+
if not buffer:
286+
return
287+
288+
self._start()
289+
self._write_bulk(buffer, self._bits)
290+
self._stop()
291+
292+
def readinto(
293+
self,
294+
buffer: Union[WriteableBuffer, List[int]],
295+
*,
296+
start: int = 0,
297+
end: int = None,
298+
write_value: int = 0,
299+
) -> None:
300+
"""Read into `buffer` while writing `write_value` for each byte read.
301+
302+
If the number of bytes to read is 0, nothing happens.
303+
304+
Parameters
305+
----------
306+
buffer : bytearray or memoryview or list_of_int (for bits >8)
307+
Read data into this buffer.
308+
start : int
309+
Start of the slice of `buffer` to read into: `buffer[start:end]`.
310+
end : int
311+
End of the slice; this index is not included. Defaults to `len(buffer)`.
312+
write_value : int
313+
Value to write while reading. (Usually ignored.)
314+
"""
315+
end = len(buffer) if end is None else end
316+
bytes_to_read = end - start
317+
318+
if bytes_to_read == 0:
319+
return
320+
321+
self._start()
322+
data = self._transfer_bulk([write_value] * bytes_to_read, self._bits)
323+
self._stop()
324+
325+
for i, v in zip(range(start, end), data):
326+
buffer[i] = v
327+
328+
def write_readinto(
329+
self,
330+
buffer_out: Union[ReadableBuffer, List[int]],
331+
buffer_in: Union[WriteableBuffer, List[int]],
332+
*,
333+
out_start: int = 0,
334+
out_end: int = None,
335+
in_start: int = 0,
336+
in_end: int = None,
337+
):
338+
"""Write out the data in buffer_out while simultaneously read into buffer_in.
339+
340+
The lengths of the slices defined by buffer_out[out_start:out_end] and
341+
buffer_in[in_start:in_end] must be equal. If buffer slice lengths are both 0,
342+
nothing happens.
343+
344+
Parameters
345+
----------
346+
buffer_out : bytes or bytearray or memoryview or list_of_int (for bits >8)
347+
Write out the data in this buffer.
348+
buffer_in : bytearray or memoryview or list_of_int (for bits >8)
349+
Read data into this buffer.
350+
out_start : int
351+
Start of the slice of `buffer_out` to write out:
352+
`buffer_out[out_start:out_end]`.
353+
out_end : int
354+
End of the slice; this index is not included. Defaults to `len(buffer_out)`
355+
in_start : int
356+
Start of the slice of `buffer_in` to read into:`buffer_in[in_start:in_end]`
357+
in_end : int
358+
End of the slice; this index is not included. Defaults to `len(buffer_in)`
359+
"""
360+
out_end = len(buffer_out) if out_end is None else out_end
361+
in_end = len(buffer_in) if in_end is None else in_end
362+
buffer_out = buffer_out[out_start:out_end]
363+
bytes_to_read = in_end - in_start
364+
365+
if len(buffer_out) != bytes_to_read:
366+
raise ValueError("buffer slices must be of equal length")
367+
if bytes_to_read == 0:
368+
return
369+
370+
self._start()
371+
data = self._transfer_bulk(buffer_out, self._bits)
372+
self._stop()
373+
374+
for i, v in zip(range(in_start, in_end), data):
375+
buffer_in[i] = v

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy