Forum: Mikrocontroller und Digitale Elektronik Problem mit I2C


von Andy (Gast)


Lesenswert?

Hallo,

Ich benutze das RD4247Mag3110-Evaluationskit von Freescale zum Aufbau
eines eKompasses.

Auf diesem Board befindet sich zum einen der
MMA8451Q-Beschleunigungssensor(3-Achsen) und der bereits erwähnte
Magnetfeldsensor MAG3110(3-Achsen).

Die beiden hängen an einem I2C-Bus.

Nun hab ich aber dass Problem, dass sich der Beschleunigungssensor ohne
Probleme auslesen lässt, aber der Magnetfeldsensor leider Probleme
macht.

Dieser liefert mir beim ACK-Bit bei richtiger Addressierung ein Bit mit
halber VCC, was der Master aber leider (natürlich) als NACK erkennt.
Adressiere ich den Magnetfeldsensor absichtlich falsch, liefert er mir
ein NACK mit normalem Pegel von VCC, wie es auch normalerweise sein
sollte.

An den Routinen kanns nicht legen, da der Beschleunigungssensor das
gleiche Kommunikationsprotokoll hat wie der Magnetfeldsensor, und dieser
ja funktioniert.

Ich habe bereits mehrere Pullups von 4,7k bis 1k versucht, leider ändert
sich hierbei nichts.

Bin momentan Ratlos, und wär für jeden Tip dankbar.

Gruß
Andy

von Sven B. (scummos)


Lesenswert?

Kannst du mal das Steuerprogramm für den Magnetfeldsensor posten? Ich 
hab das Ding auch (funktioniert gut), erinnere mich aber, dass es ein 
bisschen knifflig in Betrieb zu nehmen war.
Wenn ich daheim bin, poste ich mein Steuerprogramm mal.

von Andy (Gast)


Lesenswert?

Wär super von dir.

Hier mal der i2c-code, is momentan eh nur ganz simpel gehalten.
Wollte damit nur am anfang das auslesen der Register probieren.
1
#include <stdio.h>
2
3
#include "derivative.h" /* include peripheral declarations */
4
5
#define GPIO_PIN_MASK            0x1Fu
6
#define GPIO_PIN(x)              (((1)<<(x & GPIO_PIN_MASK)))
7
8
void transfer_complete(void);
9
  
10
int acceleration_x;
11
int acceleration_y;
12
int debug = 0;
13
14
15
int counter;
16
int i;
17
int test;
18
19
int main(void)
20
{
21
  
22
  // Turn on I2C0 clock
23
    SIM_SCGC4 |= 0xC0; 
24
        
25
  // Turn on all port clocks
26
    SIM_SCGC5 = SIM_SCGC5_PORTA_MASK | SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTE_MASK | SIM_SCGC5_PORTF_MASK;
27
28
  // Einstellen des Taktes MCGOUTCLK = 50 MHz
29
    MCG_C1 |= MCG_C1_CLKS(2);           // Externer Takt als Quelle
30
    
31
    PORTE_PCR19 = PORT_PCR_MUX(4); // SCL
32
    PORTE_PCR18 = PORT_PCR_MUX(4); // SDA 
33
    
34
  // I2C1 clock configuration
35
    I2C0_F = 0x23;              // I2C bus clock 100 kHz
36
37
  for(;;) {     
38
    // read out MMA7660FC tilt register to enable next interrupt  
39
    I2C0_C1 |= I2C_C1_IICEN_MASK;        // enable I2C0
40
      I2C0_C1 |= I2C_C1_MST_MASK;          // I2C0 is master, start condition
41
      for (i = 0; i < 100; i++);          // wait
42
      I2C0_C1 |= I2C_C1_TX_MASK;          // transmit mode  
43
      I2C0_D = 0x1C;                // MMA7660FC write address  1C/38
44
      transfer_complete();            // wait until transfer is complete
45
      if (I2C0_S & I2C_S_RXAK_MASK)
46
        printf("Fehler, kein ACK bekommen");
47
      I2C0_D = 0x07;                // address MMA7660FC tilt register  07/0D
48
      transfer_complete();            // wait until transfer is complete
49
      if (I2C0_S & I2C_S_RXAK_MASK)
50
        printf("Fehler, kein ACK bekommen");
51
      I2C0_C1 |= I2C_C1_RSTA_MASK;        // repeat start condition  
52
      for (i = 0; i < 100; i++);          // wait
53
      I2C0_D = 0x1D;                // MMA7660FC read address   1D/39
54
      transfer_complete();            // wait until transfer is complete
55
      if (I2C0_S & I2C_S_RXAK_MASK)
56
        printf("Fehler, kein ACK bekommen");
57
      I2C0_C1 &= ~I2C_C1_TX_MASK;          // receive mode
58
      I2C0_C1 |= I2C_C1_TXAK_MASK;        // no acknowledge needed
59
      acceleration_x = I2C0_D;          // dummy read to start receiving
60
      transfer_complete();            // wait until transfer is complete
61
      I2C0_C1 &= ~I2C_C1_MST_MASK;        // send stop condition
62
      acceleration_x = I2C0_D;          // read out data   
63
      I2C0_C1 &= ~I2C_C1_IICEN_MASK;        // disable I2C0
64
      
65
      printf("%d\n\r", acceleration_x);
66
      
67
      for (i = 0; i < 100000; i++);          // wait
68
      
69
  }
70
  
71
  return 0;
72
}
73
74
75
76
77
// function to test transfer complete flag
78
void transfer_complete(void)
79
{
80
  test = 1;
81
  while (test)
82
  {
83
    if (I2C0_S & I2C_S_TCF_MASK)
84
        {
85
          test = 0;
86
        }
87
  }
88
}

von Andy S. (andy87)


Lesenswert?

Sven B. schrieb:
> Ich
> hab das Ding auch (funktioniert gut), erinnere mich aber, dass es ein
> bisschen knifflig in Betrieb zu nehmen war.

Wenn du denn schon mal in Gebrauch hattest, würd mich interresieren 
welche Genauigkeit du mit dem MAG3110 erreicht hast. z.B wenn ich mich 
um 90°drehe, wie weit liegt man dann von den wirklichen 90° weg?

von Sven B. (scummos)


Lesenswert?

Andy S. schrieb:
> Sven B. schrieb:
>> Ich
>> hab das Ding auch (funktioniert gut), erinnere mich aber, dass es ein
>> bisschen knifflig in Betrieb zu nehmen war.
>
> Wenn du denn schon mal in Gebrauch hattest, würd mich interresieren
> welche Genauigkeit du mit dem MAG3110 erreicht hast. z.B wenn ich mich
> um 90°drehe, wie weit liegt man dann von den wirklichen 90° weg?

Kann ich Dir nicht sagen, weil ich bisher nicht in der Lage (bzw. eher 
zu faul) war, die Werte in Neigungswinkel umzurechnen. Das ist nicht 
ganz trivial, weil du ja sowas bekommst wie "Projektion des 
Magnetfeldvektors auf x, y, und z-Achse des Geräts", und der 
Magnetfeldvektor zeigt irgendwie schräg nach unten und nach Norden. Du 
bekommst also nichtmal Winkel raus, sondern eben die Projektionen dieses 
Vektors auf das Koordinatensystem, und daraus müsste man die Winkel 
erstmal errechnen, und dann noch richtig hindrehen (bzw. andersrum). *
Wenn man ein paar Werte mittelt, ist der Jitter aber ~1 Grad. Ich hab 
mal ein paar Objekte in Blender damit gedreht, das geht recht flüssig 
(bis darauf, dass die Winkel halt alle total komisch und falsch sind).

Zum eigentlichen Problem: Sendest Du denn keine Konfiguration an das 
Ding? Ich weiß nicht, was das tut, wenn Du alle Steuer-Register nicht 
initialisierst. Hier ist jedenfalls mal das, was ich mache (auf dem 
Raspberry Pi, deshalb ein bisschen mehr High-Level):
1
#include <errno.h>
2
#include <string.h>
3
#include <stdio.h>
4
#include <stdlib.h>
5
#include <unistd.h>
6
#include <i2c-dev.h>
7
#include <i2cbusses.h>
8
#include <util.h>
9
10
int main()
11
{
12
    int res, file;
13
    char filename[20] = "/dev/i2c-0";
14
    int axis = 0, byte = 0, count = 0;
15
    
16
    file = open_i2c_dev(0, filename, 0);
17
    set_slave_addr(file, 0x0e, 0);
18
    
19
    //                   DR(3)             OS(2)         FR(1)
20
    unsigned char reg0 = (0b000 << 5) + (0b00 << 3) +   (0 << 2)
21
    //                   TRIG(1)    ACT(1)
22
                        + (0 << 1) + (1 << 0);
23
    //                   ARST(1)   Res(1)  RAW(1)      RST(1)   Res(4)
24
    unsigned char reg1 = (0b1 << 7) +     (0b0 << 5) + (0b0 << 4);
25
    i2c_smbus_write_byte_data(file, 0x10, reg0);
26
    i2c_smbus_write_byte_data(file, 0x11, reg1);
27
    
28
    // x, y, z offset
29
    i2c_smbus_write_byte_data(file, 0x09, 0);
30
    i2c_smbus_write_byte_data(file, 0x0A, 0);
31
    i2c_smbus_write_byte_data(file, 0x0B, 0);
32
    i2c_smbus_write_byte_data(file, 0x0C, 0);
33
    i2c_smbus_write_byte_data(file, 0x0D, 0b11110110);
34
    i2c_smbus_write_byte_data(file, 0x0E, 0b11111111);
35
    
36
    float fullScale = 925.0;
37
    
38
    while ( 1 ) {
39
        count++;
40
        res = i2c_smbus_read_byte_data(file, 0x00);
41
        if ( res != 0xff )
42
            continue;
43
        for ( axis = 0; axis < 3; axis++ ) {
44
            int value = 0;
45
            for ( byte = 0; byte <= 1; byte++ ) {
46
                value += i2c_smbus_read_byte_data(file, axis*2 + 1 + byte) << (1-byte)*8;
47
            }
48
            if ( value >= (1 << 15) ) {
49
                value -= 1 << 16;
50
            }
51
            printf("%i ", (int) ( value / fullScale ));
52
        }
53
        printf("\n");
54
        fflush(stdout);
55
    }
56
    exit(0);
57
}

Als Slave Address habe ich irgendwie 0x0e, das ist anders als bei Dir, 
oder?

Grüße,
Sven

_______

* P.S.: Wenn jemand Code dafür hat, den nehme ich gern! :D

von Andy (Gast)


Lesenswert?

Hab auch schon probiert, vorher die register zu konfigurieren, leider 
kann ich ja ned mit dem Baustein sprechen, was die sache erschwert;:).

Die Adresse ist 0x0E, hab ich auch. Du betreibst den baustein alleine am 
bus oder?

Ich werds morgen auch mal mitn raspberry pi ausprobieren, vielleicht 
gehts so.

Aber weshalb mein ACK bei halb Vcc liegt weiss keiner oder?
Deshalb funzt die kommunikation leider nicht.

von Sven B. (scummos)


Angehängte Dateien:

Lesenswert?

Ah, du hast ein Raspberry Pi? Das ist ja günstig, dann kannst du ja 
einfach mal meinen Code probieren. Wenn's damit funktioniert, wissen wir 
immerhin, ob es an der Software oder an der Hardware liegt.

Der Baustein ist bei mir allein am Bus, ja.

Wegen des ACK habe ich leider überhaupt keine Ahnung.

Im Anhang der Code mit Makefile und so.

von Andy (Gast)


Lesenswert?

Jep, werd ich morgen dann mal ausprobieren. Sobald ich mehr weiss, werd 
ich meine Erkenntnise morgen dann posten.

von Andy S. (andy87)


Lesenswert?

Also ich hab das Problem gelöst, wobei die Lösung schon sehr komisch 
ist.

Hab jetzt 14,7k Pullups drin, jetzt liegt der Pegel des ACK endlich bei 
<0,3VCC.

Entweder ist auf dem Board ein riesen Serienwiederstand drin, oder der 
Open-Kollektor Transister des MAG3110 kann den Transistor nicht komplett 
durchschalten, wobei ich nicht weiss warum und weshalb er das nicht 
machen sollte.

Mit FAST-I2C wirds dann wahrscheinlich nichts mehr bei den Pullups:).

von Sven B. (scummos)


Lesenswert?

Ich hab das Ding genau so aufgebaut wie im Datenblatt beschrieben [1] 
und bei mir funktioniert es anstandslos. Weiß ich dann auch nicht. ;)

___
[1] Foto: 
http://2.bp.blogspot.com/-ymnNCx3JuYI/ULF1COlw4kI/AAAAAAAAAPw/BSSYQvIiNZ4/s1600/magnetometer_front.jpg

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.