www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik SPI ansteuerung von Gyro


Autor: Crashdemon (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?
void SPI_MasterInit(void)
{
  DDRB |= (1 << PB2) | (1 << PB3) | (1 << PB5); // Setze SS, MOSI and SCK as Ausgang
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Enable SPI, Master, set clock rate fck/16 = 250kHz
}

unsigned int SPI_talk(unsigned int tData)
{
  unsigned int rData, rData_1, rData_2;

  // Sende 8Bit großes Telegramm, bekomme als Antwort
  // 16Bit großes Telegramm
  PORTB &= (1 << PB2); // SS am Slave, low --> Beginn der Übertragung  

  SPDR = tData; // Start transmission
  while(!(SPSR & (1 << SPIF))) // Wait for transmission complete
  {
  }

  rData_1 = SPDR;

  while(!(SPSR & (1 << SPIF))) // Wait for transmission complete
  {
  }

  rData_2 = SPDR;

  rData = rData_1 + rData_2;

  return rData;

  PORTB |= (1 << PB2); // Datenübertragung beendet
}

unsigned int SPI_get_Measurement(void)
{
  unsigned int rData;
  unsigned int measurement = 0;
  unsigned int instruction[4] = {0b10010100, 0b10010100, 0b10000000, 0b10010000};

  rData = SPI_talk(instruction[0]); // Telegramm um ADC zu aktivieren
  rData = (rData >> 15);
  if(rData == 0) // Telegramm korrekt?
  {
    _delay_us(200);

    rData = SPI_talk(instruction[1]); // Telegramm um Messung zu starten
    rData = (rData >> 15);
    if(rData == 0) // Telegramm korrekt?
    {
      _delay_us(200);

      rData = SPI_talk(instruction[2]); // Rückgabe der Messung anfordern

      measurement = rData & 0b111111111111; // Die eigentlichen Daten der Messung
      rData = (rData >> 12) & 0b1010;
      if(rData == 0b0010)
      {
        _delay_us(200);
    
        rData = SPI_talk(instruction[3]); // ADC schlafen legen
        rData = (rData >> 15);
        _delay_us(200);
      }
    }
  }

  return measurement;
}

int main(void)
{
    unsigned int GYR_angle;

    SPI_MasterInit(); // SPI Bus Initialisieren

    while(1)
    {
        GYR_angle = SPI_get_Measurement();  
    }
}

Autor: Crashdemon (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt habe ich doch glatt das Datenblatt vergessen....

Autor: risu (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Crashdemon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmm,

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

Autor: Crashdemon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So habe den Code jetzt verbessert hoffe er ist jetzt richtig:
void SPI_MasterInit(void)
{
  DDRB |= (1 << PB2) | (1 << PB3) | (1 << PB5); // Setze SS, MOSI and SCK as Ausgang
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Enable SPI, Master, set clock rate fck/16 = 250kHz
}

unsigned int SPI_talk(unsigned int tData)
{
  unsigned int rData, rData_1, rData_2;

  // Sende 8Bit großes Telegramm, bekomme als Antwort
  // 16Bit großes Telegramm
  PORTB &= ~(1 << PB2); // SS am Slave, low --> Beginn der Übertragung  

  SPDR = tData; // Start transmission
  while(!(SPSR & (1 << SPIF))) // Wait for transmission complete
  {
  }

  rData_1 = SPDR;

  while(!(SPSR & (1 << SPIF))) // Wait for transmission complete
  {
  }

  rData_2 = SPDR;

  rData = rData_1 + rData_2;

  PORTB |= (1 << PB2); // Datenübertragung beendet

  return rData;
}

unsigned int SPI_get_Measurement(void)
{
  unsigned int rData;
  unsigned int measurement = 0;
  unsigned int instruction[4] = {0b10010100, 0b10010100, 0b10000000, 0b10010000};

  rData = SPI_talk(instruction[0]); // Telegramm um ADC zu aktivieren
  rData = (rData >> 15);
  if(rData == 0) // Telegramm korrekt?
  {
    _delay_us(200);

    rData = SPI_talk(instruction[1]); // Telegramm um Messung zu starten
    rData = (rData >> 15);
    if(rData == 0) // Telegramm korrekt?
    {
      _delay_us(200);

      rData = SPI_talk(instruction[2]); // Rückgabe der Messung anfordern

      measurement = rData & 0b111111111111; // Die eigentlichen Daten der Messung
      rData = (rData >> 12) & 0b1010;
      if(rData == 0b0010)
      {
        _delay_us(200);
    
        rData = SPI_talk(instruction[3]); // ADC schlafen legen
        rData = (rData >> 15);
        _delay_us(200);
      }
    }
  }

  return measurement;
}

int main(void)
{
    unsigned int GYR_angle;

    SPI_MasterInit(); // SPI Bus Initialisieren

    while(1)
    {
        GYR_angle = SPI_get_Measurement();  
    }
}


Autor: Dirk Schmidt (disc)
Datum:

Bewertung
0 lesenswert
nicht 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:

// Initialisierungsroutine
void SpiMasterInit( void )
   {
   // Ports konfigurieren
   // MOSI und SCK Output
   SPI_PORT_DDR |= _BV( SPI_MOSI_PIN ) | _BV( SPI_SCK_PIN );
   // MISO Input
   SPI_PORT_DDR &= ~_BV( SPI_MISO_PIN );
   // Rest Output
   SPI_SENSOR_CS_PORT |= _BV( SPI_SENSOR_CS1_PIN ) | _BV( SPI_SENSOR_CS2_PIN ) | _BV( SPI_SENSOR_CS3_PIN );
   SPI_SENSOR_CS_PORT_DDR |= _BV( SPI_SENSOR_CS1_PIN ) | _BV( SPI_SENSOR_CS2_PIN ) | _BV( SPI_SENSOR_CS3_PIN );

   // SPI konfigurieren
   // SPI enablen
   SPCR = _BV( SPE );
   // Interrupt enablen
   //SPCR |= _BV(SPIE);
   // Data order LSB first
   //SPCR |= _BV(DORD);
   // Master mode
   SPCR |= _BV( MSTR );
   // Clock polarity
   SPCR |= _BV( CPOL );
   // Clock phase
   SPCR |= _BV( CPHA );
   // Clock rate
   //SPCR |= _BV( SPR1 ) | _BV( SPR0 ); // F_CPU / 128
   SPSR |= _BV( SPI2X ); // * 2
   SPCR |= _BV( SPR1 ); // F_CPU / 64
   //SPCR |= _BV( SPR0 ); // F_CPU / 16

   return ;
   }


Gruß

Dirk

Autor: Crashdemon (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
void SPI_MasterInit(void)
{
  DDRB |= (1 << PB2) | (1 << PB3) | (1 << PB5); // Setze SS, MOSI and SCK as Ausgang
  DDRB &= ~(1 << PB4); // Miso als Eingang
  SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Enable SPI, Master, set clock rate fck/16 = 250kHz

  return;
}

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:
   SPCR = _BV( SPE );
   // Master mode
   SPCR |= _BV( MSTR );
   // Clock polarity
   SPCR |= _BV( CPOL );
   // Clock phase
   SPCR |= _BV( CPHA );
   // Clock rate
   //SPCR |= _BV( SPR1 ) | _BV( SPR0 ); // F_CPU / 128
   SPSR |= _BV( SPI2X ); // * 2
   SPCR |= _BV( SPR1 ); // F_CPU / 64
   //SPCR |= _BV( SPR0 ); // F_CPU / 16

bei mir ist das dann so:
   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.

Autor: Dirk Schmidt (disc)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Patrick L. (crashdemon)
Datum:

Bewertung
0 lesenswert
nicht 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
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0) | (1 << CPOL) | (1 << CPHA); // Enable SPI, Master, CLK = 250kHz, CLK_Polarity, CLK_Phase

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.