Forum: Mikrocontroller und Digitale Elektronik SPI ansteuerung von Gyro


von Crashdemon (Gast)


Lesenswert?

Hallo,

habe mir einen Gyro (MLX90609) von Melexis auf einer Platine von 
Sparkfun besorgt. Will diesen per SPI ansteuern, bin mir aber noch nicht 
ganz im klaren wie das funktioniert, SCLK, MOSI, MISO und SS hab ich mit 
den entsprechenden Ports am Atmega 8 verbunden, allerdings hapert es 
weniger an der Hardware Technischen umsetzung als an dem C Code zum 
auslesen der Messwerte, hab ihn hier mit mal mit drangehängt weil im 
Anhang schon das Datenblatt der Sensors ist. Wich würde interessieren ob 
die umsetzung wie ich sie gemacht habe so gehen würde?
1
void SPI_MasterInit(void)
2
{
3
  DDRB |= (1 << PB2) | (1 << PB3) | (1 << PB5); // Setze SS, MOSI and SCK as Ausgang
4
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Enable SPI, Master, set clock rate fck/16 = 250kHz
5
}
6
7
unsigned int SPI_talk(unsigned int tData)
8
{
9
  unsigned int rData, rData_1, rData_2;
10
11
  // Sende 8Bit großes Telegramm, bekomme als Antwort
12
  // 16Bit großes Telegramm
13
  PORTB &= (1 << PB2); // SS am Slave, low --> Beginn der Übertragung  
14
15
  SPDR = tData; // Start transmission
16
  while(!(SPSR & (1 << SPIF))) // Wait for transmission complete
17
  {
18
  }
19
20
  rData_1 = SPDR;
21
22
  while(!(SPSR & (1 << SPIF))) // Wait for transmission complete
23
  {
24
  }
25
26
  rData_2 = SPDR;
27
28
  rData = rData_1 + rData_2;
29
30
  return rData;
31
32
  PORTB |= (1 << PB2); // Datenübertragung beendet
33
}
34
35
unsigned int SPI_get_Measurement(void)
36
{
37
  unsigned int rData;
38
  unsigned int measurement = 0;
39
  unsigned int instruction[4] = {0b10010100, 0b10010100, 0b10000000, 0b10010000};
40
41
  rData = SPI_talk(instruction[0]); // Telegramm um ADC zu aktivieren
42
  rData = (rData >> 15);
43
  if(rData == 0) // Telegramm korrekt?
44
  {
45
    _delay_us(200);
46
47
    rData = SPI_talk(instruction[1]); // Telegramm um Messung zu starten
48
    rData = (rData >> 15);
49
    if(rData == 0) // Telegramm korrekt?
50
    {
51
      _delay_us(200);
52
53
      rData = SPI_talk(instruction[2]); // Rückgabe der Messung anfordern
54
55
      measurement = rData & 0b111111111111; // Die eigentlichen Daten der Messung
56
      rData = (rData >> 12) & 0b1010;
57
      if(rData == 0b0010)
58
      {
59
        _delay_us(200);
60
    
61
        rData = SPI_talk(instruction[3]); // ADC schlafen legen
62
        rData = (rData >> 15);
63
        _delay_us(200);
64
      }
65
    }
66
  }
67
68
  return measurement;
69
}
70
71
int main(void)
72
{
73
    unsigned int GYR_angle;
74
75
    SPI_MasterInit(); // SPI Bus Initialisieren
76
77
    while(1)
78
    {
79
        GYR_angle = SPI_get_Measurement();  
80
    }
81
}

von Crashdemon (Gast)


Angehängte Dateien:

Lesenswert?

Jetzt habe ich doch glatt das Datenblatt vergessen....

von risu (Gast)


Lesenswert?

Hallo,

Deinen Code habe ich mir nur bis zu den ersten 2 Stellen angesehen, die 
ich für fehlerhaft halte:
  PORTB &= (1 << PB2); // SS am Slave, low --> Beginn der Übertragung
Damit hältst Du PB2 auf H, wenn es schon H ist, was Deinem Kommentar 
widerspricht, und setzt MOSI + CLK auf L. Meinst Du vielleicht (?)
   PORTB &= ~(1 << PB2); // SS=L

Später schreibst Du:
  return rData;
  PORTB |= (1 << PB2); // Datenübertragung beendet

Die Funktion wird mit dem "return" beendet und die "PORTB="-Anweisung 
nie ausgeführt.

Gruß

 risu

von Crashdemon (Gast)


Lesenswert?

Hmm,

ok werde die folgenden Punkte verbessern und dann den verbesserten Code 
nochmal posten.

von Crashdemon (Gast)


Lesenswert?

So habe den Code jetzt verbessert hoffe er ist jetzt richtig:
1
void SPI_MasterInit(void)
2
{
3
  DDRB |= (1 << PB2) | (1 << PB3) | (1 << PB5); // Setze SS, MOSI and SCK as Ausgang
4
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Enable SPI, Master, set clock rate fck/16 = 250kHz
5
}
6
7
unsigned int SPI_talk(unsigned int tData)
8
{
9
  unsigned int rData, rData_1, rData_2;
10
11
  // Sende 8Bit großes Telegramm, bekomme als Antwort
12
  // 16Bit großes Telegramm
13
  PORTB &= ~(1 << PB2); // SS am Slave, low --> Beginn der Übertragung  
14
15
  SPDR = tData; // Start transmission
16
  while(!(SPSR & (1 << SPIF))) // Wait for transmission complete
17
  {
18
  }
19
20
  rData_1 = SPDR;
21
22
  while(!(SPSR & (1 << SPIF))) // Wait for transmission complete
23
  {
24
  }
25
26
  rData_2 = SPDR;
27
28
  rData = rData_1 + rData_2;
29
30
  PORTB |= (1 << PB2); // Datenübertragung beendet
31
32
  return rData;
33
}
34
35
unsigned int SPI_get_Measurement(void)
36
{
37
  unsigned int rData;
38
  unsigned int measurement = 0;
39
  unsigned int instruction[4] = {0b10010100, 0b10010100, 0b10000000, 0b10010000};
40
41
  rData = SPI_talk(instruction[0]); // Telegramm um ADC zu aktivieren
42
  rData = (rData >> 15);
43
  if(rData == 0) // Telegramm korrekt?
44
  {
45
    _delay_us(200);
46
47
    rData = SPI_talk(instruction[1]); // Telegramm um Messung zu starten
48
    rData = (rData >> 15);
49
    if(rData == 0) // Telegramm korrekt?
50
    {
51
      _delay_us(200);
52
53
      rData = SPI_talk(instruction[2]); // Rückgabe der Messung anfordern
54
55
      measurement = rData & 0b111111111111; // Die eigentlichen Daten der Messung
56
      rData = (rData >> 12) & 0b1010;
57
      if(rData == 0b0010)
58
      {
59
        _delay_us(200);
60
    
61
        rData = SPI_talk(instruction[3]); // ADC schlafen legen
62
        rData = (rData >> 15);
63
        _delay_us(200);
64
      }
65
    }
66
  }
67
68
  return measurement;
69
}
70
71
int main(void)
72
{
73
    unsigned int GYR_angle;
74
75
    SPI_MasterInit(); // SPI Bus Initialisieren
76
77
    while(1)
78
    {
79
        GYR_angle = SPI_get_Measurement();  
80
    }
81
}

von Dirk S. (disc)


Lesenswert?

Hallo Crashdemon,
ich glaube, bei Deiner SPI-Initialisierung fehlen ein noch paar 
Parameter.

Ich arbeite auch mit den Melexis Sensoren und habe das SPI 
folgendermaßen initialisiert:

1
// Initialisierungsroutine
2
void SpiMasterInit( void )
3
   {
4
   // Ports konfigurieren
5
   // MOSI und SCK Output
6
   SPI_PORT_DDR |= _BV( SPI_MOSI_PIN ) | _BV( SPI_SCK_PIN );
7
   // MISO Input
8
   SPI_PORT_DDR &= ~_BV( SPI_MISO_PIN );
9
   // Rest Output
10
   SPI_SENSOR_CS_PORT |= _BV( SPI_SENSOR_CS1_PIN ) | _BV( SPI_SENSOR_CS2_PIN ) | _BV( SPI_SENSOR_CS3_PIN );
11
   SPI_SENSOR_CS_PORT_DDR |= _BV( SPI_SENSOR_CS1_PIN ) | _BV( SPI_SENSOR_CS2_PIN ) | _BV( SPI_SENSOR_CS3_PIN );
12
13
   // SPI konfigurieren
14
   // SPI enablen
15
   SPCR = _BV( SPE );
16
   // Interrupt enablen
17
   //SPCR |= _BV(SPIE);
18
   // Data order LSB first
19
   //SPCR |= _BV(DORD);
20
   // Master mode
21
   SPCR |= _BV( MSTR );
22
   // Clock polarity
23
   SPCR |= _BV( CPOL );
24
   // Clock phase
25
   SPCR |= _BV( CPHA );
26
   // Clock rate
27
   //SPCR |= _BV( SPR1 ) | _BV( SPR0 ); // F_CPU / 128
28
   SPSR |= _BV( SPI2X ); // * 2
29
   SPCR |= _BV( SPR1 ); // F_CPU / 64
30
   //SPCR |= _BV( SPR0 ); // F_CPU / 16
31
32
   return ;
33
   }

Gruß

Dirk

von Crashdemon (Gast)


Lesenswert?

Hallo, ja ich glaube bei mir fehlte echt was, hab meine initialisierung 
um die Definition von MISO als Ausgang erweitert, sieht jetzt 
folgendermaßen aus:
1
void SPI_MasterInit(void)
2
{
3
  DDRB |= (1 << PB2) | (1 << PB3) | (1 << PB5); // Setze SS, MOSI and SCK as Ausgang
4
  DDRB &= ~(1 << PB4); // Miso als Eingang
5
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Enable SPI, Master, set clock rate fck/16 = 250kHz
6
7
  return;
8
}

sonst ist ja alles wie bei dir, nur das du die Bits des SPCR Registers 
jeweils einzeln setzts und ich dass in einer zeile mache.

deine variante:
1
   SPCR = _BV( SPE );
2
   // Master mode
3
   SPCR |= _BV( MSTR );
4
   // Clock polarity
5
   SPCR |= _BV( CPOL );
6
   // Clock phase
7
   SPCR |= _BV( CPHA );
8
   // Clock rate
9
   //SPCR |= _BV( SPR1 ) | _BV( SPR0 ); // F_CPU / 128
10
   SPSR |= _BV( SPI2X ); // * 2
11
   SPCR |= _BV( SPR1 ); // F_CPU / 64
12
   //SPCR |= _BV( SPR0 ); // F_CPU / 16

bei mir ist das dann so:
1
   SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Enable SPI, Master, set clock rate fck/16 = 250kHz

kannst ja mal deinen Code posten den du zum Auslesen des MLX benutzt, 
dan kann ich den mit meinen Vergleichen und schauen ob ich da noch 
fehler drin habe, ich bin mir da speziell mit den Telegrammen die ich 
versende nicht ganz sicher, da ich ja jeweils immer nur ein 1 Byte 
größes sende, er aber eigentlich ein 3 Byte großes erwartet.

von Dirk S. (disc)


Lesenswert?

Hallo,
Du darfst CPOL und CPHA nicht vergessen, sonst wird das mit der 
Kommunikation wohl nicht klappen.

Das ganze SPI/Gyro Modul von mir ist etwas zu lang und unsortiert, um es 
hier zu posten. Kannst mir bei Interesse ja eine PM mit deiner 
EMail-Adresse schicken, dann sende ich es Dir gerne zu.

Gruß

Dirk

von Patrick L. (crashdemon)


Lesenswert?

Dirk Schmidt wrote:
> Hallo,
> Du darfst CPOL und CPHA nicht vergessen, sonst wird das mit der
> Kommunikation wohl nicht klappen.
>

Ok, so hab meine Code mal geändert
1
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0) | (1 << CPOL) | (1 << CPHA); // Enable SPI, Master, CLK = 250kHz, CLK_Polarity, CLK_Phase

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.