SPI Kommunikation mit AD7780

Hallo Leute,

ich bin hier gerade am verzeifeln.
Ich möchte den AD-Wandler AD7780 mit meinem Arduino Mega auslesen.

Zualler erst weiß ich nicht genau wie ich den AD Wandler anschließen soll, da der AD7780 nur einen SCK und einen DOUT/RDY Pin für die Kommunikation hat.

Ich bin jetzt einfach davon ausgegangen, dass ich den SlaveSelect Pin hier nicht benötige (habe nur den ADC an meinem Arduino über SPI angeschlossen) und ich somit meinen ADC nicht direkt ansprechen muss und er immer sendet.
Daher habe ich nur den SCK Pin an meinen Arduino PIN 52 (SCLK) und mein DOUT/RDY an den Arduino PIN 50 (MISO) angeschlossen.

Mein Zweites Problem ist, dass ich gern die PINs über die SPI Library auslesen möchte.
Dazu habe ich folgenden Code geschrieben:

#include <SPI.h>


#define DOUT 51           //MOSI
#define DIN  50           //MISO
#define SCK  52         //sck
#define SS 53      //ss
#define GAIN 40 //GAIN (1 = Gain 128; 0 = Gain 1
  void setup (void) {

  Serial.begin(115200);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV16);  // 1 MHz
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE0);   
  pinMode(SCK, OUTPUT);
 
  //digitalWrite(SS, HIGH);

  }


  void loop() {
  while(digitalRead(50)==HIGH);       // MISO

  byte spia=SPI.transfer(0);                   //byte
 
  Serial.println (spia, BIN);
 

  }

Dabei bekomme ich allerdings nur sowas hier raus.

1110010
1110010
1111000
1111101
1001
1110001
1101100
100000
1001
1110011
1000000
1001001
1001
1110010
1110011

Ich verstehe dabei nicht wieso die Länger meiner Ausgabe unterschiedlich lang ist.
Normalerweise möchte ich als Ausgabe ein 32bit lange binäre Zahl.
Laut Datenblatt (des AD7780 sind die ersten 8 bit die Status-bits und die restenlichen 24-bit mein Messwert.

Danke schonmal für eure Hilfe.

Gruß
Dave

BIN schreibt keine führenden Nullen.

Gruß Tommy

Hallo,

erstmal muss er laut Standardbeschaltung im Datenblatt beschalten sein. Ist er das? Nicht nur SCLK und DOUT/Ready anklemmen. Da gibts noch mehr. Zum Bsp. muss /PDRST High sein. DIN hat er nicht. Pin53 muss zudem immer Augang sein. Damit sind wir schon beim Punkt, der Datenpin vom AD heißt DOUT/RDY, hat also eine doppelte Funktion. Das heißt, er signalisiert wenn neue Daten bereit stehen, was bedeutet, man kann nicht einfach Daten abfragen. Laut Beschreibung ignoriert er dann die eingehenden Takte. Also erst Readysignal erkennen und dann immer komplett auslesen. Dafür musste alle Bits einlesen. Pauschal paar Bytes geht auch wiederum nicht. Wie lang der Ready Low Impuls ist kann ich nicht erlesen. Es wird aber von einem Interrupt seitens des µC gesprochen, womöglich gehts nicht ohne. Das Timingdiagramm sagt dazu leider auch nichts aus, über die Länge des Impulses. Ich rate dir dafür, wenn du das wirklich durchziehen möchtest, einen Logic Analyzer zu kaufen. Du siehst sonst nicht was auf den Leitungen los und operierst völlig blind. Ist machbar, aber nicht so einfach wie vielleicht gedacht.

Die Anbindung erscheint mir ähnlich wie bei einem HX711,
ich würde das Teil nicht an den SPI Bus hängen, sondern gemütlich mit Software lesen.

Hallo,

aha, bei dem Teil gibts ein besseres Timingdiagramm. Das heißt man muss keinen Impuls auswerten sondern nur zügig reagieren sobald DOUT auf low wechselt. Ab da seine Takte rausschicken und gleichzeitig einlesen. :wink:

Laut Datenblatt (des AD7780 sind die ersten 8 bit die Status-bits und die restenlichen 24-bit mein Messwert.

Das glaube ich nicht.
Ist das nicht eher anders rum?

Hallo,

naja, glauben reicht hier nicht. Datenblatt angeschaut? Aus der Beschreibung im Datenblatt werde ich jedenfalls nicht schlau. Es geht nur daraus hervor das in den 32Bits 8 Statusbits und 24 Datenbits enthalten sind. In welcher Reihenfolge steht nicht da. Außer noch das von den Daten zuerst MSB gesendet wird. Die Interpretation von Seite 13 liese zur Zeit wirklich darauf schließen das nach dem Ready Signal zuerst die Statusbits auf Reise gehen. Bekommt man aber raus wenn man den Code zum konstanten einlesen am laufen hat. Dann sieht man was wie los ist.

Vielen Dank erstmal für die schnellen Antworten.

Das mit den führenden Nullen ist natürlich blöd zum schnellen Anzeigen der 32bit. Aber hierfür scheint es ja bereits einige Lösungsansätze zu geben.

Doc_Arduino:
Pin53 muss zudem immer Augang sein.

Aber ich benötige doch hierbei nicht den SlaveSelect Pin? Oder sehe ich das falsch?
Ich habe ja nur den SCK und den DOUT/RDY Pin als ausgang vom ADC.

Hier mal meine jetztige PIN-Belegung:

#define MOSI 51                       //MOSI
#define MISO  50                      //MISO
#define SCK  52                       //sck
#define SS 53                         //ss
#define GAIN 40                       
#define PDRST 41                      
#define FILTER 42

pinMode(MOSI, OUTPUT);              //nicht verbunden
  pinMode(MISO, INPUT);               //DOUT/RDY vom ADC
  pinMode(SCK, OUTPUT);               //SCK vom ADC
  pinMode(SS, OUTPUT);                //nicht verbunden
  pinMode(GAIN, OUTPUT);
  pinMode(PDRST, OUTPUT);
  pinMode(FILTER, OUTPUT);

  digitalWrite(SS, HIGH);
  digitalWrite(GAIN, HIGH);          //GAIN (1 = Gain 128; 0 = Gain 1
  digitalWrite(PDRST, HIGH);         // Power-Down / Reset -> PIN muss High sein damit ADC aktiv ist
  digitalWrite(FILTER, HIGH);        // 0 = 16,7 Hz || 1 = 10 Hz                //nicht verbunden

Für die Detektion des RDY Bits muss ich ja zunächst erstmal die gesamten 32 bit einlesen und dann das erste Bit von links (sprich das letzte/MSB bestimmen) Aber wie mache ich das genau? Ich kann ja immer nur 8 bit auslesen.
Im endeffekt möchte ich ja dann die letzten 8 bit als Statusbits einlesen und dann die restlichen 24 bit als mein Messwert bestimmen. Damit habe ich derzeit noch ein Problem.

Whandall:
Die Anbindung erscheint mir ähnlich wie bei einem HX711,
ich würde das Teil nicht an den SPI Bus hängen, sondern gemütlich mit Software lesen.

Wie meinst du das mit Software auslesen? Also nicht mit der SPI Lib?

Doc_Arduino:
Das heißt man muss keinen Impuls auswerten sondern nur zügig reagieren sobald DOUT auf low wechselt. Ab da seine Takte rausschicken und gleichzeitig einlesen. :wink:

Also muss ich über eine if Schleife schauen wann DOUT High ist und dann 32 bit auslesen, oder wie mache ich das in dem Fall?
Ich muss ja sicher gehen, dass ich auch nur das RDY Signal Detektiere und nicht irgendwelche anderen Bits bspw. vom Messwert.

combie:
Das glaube ich nicht.
Ist das nicht eher anders rum?

Da hast du natürlich vollkommen recht. Habe einfach meine 32bit von "links nach rechts" gelesen.

Hier auch nochmal der etwas angepasste Code.

#include <SPI.h>


#define MOSI 51                       //MOSI
#define MISO  50                      //MISO
#define SCK  52                       //sck
#define SS 53                         //ss
#define GAIN 40                       
#define PDRST 41                      
#define FILTER 42                     
void setup (void) {

  Serial.begin(115200);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV16);  // 16 MHz Prozessoertakt geietlt durch 16 = 1 MHz
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3);         //CPOL=1 the base value of the clock is one
                                      //CPHA=1 data are captured on clock's rising edge
                                      //and data are propagated on a falling edge.
   //SPI Out/Inputs 
  pinMode(MOSI, OUTPUT);              //nicht verbunden
  pinMode(MISO, INPUT);               //DOUT/RDY vom ADC
  pinMode(SCK, OUTPUT);               //SCK vom ADC
  pinMode(SS, OUTPUT);                //nicht verbunden
  pinMode(GAIN, OUTPUT);
  pinMode(PDRST, OUTPUT);
  pinMode(FILTER, OUTPUT);

  digitalWrite(SS, HIGH);
  digitalWrite(GAIN, HIGH);          //GAIN (1 = Gain 128; 0 = Gain 1
  digitalWrite(PDRST, HIGH);         // Power-Down / Reset -> PIN muss High sein damit ADC aktiv ist
  digitalWrite(FILTER, HIGH);        // 0 = 16,7 Hz || 1 = 10 Hz
  delay(50);                         // Warten bis ADC initialisiert ist
}


void loop() {
  while (digitalRead(50) == HIGH);    // 
  
  
  int spia = SPI.transfer(0);         //byte
  int spib = SPI.transfer(0); 
  int spic = SPI.transfer(0); 
  int spid = SPI.transfer(0); 
  
  Serial.println (spia, BIN);
  Serial.println (spib, BIN);
  Serial.println (spic, BIN);
  Serial.println (spid, BIN);
}

Hallo,

ne, du wartest bis DOUT auf low wechselst, dann gehts erst los. Sonst bekommste gar keine Daten. bzw. irgendwas sinnloses, weil es irgendwelche Reste sind.

zur Bitformatierung mit 0 Anzeige

void formatiere_Byte (byte data)
{
  for (char i=7;i>=0;i--) {
    Serial.print(bitRead(data,i)); 
  }
  // Serial.print('\t');
  Serial.println();
}

Wenn Hardware SPI genutzt wird muss Pin53 immer Ausgang sein. Egal ob der genutzt wird oder nicht. Ist nun einmal so. Nur ohne konkreten CS Pin am AD ist es wirklich einfacher das per Fuss zu machen. Also ohne Hardware SPI. Das heißt SPI darfst nicht einschalten.

Wie meinst du das mit Software auslesen? Also nicht mit der SPI Lib?

Ja.

Ein Gerät ohne /CS bzw. OE, das nur Output liefert, lässt sich meiner Ansicht nach nicht gut via SPI betreiben.

So lese ich die 24 Bits des HX711, vollständig hier GitHub - whandall/NBHX711: A non-blocking Avia HX711 library for Arduino

void NBHX711::putData(byte* storeTo) {
 // pulse the clock pin 24 times to read the data
 storeTo[2] = shiftIn(dataPin, clockPin, MSBFIRST);
 storeTo[1] = shiftIn(dataPin, clockPin, MSBFIRST);
 storeTo[0] = shiftIn(dataPin, clockPin, MSBFIRST);
 // set the channel and the gain factor for the next reading using the clock pin
 for (byte i = 0; i < gainCode; i++) {
 digitalWrite(clockPin, HIGH);
 digitalWrite(clockPin, LOW);
 }
}

Ein Gerät ohne /CS bzw. OE, das nur Output liefert, lässt sich meiner Ansicht nach nicht gut via SPI betreiben.

Seltsame Ansicht....

naja, glauben reicht hier nicht. Datenblatt angeschaut?

Ach....

Each time a data read occurs, eight status bits
are appended to the 24-bit conversion.

Was "appended" bedeutet, findest du aber selber raus, oder?

combie:
Seltsame Ansicht....

Seltsam finde ich das man nicht SPI Geräte per SPI betreiben will.

MISO muss tristate sein um mit anderen Devices reden zu können, wie willst du das ohne CS oder OE machen?

MISO muss tristate sein um mit anderen Devices reden zu können, wie willst du das ohne CS oder OE machen?

Bemerke:

(habe nur den ADC an meinem Arduino über SPI angeschlossen)

Bist also irgendwie auf der falschen Baustelle unterwegs.


Hier völlig ungetesteter Code, da ich keinen solchen Wandler hier habe:
Größtenteils übernommen, nur an den wichtigen Stellen überarbeitet

#include <SPI.h>

/* ueberfluessig
#define MOSI 51                       //MOSI
#define MISO  50                      //MISO
#define SCK  52                       //sck
#define SS 53                         //ss

*/
const byte GAIN   = 40;
const byte PDRST  = 41;                      
const byte FILTER = 42;  

struct AD7780
{
  long value:24;
  byte status:8;
} __attribute__ ((packed));

union 
{
  AD7780 daten;
  byte bytefeld[sizeof(AD7780)];
} wandlerDaten;
                   
void setup (void) 
{

  Serial.begin(115200);
  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV16);  // 16 MHz Prozessoertakt geietlt durch 16 = 1 MHz
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3);         //CPOL=1 the base value of the clock is one
                                      //CPHA=1 data are captured on clock's rising edge
                                      //and data are propagated on a falling edge.
   //SPI Out/Inputs 
  pinMode(MOSI, OUTPUT);              //nicht verbunden
  pinMode(MISO, INPUT);               //DOUT/RDY vom ADC
  pinMode(SCK, OUTPUT);               //SCK vom ADC
  pinMode(SS, OUTPUT);                //nicht verbunden
  pinMode(GAIN, OUTPUT);
  pinMode(PDRST, OUTPUT);
  pinMode(FILTER, OUTPUT);

  // digitalWrite(SS, HIGH); ueberfluessig, Output reicht
  digitalWrite(GAIN, HIGH);          //GAIN (1 = Gain 128; 0 = Gain 1
  digitalWrite(PDRST, HIGH);         // Power-Down / Reset -> PIN muss High sein damit ADC aktiv ist
  digitalWrite(FILTER, HIGH);        // 0 = 16,7 Hz || 1 = 10 Hz
  delay(50);                         // Warten bis ADC initialisiert ist
}


void loop() 
{
  while(digitalRead(MISO));     
  for(byte & d:wandlerDaten.bytefeld) d = SPI.transfer(0);
  Serial.print("Messwert "); Serial.println (wandlerDaten.daten.value);
  Serial.print("Status ");   Serial.println (wandlerDaten.daten.status);
  Serial.println ("---------");
}

Wenn man seinen gesamten SPI Bus der Schnecke von AD Wandler schenken will, nur zu.

Keine SD Karte, kein NRF, kein Ethernet, keine RFIDs, kein TFTempfinde ich als untragbare Einschränkung.

Ich interessiere mich eher für allgemein brauchbare Lösungen.

Ich interessiere mich eher für allgemein brauchbare Lösungen.

Kein Problem....
Ist nur hier nicht gefragt.

Wenn Hardware SPI genutzt wird muss Pin53 immer Ausgang sein. Egal ob der genutzt wird oder nicht. Ist nun einmal so

Das ist übrigens nicht (ganz) richtig.

Richtig ist:
Wenn SPI im Master Modus laufen soll, muss der SS Pin entweder High sein, oder ein Output.

Wenn der Pin ein Input ist und Low, dann schaltet die SPI Hardware in den Slave Modus.
Der Slave Modus hilft uns hier nicht.

INPUT_PULLUP würde reichen, wenn an dem Pin nichts angeschlossen ist.

Ich bemühe mich halt eher technisch sinnvolle Antworten zu geben.

Dein "sinnvoll" scheint sich manchmal von meinem "sinnvoll" zu unterscheiden.

Das ist nicht schlimm, solange dir nicht die absolute Deutungshoheit zugesprochen wird.

So ich habe jetzt mal schnell den Code von Combie getestet.
Dieser Funktionert ganz gut für die Statusbits und Das Ergebnis ist rekonstruierbar.
Allerdings kann ich mit den Messwert nicht so wirklich was Anfangen.
Ich verstehe den AD Wandler so, dass ich meinen Eingansspannungsbereich (+-V_Ref/Gain = +-5V/1) in 24 bit auflöse? Dann ist mir aber der negative Messwert nicht ganz klar.
(Der AD-Wandler hat 2,52V am Eingang anliegen)

Messwert 2739648
Status 77

Messwert -3027776
Status 77

Messwert 1428928
Status 77

Messwert 2149824
Status 77

Messwert 2608576
Status 77

Messwert 2018752
Status 77

Messwert -2110272
Status 77

Messwert 2936256
Status 77

Messwert 3984832
Status 77

Was mir auch noch aufgefallen ist, dass er, wenn ich während der Messung den GAIN Pin löse, er mir den Status nicht aktualisiert.

Kannst du mir vll kurz erklären, was es mit

__attribute__ ((packed));
UND
wandlerDaten;

aufsich hat?

Wahrscheinlich werde ich die Vorgehensweise, welche DOC und Whandall beschrieben haben, anweden müssen.
Ich sehe gerade, dass ich auch noch einen LS7366R (Quadrature Counter) über SPI auslesen muss =/

In diesem Fall macht es ja dann doch Sinn, den AD-Wandler ohne SPI auszulesen, wenn das wegen dem SelectSlave nicht funktionert.

@Whandall
So ganz habe ich den Code von dir noch nicht verstanden.
Du schiebst mithilfe von shiftIn 8 bits in storeTo[] und das 3x -> 24bit

Doch verstehe ich die for-Schleife danach nicht. Du gibst ja irgendwie einen unbestimmten Takt damit vor?

Habe auch den ganzen Code nicht auf github gefunden um es besser nachzuvollziehen.

Ich muss mir ja irgendwie nen Takt auf mein SCK Pin vorgeben und dann auf einen anderen PIN detektieren, wenn RDY von HIGH auf LOW geht um dann meine 32 bit aufzuzeichnen.
Diese wiederum in 8-bit und 24-bit aufteilen.
So die Theorie, jedoch scheitert es jetzt an der Praxis =/

Gruß
Dave