Forum: Mikrocontroller und Digitale Elektronik Attiny2313 spi-slave c


von Kimmy (Gast)


Lesenswert?

Hallo,
ich möchte einen Attiny2313 als slave in einem SPI-Bus benutzen. 
allerdings habe ich probleme die Daten richtig zu empfangen.
1
ISR(INT0_vect){
2
  while(!(USISR& (1<<USIOIF)))
3
  spi_data = USIDR;
4
  new_spi_data = 1;
5
}

new_spi_data frage ich dann in der main-schleife ab. Allerdings bekomme 
ich nur 0x00 als daten. egal was ich sende. spi_data ist dabei als 
volatile definiert.

Am Master funktioniert die Übertragung richtig. Ich bekomme die Daten 
auch richtig zurück. Also kann es schon einmal nicht total verkehrt 
sein.
weiss einer, wie ich die Daten bei einem Attiny richtig abfragen muss?

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


Lesenswert?

Kimmy schrieb:
> Am Master funktioniert die Übertragung richtig. Ich bekomme die Daten
> auch richtig zurück. Also kann es schon einmal nicht total verkehrt
> sein.
> weiss einer, wie ich die Daten bei einem Attiny richtig abfragen muss?

 Poste mal dein Programm, es ist meistens so, dass irgendetwas ganz
 anders ist als in Fragestellung.

 Verstehe das sowieso nicht:
 "Ich habe ein Problem mit meinem Programm aber den poste ich nicht,
 weil absolut unwichtig, alles andere stimmt 100%".

 Wie ist new_spi_data deklariert ?

 Was hat INT_0 ISR mit SPI zu tun ?

: Bearbeitet durch User
von Kimmy (Gast)


Lesenswert?

INT0 ist quasi mein SlaveSelect, da ich anders nicht weiss wie ich 
mitbekommen kann, dass der Master etwas gesendet hat. Wenn der Master zu 
senden anfängt, setzt er diesen Pin auf Low, wodurch die ISR aufgerufen 
wurde.

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
5
#define F_CPU 8000000UL // for _delay_ms(); _delay_us()
6
#define FOSC 8000000UL // for Baudrate
7
8
/* -- includes -- */
9
#include <avr/io.h>
10
#include <avr/interrupt.h>
11
#include <util/delay.h>
12
#include "spi.h"
13
#include "uart.h"
14
15
/* -- USART -- */
16
#define USART_BAUD 1200
17
#define USART_MYUBRR FOSC/16/USART_BAUD-1
18
/* --  -- */
19
20
/* -- SPI -- */
21
#define PORT_SPI    PORTB
22
#define DDR_SPI     DDRB
23
#define DD_MISO     DDB6
24
#define DD_MOSI     DDB5
25
#define DD_SS       DDB2
26
#define DD_SCK      DDB7
27
28
volatile unsigned char spi_data;
29
volatile unsigned char new_spi_data;
30
/* -- -- */
31
32
void spi_init()
33
// Initialize pins for spi communication
34
{
35
  /* --- SLAVE --- */
36
  /* Set MISO as output, all others input */ 
37
  DDR_SPI = (1 << DD_MISO);
38
  DDR_SPI &= ~((1 << DD_MOSI) | (1 << DD_SCK));
39
40
  /* Enable SP */
41
  USICR = ((0<<USISIE)|            // Start Condition Interrupt Enable
42
       (0<<USIOIE)|            // Counter Overflow Interrupt Enable
43
       (0<<USIWM1)|(1<<USIWM0)|      // Three-wire mode
44
       (1<<USICS1)|(0<<USICS0)|(0<<USICLK)|
45
       (0<<USITC));            // Toggle Clock Port Pin
46
47
  extern_interrupt_init();
48
49
}
50
51
void extern_interrupt_init(void){
52
  DDRB &= ~(1 << DDD2); // External Interrupt on INT0
53
54
  MCUCR |= (1 << ISC01); // INT0 falling edge
55
  MCUCR &= ~(1 << ISC00); // INT0 falling edge
56
57
  GIMSK |= (1 << INT0);  // enable INT0 interrupt
58
}
59
60
ISR(INT0_vect){
61
  while(!(USISR& (1<<USIOIF)))
62
  spi_data = USIDR;
63
  new_spi_data = 1;
64
}
65
66
67
int main(void){
68
  spi_data = 0;
69
  usart_data = 0;
70
  new_usart_data = 0;
71
  usart_init(USART_MYUBRR);
72
  usart_transmit_string("USART devices ready \r\n"); 
73
  spi_init();
74
  usart_transmit_string("SPI devices ready \r\n"); 
75
  sei(); // Global Interrupts activate
76
  DDRB |= (1<<PORTD5); // PD5 -> Output
77
  PORTD &= ~(1<<PORTD5); // PD5 -> Low
78
  while (1){
79
    if(new_spi_data==1){
80
      usart_transmit_string("\r\n received data: ");
81
      usart_transmit_char(spi_data);
82
      new_spi_data = 0;
83
    }
84
85
  }
86
}

von S. Landolt (Gast)


Lesenswert?

Zwei Schreibfehler:

> DDRB &= ~(1 << DDD2); // External Interrupt on INT0
> DDRB |= (1<<PORTD5); // PD5 -> Output

Wird nicht mit Letzerem MOSI auf Ausgang geschaltet?

von Kimmy (Gast)


Lesenswert?

Das stimmt, war beides falsch geschrieben.

Habe die pins jetzt auf dem richtigen Port gelegt.

> DDRD &= ~(1 << DDD2); // External Interrupt on INT0
> DDRD |= (1<<PORTD5); // PD5 -> Output

Doch leider erhalte ich immer noch nur 0x00 als ergebnis

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


Lesenswert?

Kimmy schrieb:
> INT0 ist quasi mein SlaveSelect, da ich anders nicht weiss wie ich
> mitbekommen kann, dass der Master etwas gesendet hat.
1
  USISR |=  (1<<USIOIF);

 Muss auch mal zurückgesetzt werden - normalerweise beim Init
 und dann vor jedem Empfang ;)

 P.S.
1
  USIDR =  _PassendeAntwort_;
2
  USISR |=  (1<<USIOIF);
 Wäre auch nicht schlecht...

: Bearbeitet durch User
von Kimmy (Gast)


Lesenswert?

Habe das in der ISR zum schluss eingefügt und bei der initialisierung. 
Das hat aber gebracht, dass ich zunächst völlig falsche werte erhalte 
und nach ein paar mal senden (ca. 8mal ) gar nichts mehr empfangen wird.

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


Lesenswert?

Kimmy schrieb:
> Habe das in der ISR zum schluss eingefügt und bei der initialisierung.
1
ISR(INT0_vect){
2
3
  USIDR =  _PassendeAntwort_;
4
  USISR =  (1<<USIOIF);
5
6
  while(!(USISR& (1<<USIOIF)))
7
  spi_data = USIDR;
8
  new_spi_data = 1;
9
}

 EDIT:
 Nicht |= , sondern =

: Bearbeitet durch User
von Kimmy (Gast)


Lesenswert?

Was bedeutet
1
USIDR =  _PassendeAntwort_;
?

Habe jetzt

1
ISR(INT0_vect){
2
  USISR |=  (1<<USIOIF);
3
4
  while(!(USISR& (1<<USIOIF)))
5
  spi_data = USIDR;
6
  new_spi_data = 1;
7
}
8
9
void spi_init()
10
// Initialize pins for spi communication
11
{
12
  /* --- SLAVE --- */
13
  /* Set MISO as output, all others input */ 
14
  DDR_SPI = (1 << DD_MISO);
15
  DDR_SPI &= ~((1 << DD_MOSI) | (1 << DD_SCK) | (1 << DD_SS));
16
17
  /* Enable SP */
18
  USICR = ((0<<USISIE)|            // Start Condition Interrupt Enable
19
       (0<<USIOIE)|            // Counter Overflow Interrupt Enable
20
       (0<<USIWM1)|(1<<USIWM0)|      // Three-wire mode
21
       (1<<USICS1)|(0<<USICS0)|(0<<USICLK)|
22
       (0<<USITC));            // Toggle Clock Port Pin
23
24
  USISR |=  (1<<USIOIF);
25
  extern_interrupt_init();
26
27
}
Aber jetzt passiert von vornerein gar nichts mehr. Jetzt scheint gar 
nicht mehr in die ISR gesprungen zu werden.

von Kimmy (Gast)


Lesenswert?

auch mit = anstelle von |= habe ich gleiches verhalten. Das müsste doch 
auch eigentlich egal sein oder? es wird doch nur das bit USIOIF 
berücksichtigt. dann ist es doch egal ob |= oder = oder nicht?

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


Lesenswert?

Kimmy schrieb:
> Was bedeutetUSIDR =  PassendeAntwort;?
>
> Habe jetzt
>
> ISR(INT0_vect){
>   USISR |=  (1<<USIOIF);
>
>   while(!(USISR& (1<<USIOIF)))
>   spi_data = USIDR;
>   new_spi_data = 1;
> }

 Und so ?
1
volatile unsigned char spi_antwort = 0;
2
...
3
...
4
ISR(INT0_vect){
5
6
  USIDR =  spi_antwort++;
7
  USISR =  (1<<USIOIF);
8
9
  while(!(USISR& (1<<USIOIF)))
10
  spi_data = USIDR;
11
  new_spi_data = 1;
12
}

: Bearbeitet durch User
von Kimmy (Gast)


Lesenswert?

Es wird doch empfangen, war ein Wackelkontakt.
Allerdings falsch und zwar bekomme ich beim Slave sowohl als auch beim 
Master 0xFF heraus. egal was ich sende

von S. Landolt (Gast)


Lesenswert?

Leitungen MOSI <-> MISO vertauscht?

von Kimmy (Gast)


Lesenswert?

S. Landolt schrieb:
> Leitungen MOSI <-> MISO vertauscht?

nein, wenn ich aber die sck leitung trenne, findet der sich wieder 
zurecht.
dann funktioniert auch die Übertragung. Das richtige Ergebnis wird auch 
übertragen.
Aber das widerspricht meinen Kenntnissen von SPI. Eigentlich schiebe ich 
doch vom Master die Daten rein und lese diese sofort (bzw. die die davor 
gesendet wurden und in USISDR stehen) wieder aus.
Jetzt schreibe ich aber einen anderen Wert in USISDR rein. Diese erhält 
dann auch der Master. Aber das sind ja nicht die, die ich vorher 
gesendet habe

von S. Landolt (Gast)


Lesenswert?

Wie sieht das Senden auf dem Master aus? Nach dem Setzen von /SS muss 
eine gewisse Verzögerung vorhanden sein, bevor SPI gestartet wird; 
schließlich benötigt der Slave etwas Zeit, um in die INT0-ISR zu 
gelangen.

von S. Landolt (Gast)


Lesenswert?

Das
  USISR =  (1<<USIOIF);
ans Ende der INT0-ISR setzen wird die Sache etwas beschleunigen.

von S. Landolt (Gast)


Lesenswert?

>  Nur kann er dann ewig in der while schleife hängen bleiben.
Das ist mir unklar - unter welcher Voraussetzung?

von Kimmy (Gast)


Lesenswert?

Wenn ich das am ende der ISR schreibe, bekomme ich immer falsche 
Ergebnisse und irgendwann bleibt es hängen. Wenn ich das am anfang 
hinschreibe, sind die Ergebnisse richtig aber es bleibt trotzdem hängen.
Beim Master setze ich den pin auf low, warte 10ms und fange dann mit dem 
ÜBertragen an.
Ich lasse mir die Übertragenen Daten in der mein-Schleife anzeigen, also 
wenn die ÜBertragung eigentlich schon lange vorüber ist. Trotzdem bleibt 
es hängen, wenn ich es erst dann neue Daten sende.

von S. Landolt (Gast)


Lesenswert?

In welchem zeitlichen Abstand wird gesendet? Und wie sieht jetzt das 
Slave-Programm aus?

von Kimmy (Gast)


Lesenswert?

Das Programm hat sich nicht wirklich geändert, bis auf die Tippfehler 
(DDRB-> DDRD) und USISR =  (1<<USIOIF); in der initialisierung und in 
der ISR eingefügt.

Aber wenn USISR =  (1<<USIOIF); am anfang von der ISR steht, läuft das 
alles noch ein bisschen stabiler.

Gesendet wird ganz langsam. Das mache ich über den Computer zum Master. 
Dieser empfängt die Daten über UART und gibt diese über SPI weiter.

Im Slave in der HAuptschleife lasse ich mir das Ergebnis ausgeben (auch 
das rückgabeergebnis vom Master lasse ich mir ausgeben). Erst wenn alles 
ausgegeben ist, schicke ich neue Daten. Also zu schnell dürfte das ganze 
nicht sein. Beim Master ist es so, dass dieser den Pin für die ISR auf 
Low zieht und dann 10ms wartet, bevor die Übertragung startet

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
5
#define F_CPU 8000000UL // for _delay_ms(); _delay_us()
6
#define FOSC 8000000UL // for Baudrate
7
8
/* -- includes -- */
9
#include <avr/io.h>
10
#include <avr/interrupt.h>
11
#include <util/delay.h>
12
#include "spi.h"
13
#include "uart.h"
14
15
/* -- USART -- */
16
#define USART_BAUD 1200
17
#define USART_MYUBRR FOSC/16/USART_BAUD-1
18
/* --  -- */
19
20
/* -- SPI -- */
21
#define PORT_SPI    PORTB
22
#define DDR_SPI     DDRB
23
#define DD_MISO     DDB6
24
#define DD_MOSI     DDB5
25
#define DD_SS       DDB2
26
#define DD_SCK      DDB7
27
28
volatile unsigned char spi_data;
29
volatile unsigned char new_spi_data;
30
/* -- -- */
31
32
void spi_init()
33
// Initialize pins for spi communication
34
{
35
  /* --- SLAVE --- */
36
  /* Set MISO as output, all others input */ 
37
  DDR_SPI = (1 << DD_MISO);
38
  DDR_SPI &= ~((1 << DD_MOSI) | (1 << DD_SCK));
39
40
  /* Enable SP */
41
  USICR = ((0<<USISIE)|            // Start Condition Interrupt Enable
42
       (0<<USIOIE)|            // Counter Overflow Interrupt Enable
43
       (0<<USIWM1)|(1<<USIWM0)|      // Three-wire mode
44
       (1<<USICS1)|(0<<USICS0)|(0<<USICLK)|
45
       (0<<USITC));            // Toggle Clock Port Pin
46
47
  USISR =  (1<<USIOIF);
48
49
  extern_interrupt_init();
50
51
}
52
53
void extern_interrupt_init(void){
54
  DDRB &= ~(1 << DDD2); // External Interrupt on INT0
55
56
  MCUCR |= (1 << ISC01); // INT0 falling edge
57
  MCUCR &= ~(1 << ISC00); // INT0 falling edge
58
59
  GIMSK |= (1 << INT0);  // enable INT0 interrupt
60
}
61
62
ISR(INT0_vect){
63
  while(!(USISR& (1<<USIOIF)))
64
  spi_data = USIDR;
65
  new_spi_data = 1;
66
  USISR =  (1<<USIOIF);
67
}
68
69
70
int main(void){
71
  spi_data = 0;
72
  usart_data = 0;
73
  new_usart_data = 0;
74
  usart_init(USART_MYUBRR);
75
  usart_transmit_string("USART devices ready \r\n"); 
76
  spi_init();
77
  usart_transmit_string("SPI devices ready \r\n"); 
78
  sei(); // Global Interrupts activate
79
  DDRD |= (1<<PORTD5); // PD5 -> Output
80
  PORTD &= ~(1<<PORTD5); // PD5 -> Low
81
  while (1){
82
    if(new_spi_data==1){
83
      usart_transmit_string("\r\n received data: ");
84
      usart_transmit_char(spi_data);
85
      new_spi_data = 0;
86
    }
87
88
  }
89
}

von Kimmy (Gast)


Lesenswert?

Die ISR sieht natürlich so aus:
1
ISR(INT0_vect){
2
  USIDR = spi_antwort++;
3
  while(!(USISR& (1<<USIOIF)))
4
  spi_data = USIDR;
5
  new_spi_data = 1;
6
  USISR =  (1<<USIOIF);
7
}

von S. Landolt (Gast)


Lesenswert?

Für mich sieht das Slave-Programm okay aus (vom belanglosen 
Schreibfehler DDRB &= ~(1 << DDD2) mal abgesehen). Ich würde jetzt den 
Fehler eher in der Verdrahtung oder auch im Master suchen, aber so 
richtig erklären kann ich mir das Fehlverhalten, speziell das 
Hängenbleiben, nicht.

von S. Landolt (Gast)


Lesenswert?

"The Universal Serial Interface, or USI... Three-wire Synchronous Data 
Transfer (Master, fSCKmax = fCK/2, Slave fSCKmax = fCK/4)"

Die letztere Bedingung ist erfüllt?

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.