Forum: Compiler & IDEs [AVR] SPI wartet endlos auf SPIF Flag


von Malte _. (malte) Benutzerseite


Lesenswert?

Hallo,
ich versuche gerade die SPI Schnittstelle eines MEGA128 als Master für 
die Ansteuerung einer MMC Karte zu verwenden, wobei der MMC Treiber 
bereits von Nut/OS bereit gestellt wird.
Nur scheint das SPIF Flag nie gesetzt zu werden und meine Anwendung 
hängt endlos.
1
#define SPIDDR        DDRB
2
#define SPIPORT       PORTB
3
#define SCLK          0x02
4
#define MOSI          0x04
5
#define MISO          0x08
6
7
static uint8_t SpiMmCardIo(uint8_t val)
8
{
9
    SPDR = val;               /* put byte to send in SPDR, which initiates xmit  */
10
    while(!(SPSR & (1<<SPIF))) { /* wait for completion */
11
        printf("spi wait\n");
12
     }
13
    return SPDR;               /* return with byte shifted in from slave */
14
}
15
16
17
static int SpiMmcIfcInit(NUTDEVICE * dev)
18
{
19
    SPIDDR = SCLK + MOSI;
20
    SPIPORT = 0x00;
21
    NutSleep(500);
22
    SpiMmCardSelect(0);
23
    SPCR = (1 << SPE) | (1 << MSTR);  /* enable SPI as master, set clk divider and max speed */
24
    NutSleep(250);
25
    /* start off with 80 bits of high data with card deselected */
26
    int i;
27
 printf("\nSend dummy bytes\n");
28
    for (i = 0; i < 10; i++) {
29
      SpiMmCardIo(0xff);
30
      printf("byte send\n");
31
    }
32
 printf("\nInit device\n");
33
    return MmCardDevInit(dev);
34
}
Die Warteschleife sieht aber genau so aus, wie in der ATMEL Doku und 
auch wird erst SPDR geschrieben, bevor das Flag zum ersten mal abgefragt 
wird.

Auf dem UART erscheint endlos die "spi wait" Meldung und niemals "byte 
send". Was geht hier schief?

von VonNixNeAhnung (Gast)


Lesenswert?

hmmm...

Ist /SS als Ausgang definiert?!
1
Master Mode When the SPI is configured as a master (MSTR in SPCR is set), the user can determine the
2
direction of the SS pin.
3
If SS is configured as an output, the pin is a general output pin which does not affect the SPI
4
system. Typically, the pin will be driving the SS pin of the SPI slave.
5
If SS is configured as an input, it must be held high to ensure Master SPI operation. If the SS pin
6
is driven low by peripheral circuitry when the SPI is configured as a master with the SS pin
7
defined as an input, the SPI system interprets this as another master selecting the SPI as a
8
slave and starting to send data to it. To avoid bus contention, the SPI system takes the following
9
actions:
10
1. The MSTR bit in SPCR is cleared and the SPI system becomes a slave. As a result of the
11
SPI becoming a slave, the MOSI and SCK pins become inputs.
12
2. The SPIF flag in SPSR is set, and if the SPI interrupt is enabled, and the I-bit in SREG is
13
set, the interrupt routine will be executed.
14
Thus, when interrupt-driven SPI transmission is used in master mode, and there exists a possibility
15
that SS is driven low, the interrupt should always check that the MSTR bit is still set. If the
16
MSTR bit has been cleared by a slave select, it must be set by the user to re-enable SPI master
17
mode.
siehe auch Datenblatt S.167

mfg

von Gast (Gast)


Lesenswert?

> Auf dem UART erscheint endlos die "spi wait" Meldung und niemals "byte
send". Was geht hier schief?

Endlos? Es sollte doch eher einmal kommen und dann hängt es. Wenn es 
endlos kommt stimmt was anderes nicht.

von Simon K. (simon) Benutzerseite


Lesenswert?

Gast wrote:
>> Auf dem UART erscheint endlos die "spi wait" Meldung und niemals "byte
> send". Was geht hier schief?
>
> Endlos? Es sollte doch eher einmal kommen und dann hängt es. Wenn es
> endlos kommt stimmt was anderes nicht.

Quatsch.

von Malte _. (malte) Benutzerseite


Lesenswert?

> Ist /SS als Ausgang definiert?!
Danke, den Teil im Datenblatt hatte ich übersehen. Jetzt funktionierts.

von Gast (Gast)


Lesenswert?

Simon K. (simon) wrote:
> Quatsch.

Selber Quatsch. Jetzt lieste nochmal durch was der OP geschrieben hat.
Einmal hängt die Anwendung endlos und einmal wird endlos spi wait 
ausgegeben.

Entweder hängt es oder es gibt dauernd spi wait aus.

von Malte _. (malte) Benutzerseite


Lesenswert?

> Entweder hängt es oder es gibt dauernd spi wait aus.
Die Anwendung hing in der Warteschleife fest. Und um sicher zu gehen, 
dass es auch wirklich die Warteschleife und nichts anderes (wie z.B. 
Sprünge ins Nirvana) ist, hatte ich dann da die Meldung eingebaut, die 
dann eben dauerhaft ausgegeben wurde.

von VonNixNeAhnung (Gast)


Lesenswert?

>>> Ist /SS als Ausgang definiert?!
>>Danke, den Teil im Datenblatt hatte ich übersehen. Jetzt funktionierts.
Gern geschehen! Zumal, hatte ich ähnliches Problem (den interessanten 
Teil des Datenblattes zuvor geflissentlich ignoriert) auch schon mal.

mfg

von Philipp B. (philipp_burch)


Lesenswert?

1
SPCR = (1 << SPE) | (1 << MSTR);  /* enable SPI as master, set clk divider and max speed */
Entweder solltest du da noch den Kommentar oder den Code ändern. 
Maximale Frequenz des SPIs erreichst du erst, wenn auch SPI2X in SPSR 
gesetzt ist (F_CPU / 2). Das nur so am Rande.

von Daniel Luscher (Gast)


Lesenswert?

Hallo, ich habe das gleiche Problem - bei mir hängt wird ebenfalls auf 
SPIF gewartet und es geht nicht weiter.


Ich initialisiere als Master:
1
void SPI_InitMaster()
2
{
3
  SPI_DDR |= (1<<SPI_MOSI) | (1<<SPI_SCK) | (1<<SPI_SS);    // outputs
4
  SPI_DDR &= ~(1<<SPI_MISO);                  // input
5
  SPI_PORT |= (1<<SPI_MISO);                  // pull-up
6
7
  SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPIE);  // enable SPI, Master mode, enable Interrupt
8
  SPCR = (1<<SPR0 | 1<<SPR1);          // set clock rate /128
9
}

Danach wird ein byte gesendet:
1
void SPI_MasterTransmit(uint8_t byte)
2
{
3
  SPDR = byte;
4
  while( !(SPSR & (1<<SPIF)) );  // wait until transmission complete
5
}

Wenn ich das richtig verstehe, wird SPIF gesetzt, nachdem das byte durch 
das Schieberegister durch ist, es muss also nichtmal ein zweites Gerät 
angeschlossen sein, oder? Man empfängt im Gegenzug praktisch 0x00...

Also Kontroller wird bei mir vor Ausführung des Befehls eine LED 
ausgeschaltet und nach dem Befehl danach wieder eingeschaltet. Sie geht 
aus, aber nicht wieder an, entprechend wird es an der Schleife liegen.

Slave Select wird in der Initialisierung als Output gesetzt, das löst 
das Problem leider nicht.

Vielen Dank schonmal!

von Daniel L. (danielschlumpf)


Lesenswert?

Noch ein Nachtrag zu meinem vorigen Post:

Ich verwende einen ATMega32 bei 8Mhz und folgenden Port-Definitionen:
1
#define SPI_PORT    PORTB
2
#define SPI_PIN      PINB
3
#define SPI_DDR      DDRB  // direction
4
#define SPI_MOSI    5    // master out / slave in
5
#define SPI_MISO    6    // master in / slave out
6
#define SPI_SCK      7    // clock
7
#define SPI_SS      4    // slave select

von holger (Gast)


Lesenswert?

>  SPCR = (1<<SPE) | (1<<MSTR) | (1<<SPIE);  // enable SPI, Master mode, >enable 
Interrupt

Mach das SPIE da weg.

von Daniel L. (danielschlumpf)


Lesenswert?

Hey Holger,

danke für den Tipp, jetzt geht's! Super.

Heißt das, ich kann nur entweder den Interrupt oder die SPIF flag 
verwenden? Der Interrupt ist bei mir nämlich ausgelöst worden, habe ich 
festgestellt... jetzt ist er natürlich deaktiviert.

Übrigens: habe in dem Code noch einen anderen Fehler entfernt, es muss 
natürlich
1
SPCR |= (1<<SPR0 | 1<<SPR1);

heißen, mit dem "|=" anstelle "=", sonst wird der ISP direkt wieder 
deaktivert.

Danke nochmal!

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.