Atmega SPI-Slave bleibt bekommt kein SPIF Signal und bleibt hängen

Gast #4650639
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.
Gast #4650694
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
.
Gast #4650749
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.
(Firma: Vescomp) #4650778
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...
Gast #4650958
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren