Forum: Mikrocontroller und Digitale Elektronik MPU-9150 Register auslesen


von Tim (Gast)


Lesenswert?

Hallo,
Ich arbeite gerade an einer anwendung mit dem beschleunigungssensor 
MPU-9150 von Invensense. Da ich Assembler benutze muss ich mir leider 
alles selbst zusammenbasteln und kann nicht auf APIs zurückgreifen.

Zuerst habe ich die I²C Verbindung überprüft indem ich das WHO_AM_I 
register (0x75) ausgelesen habe. Laut Datenblatt hat dieses 
Stamdartmäßig den Wert 0x68. Das stimmt auch mit dem überein was ich 
empfange.

Daher habe ich als nächstes die interessanteren Register in angriff 
genommen. Zuerst TEMP_OUT_H und TEMP_OUT_L (0x41,0x42) In diesen 
Registern soll der Wert des Temperatursensors stehen. Allerdings lese 
ich immer nur 0x00. Auch alle anderen Register werden mit 0x00 als Wert 
gelesen. Woran kann das liegen? Hat jemand das IC schonmal benutzt? Muss 
ich zuerst einstellungen vornehmen um die Messungen zu aktivieren? Habe 
soetwas weder im Datenblatt noch in der Register Map gefunden.

Irgendwie komme ich da nicht weiter...

von gustl (Gast)


Lesenswert?

Gab es da nicht irgendein Sleepmode-Register, welches man zuerst 
beschreiben muss?

Übrigens mal dumm gefragt: Warum willst Du einen komplexen 6-Achsen 
Intertialsensor mit Assembler ansteuern? Ich kann mir wirklich kaum 
einen Einsatzzweck vorstellen, der so etwas rechtfertigt.

von Raphael F. (erdbewohner)


Lesenswert?

genau, du musst zuerst im Register 0x6B den Sleep-Mode ausschalten

von Tim (Gast)


Lesenswert?

gustl schrieb:
> Übrigens mal dumm gefragt: Warum willst Du einen komplexen 6-Achsen
> Intertialsensor mit Assembler ansteuern?

Die Antwort ist so einfach wie traurig: Ich kann nichts anderes...  ;)

Raphael F. schrieb:
> genau, du musst zuerst im Register 0x6B den Sleep-Mode ausschalten

Werds gleich testen. Danke schonmal für die hilfe

von Tim (Gast)


Lesenswert?

Funktioniert leider nicht.
Im register 0x6B befindet sich zwar das bit "SLEEP" allerdings ist in 
der beschreibung erläutrt, das der Sensor bei einer 1 in SLEEP in den 
Sleepmodus wechselt. Da aber alle register beim reset den Wert 0 haben 
dürfte er doch garnicht im Sleepmode sein oder?
ein schreiben mit dem Wert 0b11000000 (Reset und Sleep) oder 0b10000000 
(Reset) brachte nicht den erwarteten Erfolg: weiterhin alle Sensor 
Register=0.

Ohne API ist dieser Chip irgendwie die reinste Qual.
Die in der Werbung hochgelobte DMP (digital motion processing)ist auch 
nicht auffindbar...

von Carsten M. (ccp1con)


Lesenswert?

Alles geht mit dem AD0 pin los!
Ist der high or low bei dir?

Denn der bestimmt die I2C Adresse.

: Bearbeitet durch User
von Tim (Gast)


Lesenswert?

Das passt.
das Who_am_I register kann ich ja fehlerfrei auslesen.
Habs auch mit nem logic analyzer angeschaut. da stimmt alles

von Tim (Gast)


Lesenswert?

Vllt kann ja mal einer posten wie die AIP das macht. Also allein die 
logischen schritte das man was was da eigentlich passiert. Besonders 
interessant wäre hier natürlich auhc die initialisierung da ich glaube 
das mein Problem hier liegt

von Carsten M. (ccp1con)


Lesenswert?

Das ist, was ich gemacht habe ... ohne API ...


1
void configure_for_INT2_PID_stabi_ctrl(const Word INT2_interval_ms)
2
{
3
     Word  Gyro_Output_Rate_Hz;
4
     Bool on_off;
5
6
     on_off = (INT2_interval_ms > 0);
7
8
     memset((void *) &MPU9150_Registers, 0, sizeof (MPU9150_Registers));
9
10
     //OPTION we can play with Bandwidth
11
     MPU9150_Registers._0x1A_Config.EXT_SYNC_SET = no;
12
     MPU9150_Registers._0x1A_Config.DLPF_CFG = DLPF_20_kHz;
13
14
     if (MPU9150_Registers._0x1A_Config.DLPF_CFG > DLPF_off)
15
     {
16
          Gyro_Output_Rate_Hz = 1000; // if filter is on - 1 kHz
17
     }
18
     else
19
     {
20
          Gyro_Output_Rate_Hz = 8000; // without filter - 8 kHz
21
     }
22
23
     MPU9150_Registers._0x19_Sample_rate_divider = (Gyro_Output_Rate_Hz / (1000.0/INT2_interval_ms) - 1);
24
25
     //OPTION we can play with full scale range
26
     MPU9150_Registers._0x1B_Gyro_config.FS_SEL = _2000_Grad_pro_Sekunde;
27
     switch (MPU9150_Registers._0x1B_Gyro_config.FS_SEL)
28
     {
29
             case _250_Grad_pro_Sekunde : MPU9150_Data.OMEGA_scale_factor = 131.0; break;
30
             case _500_Grad_pro_Sekunde : MPU9150_Data.OMEGA_scale_factor = 65.5; break;
31
             case _1000_Grad_pro_Sekunde : MPU9150_Data.OMEGA_scale_factor = 32.8; break;
32
             case _2000_Grad_pro_Sekunde : MPU9150_Data.OMEGA_scale_factor = 16.4; break;
33
     };
34
35
     MPU9150_Registers._0x1C_Accel_config.AFS_SEL = _scale_16g;
36
     switch (MPU9150_Registers._0x1C_Accel_config.AFS_SEL)
37
     {
38
             case _scale_2g : MPU9150_Data.ACC_scale_factor = 16384.0; break;
39
             case _scale_6g : MPU9150_Data.ACC_scale_factor = 8192.0; break;
40
             case _scale_8g : MPU9150_Data.ACC_scale_factor = 4096.0; break;
41
             case _scale_16g : MPU9150_Data.ACC_scale_factor = 2048.0; break;
42
     };
43
44
     MPU9150_Registers._0x1C_Accel_config.ACCEL_HPF = no;
45
46
     MPU9150_Registers._0x24_I2C_master_control.WAIT_FOR_ES = no;
47
     MPU9150_Registers._0x24_I2C_master_control.I2C_MST_CLK = _400kHz;
48
49
// I2C Slave 0 AK8975C Magnetometer read out data
50
     MPU9150_Registers._0x25_Slave0._7bit_address = AK8975C_7bit_address;
51
     MPU9150_Registers._0x25_Slave0._RW = I2C_read;
52
     MPU9150_Registers._0x26_Slave0.Reg_address = AK8975C_Status1_address;
53
     MPU9150_Registers._0x27_Slave0.Lenght = 8;
54
     MPU9150_Registers._0x27_Slave0.Enable = yes;
55
56
// I2C Slave 1 AK8975C Magnetometer write/start new meassurement
57
     MPU9150_Registers._0x28_Slave1._7bit_address = AK8975C_7bit_address;
58
     MPU9150_Registers._0x28_Slave1._RW = I2C_write;
59
     MPU9150_Registers._0x29_Slave1.Reg_address = AK8975C_cntrl2_address;
60
     MPU9150_Registers._0x64_Slave1_Data_Out = single_meass_mode;
61
     MPU9150_Registers._0x2A_Slave1.Lenght = 1;
62
     MPU9150_Registers._0x2A_Slave1.Enable = yes;
63
64
     MPU9150_Registers._0x38_INT_enable.DATA_RDY_EN = yes;
65
     MPU9150_Registers._0x38_INT_enable.I2C_MST_INT_EN = yes;
66
67
     MPU9150_Registers._0x6A_User_control.I2C_MST_EN = 1;
68
69
     if (on_off) // turn on
70
     {
71
          MPU9150_Registers._0x6B_Power_management_1.CLKSEL = PLL_with_X_axis;
72
          MPU9150_Registers._0x6B_Power_management_1.SLEEP = no;
73
     }
74
     else // turn off
75
     {
76
          MPU9150_Registers._0x6B_Power_management_1.CLKSEL = PLL_Stop;
77
          MPU9150_Registers._0x6B_Power_management_1.SLEEP = yes;
78
     }
79
     MPU9150_Registers._0x6B_Power_management_1.CYCLE = no;
80
81
     burst_write_MPU9150(0x19, (Byte*)&MPU9150_Registers._0x19_Sample_rate_divider, 27); // von 0x19 - 0x34
82
     burst_write_MPU9150(0x37, (Byte*)&MPU9150_Registers._0x37_INT_pin_configuration, 2); // 0x37 und 0x38
83
     burst_write_MPU9150(0x63, (Byte*)&MPU9150_Registers._0x63_Slave0_Data_Out, 10); // 0x63 und 0x6C
84
85
     //INT2
86
     INTCON2bits.INT2EP = 1; // interrupt on negative edge
87
     IFS1bits.INT2IF = clear; // Reset INT1 interrupt flag
88
     IPC7bits.INT2IP = priority_Int2;
89
     IEC1bits.INT2IE = on_off; // Enable INT1 Interrupt Service Routine
90
91
    INT2_dt = 1;
92
    set_PID_factors_XY (35.00, 00.00, 9.00); // PD regler
93
    set_PID_factors_Z (08.40, 04.00, 00.00); // PI regler
94
    set_PID_timing_XYZ (00.90, INT2_interval_ms); // T, PR1
95
96
}

von Carsten M. (ccp1con)


Lesenswert?

Wenn alle Register nach dem Reste null sind - was willst du dann lesen? 
Und von alleine produziert der Chip keine Daten(glaube ich). Also muss 
er erst konfiguriert werden.

: Bearbeitet durch User
von Tim (Gast)


Lesenswert?

wenn du in das Register 0x1A etwas geschrieben hast (z.B. $04 für 20Hz) 
und du dieses dann gleich wieder liest kommt bei mir auch 0 zurück. Das 
kann doch eigentlich nicht sein oder?

von Carsten M. (ccp1con)


Angehängte Dateien:

Lesenswert?

Hi Tim,

natürlich liest man den Wert zurück, den man vorher (erfolgreich) 
geschrieben hat! Falls das bei dir nicht der Fall ist, könnte es sein, 
dass deine I2C write procedure nicht so tut wie sie soll ... denn das 
Lesen funzt ja offensichtlich.

Das ist mein pseudo code:
1
void burst_write_MPU9150(const Byte Reg_addr, Byte* Data, Byte count)
2
{
3
     disable_Interrupts;
4
5
     I2C3_start;
6
     I2C3_write(0xD2); // MPU9150_write
7
     I2C3_write(Reg_addr);
8
9
     do
10
     {
11
          I2C3_write(*Data++);
12
          count--;
13
14
     } while (count > 0);
15
16
     I2C3_stop;
17
18
     enable_Interrupts;
19
}

Stimmt deine Schreibadresse?

von Tim (Gast)


Angehängte Dateien:

Lesenswert?

Für mich sieht es aus als würde das write procedure stimmen. Ist ähnlich 
wie bei dir.
Die schreib/leseadresse ist 0x1A und der Wert der geschrieben werden 
soll ist 4.
Habe mal schreib und leseprozess als Bild angehängt. Villeicht ist ja 
doch ein doofer Fehler drin. Die clk Frequenz ist ca. 400kHz und 
zwischen stop von schreiben und start von lesen liegen ca 0.012 ms.
Bis auf den Zurückgegebenen wert scheint alles zu passen.

(getriggert wurde bei fallender Flanke der Datenleitung. Daher ist die 
erste start kondition nicht gut zu erkennen.)

Grüße Tim

von Tim (Gast)


Lesenswert?

Carsten M. schrieb:
> I2C3_write(0xD2); // MPU9150_write

Du hast den AD0 pin demnach wohl auf "1" gelegt oder?

von Carsten M. (ccp1con)


Lesenswert?

Ja AD0 ist high bei mir.
Bei dir also low.
Demnach die Adressen 0xD0 schreiben und 0xD1 lesen.

Vielleicht sehe ich falsch aber beim schreiben - 0xD01A04 sehe ich die 
Registeradresse 0x1A nicht. Das kommt was anderes!? oder ist das das 
ACK.
Weiß gerade nicht ...

an Pos. 9 ist ACK und dann kommt aber gleich ne 1, wieso?

: Bearbeitet durch User
von Tim (Gast)


Angehängte Dateien:

Lesenswert?

Hi Carsten,
An dieser stelle erstmal vielen Dnak für deine Mühe! Super das einem 
hier echt geholfen wird!!

Carsten M. schrieb:
> Vielleicht sehe ich falsch aber beim schreiben - 0xD01A04 sehe ich die
> Registeradresse 0x1A nicht

Die Adresse ist da. Zur übersichtlichkeit habe ich die beiden Bilder 
nochmal bearbeitet.

Carsten M. schrieb:
> an Pos. 9 ist ACK und dann kommt aber gleich ne 1, wieso?

Habe ich mich auch schon gefragt...
Ich bin zu dem Schluss gekommen das dies der IDLE Zustand des Busses 
sein müsste. Wahrscheinlich wird keine "1" gesendet sondern beide 
Teilnehmer lassen den Bus los. Dieser wird dann auf High gezogen. Ist 
aber nur meine Vermutung...

Kann die Ursache des Problems in einer fehlerhaften Verlötung liegen? 
Also ein Pin kein Kontakt zur Platine o.ä. Bei diesen Bauformen weis man 
ja nie...
Das wäre das letzte was mir noch einfallen würde.

Grüße
Tim

von Carsten M. (ccp1con)


Angehängte Dateien:

Lesenswert?

Ich habe gerade nichts zu tun ...
Hier mal, wie es bei mir aussieht.
Also den high state nach dem 9ten Bit gibt's bei mir nicht. Könnte mir 
vorstellen, dass das der MPU nicht gefällt.

Welchen Controller benutzt du eigentlich? Stimmt mit der I2C config was 
nicht. (bin jetzt auch nicht so der Bus Profi).

von Tim (Gast)


Lesenswert?

Problem Fixed! :D

Ich habe jetzt das Register 0x6B auf 0 gesetzt. (Reset:0x40)
Der MPU erwartet nach dem Reset offenbar eine externe Frequenz von 
32,768kHz.
die gab es in meiner Schaltung jedoch nicht. Also habe ich auf interne 
8MHz umgestellt und siehe da: alles funktioniert. Offenbar speichert der 
9150 auch keine Werte in anderen Registern solange keine Clock da ist.
Jetzt werden die übertragenen Werte zurück gegeben und alles tut wie es 
soll.

Carsten M. schrieb:
> Also den high state nach dem 9ten Bit gibt's bei mir nicht

Ich glaube mein Analyzer interpretiert die spikes nach dem ACK als High. 
Hat halt nur digitale Eingänge.

Eine Frage habe ich aber noch. Weist du was es mit dieser DMP auf sich 
hat. Laut beschreibung verarbeitet die ja schon die Daten und man kann 
sie dann in verschiedenen Varianten abrufen. Das steht zwar ein paar mal 
im DS aber wie das ganze Funktioniert wird nirgens erwähnt.

Ich denke mit Assembler wird eine solche Verarbeitung sehr schwierig. 
Desshalb wäre diese DMP enorm praktisch.

Grüße und Danke nochmal
Tim

von Carsten M. (ccp1con)


Lesenswert?

Als ich mich darüber informiert hatte, musste man erst ein gutes Stück 
firmware hochladen, bevor man DMP nutzen konnte ... Aber das hexfile 
wurde von Invensense nur an Firmenkunden herausgegeben. Aber im Netz war 
einiges darüber zu finden. Kann aber sein, dass es heute anders ist.

Gruß

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.