AD Wandler mittels Raspberry Pi auslesen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
ZorroRasp
User
Beiträge: 9
Registriert: Donnerstag 2. November 2017, 13:21

Hallo Zusammen,

als aller erstes ich bin ein totaler Neuling, was Python angeht. Ich möchte im Zuge eines Projektes einen AD-Wandler mit einem RP auslesen. Dafür habe ich mich für den AD7357 entschieden.
Hier das Datenblatt: http://www.analog.com/en/produ…g-ad-con ... /ad7357.ht
Ich habe dazu eine Platine entworfen, die wunderbar funktioniert, wenn ich eine Spannung anlege.
Der AD-Wandler kommuniziert über SPI mit dem RP. Verbunden sind diese beiden über ein 40 poligen Stecker. Den Code den ich nun in Python geschrieben habe sieht wie folgt aus :[/code]

Code: Alles auswählen

[Codebox=python file=Unbenannt.py]#Verbunden sind MISO und SDATAa( Datentransfer vom AD-Wandler zum RP).....SCLK und SCLK für die Clock...... CS und CEON...MOSI meiner Meinung nach hier nicht notwendig, da nur Daten vom AD-Wandler kommen und SCLK und CS seperat angesteuert werden.


import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BCM)

HIGH = True
LOW = False

try:

def readAnalogData (SCLKPin, MISOPin, CSPin):

GPIO.output(CSPin, LOW)
# print (CSPin)
GPIO.output(CSPin, HIGH) # Nun ist Chip bereit zum auslesen
# print (CSPin)
GPIO.output(SCLKPin,HIGH) # da der negative flankenwechsel entscheidenden ist, muss die SCLK vorher auf HIGH gesetzt werden
# print (SCLKPin)
time.sleep (0.0000000055) # Delay nach NChipSelect auf negativ
list=[]
# print list
for i in range(32): # ich lese beide Kanäle über SDATAa aus
GPIO.output(SCLKPin, LOW) # Auf Low damit das SDATA ausgelesen werden kann
# print (SCLKPin) # Wenn der ausgeschaltet ist, funktioniert es nicht --> nur 0.
x = (GPIO.input(MISOPin)) # Der wert der jetzt auf der Sdata ist wird ausgelesen und in x gespeichert
#print x,i
list.append(x) #a.append(adcvalue), in eine liestegespeichert, die am Ende 32 bits bestitzen soll
time.sleep (0.00000001) # Dauer des SCLK LOW pulse width
GPIO.output(SCLKPin, HIGH) # Setzte wieder auf HIGh damit der nächste flankenwechsel vorbeeitet wird.
#print (SCLKPin)
time.sleep (0.00000001) # Dauer des SCLK HIGH pulse width

return list # 32 Bit Liste returnen
GPIO.output (CSPin, HIGH) # packe CS wieder auf HIGh um lesevorgang zu beenden
time.sleep (0.000000005) # Minimum time betweeen end of serial read ad next falling edge of NCS
SCLK = 11 # hier werden die GPIOS benannt
MISO = 9
CS = 8

GPIO.setup(SCLK, GPIO.OUT) #Eingang und Ausgang festlegen
GPIO.setup(MISO, GPIO.IN)
GPIO.setup(CS, GPIO.OUT)

while True:
print readAnalogData(SCLK,MISO,CS) # Übergeben der Daten an die Funktion und dan ausgeben des Ergebnisses ( hier list)
except KeyboardInterrupt:
GPIO.cleanup()[/Codebox]


Dabei habe ich mich an das Datenblatt gehalten, welches die wesentlichen Informationen für das auslesen des AD-Wandlers hergibt(Zeitverzögerungen, Taktflanken etc). Ich möchte die 32 Bits (14 Bits pro Kanal die mit 2 Nullen am Anfang angekündigt werden(siehe Datenblatt Seite 21)) über SDATAa auslesen. Dies funktioniert nach Datenblatt auch. Diese will ich in eine Liste speichern und ausgeben. Allerdings funktioniert mein Programm auf der semantischen Ebene überhaupt nicht. Er gibt mir sogar andere Werte aus wenn ich print befehle dazu schalten( Hier mit der Raute versehen). Vielleicht kann mir jemand helfen, dass ich das Programm doch noch zum laufen bringe.

Grüße
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@ZorroRasp: auf Bit-Ebene kann man kein Protokoll mit Python umsetzen. Dafür muß man einen Kernel-Treiber schreiben, der beim Raspi aber auch schon dabei ist. Auf die schnelle habe ich spidev gefunden.
ZorroRasp
User
Beiträge: 9
Registriert: Donnerstag 2. November 2017, 13:21

Vielen Dank für die Antwort. Verstehe ich dann aber diesen Beitrag falsch ?

https://www.google.de/search?q=erik+bar ... 0&ie=UTF-8

An diesem habe ich mich längs gehangelt für meinen Code
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Sirius3 hat geschrieben:@ZorroRasp: auf Bit-Ebene kann man kein Protokoll mit Python umsetzen. spidev gefunden.
Natuerlich kann man das. Gerade SPI mit seiner expliziten CLK-Leitung ist dazu geeignet. Wenn man da nicht an ein wirklich komisches Device geraet sollte das problemlos klappen. Das es sehr langsam ist (Ausfuehrungsgeschwindigkeit, siehe den anderen Thread gerade...) steht auf einem anderen Blatt.

Aber natuerlich sollte man die eingebaute Hardware-Unterstuetzung nutzen. Das generische SPIDEV ist dafuer der geeignete Weg.

@ZorroRasp: Du solltest von diesem Code abstand nehmen. Das ist ziemlich grauslig, und verschwenderisch. Fuer Python gibt es das spidev-Modul das du installieren koennen solltest, und du musst deinem PI durch entsprechende Einstellungen in der config.txt dazu bringen, das SPI-Device zu aktivieren. Dann sollte sich unter /dev/spidev* etwas finden, aller Wahrscheinlichkeit nach /dev/spidev1.0.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@ZorroRasp: entweder hat der Autor hier einen sehr genügsamen AD-Wandler, der wirklich mit jedem Clock-Signal umgehen kann, oder es ist reiner Zufall, dass das da funktioniert. Ein sleep unterhalb einer Millisekunde macht gar keinen Sinn, da Threadwechsel auch im Millisekundenbereich stattfinden. Und auch ohne sleep, sobald ein Threadwechsel (oder auch nur ein Kernelinterrupt) auftritt, ist Dein µs-Timing dahin (Du versuchst ja sogar ns zu kontrollieren, was nicht einmal auf Hardwareebene möglich ist). Vergiß was da geschrieben steht und nutze den SPI-Treiber.
Benutzeravatar
noisefloor
User
Beiträge: 3843
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

den gleichen Thread gibt's auch im Raspi-Forum: https://forum-raspberrypi.de/forum/thre ... -auslesen/

Allerdings sind hier bis dato die Antworten besser :-)

Gruß, noisefloor
ZorroRasp
User
Beiträge: 9
Registriert: Donnerstag 2. November 2017, 13:21

Vielen Dank für die ausführlichen Antworten. :)
Ich werde mich mal in spidev einarbeiten und hoffen, dass das dann klappt.
ZorroRasp
User
Beiträge: 9
Registriert: Donnerstag 2. November 2017, 13:21

__deets__ hat geschrieben:
Sirius3 hat geschrieben:@ZorroRasp: auf Bit-Ebene kann man kein Protokoll mit Python umsetzen. spidev gefunden.
@ZorroRasp: Du solltest von diesem Code abstand nehmen. Das ist ziemlich grauslig, und verschwenderisch. Fuer Python gibt es das spidev-Modul das du installieren koennen solltest, und du musst deinem PI durch entsprechende Einstellungen in der config.txt dazu bringen, das SPI-Device zu aktivieren. Dann sollte sich unter /dev/spidev* etwas finden, aller Wahrscheinlichkeit nach /dev/spidev1.0.
könnt ihr mir da vielleicht einen kleinen Denkanstoss geben? ich verstehe das ich die spidev Bibliothek brauche und das man damit ganz leicht etwas auslesen kann über den SPI Bus. Aber das wie erscheint mir irgendwie sehr suspekt. Auch Tutorials bringen mich nicht weiter. :/
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was heißt denn suspekt? Suspekt ist mir ein alter weißer Sack mit schlecht aufgetragenem Selbstbräuner in der Frauenumkleide.

SPI ist ja ein einfacher Bus. Und du hast doch sicher das Datenblatt zu deinem IC. Was steht denn da drin bezüglich der Kommunikation?
ZorroRasp
User
Beiträge: 9
Registriert: Donnerstag 2. November 2017, 13:21

:D :D :D :D :D

Es geht dabei um die Befehle, die man mit der SPIDEV ausführen kann.

Ich habe einen dualen 14 bit AD-Wandler, diesen möchte ich über den Eingang SDATAa (Verbunden mit MISO am PI) auslesen. Dabei werden die jeweils 14 Bits eines AD Wandlers immer mit zwei nullen angekündigt. Macht also insgesamt 32 Bits, die ich über SDATAa auslesen soll. Jeder AD-Wandler gibt eine momentane Spannung an.(In meinem Fall können die Spannungen jedoch als gleich betrachtet werden). Das Auslesen wir durch das Setzen vom NChipselect auf LOW begonnen (Verbunden mit CE0 am PI). Dann wird bei jedem negativen Taktwechsel des SLCK ein Bit ausgelesen.

http://www.analog.com/media/en/technica ... AD7357.pdf hier auch nochmal zu sehen auf Seite 21.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und was ist dir nicht klar am spidev Modul? Hier ist doch alles ausführlich beschreiben. https://github.com/doceme/py-spidev

Du musst dich nur dein device öffnen und dann 4 Bytes lesen.
ZorroRasp
User
Beiträge: 9
Registriert: Donnerstag 2. November 2017, 13:21

ich bewunder deine Ruhe und möchte dir dafür erstmal danken. :D
Ich habe kaum Erfahrung im Programmieren. Ich schaue mir ersteinmal nochmal an und melde mich dann notfalls nochmal :roll:
ZorroRasp
User
Beiträge: 9
Registriert: Donnerstag 2. November 2017, 13:21

Code: Alles auswählen

# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
import time
import spidev
 
GPIO.setwarnings(False)
 
spi = spidev.SpiDev()
#spi.open(0, 0)      #Lese aus CS0
#spi.cshigh         #setzte cs auf high --> ncs auf low
#spi.mode =0b010  #negative Flanke an der er MISO übernimmt.
rawData = spi.readbytes(4)

def getreading_1(rawData):
    processedData_1 = (rawData[0] & 6 << 8 + rawData [1])
    return processedData_1

def getreading_2(rawData):
    processedData_2 = (rawData[2] & 6 << 8 + rawData [3])
    return processedData_2

def convertvoltage (bitValue, decimalPlaces = 2):
    voltage = (bitValue * 2.048) /float(16383)
    voltage = round (voltage, decimalPlaces)
    return voltage

while True:
    SignalData_1 = getreading_1(rawData)
    Signalvoltage_1 = convertvoltage (SignalData_1)
    print (" Sinal bitValue_1 = {}, volage_1 = {} V".format (SignalData_1, Signalvoltage_1))
    SignalData_2 = getreading_2(rawData)
    Signalvoltage_2 = convertvoltage (SignalData_2)
    print (" Sinal bitValue_2 = {}, volage_2 = {} V".format (SignalData_2, Signalvoltage_2))       
 
Ich habe übers Wochenende nun diesen Code geschrieben. Leider gib er mir immer nur 0 Volt aus. Wenn ich den spi.readbytes(4) anzeigen lassen steht da [255,255,255,255]. Dabei spielt es keine Rolle, was für eine Spannung ich auslesen will. Kann mir jemand helfen?

PS: Es ist beabsichtigt, dass beide AD Wandler das selbe ausgeben!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@ZorroRasp: ist es beabsichtigt, dass Du den Wert nur einmal am Anfang einliest und dann in der while-Schleife immer das selbe ausgibst?

Du solltest copy-paste-Programmierung vermeiden. getreading_1 und getreading_2 sind quasi identisch, das sollte also nur eine Funktion sein. Wenn Du anfängst Variablen durchzunummerieren willst Du eigentlich Listen und Schleife benutzen. Zahlen werden normalerweise nicht gerundet, sondern man rundet erst bei der Ausgabe durch die passende Format-Angabe '{:.2f}V'

Die Konvention ist, Variablennamen klein_mit_unterstrich zu schreiben.
ZorroRasp
User
Beiträge: 9
Registriert: Donnerstag 2. November 2017, 13:21

@Sirius3 Nein, das war leider nicht beabsichtigt. Aber ich kann das while True: Dann ja einfach weiter nach oben setzen, oder?

Du hast völlig recht, dass sie quasi identisch sind. Die Platine, die benutzt wird hat allerdings zwei AD Wandler, die ihre Daten nacheinander auf einer Leitung (SATAa) ausgegeben werden. Dabei sind sie zwar identisch in meinem Fall, aber allgemein können diese auch unterschiedliche Werte annehmen, da ich beide mit anderen Spannungen speisen könnte. Deshalb habe ich zwei unterschiedliche Schleifen gemacht. Okay, das mit dem Runden ändere ich mal. Sieht auch schon viel besser aus, danke !

Ich habe nur das Problem, dass er mir halt keine Werte ausgibt und ich fange an zu glauben, dass es an der Verbindung über SPI vom AD Wandler zum PI liet.
__deets__
User
Beiträge: 14493
Registriert: Mittwoch 14. Oktober 2015, 14:29

Statt das while vorzuziehen gehoert die Abfrage von raw_data *in* die while-Schleife.

Und zwei Funktionen die bis auf einen Index das gleiche machen und auch noch durchnummeriert sind schreibt man stattdessen als eine Funktion ohne Nummerierung, aber mit einem zweiten Parameter fuer den Start-Index. Oder du rufst die Funktion gleich mit raw_data[0:2] und raw_data[2:4] auf, statt das muehselig da drin zu machen - dann sind die Indizes *in* der Funktion immer 0 und 1.

Ausserdem sieht die rumrechnerei darin falsch aus, das verunden eines Wertes von 0-255 mit einem Wert 1536 ergibt *immer* 0. Ob das zur Erklaerung deiner Probleme reicht weiss ich nicht. Aber du solltest dir stattdessen nur die Rohdaten ausgeben lassen, und kannst auch mal probieren MISO auf HIGH bzw. LOW zu ziehen, und spaetestens dann sollte ja etwas deutlich anderes zurueckkommen.
ZorroRasp
User
Beiträge: 9
Registriert: Donnerstag 2. November 2017, 13:21

Vielen Dank!
Ich habe es jetzt anders gelöst und es scheint auch auf dem Board alles zu funktionieren. Das einzige Problem, was ich jetzt noch habe:
Ich habe die 32 Bits nacheinander ausgelesen und in einer Liste gespeichert. In dieser sind ja jetzt 32 Nullen und Einsen. Ich möchte nun jeweils Bit 2-15 und Bit 17-32 aus dieser Liste in integer und binären Werten haben. Dabei soll jeweils Bit 2 und Bit 17 das MSB sein. Leider funktioniert Software wie stiften nicht und eine Schleife mit hochzuholendem Index i und multiplizieren des Listenwertes mit einer 2er Potenz scheint mit etwas viel Aufwand. Kann mir jemand bei diesem letzten Problem bitte nochmal helfe, damit ich Spannungswerte bestimmen kann und nicht nur so doofe Nullen und Einsen rumfliegen habe?
Oder gibt es von vorne rein eine elegantere Lösung als die einzelnen Werte nacheinander in eine Liste zu schreiben?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@ZorroRasp: zeig doch mal, was Du hast.
Antworten