Guten Abend liebe Forumsmitglieder,
ich bin noch ein Anfänger und meine Erfahrungen in Sachen
Mikrocontrollerprogrammierung sind noch nicht so gut, von daher möchte
ich gerne eine Frage in dieses Forum hineinstellen - genaugenommen sind
es mehrere Fragen. Einiges habe ich schon anhand des Datenblatts
verstanden, aber an anderen Stellen bin ich mir noch nicht so sicher.
Ich habe einen AD-Wandler mit der Bezeichnung Max186. Dabei handelt es
sich um einen 12bit-AD-Wandler, der acht Kanäle hat. Die Kommunikation
findet über den SPI-Bus statt - und genau an der Stelle harpert es.
Ich möchte den Max186 mit meinem Raspberry Pi verbinden. Der Raspberry
Pi verfügt schon über einen SPI-Bus und über Python kann ich die
SPI-Funktionen einbinden.
Hier ist mal ein Link zum Datenblatt von dem ADC:
http://datasheets.maximintegrated.com/en/ds/MAX186-MAX188.pdf
Der SPI-Bus besitzt also 3 Verbindungsleitungen - MISO, MOSI, SCLK/CLK.
Diese drei Leitungen verbinde ich mit dem Raspberry.
Ein Problem ist - der ADC arbeitet mit 5 Volt, der Raspi mit 3,3 Volt.
Die Pegel an den GPIO-Ports am Raspi betragen etwa 3 Volt. Die
Mindestspannung an den Kontakten vom ADC muss 2,4 Volt betragen, damit
der ADC an dem jeweiligen Kontakt auf HIGH schaltet. Also reicht das aus
vom Raspi.
Der ADC liefert einen Pegel von 4 Volt (Output Voltage High). Da baue
ich mir dann einfach einen kleinen Spannungsteiler, damit die Spannung,
die ich an den Pin des Raspis sende, max. 3 Volt beträgt und ich den
Raspi nicht kaputt mache.
Dann muss ich noch CS mit einem freien GPIO-Port des Raspis verbinden
und da fangen meine Schwierigkeiten an. Im Datenblatt steht über dem
Anschluss CS (Chipselect) ein Balkten. Dass heisst für mich, dass ich
alles negiert zu betrachten habe. Ich habe es jetzt so verstanden - ist
der Pegel von CS_quer = HIGH, dann befindet sich der ADC im Ruhezustand
- also muss ich den Pin vom Raspi auf HIGH setzen, wenn der ADC aus sein
soll. Möchte ich nun mit dem ADC kommunizieren, dann muss ich den
GPIO-Port vom Raspi auf LOW setzen, damit der ADC "eingeschaltet" wird.
Habe ich das so richtig kapiert?
Und jetzt kommt mein nächstes Problem - die Sache mit dem Clock. Am
SPI-Bus ist ja ein Anschluss mit der Bezeichnung Clock vorhanden (SCLK).
Ich habe es jetzt so verstanden - immer, wenn ein Clock-Signal gesendet
wird, dann wird ein Bit vom ADC gelesen und auch gesendet (auch auf dem
Raspi).
Wenn ich nun mit meinem ADC kommunizieren will, dann würde ich es
folgendermassen machen:
Init-Zustand:
GPIO = HIGH (damit ADC ausgeschaltet ist).
Kommunikationszustand:
GPIO = LOW (ADC einschalten)
Sende/Empfange über SPI, bis Vorgang abgeschlossen
GPIO = HIGH (ADC ausschalten)
Ich bin mir jetzt leider noch nicht sicher, ob ich es so richtig
verstanden habe. Ich würde mich sehr freuen, wenn jemand von Euch mir
etwas weiterhelfen könnte.
Das Raspberry Pi hat Harware-CS-Pins für SPI, das sind die CE0 und CE1
hier: http://elinux.org/images/2/2a/GPIOs.png
Nimm einfach die, dann sollte der SPI-Controller dir diesen
Problembereich schonmal abnehmen.
AD-Wandler mittels SPI auslesen schrieb:> Wenn ich nun mit meinem ADC kommunizieren will, dann würde ich es> folgendermassen machen:>> Init-Zustand:> GPIO = HIGH (damit ADC ausgeschaltet ist).>> Kommunikationszustand:> GPIO = LOW (ADC einschalten)> Sende/Empfange über SPI, bis Vorgang abgeschlossen> GPIO = HIGH (ADC ausschalten)
Richtig, in etwa so läuft das im Allgemeinen, auch wenn du vergessen
hast zu erwähnen, ob die auch den richtigen SPI-Mode eingestellt hast,
es gibt nämlich derer vier. Allerdings beschreibt SPI auch bloß die
gundsätzliche Funktionsweise der Kommunikation.
Der Teufel steckt aber oft im Detail, nämlich in deiner Zeile
> Sende/Empfange über SPI, bis Vorgang abgeschlossen
hast du gleich zwei völlig nichtssagende Allgemeinplätze verwendet,
nämlich "Vorgang" und "abgeschlossen". Das ist beides nicht von SPI
abgedeckt, sondern fast bei jedem Scheiß-Chip ein wenig anders
umgesetzt.
Und die Beschreibung dieser wichtigen Details ist leider nur in wenigen
Datenblättern wirklich eindeutig und völlig unmißverständlich. Manchmal
hat man sogar fast den Eindruck, daß ausgerechnet bei diesem Kapitel der
Schreiberling absichtlich vorher abgefüllt wurde...
Wie auch immer. Was ich eigentlich sagen wollte: SPI kann schon für sich
selber genug Probleme schaffen. Zusätzliche Probleme durch improvisierte
oder gleich ganz abwesende Pegelwandler will man da echt nicht auch noch
haben. Du solltest also deine Bastellösungen besser über Bord werfen,
wenn du nicht tagelang darüber rätseln willst, ob nun deine Software
noch unfertig ist oder ob es wegen der improvisierten Hardware nicht
funktioniert.
Solche Bastellösungen kann man mal ausprobieren, wenn man sich mit dem
speziellen Target bereits auskennt und es in einer ordentlichen
Hardwareanbindung stabil am Laufen hat. Wenn es nämlich dann ohne
Pegelwandler nicht mehr funktioniert, weiß man wenigstens sofort, woran
es liegt...
AD-Wandler mittels SPI auslesen schrieb:> Dann muss ich noch CS mit einem freien GPIO-Port des Raspis verbinden> und da fangen meine Schwierigkeiten an. Im Datenblatt steht über dem> Anschluss CS (Chipselect) ein Balkten. Dass heisst für mich, dass ich> alles negiert zu betrachten habe. Ich habe es jetzt so verstanden - ist> der Pegel von CS_quer = HIGH, dann befindet sich der ADC im Ruhezustand> - also muss ich den Pin vom Raspi auf HIGH setzen, wenn der ADC aus sein> soll. Möchte ich nun mit dem ADC kommunizieren, dann muss ich den> GPIO-Port vom Raspi auf LOW setzen, damit der ADC "eingeschaltet" wird.> Habe ich das so richtig kapiert?
Hast du. Der Raspberry ist der Master und der kann mit den Slaves
sprechen. Damit die Slaves auch wissen wer genau gemeint ist bekommen
sie das durch ChipSelect mitgeteilt. Und den Querstrich hast du richtig
interpretiert ;)
AD-Wandler mittels SPI auslesen schrieb:> Ich habe es jetzt so verstanden - immer, wenn ein Clock-Signal gesendet> wird, dann wird ein Bit vom ADC gelesen und auch gesendet (auch auf dem> Raspi).
Auch das ist richtig.
Doch vorsicht. Wichtig ist hier auch in welchem Clock-Mode du dich
befindest. Bist du im external Mode dann gibst du an der SCKL-Leitung
die Abtastrate vor mit der die Analogsignale gesampelt werden. Das ist
ein wenig tricky. Schau dir auch mal die Timing-Diagramme an.
Michael Köhler schrieb:> Doch vorsicht. Wichtig ist hier auch in welchem Clock-Mode du dich> befindest. Bist du im external Mode dann gibst du an der SCKL-Leitung> die Abtastrate vor mit der die Analogsignale gesampelt werden. Das ist> ein wenig tricky. Schau dir auch mal die Timing-Diagramme an.
Ich möchte gerne den internen Clock-Mode benutzen, aber das kann ich ja
über das Datenbit einstellen, dass ich dann über den SPI-Bus versenden
möchte. In der Tabelle 2 in dem Datasheet (Control-Byte-Format) kann ich
ja einstellen, welchen Clock-Modus ich verwenden will, welcher der 8
Kanäle abgetastet werden soll, ob die Messung uni- oder bipolar und
sigle-ended oder differentiell ist.
Wenn ich es also erfolgreich angeschlossen habe und ich am Kanal 1 mit
Internal-Clock, Single-Ended, unipolar messen möchte, dann bastele ich
mir ein Byte:
SendByte = 10001110
Also würde mein Programm im Pseudocode etwa so aussehen:
# init
GPIO(CE0) = HIGH
SendByte = 10001110
# LeseWert:
CE0 = LOW
Sende SendByte
CE0 = HIGH
warte 1,5 Mikrosekunden (acquisition time)
CE0 = LOW
Lese LeseBytes
CE0 = HIGH
Ich muss ja einen Moment warten, bis die Messung am ADC fertig ist. Ich
habe es jetzt so verstanden, dass ich nach dem Senden von SendByte CE0
erstmal wieder auf HIGH setzen muss (Figure 9 in dem Datasheet). Nach
der Acquisition-Time von 1,5 Mikrosenkunden setze ich CS = LOW und bei
der fallenden Flanke von SCLK wird das erste Bit empfangen.
Kann ich eigentlich auch länger als die 1,5 Mikrosekunden warten? In dem
Datenblatt habe ich gelesen, dass man ein ExternalClock nur benutzen
soll, wenn es schnell genug geht. Wenn man länger als 10 Mikrosekunden
wartet, dann entläd sich der Kondensator am Hold-Glied und die Messung
wird verfälscht. Aber um den erzeugten Wert zu lesen, müsste ich doch
theoretisch auch eine Sekunde warten können - oder geht der binäre Wert,
der dann seriell über den SPI-Bus versendet wird, auch nach einiger Zeit
"verloren", wenn er nicht schnell genug gelesen wird (also meine
Wartezeit zu lange ist)?
Ich glaube, das ist oben untergegangen: Der SPI-Controller hat ein
Hardware-CE, was automatisch immer so geschaltet wird, wie es sein soll
(CE0/CE1 auf dem Pin-Header). Bei mir hat das immer funktioniert. Willst
du es nicht erstmal damit versuchen?
Sven B. schrieb:> Willst du es nicht erstmal damit versuchen?
Doch will ich - ich habe es erst durch Deinen Beitrag verstanden, dass
die beiden CE0/1 auch zum SPI-Bus gehören, aber ich wollte es gerne vom
Grundprinzip her verstanden haben. CE0/1 wird ja automatisch durch das
SPI-dev-Modul von Python gesetzt, weil ich dort ja anwählen muss,
welcher device benutzt wird.
Ich hab jetzt noch ein Problem mit der maximalen Strombelastbarkeit des
D_out-PINS an dem ADC. Ich muss mir ja einen Spannungsteiler bauen und
der Gesamtwiderstand des Spannungsteilers muss so gewählt werden, dass
der Strom nicht zu groß (und ggf. auch nicht zu klein) sein darf. Ich
finde dazu keine Angabe in dem Datenblatt. Ich habe in der Tabelle bei
"Electrical Characteristics" im Datasheet geschaut (Seiten 3-5) und
lediglich auf Seite 4 unter "DIGITAL OUTPUTS DOUT, SSTRB) gefunden, dass
Output Voltage Low = max. 0,4 Volt ist
Output Voltage High = min 4 Volt
Leeakage Current = +- 10 uA
Output Capacity = 15pF.
Ist das die Angabe Leakage Current, die ich zur Bestimmung des
Gesamtwiderstands verwenden muss?
Ist mit "Sink Current" der Gesamtstrom gemeint, mit dem der ADC belastet
werden darf?
Dort steht auch bei Absolute Maximum Ratings: Vdd to AGND -0,3V to 6 V.
Warum ist dort von -0,3 Volt die Rede? Heisst das "nur", dass der ADC
bis -0,3 Volt nicht kaputt geht? Könnte ich den ADC auch mit 3,3 Volt
betreiben? So würde ich das jetzt verstehen. Aber das geht ja nicht, da
die Vergleichsspannung vom ADC 4,096 Volt betragen muss. Dat der ADC
dazu einen internen Spannungsregler, der dann aus den 5 Volt exakte
4,096 Volt macht?
Die Absolute Maximum Ratings geben an, bei welchen Werten der IC knapp
noch nicht kaputt wird. Das heißt aber nicht dass er im gesamten Bereich
auch zuverlässig funktioniert. An diesen sollte man sich im Normalfall
auch nicht orientieren.
In den ELECTRICAL CHARACTERISTICS steht was von
>Positive Supply Voltage VDD 5 ±5% V
AD-Wandler mittels SPI auslesen schrieb:> Ist mit "Sink Current" der Gesamtstrom gemeint, mit dem der ADC belastet> werden darf?
Ich weiß leider nicht, ob sich das auf einzelne Outputs oder auf die
Summe bezieht. 25mA pro Output klingt eigentlich zu viel. Aber bestimmt
weiß das jemand anders hier.
Ok, ich belaste den D_Out vom ADC mit 1mA.
Ich hab jetzt ein kleines Problem. Ich habe jetzt versucht, mit dem Oszi
den SPI-Bus zu checken. Wenn ich MISO und MOSI brücke und mit dem Oszi
messe, dann sehe ich ein Binärsignal im Oszi und empfange am SPI-Bus
etwas.
Wenn ich jetzt nur alleine den MOSI-Anschluss checke, dann sehe ich am
Oszi garnichts. Ich habe auch schon versucht, den MISO-Anschluss auf
Masse und einmal auf Vcc zu legen - da misst das Oszi auch nichts.
CS und SCLK funktionieren beide einwandfrei. Ich habe auch es dierekt am
ADC ausprobiert, MOSI an D_In am ADC und MISO mit D_out verbunden. Dort
genauso - ist das verbunden, dann messe ich keine Pegel im Oszi. Woran
könnte das liegen?
Wenn der CS falsch ist sendet der ADC nicht, sondern hat tristate and
Dataout.
Ich implementiere eine SPI Schnittstelle jeweils per software genau nach
datenblatt. Manche Datenblaetter haben diesbezueglich keine Redundanz,
dh man muss jeden Satz genau lesen und verstanden haben, nicht einfach
Annahmen treffen.
Meine Erfahrung mit SPI ist dass man beim Empfänger (also beim Slave bei
MOSI und CS und beim Master bei MISO) einen kleinen Kondensator (100pF)
nach GND braucht, weil sonst wegen kleiner Störungen oft komisches Zeug
passiert. Kannst du ja mal versuchen.
Grüße,
Sven
Vielen Dank fuer die Vielzahl Eurer Tipps.
Irgendwie hats auf einmal funktioniert. Ich hoffe, dass es jetzt aber
nur nicht auf dem Steckbrett so ist, sondern auch noch, wenn ich später
den Kram auf eine Platine schweiße.
AD-Wandler mittels SPI auslesen schrieb:> wenn ich später> den Kram auf eine Platine schweiße.
Ich empfehle löten, beim Schweißen wirst du die Bauteile wahrscheinlich
töten.
Ich habe nun ein Softwareproblem beim Auslesen des AD-Wandlers. Ich
empfange etwas und kann auch was senden.
Ich habe ein kleines Python-Programm für den Raspberry geschrieben, dass
den AD-Wandler auslesen soll:
1
Importspidev
2
Importtime
3
4
spi=spidev.SpiDev()
5
spi.open(0,0)
6
7
sendbit=[]
8
sendbit.append(0b10000010)#bipolarerModus
9
acquisition_time=12./1000000
10
11
spi.writebytes(sendbit)
12
time.sleep(acquisition_time)
13
result=spi.readbytes(2)
Bei der Variable result hab ich so meine Probleme. Es sind dort zwei
Werte enthalten, einmal für das bit0 und dann für das bit1. Das
AD-Wandlerergebnis ist 12bit breit. Ich messe bipolar, also von -2 bis
+2 Volt. Eines der 12 Bits muss also für das Vorzeichen stehen, ob plus
oder minus. Ich gehe davon aus, wenn das MSB=True ist (most significant
bit), dann ist das Ergebnis positiv, also Spannung größer Null. Ich habe
es im Datenblatt aber noch nicht gefunden.
Jetzt geht es noch darum, die Bits zusammenzufassen, um ein
Gesamtergebnis zu bekommen. Dazu habe ich mir gedacht, dass ich Bit0
einfach um vier stellen nach links shifte, Bit1 vier Stellen nach
rechts.
Regebnis = (result[0]<<4)&(result[1]>>4)
Aber irgendwie kommt da nichts gescheites bei heraus und ich weis nicht,
wo der Fehler liegen könnte.