Forum: Mikrocontroller und Digitale Elektronik SPI ist komisch


von Gast (Gast)


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):
1
/*******************************************************
2
  Funktion :    Wähle Messchip aus
3
  Eigenschaften:  PB4 als Ausgang => auf low
4
  Übergabewert:  -
5
  Rückgabewert:  -
6
********************************************************/
7
void SPI_select_Messchip(void)
8
{
9
  DDR_SPI = (1 << PB3) | ( 1 << PB4);  // 3 & 4 als Ausgang
10
  PORTB |= (1 << PB3);         // SD-Karte CS ausschalten
11
  PORTB &= ~(1 << PB4);        // Messchip CS einschalten (löschen von PB4)
12
}
13
14
15
16
/*******************************************************
17
  Funktion :    Wähle SD-Karte aus
18
  Eigenschaften:  PB 3 als Ausgang => auf low
19
  Übergabewert:  -
20
  Rückgabewert:  -
21
********************************************************/
22
void SPI_select_SDcard(void)
23
{
24
  DDR_SPI = (1 << PB3) | ( 1 << PB4);  // 3 & 4 als Ausgang
25
  PORTB |= (1 << PB4);         // Messchip CS ausschalten
26
  PORTB &= ~(1 << PB3);        // SD-Karte CS einschalten (löschen von PB3)
27
}

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:
1
SPI_send_start_conversions();
2
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:
1
void SPI_send(uint8_t data) 
2
{
3
  SPDR = data;            // Gib Daten in Übertragungspuffer
4
  while(!(SPSR & (1 << SPIF)) );    // Warte bis Übertragung fertig
5
}

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


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!

von Johannes M. (johnny-m)


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...

von holger (Gast)


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.

von Klaus F. (kfalser)


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.

von holger (Gast)


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).

von Gast (Gast)


Lesenswert?

Ok habe es jetzt so abgeändert:
1
SPI_send_start_conversions();
2
        SPI_get();
3
        USART_send(0x01);
4
        SPI_send_sync1();
5
        USART_send(0x02);
6
7
        while(1)
8
        {
9
          USART_send(0xFF);
10
        }

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

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

von Gast (Gast)


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

von Johannes M. (johnny-m)


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...;-}

von Klaus F. (kfalser)


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 ?

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.