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...
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.
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
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...
Alles geht mit dem AD0 pin los! Ist der high or low bei dir? Denn der bestimmt die I2C Adresse.
:
Bearbeitet durch User
Das passt. das Who_am_I register kann ich ja fehlerfrei auslesen. Habs auch mit nem logic analyzer angeschaut. da stimmt alles
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
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 | }
|
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
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?
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?
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
Carsten M. schrieb: > I2C3_write(0xD2); // MPU9150_write Du hast den AD0 pin demnach wohl auf "1" gelegt oder?
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
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
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).
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.