Hallo,
ich hab einen Arduino Due und möchte damit einen AD7356 auslesen. Hält
man den CS Pin länger auf low werden die Daten von beiden Kanälen des
ADC auf einem SPI MISO ausgegeben, mit meinem Code versuche ich das so
hinzubekommen aber es werden aber nur nullen zurückgegeben (oder gar
nichts?). Liegt das Problem am Code oder ist da evtl. was an meiner
Hardware falsch aufgebaut?
1
#include <SPI.h>
2
3
#define CS_ADC 4
4
5
void setup() {
6
// put your setup code here, to run once:
7
pinMode(CS_ADC, OUTPUT);
8
9
Serial.begin(9600);
10
11
SPI.begin(4);
12
SPI.setClockDivider(4,1);
13
SPI.setDataMode(4,SPI_MODE2);
14
SPI.setBitOrder(MSBFIRST);
15
16
}
17
18
void loop() {
19
// put your main code here, to run repeatedly:
20
unsigned int val1 = 0;
21
unsigned int val2 = 0;
22
byte MSB1;
23
byte LSB1;
24
byte MSB2;
25
byte LSB2;
26
27
MSB1 = SPI.transfer(4, 0x00, SPI_CONTINUE);
28
LSB1 = SPI.transfer(4, 0x00, SPI_CONTINUE);
29
MSB2 = SPI.transfer(4, 0x00, SPI_CONTINUE);
30
LSB2 = SPI.transfer(4, 0x00);
31
32
val1 = MSB1<<8;
33
val1 = val1 | LSB1;
34
35
val2 = MSB2<<8;
36
val2 = val2 | LSB2;
37
38
// val1 = SPI.transfer16(4,0x00,SPI_CONTINUE); //transfer16 nicht deklaiert???
So wie ich das sehe, setzt Du den CS Pin nur einmalig LOW.
Ich denke, da passiert Gar nichts, weil:
The CS signal initiates the data transfer
!!! and !!!!
conversion process.
The falling edge of CS puts the track and hold into hold mode,
at which point the analog input is sampled and the bus is taken
out of three-state. The conversion is also initiated at this point
and requires a minimum of 14 SCLKs to complete.
Nach dem Powerup kommen also einmalig Müll-Daten. Theroetisch kommen
erst beim 2. CS-Low die Daten der vorherigen Conversion.
Also: Mach das Auslesen mal zyklisch (Alle 1 Sek oder so) und lass dir
die Werte ausgeben.
Dann wirst Du immernoch was an deinem Bit-geschiebe ändern müssen, denn:
The 12-bit result then follows with the final bit in the data transfer
and is valid on the 14th falling edge (having been clocked out on the
previous (13th) falling edge). In applications with a slower SCLK, it
may be
possible to read in data on each SCLK rising edge depending on
the SCLK frequency. With a slower SCLK, the first rising edge,
of SCLK after the CS falling edge has the second leading zero
provided, and the 13th rising SCLK edge has DB0 provided.
Datenblatt lesen!
Werner
Werner schrieb:> So wie ich das sehe, setzt Du den CS Pin nur einmalig LOW.
Durch das SPI_CONTINUE in den SPI.transfer() Funktionen wird der CS PIN
weiterhin low gehalten, beim letzen .transfer sollte der Pin dann wieder
auf high gehen. Oder muss ich den Pin auf low setzen, 14CLKs warten und
dann anfagen auszulesen? Bei einem SAR-ADC sollten er doch dirket
anfangen können Bits zu liefern oder?
Werner schrieb:> Also: Mach das Auslesen mal zyklisch (Alle 1 Sek oder so) und lass dir> die Werte ausgeben.
Das Problem besteht danach immer noch...nur nullen.
Kann es sein das ich den falschen SPI Mode benutze?
Werner schrieb:> Dann wirst Du immernoch was an deinem Bit-geschiebe ändern müssen, denn:
stimmt, da schaue ich später nochmal nach...
name123 schrieb:> Das Problem besteht danach immer noch...nur nullen.> Kann es sein das ich den falschen SPI Mode benutze?
Warum denkst du denn das Mode 2 richtig ist?
Nico W. schrieb:> Warum denkst du denn das Mode 2 richtig ist?
Ich hab Fig. 31 im Datenblatt des ADC mit der Fig.32-4 auf S. 681 im
Datenblatt des uC auf dem Due verglichen und habe daraus abgelesen, dass
NCPHA = 0 und CPOL = 1 sein sollte.
In der Tabelle https://www.arduino.cc/en/Reference/SPI zu den SPI Modes
komme ich dann auf Mode 2, ist das korrekt?
Ok, noch eine Idee
(ich mache nix mit den Arduio Libs, deswegen kenn ich mich da nicht aus.
Ich bleibe lieber nahe am Datenblatt und schreib mir meine eigenen Libs.
Deswegen weiß ich wenig über die Funktionen, und dwas die so tun).
Aber das hier scheint auch noch Wert zu sein drüber nachzudenken:
>Kann es sein das ich den falschen SPI Mode benutze?
Wenn ich das Datenblatt richtig interpretiere, dann brauchst du wohl
CPOL = 1
und
CPHA = 1
das entspricht aber nicht MODE2, sondern 3.
https://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>Oder muss ich den Pin auf low setzen, 14CLKs warten und>dann anfagen auszulesen?
Nein, das hab ich so nicht aus dem Datenblatt verstanden.
Werner
Werner schrieb:> das entspricht aber nicht MODE2, sondern 3.
Mode3 nach Datenblatt oder nach der Arduino Doku, die sind
komischerweise nicht gleich?
Ich konnte mir ein Oszi organisieren und das Problem ist, das der CS Pin
konstant auf 0 liegt, kennt sich hier jemand mit der Extended SPI
Library vom Due aus und weiß woran es liegt?
Der ADC kann theroetisch 5MS/s, ich würde das gerne so gut es geht
ausnutzen und ich vermute das das über die .transfer Funktion etwas
effektiver ist, als wenn ich den CS Pin vor einem lesevorgang auf low
setze und danach wieder auf high, vorallem, da ich nicht weiß wann 14
SCLK rum sind?!
Hi.
Ich kenne mich -wie gesagt- mit dem Arduino Zeug nicht aus.
Vielleicht solltest Du mal:
Die Zeile "pinMode(CS_ADC, OUTPUT);" wegnehmen. Kann ja sein, dass
dieses ganze SPI.machirgendwas() den Pin und dessen Funktion
selbstständig organisiert.
Wenn das nicht hilft, dann -wie Du selbst schon sagtest- ein "PinLow"
vor dem ganzen SPI.transfer und ein "PinHigh" dahinter, wenn alles
fertig ist.
Wahrscheinlich musst Du dann aber der SPI.transfer() Funktion einen
anderen (unbenutzten) CS Pin mitteilen, damit die Funktion damit machen
kann, was sie möchte und Du selbst dien CS Pin in der Hand hast.
Das ist dann Geschwindigkeitstechnisch vielleicht nicht der Hit, aber
immerhin hast Du vielleicht ein Ergebnis.
>Mode3 nach Datenblatt oder nach der Arduino Doku, die sind>komischerweise nicht gleich?
Ich hatte nur überflogen, aber sind die Modes in der Arduino Doku nicht
an den Wiki-Artikel angelehnt? Für mich sah die Belegung gleich aus.
Werner
Werner schrieb:> Die Zeile "pinMode(CS_ADC, OUTPUT);" wegnehmen
DANKE! ohne die Zeile Funktioniert es so wie es soll!
Werner schrieb:> Ich hatte nur überflogen, aber sind die Modes in der Arduino Doku nicht> an den Wiki-Artikel angelehnt? Für mich sah die Belegung gleich aus.
Ich hab es gerade nochmal verglichen, bin da wohl irgendwie in der
Splate verrutscht, mit Mode 3 geht es.
Wow.
Ein ganzer Thread, der ein Problem gelöst hat,
ganz ohne irgendeinen Troll oder chronischer-Hater Post.
Das lässt neue Hoffnung in mir keimen, dass dieses Forum doch noch von
vernünftigen Leuten Besucht wird.
Danke!
Werner
PS: Freut mich, dass es nun funktionert. Schönes Wochenende.
Ich benötige doch nochmal Hilfe bei der Umrechnung.
Ich nutze folgenden Code:
1
byte MSB1;
2
byte LSB1;
3
byte MSB2;
4
byte LSB2;
5
unsigned int volt = 0;
6
7
SPI.beginTransaction(ADC_settings);
8
MSB1 = SPI.transfer(4, 0x00, SPI_CONTINUE);
9
LSB1 = SPI.transfer(4, 0x00, SPI_CONTINUE);
10
MSB2 = SPI.transfer(4, 0x00, SPI_CONTINUE);
11
LSB2 = SPI.transfer(4, 0x00);
12
13
volt = (MSB1 << 8);
14
volt = (volt | LSB1);
15
volt = (volt >> 2);
Laut DB kommen erst 2 nullen, dann 12 Daten und dann nochmal 2 nullen
für MSB1 und LSB1 (Fig. 31 auf S. 19 im DB).
Speise ich mit einem Netzeil 0,6V an INA+ an und an INA+ liegt GND
erhalte ich aber
MSB1: 0b00101001
LSB1: 0b00101000
lässt man die beiden Nullen am Anfang und am Ende weg kommt 2634 (dez)
raus, da U=(ADC*Vref)/4096 ist müssen es 1,3V sein?! Habe ich irgendwo
einen Umrechnungsfehler gemacht?
name123 schrieb:> lässt man die beiden Nullen am Anfang und am Ende weg kommt 2634 (dez)> raus, da U=(ADC*Vref)/4096 ist müssen es 1,3V sein?! Habe ich irgendwo> einen Umrechnungsfehler gemacht?
Warum nimmst Du nicht einfach ein Multimeter in die Hand, geht deutlich
schneller als hier Fragen zu formulieren.
Spannungsquelle (2 Batterien) und Drehpoti oder ein Labornetzgerät.
Spannung an den ADC, messen, gucken welchen Wert der ausspuckt und gut
gewesen.
Manfred schrieb:> Warum nimmst Du nicht einfach ein Multimeter in die Hand, geht deutlich> schneller als hier Fragen zu formulieren.
Ich halte 0,6V vom Netzteil direkt an den ADC Eingang und das Ergebnis
das ich ausrechne ist dann 1,3V. Wo soll ich da noch was mit einem
Multimeter messen?
Kann es daran liegen, dass ich nicht 16bit einlesen sondern 2x8Bit?
Aber eigentlich müsste ich doch durch das low halten des CS Pin diese
einfach aneinander hängen können oder?
Das Problem ist: MSB war nur 8 bit lang. Deshalb geht das Schieben
schief.
Anmerkung: Bei Microcontrollern immer stdint.h verwenden, nie die
C-Typen.
<c>
uint16_t MSB1;
uint16_t LSB1;
uint16_t MSB2;
uint16_t LSB2;
uint32_t = 0;
SPI.beginTransaction(ADC_settings);
MSB1 = SPI.transfer(4, 0x00, SPI_CONTINUE);
LSB1 = SPI.transfer(4, 0x00, SPI_CONTINUE);
MSB2 = SPI.transfer(4, 0x00, SPI_CONTINUE);
LSB2 = SPI.transfer(4, 0x00);
volt = MSB1 << 8;
volt = volt | LSB1;
volt = volt >> 2;
</c>
chris_ schrieb:> Das Problem ist: MSB war nur 8 bit lang. Deshalb geht das Schieben> schief
mann kann auch so lösen:
uint16_t val=0;
val = (uint16_t)SPI.transfer(4, 0x00, SPI_CONTINUE)<<8; //MSB1
val|= (uint16_t)SPI.transfer(4, 0x00, SPI_CONTINUE)<<0;
chris_ schrieb:> Das Problem ist: MSB war nur 8 bit lang. Deshalb geht das Schieben> schief.
danke, war mir nicht bewusst, dass erst in MSB geschoben wird und der
Wert dann in die variable volt übernommen wird.
Das Problem besteht leider immernoch, schaue ich mir die Werte, die
dirket nach dem lesen in MSB und LSB stehen und setzte diese zusammen
dann kommt bei beiden Kanälen 1,3V raus. Ist das IC so im falschen
operation mode?