Forum: Mikrocontroller und Digitale Elektronik Atmega SPI-Slave bleibt bekommt kein SPIF Signal und bleibt hängen


von Mareike (Gast)


Lesenswert?

Hallo,
ich möchte einen Atmega als Slave im SPI-Bus erstellen. Doch dieser 
springt nicht in die ISR vom SPI. Der Pin wird aber auf low gezogen.
1
  // SPI Transmission/reception complete ISR
2
  ISR(SPI_STC_vect)
3
  {
4
    PORTD |= (1<<PORTD3); // LED ON
5
    SPSR = (1 << SPIF);
6
    SPDR = spi_dummy++; // dummy
7
    /* Wait for reception complete */
8
    while(!(SPSR & (1<<SPIF)));
9
    /* Return Data Register */
10
    spi_data = SPDR;
11
    PORTD &= ~(1<<PORTD3); // LED OFF
12
  }


Für die Initialisierung habe ich
1
  void spi_init()
2
  // Initialize pins for spi communication
3
  {
4
    /* Set MOSI SCK and SS output, all others input */
5
    DDR_SPI = (1 << DD_MISO);
6
    DDR_SPI &= ~((1 << DD_MOSI) | (1 << DD_SCK) | (1 << DD_SS));
7
    
8
    /* Enable SP */
9
    SPCR = ((1<<SPE)|               // SPI Enable
10
    (1<<SPIE)|              // SPI Interupt Enable
11
    (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
12
    (0<<MSTR)|              // Master/Slave select -> Slave
13
    (0<<SPR1)|(0<<SPR0)|    // SPI Clock Rate FOSC/64
14
    (0<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
15
    (0<<CPHA));             // Clock Phase (0:leading / 1:trailing edge sampling)
16
    
17
    SPSR = (1<<SPIF); // initialize
18
  }

Ist bei der Initialisierung etwas verkehrt? Wäre suppi, wenn ihr mal 
kurz drüber gucken könntet.

von Frickelfritze (Gast)


Lesenswert?

Mareike schrieb:
> Der Pin wird aber auf low gezogen.

Welcher Pin?

von Mareike (Gast)


Lesenswert?

Frickelfritze schrieb:
> Welcher Pin?

der slave select pin
DD_SS bzw. PB2

von Frickelfritze (Gast)


Lesenswert?

sei();

vergessen?

von Brogdan (Gast)


Lesenswert?

> Der Pin wird aber auf low gezogen.

Hat nur im "maste mode" Erfolg.

von Mareike (Gast)


Lesenswert?

Frickelfritze schrieb:
> sei();
>
> vergessen?

nein

Brogdan schrieb:
>> Der Pin wird aber auf low gezogen.
>
> Hat nur im "maste mode" Erfolg.

Ich meinte auch, dass der Pin vom Master auf Low gezogen wird. (evtl. 
ein bisschen unglücklich ausgedrückt :) )

von S. Landolt (Gast)


Lesenswert?

In der SPI-ISR darf nicht mehr auf SPIF gewartet werden, dieses hat ja 
bereits die ISR ausgelöst.
  Zum Verständnis hilft vielleicht folgendes Assemblerprogramm:
1
.org $0000
2
  rjmp   reset
3
4
.org SPIaddr
5
  in    tmp0,SPDR
6
  rcall auxLCDbyte
7
  reti
8
9
main:
10
  sbi   DDR_SPI,MISO
11
  ldi   tmp0,(1<<SPE)+(1<<SPIE)
12
  out   SPCR,tmp0
13
  sei
14
main_loop:
15
  rjmp  main_loop
16
;*******************************************************
17
reset:
18
.
19
.

von Mareike (Gast)


Lesenswert?

Ja, da hast du recht. Jetzt habe ich allerdings ein anderes Problem. und 
zwar wird empfängt und sendet der Slave nur 0x00, auch wenn ich etwas 
anderes schicke.

Slave
1
  void spi_init()
2
  // Initialize pins for spi communication
3
  {
4
    /* Set MOSI SCK and SS output, all others input */
5
    DDR_SPI = (1 << DD_MISO);
6
    DDR_SPI &= ~((1 << DD_MOSI) | (1 << DD_SCK) | (1 << DD_SS)); // DDRB
7
    //spi_interrupt_init();
8
    
9
    /* Enable SP */
10
    SPCR = ((1<<SPE)|               // SPI Enable
11
    (1<<SPIE)|              // SPI Interupt Enable
12
    (0<<DORD)|              // Data Order (0:MSB first / 1:LSB first)
13
    (0<<MSTR)|              // Master/Slave select -> Slave
14
    (0<<SPR1)|(0<<SPR0)|    // SPI Clock Rate FOSC/64
15
    (0<<CPOL)|              // Clock Polarity (0:SCK low / 1:SCK hi when idle)
16
    (0<<CPHA));             // Clock Phase (0:leading / 1:trailing edge sampling)
17
    
18
    SPSR = (1<<SPIF); // initialize
19
  }
20
21
  //void spi_interrupt_init(){
22
  //  DDRD &= ~(1 << DD_SS); // Input INT0
23
  //  EICRA = (1 << ISC01); // INT0 falling edge
24
  //  EIMSK = (1 << INT0);  // enable INT0 interrupt
25
  //}
26
27
28
  // SPI Transmission/reception complete ISR
29
  ISR(SPI_STC_vect)
30
  {
31
    PORTD |= (1<<PORTD3); // LED ON
32
    spi_data = SPDR;
33
    new_spi_data = 1;
34
    PORTD &= ~(1<<PORTD3); // LED OFF
35
  }
Slave main
1
while(1){
2
...
3
if(new_spi_data==1){
4
  usart_transmit_string("\r\n received data: ");
5
  usart_transmit_char(spi_data);
6
  new_spi_data = 0;
7
}
8
...
9
}



Master: (ATTINY)
1
void spi_init()
2
  // Initialize pins for spi communication
3
  {
4
    /* Set MOSI, SCK, SS as output, all others input */
5
    DDR_SPI = ((1 << DD_MOSI) | (1 << DD_SCK) | (1 << DD_SS));
6
    DDR_SPI &= ~(1 << DD_MISO);
7
    PORT_SPI |= (1 << DD_SS); // Set SlaveSelect High
8
  }
9
10
  uint8_t spi_fast_shift(uint8_t data)
11
  // Clocks only one byte to target device and returns the received one
12
  {
13
    PORT_SPI &= ~(1 << DD_SS); // Salve Select
14
    _delay_ms(10); // Slave jumps to ISR
15
    // Load data into the data-register
16
    USIDR = data;
17
    USISR = (1 << USIOIF);
18
    while(!(USISR & (1<<USIOIF))){
19
      USICR |= ((1<<USIWM0)|(1<<USICS1)|(1<<USICLK)|(1<<USITC));
20
    }
21
    PORT_SPI |= (1 << DD_SS);
22
    return USIDR;
23
  }

Master main:
1
  while (1){
2
3
    //#ifdef SPI_MASTER
4
    if(new_usart_data==1){
5
      PORTD |= (1<<PORTD5); // LED ON
6
      spi_data = spi_fast_shift(usart_data);
7
      usart_transmit_string("\r\nslave data: ");
8
      usart_transmit_char(spi_data);
9
      new_usart_data = 0;
10
      PORTD &= ~(1<<PORTD5); // LED OFF
11
    }


Ich gebe im prinzip über uart vor, welche Daten gesendet werden sollen, 
damit ich das noch nachvollziehen kann.
Beim Master soll er mir also die zurückgegebenen Werte darstellen. Dabei 
erhalte ich immer 0x00, egal was ich sende.
Der Slave soll mir ebenfalls die erhaltenen Werte ausgeben. auch hier 
bekomme ich nur 0x00.

spi_data ist dabei als volatile definiert. Die Änderung muss also 
eigentlich übernommen werden.
Auch wenn ich die Ausgabe direkt nach dem Senden in der funktion 
spi_fast_shift bzw. in der ISR erstelle, erhalte ich nur 0x00 zurück.

von S. Landolt (Gast)


Lesenswert?

Wo wird in der neuen Version im Slave SPDR ein Wert zugewiesen?

von Mareike (Gast)


Lesenswert?

Niergendwo, aber sollte da nicht noch der alte wert vom Master drinn 
stehen?

von Mareike (Gast)


Lesenswert?

Aber selbst wenn ich es in der ISR
1
spi_data = SPDR;
2
SPDR = 0x50;
erstelle, funktioniert es auch nicht

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Mareike schrieb:
> Ja, da hast du recht. Jetzt habe ich allerdings ein anderes Problem. und
> zwar wird empfängt und sendet der Slave nur 0x00, auch wenn ich etwas
> anderes schicke.

 Vielleicht wäre es besser wenn der MASTER zuerst 0x01 sendet und
 danach einfach den empfangenen Wert um 1 erhöht zurücksendet.
 SLAVE genauso.
 MASTER gibt dann den empfangenen Wert über UART aus, ohne auf
 irgendeinen bestimmten Wert zu prüfen.

 Und in der ISR die LED beim jedem empfangenem Zeichen zu toggeln
 wäre vielleicht besser.
[c]
    PORTD ^= (1<<PORTD3); // LED TOGGLE
]/c]

 EDIT:
 Oder SLAVE gibt den Wert aus, aber MASTER muss dann Pausen machen.

 EDIT2:
 Sehe gerade, dass new_spi_data ein Flag ist, die Bezeichnung ist
 bisschen irreführend, new_spi_flag wäre vielleicht besser...

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Ad hoc fällt mir jetzt nur ein Vertauschen der Datenleitungen ein: auf 
dem ATtiny gilt DI und DO, nicht MISO und MOSI.

von Mareike (Gast)


Lesenswert?

S. Landolt schrieb:
> Ad hoc fällt mir jetzt nur ein Vertauschen der Datenleitungen ein: auf
> dem ATtiny gilt DI und DO, nicht MISO und MOSI.

Der letzte Hinweis ist meistens der richtige ;)

Bin von MISO und MOSI ausgegangen. nach vertauschen, gab es jedoch auch 
erst noch falsche Ergebnisse, da ich in der Software input und output ja 
auch falsch deklariert habe.
Jetzt läuft es und ich kann den Bus aufbauen.

Danke euch und gute nacht

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.