Forum: Mikrocontroller und Digitale Elektronik MCP23S17 (RPi) per Python schalten


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Jay M. (blubb33)


Lesenswert?

Ich versuche den MCP23S17 (Expander) per SPI über einen Raspberry Pi 
anzusprechen. Aber es will mir überhaupt nicht gelingen.

Im folgenden Code fällt auf, dass ich nicht CE0 oder CE1 verwende, 
sondern GPIO27. Das sollte grundsätzlich als CS möglich sein.
Zudem habe ich in der letzten Zeile von main() den hex-Code 0x10. Nach 
meinen Überlegungen, will ich ja den Pin5 des Expanders (=GPB4) 
schalten, somit muss das fünfte Bit auf 1 gesetzt werden -> 0x10. 
Richtig?

Ich sehe aber leider überhaupt nicht den Fehler an der Sache. Vielleicht 
seht ihr ja mehr...
1
import RPi.GPIO as GPIO
2
GPIO.setmode(GPIO.BCM)
3
4
SPI_SLAVE_ADDR = 0x40
5
SPI_IOCTRL     = 0x0A
6
SPI_IODIRA     = 0x00
7
SPI_IODIRB     = 0x01
8
SPI_GPIOA      = 0x12
9
SPI_GPIOB      = 0x13
10
11
SCLK        = 11 # Serial-Clock
12
MOSI        = 10 # Master-Out-Slave-In
13
MISO        = 9 # Master-In-Slave-Out
14
CS          = 27 # Chip-Select
15
16
def sendValue(value):
17
    for i in range(8):
18
        if (value & 0x80):
19
            GPIO.output(MOSI, GPIO.HIGH)
20
        else:
21
            GPIO.output(MOSI, GPIO.LOW)  
22
        GPIO.output(SCLK, GPIO.HIGH)
23
        GPIO.output(SCLK, GPIO.LOW)
24
        value <<= 1
25
26
def sendSPI(opcode, addr, data):
27
    GPIO.output(CS, GPIO.LOW)
28
    
29
    sendValue(opcode)
30
    sendValue(addr)
31
    sendValue(data)
32
33
    GPIO.output(CS, GPIO.HIGH) 
34
35
def main():     
36
    GPIO.setup(SCLK, GPIO.OUT)
37
    GPIO.setup(MOSI, GPIO.OUT)
38
    GPIO.setup(MISO, GPIO.IN)
39
    GPIO.setup(CS,   GPIO.OUT)
40
    
41
    GPIO.output(CS,   GPIO.HIGH)    
42
    GPIO.output(SCLK, GPIO.LOW)
43
    
44
    sendSPI(SPI_SLAVE_ADDR, SPI_IODIRB, 0x00)
45
    sendSPI(SPI_SLAVE_ADDR, SPI_GPIOB, 0x10)
46
47
if __name__ == '__main__':
48
    main()

von Irgendwer (Gast)


Lesenswert?

Hast du schon mal mit einem protocolanalyser geschaut ob das recht 
unkoordinierte Bitgewackel in deiner sendValue überhaupt ein gültiges 
Timing ergibt?
Keine Ahnung ob das Python-Geraffel hier langsam genug ist.

von Simon S. (-schumi-)


Lesenswert?

Warum nimmst du eigentlich nicht Hardware-SPI? Gibt doch schon alles 
fertig: http://elinux.org/RPi_SPI

Es gibt sogar im Linuxkernel einen Treiber für den Expander:
> * MCP23S08 SPI/I2C GPIO gpio expander driver
> *
> * The inputs and outputs of the mcp23s08, mcp23s17, mcp23008 and mcp23017 are
> * supported.
https://github.com/torvalds/linux/blob/master/drivers/gpio/gpio-mcp23s08.c
(allerdings weis ich nicht, wie man den benutzt..)


[EDIT]
Es gibt auch eine fertige Python-Bibliothek: 
http://wiringpi.com/extensions/spi-mcp23s08-mcp23s17/

: Bearbeitet durch User
von Jay M. (blubb33)


Lesenswert?

Da ich letztlich auf meiner Platine mehr als zwei ICs habe, habe ich 
bewusst auf die vorhandenen CE0 und CE1 verzichtet. Ich möchte/muss also 
freie GPIO-Pins als CS verwenden. Und genau da liegt wohl auch mein 
Problem...

Das gleiche PRoblem habe ich ich mit der WiringPi-Bibliothek.

von Kaj (Gast)


Lesenswert?

Hast du ne LED mit Python schon mal zum blinken bekommen?

Jay Myon schrieb:
> Das gleiche PRoblem habe ich ich mit der WiringPi-Bibliothek.
http://raspberrypiguide.de/howtos/raspberry-pi-gpio-how-to/

von Jay M. (blubb33)


Lesenswert?

@Kaj: Vielleicht verstehe ich es ja falsch. Also grundsätzlich ist es 
für mich kein Problem GPIO-Pins zu setzen - egal ob direkt per Python 
oder über WiringPi.
Hier ist ja die SPI-Schnittstelle mein Problem.

In meinem Script wird der gewünschte GPIO-Pin ja durchaus auf High 
gesetzt - allerdings resultiert daraus noch lange keine funktionierende 
SPI-Verbindung.

von Kaj (Gast)


Lesenswert?

Jay Myon schrieb:
> @Kaj: Vielleicht verstehe ich es ja falsch. Also grundsätzlich ist es
> für mich kein Problem GPIO-Pins zu setzen - egal ob direkt per Python
> oder über WiringPi.
Das hast du schon richtig verstanden, war aber nicht böse gemeint.

gibt genug Leute die hir nach Hilfe suche, und da stellt sich dann raus 
das die mit 'nem ATTiny ein Kernkraftwerk steuern wollen, aber es noch 
nie hinbekommen haben, einfach mal ne LED zum blinken zu bringen.
Deswegen hab ich nachgefragt.

Welche Python-Version benutzt du?


Was mir gerade auffält:

Jay Myon schrieb:
> def sendSPI(opcode, addr, data):

Jay Myon schrieb:
> sendSPI(SPI_SLAVE_ADDR, SPI_IODIRB, 0x00)

So scheint das nicht zu passen ;)
in deiner definition sagst du: opcode, addr, data
und beim senden gibts du die sachen dann aber falsch in die Funktion 
rein... es sei denn das SPI_SLAVE_ADDR den opcode darstellt, was ich 
nicht glaube ;)

von Jay M. (blubb33)


Lesenswert?

Kaj schrieb:
> es sei denn das SPI_SLAVE_ADDR den opcode darstellt, was ich
> nicht glaube ;)

Doch.. ist eigentlich der Opcode. 01000000 -> 0x40

Mich ärgert es gerade sehr, dass ich endlich eine fertige Platine habe, 
alles verschaltet habe und nun das ganze Projekt daran scheitert, dass 
ich schlicht eine SPI-Schnittstelle nicht hinbekomme; nur um letztlich 
einen Pin für ein Relais zu setzen :-((((

: Bearbeitet durch User
von Kaj (Gast)


Lesenswert?

Jay Myon schrieb:
> Doch.. ist eigentlich der Opcode.
Ok, wenn du das sagst...
Ich hatte jetzt erwartet das eine Variable die SPI_SLAVE_ADDR heist, 
auch zu dem Funkrionsparameter addr gehört, aber nun gut.

Im Datenblatt von dem MCP23S17 
(https://cdn-reichelt.de/documents/datenblatt/A200/MCP23S17_MIC.pdf) 
steht:
"High-speed SPI interface (MCP23S17) 10 MHz (max.)"

Irgendwer schrieb:
> ...überhaupt ein gültiges Timing ergibt?
> Keine Ahnung ob das Python-Geraffel hier langsam genug ist.
Vermutung:
In anbetracht der Tatsache das der RPi mit gut 700MHz läuft, und du 
keine delays in deinem Code hast, dürften deine aktionen durch aus über 
den max. 10MHz liegen. Durchaus möglich das es deswegen nicht klappt.

Jay Myon schrieb:
> Mich ärgert es gerade sehr
Noch ist der Tag nicht vorbei ;)

von Jay M. (blubb33)


Lesenswert?

Leider hilft auch ein time.sleep(0.1) nicht :-(

von Jay M. (blubb33)


Lesenswert?

Nachdem ich nun endlich eine SPI-Verbindung auf dem Steckbrett ans 
Laufen gebracht habe (der obige Code funktioniert), fällt mir nun auf, 
dass nicht bei jedem Start des Scripts letztlich auch der Ausgang 
gesetzt wird (in meiner Beispiel-Schaltung wird eine LED eingeschaltet:
1
sendSPI(SPI_SLAVE_ADDR, SPI_GPIOB, 0x10)
2
time.sleep(3) 
3
sendSPI(SPI_SLAVE_ADDR, SPI_GPIOB, 0x00)

Starte ich das Script immer wieder, so funktioniert es manchmal und 
manchmal nicht. Auch mit sleep zwischen den Befehlen komme ich nicht 
weiter (wobei ich die ehrlich gesagt wahllos gesetzt habe.

Zur Schaltung: Es wird ein MCP23S17 mit einem ULN2803 kombiniert.
Der MCP23S17 wird mit 3,3V betrieben. Die geschaltete LED wird mit 5V 
über den ULN2803 betrieben.

Also manchmal geht die LED an und nicht aus, manchmal geht sie wie 
gewünscht an und aus und manchmal passiert gar nichts.

: Bearbeitet durch User
von Florian (Gast)


Lesenswert?

Auch wenn der Thread schon recht alt sein sollte. Ich habe ein 
Pythonmodul bei PyPi eingecheckt, das einen MCP23S17 abstrahiert: 
https://pypi.python.org/pypi/RPiMCP23S17/0.2.2

von Kai (Gast)


Lesenswert?

Ich hatte eben das gleiche Problem, dass es manchmal schaltet und 
manchmal eben nicht und fand's schade, dass es hier im Thread nicht 
weiterging.
Mein Problem habe ich gelöst, es war ein dämlicher Fehler. SI und SO 
hatte ich leider vertauscht. Komischerweise tat es manchmal, was dazu 
führte, dass ich die Pinbelegung gar nicht mehr geprüft habe.
(Vielleicht stand die Pinbelegung auch irgendwo falsch drin)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.