mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik SPI ist komisch


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Leute,

ich krieg noch eine Krise, ich versuche jetzt schon stunden lang eine 
SPI Kommunikation auf zu bauen und es geht einfach nicht.

Konkret soll mein µC mit einer SD Karte und mit einem Messchip (CS5463) 
kommunizieren. (die SD Karte ist jetzt einmal egal, ich versuche mich 
gerade am Messchip).

auf PB4 hängt SS von Messchip und auf PB3 der von SD Karte.
Hier schonmal meine erste Frage (mein erster Verdacht, wo Fehler liegen 
könnte):
/*******************************************************
  Funktion :    Wähle Messchip aus
  Eigenschaften:  PB4 als Ausgang => auf low
  Übergabewert:  -
  Rückgabewert:  -
********************************************************/
void SPI_select_Messchip(void)
{
  DDR_SPI = (1 << PB3) | ( 1 << PB4);  // 3 & 4 als Ausgang
  PORTB |= (1 << PB3);         // SD-Karte CS ausschalten
  PORTB &= ~(1 << PB4);        // Messchip CS einschalten (löschen von PB4)
}



/*******************************************************
  Funktion :    Wähle SD-Karte aus
  Eigenschaften:  PB 3 als Ausgang => auf low
  Übergabewert:  -
  Rückgabewert:  -
********************************************************/
void SPI_select_SDcard(void)
{
  DDR_SPI = (1 << PB3) | ( 1 << PB4);  // 3 & 4 als Ausgang
  PORTB |= (1 << PB4);         // Messchip CS ausschalten
  PORTB &= ~(1 << PB3);        // SD-Karte CS einschalten (löschen von PB3)
}

Stimmt diese zuordnung, also das dann damit wirklich der Messchip 
ausgewählt ist???

so jetzt habe ich folgendes Verhalten:

Wenn ich SPI_select_Messchip(); aufrufe und danach SPI_init(); und 
folgenden Code aufrufe:
SPI_send_start_conversions();
SPI_send_sync1();

Bleibt es beim 2ten mal Send hängen. (Im Prinzip ist egal was bei 
send_sycn1 usw. drinsteht, beide rufen einfach nur SPI_send(data) auf)
Hier der Code dazu:
void SPI_send(uint8_t data) 
{
  SPDR = data;            // Gib Daten in Übertragungspuffer
  while(!(SPSR & (1 << SPIF)) );    // Warte bis Übertragung fertig
}

Hier noch kurz meine initalisierungsfunktion:
void SPI_init(void)
{
  // Mosi + Clock als Output setzen
  DDR_SPI = (1 <<SPI_MOSI) | (1 <<SPI_CLK);
  
  // Schalte SPI ein und fck/16
  SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPR0);
}


Hat jemand eine Ahnung, warum ich nur 1nen Befehl senden kann? Ich kann 
auch anstatt SPI_send_sycn1 irgend einen anderen Send-Befehl nehmen, 
allerdings bleibt es trotzdem hängen (bleibt in einer Endlosschleife).
Wenn ich SPSR zwischen den beiden Send Befehlen mir anzeigen lasse habe 
ich 0b11000000.
Ihr würdet mir wirklich sehr helfen, wenn jemand eine Idee hat!

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du weißt, dass Du das SPDR nach der Übertragung lesen musst, damit das 
SPIF wieder gelöscht wird? Deine Sendefunktion macht das nämlich 
nicht...

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Du weißt, dass Du das SPDR nach der Übertragung lesen musst, damit das
>SPIF wieder gelöscht wird? Deine Sendefunktion macht das nämlich
>nicht...

SPIF wird bei jedem Zugriff auf SPDR gelöscht.
Also auch wenn man etwas hineinschreibt.

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zwei Anmerkungen :
- Erstens soll und muß man die DDR Register frü das CS nicht laufend 
umschalten. Diese werden in der Initialisierung als Ausgang konfiguriert 
und damit basta.
- Zweitens sollte man die CS Select Leitungen von Anfang an deaktivieren 
und nur vor der Kommunikation das CS auf Low bringen. Wichtig ist, das 
SPI Polarität und Phase richtig gesetzt werden, bevor man CS nach low 
bringt.
Nach der Kommunikation soll man CS sofort wieder auf High bringen. Es 
gibt je nach Chip auch ein paar Delay zu beachten, zwischen CS auf Low 
und starten des SPI Transfers, bzw. nach dem Transfer die CS wieder auf 
High.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>SPIF wird bei jedem Zugriff auf SPDR gelöscht.
>Also auch wenn man etwas hineinschreibt.

Oder etwas präziser:

Alternatively, the SPIF bit is cleared by first reading
the SPI Status Register with SPIF set, then accessing
the SPI Data Register (SPDR).

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok habe es jetzt so abgeändert:
SPI_send_start_conversions();
        SPI_get();
        USART_send(0x01);
        SPI_send_sync1();
        USART_send(0x02);

        while(1)
        {
          USART_send(0xFF);
        }

mit:
uint8_t SPI_get(void) 
{  
  // Warte bis fertig Empfangen
  while(!(SPSR & (1<<SPIF)) );
  return SPDR;
}

Trotzdem geht es nicht.
Ich bekomme 0x01 gesendet, aber kein 0x02 und schon gar keine 0xFF....

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein jetztiger Code sieht so aus:

[c]
uint32_t temp = 0x00;
        SPI_select_Messchip();
        SPI_send_start_conversions();
        temp = SPI_read_register(0);    // Register von Config
        SPI_unselect();

        USART_send(temp&0xFF0000UL);
        USART_send(temp&0xFF00UL);
        USART_send(temp&0xFFUL);
[c]

So dank dem Tipp mit kurz zuvor selektieren und kurz danach 
deselektieren schaffe ich es jetzt zumindest mehrere Register zu lesen 
und mehrere Bytes zu senden usw. Allerdings bekomme ich immer die 
0x0000FF zurück, wenn ich ein Register auslese, auch obwohl eigentlich 
0x000001 drinnen stehen solllte.... Jemand eine Idee, was noch sein 
könnte?
Danke aufjedenfall schonmal

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
holger wrote:
> SPIF wird bei jedem Zugriff auf SPDR gelöscht.
> Also auch wenn man etwas hineinschreibt.
Jüpp, da haste nicht ganz Unrecht...;-}

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht noch ein paar microsekunden Verzögerungen nach 
SPI_select_Messchip() und vor SPI_unselect() rein.
Wie sehen SPI_send_start_conversions() und SPI_read_register(0) aus ?

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.