MPU-9150 Register auslesen

Gast #3455922
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...
Gast #3456255
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.
Gast #3456760
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...
Gast #3456816
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
#3456847
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
}
#3459089
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?
Angehängte Dateien:
Gast #3459180
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
Angehängte Dateien:
#3459281
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?
Gast #3459438
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
Angehängte Dateien:
#3459528
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).
Angehängte Dateien:
Gast #3459798
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
#3460784
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ß

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren