Skip to content

Instantly share code, notes, and snippets.

@kcarnold
Created July 20, 2013 15:25
Show Gist options
  • Save kcarnold/6045448 to your computer and use it in GitHub Desktop.
Save kcarnold/6045448 to your computer and use it in GitHub Desktop.
SPI driver in Cython. Based on the spidev_test.c sample code included in the Linux kernel.
#
# SPI driver (using spidev device)
#
# Copyright (c) 2013 Kenneth Arnold <[email protected]>
# Copyright (c) 2007 MontaVista Software, Inc.
# Copyright (c) 2007 Anton Vorontsov <[email protected]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License.
#
from cpython.string cimport PyString_FromStringAndSize
from libc.stdlib cimport malloc, free
from libc.string cimport memset
from os import open, close, O_RDWR
from posix.ioctl cimport ioctl
cdef extern from "linux/spi/spidev.h":
struct spi_ioc_transfer:
char *tx_buf
char *rx_buf
int len
int speed_hz
int delay_usecs
int bits_per_word
int cs_change
int pad
int SPI_IOC_MESSAGE(int num)
int SPI_IOC_WR_MODE, SPI_IOC_RD_MODE
int SPI_IOC_RD_MAX_SPEED_HZ, SPI_IOC_WR_MAX_SPEED_HZ
int SPI_IOC_WR_BITS_PER_WORD, SPI_IOC_RD_BITS_PER_WORD
cdef class SpiChannel:
cdef int fd, mode, bits, speed, delay
def transfer(self, write_buf):
cdef int ret
cdef int buflen = len(write_buf)
cdef char *_read_buf = <char *> malloc(buflen)
read_buf = <bytes> _read_buf[:buflen] #PyString_FromStringAndSize(None, len(write_buf))
free(_read_buf)
cdef spi_ioc_transfer tr
memset(&tr, 0, sizeof(tr))
tr.tx_buf = write_buf
tr.rx_buf = read_buf
tr.len = len(write_buf)
tr.delay_usecs = self.delay
tr.speed_hz = self.speed
tr.bits_per_word = self.bits
ret = ioctl(self.fd, SPI_IOC_MESSAGE(1), &tr);
if ret < 1:
raise IOError("can't send spi message")
return read_buf
def __init__(self, char *device, mode=0, bits_per_word=8, speed=500000, delay=0):
self.fd = open(device, O_RDWR)
if self.fd < 0:
raise IOError("can't open device")
self.set_spi_mode(mode)
self.set_bits_per_word(bits_per_word)
self.set_max_speed_hz(speed)
self.delay = 0
print 'SPI mode:', self.get_spi_mode()
print 'Bits per word:', self.get_bits_per_word()
print 'Max speed: {} Hz ({} kHz)'.format(speed, speed/1000.)
def set_spi_mode(self, int mode):
self.mode = mode
ret = ioctl(self.fd, SPI_IOC_WR_MODE, &self.mode)
if ret == -1:
raise IOError("can't set spi mode")
def get_spi_mode(self):
ret = ioctl(self.fd, SPI_IOC_RD_MODE, &self.mode)
if ret == -1:
raise IOError("can't get spi mode")
return self.mode
def close(self):
close(self.fd)
def set_bits_per_word(self, int bits):
self.bits = bits
ret = ioctl(self.fd, SPI_IOC_WR_BITS_PER_WORD, &self.bits)
if ret == -1:
raise IOError("can't set bits per word")
def get_bits_per_word(self):
ret = ioctl(self.fd, SPI_IOC_RD_BITS_PER_WORD, &self.bits)
if ret == -1:
raise IOError("can't get bits per word");
return self.bits
def set_max_speed_hz(self, speed):
self.speed = speed
ret = ioctl(self.fd, SPI_IOC_WR_MAX_SPEED_HZ, &self.speed)
if ret == -1:
raise IOError("can't set max speed hz")
def get_max_speed_hz(self):
ret = ioctl(self.fd, SPI_IOC_RD_MAX_SPEED_HZ, &self.speed)
if ret == -1:
raise IOError("can't get max speed hz")
return self.speed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment