-
Notifications
You must be signed in to change notification settings - Fork 150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Accessing two SPI devices #11
Comments
If anyone is interested - here my version in which openSPI returns the file descriptor which then must be given to transfer and closeSPI. A little bit of a hack but works like a charm: /* SPI testing utility (see copyright beow)
* adapted for use in Python
* by Louis Thiery
* Lots more flexibility and cleanup by Connor Wolf (imaginaryindustries.com)
*
* compile for Python using: "python setup.py build"
* compiled module will be in "./build/lib.linux-armv6l-2.7/spi.so"
*
* SPI testing utility (using spidev driver)
*
* Copyright (c) 2007 MontaVista Software, Inc.
* Copyright (c) 2007 Anton Vorontsov <avorontsov@ru.mvista.com>
*
* 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.
*
*/
#include <Python.h>
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
static void pabort(const char *s)
{
perror(s);
abort();
}
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 500000;
static uint16_t delay;
static PyObject* openSPI(PyObject *self, PyObject *args, PyObject *kwargs) {
int ret = 0;
int fd;
static const char *device = "/dev/spidev0.0";
static char* kwlist[] = {"device", "mode", "bits", "speed", "delay", NULL};
// Adding some sort of mode parsing would probably be a nice idea for the future, so you don't have to specify it as a bitfield
// stuffed into an int.
// For the moment the default mode ("0"), will probably work for 99% of people who need a SPI interface, so I'm not working on that
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|siiii:keywords", kwlist, &device, &mode, &bits, &speed, &delay))
return NULL;
// It's not clearly documented, but it seems that PyArg_ParseTupleAndKeywords basically only modifies the values passed to it if the
// keyword pertaining to that value is passed to the function. As such, the defaults specified by the variable definition are used
// unless you pass a kwd argument.
// Note that there isn't any proper bounds-checking, so if you pass a value that exceeds the variable size, it's just truncated before
// being stuffed into the avasilable space. For example, passing a bits-per-word of 500 gets truncated to 244. Unfortunately, the
// PyArg_ParseTupleAndKeywords function only seems to support ints of 32 bits.
PyErr_Clear();
// printf("*** SPI.C openSPI: Mode: %i, Bits: %i, Speed: %i, Delay: %i\n", mode, bits, speed, delay);
fd = open(device, O_RDWR);
if (fd < 0)
pabort("can't open device");
// printf("*** SPI.C openSPI: fd: %i\n", fd);
/*
* Setup SPI mode
*/
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
if (ret == -1)
pabort("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
if (ret == -1)
pabort("can't get spi mode");
/*
* bits per word
*/
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
/*
* max speed hz
*/
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
// Stuff the various initilization parameters into a dict, and return that.
// Note that the returned values may not be completely real. It seems that, at least for the speed value,
// the hardware only has several possible settings (250000, 500000, 1000000, etc...) Strangely enough, the
// ioctl for setting the speed *returns the speed you specify*. However, the hardware seems to default to the
// closest avalable value *below* the specified rate. (i.e. you will never get a speed faster then you spec),
// but you may get a slower value.
//It would probably be a good idea to bin-down the passed arguement to the available values, and return
// that.
PyObject* retDict;
retDict = PyDict_New();
#if PY_MAJOR_VERSION >= 3
PyDict_SetItem(retDict, PyBytes_FromString("fd"), PyLong_FromLong((long)fd));
PyDict_SetItem(retDict, PyBytes_FromString("mode"), PyLong_FromLong((long)mode));
PyDict_SetItem(retDict, PyBytes_FromString("bits"), PyLong_FromLong((long)bits));
PyDict_SetItem(retDict, PyBytes_FromString("speed"), PyLong_FromLong((long)speed));
PyDict_SetItem(retDict, PyBytes_FromString("delay"), PyLong_FromLong((long)delay));
#else
PyDict_SetItem(retDict, PyString_FromString("fd"), PyInt_FromLong((long)fd));
PyDict_SetItem(retDict, PyString_FromString("mode"), PyInt_FromLong((long)mode));
PyDict_SetItem(retDict, PyString_FromString("bits"), PyInt_FromLong((long)bits));
PyDict_SetItem(retDict, PyString_FromString("speed"), PyInt_FromLong((long)speed));
PyDict_SetItem(retDict, PyString_FromString("delay"), PyInt_FromLong((long)delay));
#endif
return retDict;
}
static PyObject* transfer(PyObject* self, PyObject* arg) {
int ret = 0;
int fd;
PyObject* transferTuple;
// "O" - Gets non-NULL borrowed reference to Python argument.
// As far as I can tell, it's mostly just copying arg[0] into transferTuple
// and making sure at least one arg has been passed (I think)
if(!PyArg_ParseTuple(arg, "iO", &fd, &transferTuple))
return NULL;
// printf("*** SPI.C transfer: fd: %i\n", fd);
// The only argument we support is a single tuple.
if(!PyTuple_Check(transferTuple))
pabort("Only accepts a single tuple as an argument\n");
uint32_t tupleSize = PyTuple_Size(transferTuple);
uint8_t tx[tupleSize];
uint8_t rx[tupleSize];
PyObject* tempItem;
uint16_t i=0;
while(i < tupleSize)
{
tempItem = PyTuple_GetItem(transferTuple, i); //
#if PY_MAJOR_VERSION >= 3
if(!PyLong_Check(tempItem))
#else
if(!PyInt_Check(tempItem))
#endif
{
pabort("non-integer contained in tuple\n");
}
#if PY_MAJOR_VERSION >= 3
tx[i] = (uint8_t)PyLong_AsSsize_t(tempItem);
#else
tx[i] = (uint8_t)PyInt_AsSsize_t(tempItem);
#endif
i++;
}
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = tupleSize,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.cs_change = 1,
};
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
transferTuple = PyTuple_New(tupleSize);
for (i = 0; i < tupleSize; i++)
PyTuple_SetItem(transferTuple, i, Py_BuildValue("i",rx[i]));
return transferTuple;
}
static PyObject* closeSPI (PyObject* self, PyObject* arg) {
int fd;
if(!PyArg_ParseTuple(arg, "i", &fd))
return NULL;
// printf ("*** SPI.C closeSPI: fd: %i\n", fd);
PyErr_Clear();
close (fd);
Py_RETURN_NONE;
}
static PyMethodDef SpiMethods[] = {
{"openSPI", (PyCFunction)openSPI, METH_VARARGS | METH_KEYWORDS, "Open SPI Port."},
{"transfer", (PyCFunction)transfer, METH_VARARGS, "Transfer data."},
{"closeSPI", (PyCFunction)closeSPI, METH_VARARGS, "Close SPI port."},
{NULL, NULL, 0, NULL}
};
#if PY_MAJOR_VERSION >= 3
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"spi", /* m_name */
"spi library", /* m_doc */
-1, /* m_size */
SpiMethods, /* m_methods */
NULL, /* m_reload */
NULL, /* m_traverse */
NULL, /* m_clear */
NULL, /* m_free */
};
#endif
PyMODINIT_FUNC
#if PY_MAJOR_VERSION >= 3
PyInit_spi(void)
#else
initspi(void)
#endif
{
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
(void) Py_InitModule("spi", SpiMethods);
#endif
;
#if PY_MAJOR_VERSION >= 3
return module;
#endif
} |
do you know how to make a pull request out of this? that way i can look at the diffs more easily and pull it in potentially? |
Puh, I'm not very experienced with github.... (: I tried my best, but since I have no write access to the project github forced my to make a fork which is here: https://github.com/msedv/SPI-Py |
So I'm just starting to look into this but I want to use the RC522 and a touchscreen display (https://www.adafruit.com/products/2441). The touch screen display uses GPIO25 already. I know that's a general purpose I/O pin so I should be able to change the connection for the RC522's rst pin to another one of the general purpose I/O pins. I am just unsure where in the code to do this or if there's some reason I am not aware of that i cannot. Any help? |
Hi, I try to use my RPi3 and the RC522 and a touchscreen display aswell so i need to put my RC522 on the auxiliary SPI1 right ? How can I do it ?
using this as the reference layout : http://pinout.xyz/ |
As long as I'm only accessing ONE SPI device everything is fine, but when accessing TWO (in my case: MFRC522.py for two RFID-Readers) only one of them works. Looking at your code I think the problem is that
int fd;
is declared globally?!
The text was updated successfully, but these errors were encountered: