Forum: Mikrocontroller und Digitale Elektronik ADXL380 mit SPI auslesen


von Oliver M. (oliver_martens)



Lesenswert?

Hallo zusammen,
wir versuchen gerade im Rahmen einer Studienarbeit den ADXL380-1BCCZ-RL7 
via SPI auszulesen und die Beschleunigungsdaten zu protokolieren. Der 
ADXL380 wurde gemäß dem Datenblatt auf Seite 23 (siehe Bild) 
angeschlossen und wird mit dem ESP32-C3-Mini von Espressif betrieben. 
Der Stromverbrauch im Standby-Mode beträgt etwa 7uA und im High 
Performance-Mode messen wir etwa 250uA. Der ESP32 wird mit der Arduino 
IDE 2.3.6 programmiert und in der PDF ist der Leseprozess, den wir mit 
dem Oszilloskop beobachtete haben dokumentiert. Wir versuchen zurzeit 
nur die Beschleunigungsdaten der X-Achse (Register: 0x15 und 0x16) zu 
lesen und bekommen nur eine 0 als Ergebnis. Die Device_ID lässt sich 
allerdings, so wie auch einige andere Register problemlos auslesen. Die 
Ergebnisse wurden mit 2 ADXL380 getestet.

Unser Code:
1
#include <SPI.h>
2
3
const int CS_PIN = 10;
4
5
void setup() {
6
  Serial.begin(115200);
7
8
  pinMode(CS_PIN, OUTPUT);
9
  digitalWrite(CS_PIN, HIGH);
10
11
  SPI.begin(6, 2, 7, 10);
12
  SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); 
13
14
15
  //Soft-Reset
16
  writeRegister(0x2A, 0b00000010);
17
  uint16_t softReset = readRegister(0x26);
18
  Serial.print("Soft-Reset: ");
19
  Serial.println(softReset);
20
21
  //Modus-Wahl
22
  writeRegister(0x26, 0b00000000); //Standby-Mode
23
  uint16_t mode1 = readRegister(0x26);
24
  Serial.print("Mode_1: ");
25
  Serial.println(mode1);
26
27
  writeRegister(0x27, 0b11100000);
28
  uint16_t dig_En = readRegister(0x27);
29
  Serial.print("Dig_En: ");
30
  Serial.println(dig_En);
31
32
  writeRegister(0x26, 0b00001100);
33
  uint16_t mode2 = readRegister(0x26);
34
  Serial.print("Mode_2: ");
35
  Serial.println(mode2);
36
37
  //Status
38
  uint16_t status0 = readRegister(0x11);
39
  uint16_t status1 = readRegister(0x12);
40
  uint16_t status2 = readRegister(0x13);
41
  uint16_t status3 = readRegister(0x14);
42
43
  //Status
44
  Serial.print("Status0: ");
45
  Serial.println(status0);
46
  Serial.print("Status1: ");
47
  Serial.println(status1);
48
  Serial.print("Status2: ");
49
  Serial.println(status2);
50
  Serial.print("Status3: ");
51
  Serial.println(status3);
52
}
53
54
void loop() {
55
  //x-Achse lesen
56
  uint16_t ID = readRegister(0x00);
57
  uint16_t xH_Data = readRegister(0x15);
58
  uint16_t xL_Data = readRegister(0x16);
59
  
60
  Serial.print("ID: ");
61
  Serial.println(ID,HEX);
62
  Serial.print("xL_Data: ");
63
  Serial.println(xL_Data);
64
  Serial.print("xH_Data: ");
65
  Serial.println(xH_Data);
66
  delay(400);
67
}
68
69
//Register write
70
void writeRegister(uint8_t registerAddress, uint8_t value) {
71
  uint16_t command = ((registerAddress << 9) | value); // R/W-Bit = 0
72
73
  digitalWrite(CS_PIN, LOW);
74
  
75
  SPI.transfer16(command);
76
77
  digitalWrite(CS_PIN, HIGH);
78
}
79
80
//Register read
81
uint16_t readRegister(uint8_t registerAddress){
82
    
83
    digitalWrite(CS_PIN, LOW);
84
85
    uint16_t data = SPI.transfer16((registerAddress<<9) | (0x01<<8));
86
87
    digitalWrite(CS_PIN, HIGH);
88
89
    return data;
90
}

Die Ausgabe auf dem Seriellen Monitor:
1
-> Ausgabe im Setup:
2
Soft-Reset:   12
3
Mode_1:   65280
4
Dig_En:   65504
5
Mode_2:   12
6
Status0:   65280
7
Status1:   65424
8
Status2:   65436
9
Status3:   1 
10
11
-> Ausgabe beim lesen:
12
ID:   AD
13
xL_Data:   0
14
xH_Data:   0

Zusätzlich zu dem vorliegenden Code haben wir ebenfalls versucht die 
anderen Achsen und die Temperatur auszulesen und haben ebenfalls nur 0 
als Ausgabe bekommen. Vielleicht hat jemand eine Idee oder ein paar 
Tipps.
LG OLLI

: Bearbeitet durch User
von Keks F. (keksliebhaber)


Lesenswert?

Bit Shift um 8 bzw. 7 machen. Zaunpfosten Fehler.

von Oliver M. (oliver_martens)


Angehängte Dateien:

Lesenswert?

Danke für deine schnelle Antwort,

ich habe mal das Datenblatt beigefügt, auf Seite 49 wird dort das 
schreiben und lesen per SPI erklärt. Ich habe das Datenblatt so 
gedeutet, dass die Adresse insgesamt 7 Bit lang ist und in die Bits 9-15 
geschrieben wird, weswegen ich in meiner Funktion auch die Adresse um 9 
Bit shifte (von Bit 0 auf Bit 9) und der Read/Write Befehl liegt auf Bit 
8, weswegen ich das dann um 8 shifte. Vielleicht habe ich da auch einen 
Denkfehler. Könntest du mir deinen Ansatz etwas genauer erläutern.
LG Olli

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Probiers mal so:
1
  :
2
void writeRegister(uint8_t registerAddress, uint8_t value) {
3
  uint16_t command = (((uint16_t)registerAddress << 9) | value); 
4
  :
5
uint16_t readRegister(uint8_t registerAddress){
6
  uint16_t data = SPI.transfer16(((uint16_t)registerAddress<<9) | (0x01<<8));
7
  :
Das sollte der Compiler zwar von sich aus tun, aber hey, wer weiß. Das 
Oszi wäre hier wieder super, um zu sehen, ob auf dem Bus auch das 
unterwegs ist, was du erwartest.

Noch Tipp: die Bits 15..8 im empfangenen 16-Bit-Wort sind "undriven". 
Die solltest du also sinnigerweise spätestens bei der Anzeige 
ausblenden. Oder einfach nur 8 Bits zurückgeben:
1
uint8_t readRegister(uint8_t registerAddress){
2
:
3
    uint8_t data = SPI.transfer16((registerAddress<<9) | (0x01<<8));
4
:
5
    return data;

Interessant wäre hier auch, dass die Clockphase sicher zum Datenblatt 
passt. Denn sonst schreibst du evtl. die Adresse um 1 Bit versetzt.

: Bearbeitet durch Moderator
Beitrag #7915207 wurde vom Autor gelöscht.
von Oliver M. (oliver_martens)


Angehängte Dateien:

Lesenswert?

Das ist jetzt unser aktueller Code. Die Ausgabe ist jetzt etwas 
formatiert und ich habe die Verbesserung mit uint8_t bei readRegister() 
übernommen. Die Datentypkonvertierung mit (uint16_t) ist eine gute Idee 
gewesen, aber leider hat das auch keine Verbesserung ergeben.
Wir erhalten weiterhin bei allen Achsen 0 als Ausgabe und lesen derzeit 
alle 4 ID´s aus, wobei eine ID vom Datenblatt abweicht. Die ID unter der 
Adresse 0x03 sollte den Wert 0xC2 widergeben und wir erhalten eine 0xC1. 
Allerdings ist in dem Applications Examples (GitHub) in der ADXL38x.h 
auf der Analog Devices Seite zum ADXL380 auch als Rückgabewert 0xC1 
beschrieben.
Des weiteren haben wir den Status 0-3 weiter ausgewertet und haben 
"EFUSE-Fehler" lesen können:

Erweiterter Reset + NVM Control
1
writeRegister(0x2A, 0x52); //Seite 69
2
3
delay(10);
4
//NVM Control
5
writeRegister(0x29, 0b11000000);
6
delay(10);
Ausgabe:
1
Soft-Reset:     0x2  0b10
2
Mode_1:          0x0  0b0
3
Dig_En:          0xE0  0b11100000
4
Mode_2:          0xC  0b1100
5
Status0:  0x40  0b1000000
6
Status1:  0x80  0b10000000
7
Status2:  0x9C  0b10011100
8
Status3:  0x1  0b1
Erweiterter Reset
1
writeRegister(0x2A, 0x52); //Seite 69
2
3
delay(10);
Ausgabe:
1
Soft-Reset:     0x2  0b10
2
Mode_1:          0x0  0b0
3
Dig_En:          0xE0  0b11100000
4
Mode_2:     0xC  0b1100
5
Status0:  0x40  0b1000000
6
Status1:  0x80  0b10000000
7
Status2:  0x9C  0b10011100
8
Status3:  0x0  0b0
Erweiterter Reset mit Startdelay
1
delay(10);
2
writeRegister(0x2A, 0x52); 
3
4
delay(10);
Ausgabe:
1
Soft-Reset:     0x2  0b10
2
Mode_1:          0x0  0b0
3
Dig_En:          0xE0  0b11100000
4
Mode_2:          0xC  0b1100
5
Status0:  0x40  0b1000000
6
Status1:  0x80  0b10000000
7
Status2:  0x9C  0b10011100
8
Status3:  0x0  0b0
Soft-Reset
1
writeRegister(0x2A, 0b00000010); 
2
3
delay(10);
Ausgabe:
1
Soft-Reset:     0x0  0b10
2
Mode_1:          0x0  0b0
3
Dig_En:          0xE0  0b11100000
4
Mode_2:          0xC  0b1100
5
Status0:  0x0  0b0
6
Status1:  0x80  0b10000000
7
Status2:  0x9C  0b10011100
8
Status3:  0x1  0b1

Bei dem "erweiterte" Reset schreiben wir in das Reset-Register die 0x52, 
was einen sofortigen Reset zur Folge hat (S.69 im Datenblatt).
Zu erkennen ist, dass wir ohne "erweiterten" Reset NVM_Done (Bit 6) in 
Status 0  nicht gesetzt wird. Ansonsten haben wir das Problem bei alle 
Versuchen das Status 1  einen Error mit Bit 7 zum EFUSE Controller 
ausgibt und Status 2 mit Bit 3 einen EFUSE CRC Error ausgibt. Vielleicht 
haben wir auch eine Denkfehler, aber ich sehe gerade keine anderen 
Problem mehr und verstehe die EFUSE-Errors nur bedingt. Ich werde noch 
einmal den SPI-Bus mit dem Oszilloskop untersuchen und mich dann nochmal 
melden.

: Bearbeitet durch User
von Rainer W. (rawi)


Lesenswert?

Oliver M. schrieb:
> Ich werde noch einmal den SPI-Bus mit dem Oszilloskop untersuchen

Je nach dem, was du für ein Oszilloskp hast, kann das möglicherweise als 
Logikanalysator das SPI-Signal selbst dekodieren.
In dem Analyse-Dokument ist es wegen der geringen Zeitauflösung und der 
Überlagerung von Clock und Daten arg mühselig, irgendwelche Details 
bzgl. des Timings abzulesen.

: Bearbeitet durch User
von Thomas R. (dontmoan)


Lesenswert?

Moin,
ich kenne diesen Chip nicht, aber für die SPI Kommunikation ist kein 
eigenes Frame Format angegeben.
Bei anderen Chips heisst das, das exakt das I2C Frame Format benutzt 
werden muss. Also Byte1 Devadr+r/w, Byte2 regadr, byte2 Data.
Du machst nur 16bit transfers.
Und die Device Adresse sollte ja fix sein, je nachdem wie ASEL0/1 
stehen.
Könnte es daran liegen?

von Rahul D. (rahul)


Lesenswert?

Thomas R. schrieb:
> Also Byte1 Devadr+r/w, Byte2 regadr, byte2 Data.

SPI braucht keine DeviceAddress.
Das R/W-Bit wird an das Command-Byte (obere sieben Bit) als LSB 
angehängt.
Kapitel "Serial Communicatiom" im Datenblatt 
(https://www.analog.com/media/en/technical-documentation/data-sheets/adxl380.pdf 
- Seite 49)
Ob der Baustein ein Adress-Autoinkrement unterstützt, habe ich auf die 
Schnelle nicht gefunden. Normalerweise / von anderen Bausteinen wird 
sowas ja unterstützt.

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.