Skip to content

Commit

Permalink
Merge pull request #5 from m-laniakea/transfer_function
Browse files Browse the repository at this point in the history
Allow adding non-spidev SPI transfer functions
  • Loading branch information
m-laniakea authored Mar 21, 2020
2 parents f52848a + 95c3f9d commit 2968073
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 34 deletions.
28 changes: 23 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ A Python library for interfacing with [ST Spin Family devices](https://www.digik
specifically the ST Micro **L6470**, **L6472**, **L6474**, and **L6480** ICs.
Can be used nearly without modification with similar ICs.

Currently this project relies on [spidev's](https://pypi.org/project/spidev/ "spidev") SPI transfer function.
If you do not specify your own spi_transfer function when creating a SpinChain, this project relies on [spidev's](https://pypi.org/project/spidev/ "spidev") SPI transfer function.

Meant for use in embedded Linux applictions.
Python 3.6 or greater recommended.

## Getting Started
`pip install st-spin`
`pip install spidev` (if you intend to use /dev/spi and spidev's spi transfer function)

**Add imports**
```python
Expand All @@ -28,7 +28,6 @@ from stspin import (
stChain = SpinChain(
total_devices=2,
spi_select=(0, 0),
chip_select_pin=None, # Not implemented, relies on spidev for CS pin
)
```
This assumes the spi device is at 0, 0.
Expand Down Expand Up @@ -65,7 +64,7 @@ while motorMain.isBusy():
time.sleep(0.2)
# }}}
# Head back
# {{{ Head back
motorMain.setDirection(StConstant.DirReverse)
motorMain.move(steps=420000)
while motorMain.isBusy():
Expand All @@ -78,8 +77,27 @@ motorMain.hiZHard()
```
### More details
For details on the SPI setup, see [create()](https://github.com/m-laniakea/st_spin/blob/dev/stspin/spin_chain.py#L47) in spin_chain.py.
See [example.py](https://github.com/m-laniakea/st_spin/blob/dev/example.py "example.py")
See [example.py](https://github.com/m-laniakea/st_spin/blob/dev/example.py "example.py").

**Creating your own spi_transfer function**
You may use your own spi transfer function in place of spidev's xfer2.
```
def custom_spi_transfer(buffer: List[int]) -> List[int]:
# TODO: Implement me
pass
stChain = SpinChain(
total_devices=2,
spi_transfer=custom_spi_transfer,
)
```
`custom_spi_transfer()` must take a list of bytes as int,
and return a same-length list of bytes as int from the MISO pin.

It should handle latching using the Chip Select pin, and transfer data with MSB first in
SPI Mode 3 (sample on rising edge, shift out on falling edge).

On these devices, Chip Select is active low.
### Troubleshooting
getStatus() is your friend. Feel free to use getPrettyStatus() under utility.py.
The manual is also your friend.
Expand Down
2 changes: 1 addition & 1 deletion example.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def print_visual_status(device: SpinDevice) -> None:
stChain = SpinChain(
total_devices=2,
spi_select=(0, 0),
chip_select_pin=None, # Not implemented, relies on spidev for CS pin
spi_transfer=None, # Custom spi transfer in place of spidev possible
)

motorMain = stChain.create(1)
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
typing-extensions==3.7.4.1
spidev==3.4
#spidev==3.4 # Needed if not using custom spi_transfer function
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
long_description=open('README.md').read(),
long_description_content_type='text/markdown',
install_requires=[
'spidev',
'typing_extensions',
],
zip_safe=False)
51 changes: 33 additions & 18 deletions stspin/spin_chain.py
Original file line number Diff line number Diff line change
@@ -1,44 +1,60 @@
from typing import (
Callable,
List,
Optional,
Tuple,
)
from typing_extensions import (
Final,
)
import spidev

from . import SpinDevice


class SpinChain:
"""Class for constructing a chain of SPIN devices"""
def __init__(
self, total_devices: int,
spi_select: Tuple[int, int],
chip_select_pin: Optional[int] = None) -> None:
spi_select: Optional[Tuple[int, int]] = None,
spi_transfer: Optional[
Callable[[List[int]], List[int]]
] = None,
) -> None:
"""
:chip_select_pin: Chip select pin,
if different from hardware SPI CS pin
:total_devices: Total number of devices in chain
:spi_select: A SPI bus, device pair, e.g. (0, 0)
:spi_transfer: A SPI transfer function that behaves like
spidev.xfer2.
It should write a list of bytes as ints with MSB first,
while correctly latching using the chip select pins
Then return an equal-length list of bytes as ints from MISO
"""
assert total_devices > 0
assert (spi_select is None) != (spi_transfer is None), \
'Either supply a SPI transfer function or use spidev\'s'

self._chip_select_pin: Final = chip_select_pin
self._total_devices: Final = total_devices
self._total_devices: Final = total_devices

# {{{ SPI setup
self._spi: Final = spidev.SpiDev()
if spi_transfer is not None:
self._spi_transfer = spi_transfer

elif spi_select is not None:
import spidev
self._spi: Final = spidev.SpiDev()

bus, device = spi_select
self._spi.open(bus, device)

bus, device = spi_select
self._spi.open(bus, device)
self._spi.mode = 3
# Device expects MSB to be sent first
self._spi.lsbfirst = False
self._spi.max_speed_hz = 1000000
# CS pin is active low
self._spi.cshigh = False

self._spi.mode = 3
# Device expects MSB to be sent first
self._spi.lsbfirst = False
self._spi.max_speed_hz = 1000000
# CS pin is active low
self._spi.cshigh = False
self._spi_transfer = self._spi.xfer2
# }}}

def create(self, position: int) -> SpinDevice:
Expand Down Expand Up @@ -67,6 +83,5 @@ def create(self, position: int) -> SpinDevice:
return SpinDevice(
position,
self._total_devices,
self._spi,
self._chip_select_pin,
self._spi_transfer,
)
14 changes: 6 additions & 8 deletions stspin/spin_device.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import (
Callable,
List,
Optional,
)
Expand Down Expand Up @@ -38,19 +39,18 @@ class SpinDevice:

def __init__(
self, position: int,
total_devices: int, spi: SpiStub,
chip_select_pin: Optional[int] = None):
total_devices: int,
spi_transfer: Callable[[List[int]], List[int]],
):
"""
:position: Position in chain, where 0 is the last device in chain
:chip_select_pin: Chip select pin,
if different from hardware SPI CS pin
:total_devices: Total number of devices in chain
:spi: SPI object used for serial communication
"""
self._position: Final = position
self._chip_select_pin: Final = chip_select_pin
self._total_devices: Final = total_devices
self._spi: Final = spi
self._spi_transfer: Final = spi_transfer

self._direction = Constant.DirForward

Expand All @@ -66,9 +66,7 @@ def _write(self, data: int) -> int:
buffer = [0] * self._total_devices
buffer[self._position] = data

# TODO: CS LOW
response = self._spi.xfer2(buffer)
# TODO: CS HIGH
response = self._spi_transfer(buffer)

return response[self._position]

Expand Down

0 comments on commit 2968073

Please sign in to comment.