Forum: Mikrocontroller und Digitale Elektronik SPI zwischen zwei AtMega8


von Sercan S. (disaster35)


Lesenswert?

Hallo Liebe Forumgemeinde,

nachdem ich mich mit etlichen Tutorials und Infoblatt vom Atmel 
durchgeforstet habe versuche ich mal jetzt von euch ein wenig Hilfe zu 
bekommen.

Es geht wie im Betreff schon geschrieben um die Datenübertragung 
zwischen zweier ATMega8 anhand der Nutzung von SPI.

Ich erkläre erstmal was ich rausgefunden habe und falls es nicht richtig 
sein soll bitte ich um Korrektur.

Also SPI Kommunikation findet zwischen Master & Slave statt und dabei 
müssen die MISO, MOSI und SCK Pins miteinander verbunden werden?

MISO und MOSI sind die Datenkanäle.
Über SCK wird der Taktsignal übertragen und je nach eingestellem Modus 
wird erst bei eine steigende (auf HIGH) oder fallende (auf LOW) 
Taktflanke der Zustand vom MISO/MOSI beim Empfänger/Sender gelesen oder 
halt geschrieben.

Die Datenübertragung beginnt immer dann wenn SS von HIGH auf LOW gesetzt 
wird. Erst wenn SS auf LOW gezogen ist kann die Übertragung starten.

CPOL und CPHA sind Bits die ich setzen muss um die o.g. Modus 
einzustellen. Soweit ich das verstanden habe sieht es folgendermaßen 
aus.

CPOL = 0 , CPHA = 0 : Bit wird bei steigender Taktflanke übertragen
CPOL = 0 , CPHA = 1 : Bit wird bei fallender Taktflanke übertragen
CPOL = 1 , CPHA = 0 : Bit wird bei fallender Taktflanke übertragen
CPOL = 1 , CPHA = 1 : Bit wird bei steigender Taktflanke übertragen

Je nachdem ob es bei fallender oder steigender Taktflanke übertragen 
wird, wird das Bit bei gegensätziger Taktflanke geschoben (Shift). Ich 
habe mir darüber keine Gedanken gemacht, bei welcher Taktflanke gelesen 
oder geschoben wird...


Nun stellt sich für mich die Frage: Auf dem folgenden Atmel Datenblatt 
über SPI: 
http://www.atmel.com/Images/Atmel-2585-Setup-and-Use-of-the-SPI_ApplicationNote_AVR151.pdf

steht das weiter unten auch so geschrieben, wie ich es erklärt habe...

Weiter oben ist aber in der Zeichnung (Figure 1 - 1 Master and slave 
interface) Master und Slave so beschaltet, dass der Master sein SS PIN 
auf VCC und der Slave sein SS PIN auf GND schaltet.

Wie soll laut dieser Zeichnung der Master den SS Pin auf LOW setzen 
damit eine Übertragung beginnt?

Desweiteren stand im Datenblatt übersetzt: 'Master generiert nur dann 
Taktsignale wenn es Daten sendet. Dies bedeutet, dass der Master Daten 
an den Slave senden muss um Daten vom Slave zu bekommen.' Da musste ich 
kurz überlegen warum aber dachte mir okay, dann schicke ich den einfach 
lauter nullen, wenn nichts anliegt.

So hatte ich das vor:
1
            Master        Slave
2
SCK         OUTPUT        INPUT
3
MISO        INPUT         OUTPUT
4
MOSI        OUTPUT        INPUT
5
SS          OUTPUT        INPUT

Nachdem ich die beiden Mega8 mit den jeweiligen PINS aneinander 
angeschlossen habe (SCK - SCK , MISO - MISO, MOSI - MOSI, SS - SS) muss 
ich ja die Master und Slave Seite wie oben erklärt erstmal 
Konfigurieren:

MASTER:
1
 
2
void spiInitMaster(){
3
    DDRB |= ((1<<PB5)|(1<<PB3)|(1<<PB2)); //SCK, MOSI, SS als output
4
    DDRB &= ~(1<<PB4); // MISO als INPUT, wobei muss ich ja nicht mehr machen?
5
                       // da es schon standart so als INPUT ist oder?
6
    /* Enable SPI, Master, set clock rate fck/16 */
7
    SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPOL0)|(1<<CPOL1);
8
9
}
10
11
unsigned char SPI_MasterTransmit(char cData) {
12
    /* Start transmission */
13
    SPDR = cData;
14
    /* Wait for transmission complete */ 
15
    while(!(SPSR & (1<<SPIF))); 
16
    return SPDR;
17
}

SLAVE:
1
 
2
void spiInitSlave(){
3
    DDRB |= (1<<PB4); // MISO als OUTPUT rest kann ja standartmäßig so bleiben
4
    /* Enable SPI, Master, set clock rate fck/16 */
5
    SPCR = (1<<SPE);
6
7
}
8
9
unsigned char spiSlaveTransmit(char cData) {
10
    /* Start transmission */
11
    SPDR = cData;
12
    /* Wait for transmission complete */ 
13
    while(!(SPSR & (1<<SPIF))); 
14
    return SPDR;
15
}



Die Programmcodes die Ihr oben sieht habe ich aus dem kompletten 
Datenblatt der Mega8 (vllt. ein wenig optimiert).

Nun erkläre ich euch mal in PSEUDOCODE wie ich vorgehen wollte:
1
SOLANGE !WELTUNTERGANG :
2
MASTER & SLAVE rufen ihre spiInit... Methoden auf
3
SLAVE überwacht SS PIN und wartet auf ein LOW Signal
4
MASTER will senden
5
MASTER setzt SS PIN auf LOW
6
MASTER ruft SPI_MasterTransmit auf 
7
SLAVE bekommt den LOW Signal an SS PIN mit und ruft spiSlaveTransmit auf
8
MASTER & SLAVE Warten bis Datenübertragung zuende ist
9
MASTER setzt den SS PIN auf HIGH
10
MASTER & SLAVE können die empfangenen Daten verarbeiten


Ich bedanke mich bei allen, die alles durchgelesen haben und mir 
versuchen werden zu helfen :)

: Bearbeitet durch User
von Sercan S. (disaster35)


Lesenswert?

Keiner Ideen? ?

von SPISpezialist (Gast)


Lesenswert?

Sercan S. schrieb:
> Keiner Ideen?

Soweit uch das auf die Schnelle überblicke machst du alles
richtig bis auf:

Sercan S. schrieb:
> SLAVE bekommt den LOW Signal an SS PIN mit und ruft spiSlaveTransmit auf

bzw.
1
Sercan S. schrieb im Beitrag #4938136:
2
unsigned char spiSlaveTransmit(char cData) {
3
    /* Start transmission */
4
    SPDR = cData;
5
    /* Wait for transmission complete */
6
    while(!(SPSR & (1<<SPIF)));
7
    return SPDR;
8
}

Der Slave muss nicht explizit einen "Receive-Transmit" starten da
er vom Master selbständig die Daten hereingeclockt bekommt.
Im Slave musst du nur per Status-Flag abwarten (ich glaube es
kommt nur das Interrupt-Flag in Frage) bis das SPI-Datenregister
voll ist, dann kannst du es z.B. mit
1
value = SPDR;

einfach abholen.

Sercan S. schrieb:
> Weiter oben ist aber in der Zeichnung (Figure 1 - 1 Master and slave
> interface) Master und Slave so beschaltet, dass der Master sein SS PIN
> auf VCC und der Slave sein SS PIN auf GND schaltet.

Das ist wohl ein Irrtum vom Amt.

von Sercan S. (disaster35)


Lesenswert?

Endlich eine Antwort, ich hatte schon langsam die Hoffnung aufgegeben 
und habe mir wahrscheinlich 1000 weitere Tutorials & Infos über SPI 
gelesen.

Was meinst du genau mit den Status-Flag abwarten. Also mir ist bewusst, 
dass es wie ein Schieberegister funktioniert und es 8-Bits 
'rübergeclockt' werden müssen. Aber wie gehe ich dabei vor? Wie Prüfe 
ich das? Muss ich die Taktflanken beim SCK zählen und bei 8 steigenden 
Taktflanken (8-Bits, kamen rein) versuchen zu lesen, weil dann genau ein 
Byte reingekommen ist?

Ich bin echt überfordert, da es alle in den Tutorials mit Ihren Arduinos 
ohne Probleme hinbekommen und bin echt Froh, dass da mal ein Antwort 
reingekommen ist... :)



SPISpezialist schrieb:
> Sercan S. schrieb:
>> Keiner Ideen?
>
> Soweit uch das auf die Schnelle überblicke machst du alles
> richtig bis auf:
>
> Sercan S. schrieb:
>> SLAVE bekommt den LOW Signal an SS PIN mit und ruft spiSlaveTransmit auf
>
> bzw.Sercan S. schrieb:
> unsigned char spiSlaveTransmit(char cData) {
>     /* Start transmission */
>     SPDR = cData;
>     /* Wait for transmission complete */
>     while(!(SPSR & (1<<SPIF)));
>     return SPDR;
> }
>
> Der Slave muss nicht explizit einen "Receive-Transmit" starten da
> er vom Master selbständig die Daten hereingeclockt bekommt.
> Im Slave musst du nur per Status-Flag abwarten (ich glaube es
> kommt nur das Interrupt-Flag in Frage) bis das SPI-Datenregister
> voll ist, dann kannst du es z.B. mit
> value = SPDR;
>
> einfach abholen.
>
> Sercan S. schrieb:
>> Weiter oben ist aber in der Zeichnung (Figure 1 - 1 Master and slave
>> interface) Master und Slave so beschaltet, dass der Master sein SS PIN
>> auf VCC und der Slave sein SS PIN auf GND schaltet.
>
> Das ist wohl ein Irrtum vom Amt.

: Bearbeitet durch User
von SPISpezialist (Gast)


Lesenswert?

Sercan S. schrieb:
> Was meinst du genau mit den Status-Flag abwarten.

Das SPI-Statusregister (SPSR) hat ein Interrupt-Flag (Bit 7)
welches (im Slave Mode) gesetzt wird wenn ein vollständiges
Byte vom Master hereingekommmen ist. Siehe Datenblatt Seite 130.

Du musst dafür keinen Global Interrupt Enable machen (sei()),
das Flag wird immer bei Gegebenheit gesetzt.

von Sercan S. (disaster35)


Lesenswert?

> Das SPI-Statusregister (SPSR) hat ein Interrupt-Flag (Bit 7)
> welches (im Slave Mode) gesetzt wird wenn ein vollständiges
> Byte vom Master hereingekommmen ist. Siehe Datenblatt Seite 130.
>
> Du musst dafür keinen Global Interrupt Enable machen (sei()),
> das Flag wird immer bei Gegebenheit gesetzt.

Bevor du wieder verschwindest, sende ich am besten mal mein Code beider 
Seiten vielleicht entdeckst du ja etwas, was mir entgeht oder was ich 
komplett falsch mache.


Master-Vollständig
1
#define F_CPU 8000000UL
2
#include <asf.h>
3
#include <avr/io.h>
4
#include <util/delay.h>
5
6
char send = '1';
7
float increment = 0.0;
8
bool ledOn = false;
9
void SPI_MasterInit(void) {
10
  /* Set MOSI and SCK output, all others input */
11
  DDRB = (1<<PB5)|(1<<PB3) |(1<<PB2);
12
  PORTB |= (1<<PB2);
13
  /* Enable SPI, Master, set clock rate fck/16 */
14
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
15
}
16
void SPI_MasterTransmit(char cData) {
17
  /* Start transmission */
18
  PORTB &= (1<<PB2);
19
  SPDR = cData;
20
  /* Wait for transmission complete */ 
21
  while(!(SPSR & (1<<SPIF)))
22
  PORTB |= (1<<PB2);
23
; }
24
25
int main (void)
26
{
27
  /* Insert system clock initialization code here (sysclk_init()). */
28
29
  board_init();
30
  // Timer 0 konfigurieren
31
  TCCR0 = (1<<CS00);       // Start Timer 0 with prescaler 1024
32
  TIMSK |= (1<<TOIE0) /*| (1<<TOIE2)*/;               // Enable Timer 0 overflow interrupt
33
  sei();
34
  DDRD = (1<<PD0);
35
  //PORTD |= (1<<PD0);
36
  //SPI_MasterInit();
37
38
  while(1){
39
    
40
  }
41
  /* Insert application code here, after the board has been initialized. */
42
}
43
44
ISR(TIMER0_OVF_vect)
45
{
46
  
47
  increment += 0.0000255;
48
  
49
  if(increment>=2){
50
    PORTD |= (1<<PD0);
51
    SPI_MasterTransmit(send);
52
    
53
    increment -= 2;
54
    if(ledOn){
55
      PORTD &= ~(1<<PD0);
56
      ledOn = false;
57
    }else{
58
      PORTD |= (1<<PD0);
59
      ledOn = true;
60
    }
61
    
62
    
63
  }
64
}


Slave Vollständig:
1
int digits[4] = {0,0,0,0};
2
int totalSum = 0;
3
int multiplexCount = 0;
4
int multiplexInterval = 2;
5
int digitOnTurn = 1;
6
float increment = 0.0;
7
bool dataReceived = false;
8
int digitSegments[10][7] = {  {1,1,1,1,1,1,0}, // 0
9
{0,1,1,0,0,0,0}, // 1
10
{1,1,0,1,1,0,1}, // 2
11
{1,1,1,1,0,0,1}, // 3
12
{0,1,1,0,0,1,1}, // 4
13
{1,0,1,1,0,1,1}, // 5
14
{1,0,1,1,1,1,1}, // 6
15
{1,1,1,0,0,0,0}, // 7
16
{1,1,1,1,1,1,1}, // 8
17
{1,1,1,1,0,1,1}  // 9
18
};
19
char test = 0;
20
void SPI_SlaveInit(void) {
21
  /* Set MISO output, all others input */
22
  DDRB = (1<<PB4);
23
  /* Enable SPI */
24
  SPCR = (1<<SPE);
25
}
26
char SPI_SlaveReceive(void) {
27
  /* Wait for reception complete */ 
28
  while(!(SPSR & (1<<SPIF)));
29
  /* Return data register */ 
30
  return SPDR;
31
}
32
void updateDigits(){
33
  
34
  //int sumInDigits = totalSum*100; TOTALSUM UND ALLE ANDEREN SUMMEN WERDEN ALS INTEGER OHNE KOMMA GESPEICHERT. DAHER KANN MAN TOTALSUM DIREKT NEHMEN
35
  
36
  digits[0] = (totalSum - (totalSum % 1000)) / 1000;
37
  digits[1] = (totalSum - (totalSum % 100) - digits[0] * 1000 ) / 100;
38
  digits[2] = (totalSum - (totalSum % 10) - digits[1] * 100 - digits[0] * 1000) / 10;
39
  digits[3] = totalSum % 10;
40
}
41
42
//{a,b,c,d,e,f,g}
43
void changeSegmentStatus(int segment[7]){
44
  PORTD &= ~((1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6));
45
  if(segment[0] == 0){
46
    PORTD |= (1<<PD0);
47
    }if(segment[1] == 0){
48
    PORTD |= (1<<PD1);
49
    }if(segment[2] == 0){
50
    PORTD |= (1<<PD2);
51
    }if(segment[3] == 0){
52
    PORTD |= (1<<PD3);
53
    }if(segment[4] == 0){
54
    PORTD |= (1<<PD4);
55
    }if(segment[5] == 0){
56
    PORTD |= (1<<PD5);
57
    }if(segment[6] == 0){
58
    PORTD |= (1<<PD6);
59
  }
60
  
61
}
62
void changeDigitToOnAndOthersOff(int digit){
63
  if(digit == 1){
64
    PORTC |= (1<<PC0);
65
    PORTC &= ~((1<<PC1) | (1<<PC2) | (1<<PC3));
66
    }else if(digit == 2){
67
    PORTC |= (1<<PC1);
68
    PORTC &= ~((1<<PC0) | (1<<PC2) | (1<<PC3));
69
    }else if(digit == 3){
70
    PORTC |= (1<<PC2);
71
    PORTC &= ~((1<<PC0) | (1<<PC1) | (1<<PC3));
72
    }else if(digit == 4){
73
    PORTC |= (1<<PC3);
74
    PORTC &= ~((1<<PC0) | (1<<PC1) | (1<<PC2));
75
  }
76
}
77
78
void multiplexDigits(){
79
  
80
  if(multiplexCount>=multiplexInterval){
81
    changeDigitToOnAndOthersOff(digitOnTurn);
82
    changeSegmentStatus(digitSegments[digits[digitOnTurn-1]]);
83
    if(digitOnTurn==4){
84
      digitOnTurn = 1;
85
      }else{
86
      digitOnTurn++;
87
    }
88
    multiplexCount = 0;
89
  }
90
}
91
92
int main (void)
93
{
94
  /* Insert system clock initialization code here (sysclk_init()). */
95
96
  board_init();
97
  TCCR0 = (1<<CS00);       // Start Timer 0 with prescaler 1024
98
  TIMSK |= (1<<TOIE0) /*| (1<<TOIE2)*/;               // Enable Timer 0 overflow interrupt
99
  
100
  DDRC |= (1<<PC0) | (1<<PC1) | (1<<PC2) | (1<<PC3) | (1<<PC4); 
101
  DDRD |= (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) | (1<<PD6);
102
  sei();
103
  //changeDigitToOnAndOthersOff(4);
104
  //PORTC |= (1<<PC0);
105
  //PORTD |= (1<<PD0) | (1<<PD1) | (1<<PD2) | (1<<PD3) | (1<<PD4) | (1<<PD5) /*| (1<<PD6)*/;
106
  SPI_SlaveInit();
107
  
108
  while(1){
109
    //if(dataReceived){
110
      //changeDigitToOnAndOthersOff(1);
111
      //break;
112
      
113
    //}
114
    
115
  }
116
117
  /* Insert application code here, after the board has been initialized. */
118
}
119
120
ISR(TIMER0_OVF_vect)
121
{
122
  
123
  
124
  multiplexDigits();
125
  multiplexCount++;
126
  updateDigits();
127
  //SPI_SlaveReceive();
128
  //increment += 0.000255;
129
  //if(!dataReceived){
130
  //changeDigitToOnAndOthersOff(2);
131
  
132
  if(!(PINB & (1<<PB2))){
133
    
134
    SPI_SlaveReceive();
135
    totalSum = 1010;
136
    //changeDigitToOnAndOthersOff(3);
137
    dataReceived = true;
138
  }
139
  
140
}

von Sercan S. (disaster35)


Lesenswert?

Wie du sehen kannst, schalte ich den PB2 also den SS Pin erst einmal 
wider auf LOW und möchte es hochschalten wenn ich mit der Übertragung 
fertig bin, damit der Slave es mitbekommt. Du hast eigentlich Recht, da 
ich nur ein Slave habe brauche ich das ja nicht zu prüfen. Um Ehrlich zu 
sagen, habe ich das aus purer Verzweiflung gemacht, weil es sonst ja 
nicht richtig geklappt hat.
Ich habe es in allen Varianten versucht, was im Internet so rumerzählt 
wird.
SS an SS, Master-SS an VCC & Slave-SS an GND und noch andersrum, Beide 
SS nicht beschaltet, Master allein auf VCC/GND, Slave allein auf 
VCC/GND. Nichts klappt.

Ich muss auch hinzufügen: Ich habe gerade getestet ob der SCK überhaupt 
Taktsignale erzeugt, da ich kein gescheites Oszilloskop hier habe, habe 
ich einfach an den SCK PIN (mit Vorwiderstand natürlich), ein LED 
geschaltet und siehe da LED leuchtet nicht? Also werden dort dann ja 
auch keine Taktsignale erzeugt oder? Ich sende doch ununterbrochen, die 
gleichen Daten vom Master aus an den Slave?

Vielleicht kannst du ja mein Programm dort auf Fehler überprüfen und 
ggfls. etwas verändern wodurch das ganze hier ein Ende findet. Da die 
TXD/RXD PINs bereits durch Bluetooth benutzt werden, kamen diese leider 
nicht in Frage...

Ich hoffe ich schaffe das alles mal bald...

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


Lesenswert?

Sercan S. schrieb:
> Nun erkläre ich euch mal in PSEUDOCODE wie ich vorgehen wollte:
> SOLANGE !WELTUNTERGANG :
1
 MASTER & SLAVE rufen ihre spiInit... Methoden auf
2
  JA.
3
4
 SLAVE überwacht SS PIN und wartet auf ein LOW Signal
5
  NEIN. Falls mit ISR empfangen wird, macht der SLAVE das in der ISR,
6
  falls mit polling gearbeitet wird, macht der SLAVE folgendes:
7
     while (!(SPSR & (1<<SPIF)));
8
9
 MASTER will senden
10
 MASTER setzt SS PIN auf LOW
11
 MASTER ruft SPI_MasterTransmit auf
12
  JA.
13
14
 SLAVE bekommt den LOW Signal an SS PIN mit und ruft spiSlaveTransmit auf
15
  NEIN, siehe oben.
16
17
 MASTER & SLAVE Warten bis Datenübertragung zuende ist
18
 MASTER setzt den SS PIN auf HIGH
19
 MASTER & SLAVE können die empfangenen Daten verarbeiten
20
  JA.

 Jetzt muss der SLAVE nächstes Byte vorbereiten (falls nötig)
 und mit:
1
 SPDR = Antwort;
 dies auch reinschreiben.

 Beim nächsten Transmit vom MASTER kriegt der SLAVE ein neues Befehl
 und der MASTER kriegt die reingeschriebene Antwort.

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


Lesenswert?

Sercan S. schrieb:
> void SPI_MasterTransmit(char cData) {
>   /* Start transmission */
>   PORTB &= (1<<PB2);
>   SPDR = cData;
>   /* Wait for transmission complete */
>   while(!(SPSR & (1<<SPIF)))
>   PORTB |= (1<<PB2);
> ; }

 Erstens machst du es verkehrt, zweitens musst du nur einmal vorher
 SS Pin als Ausgang setzen, alles andere macht deine MEGA alleine.

 Lass SS Pin in Ruhe !!

von SPISpezialist (Gast)


Lesenswert?

Sercan S. schrieb:
> vielleicht entdeckst du ja etwas

Zuerst müsstest du dazu sagen was du von deinem Code erwartest.

Dann:

- board_init()  fehlt total, sowohl bei Master als auch bei Slave

Sercan S. schrieb:
> if(!(PINB & (1<<PB2))){

Du brauchst den SlaveSelect nicht abfragen, es reicht das SPI
Status Register zu fragen. Denn wenn SlaveSelect Low ist hast
du noch kein Byte empfangen. Das Status Register gibt zuverlässig
Auskunft darüber.

von SPISpezialist (Gast)


Lesenswert?

Sercan S. schrieb:
> ein LED
> geschaltet und siehe da LED leuchtet nicht? Also werden dort dann ja
> auch keine Taktsignale erzeugt oder?

Nein, nicht unbedingt. Das SPI Telegramm kann so kurz und schnell
sein dass du die LED nicht leuchten siehst.

SPISpezialist schrieb:
> - board_init()  fehlt total, sowohl bei Master als auch bei Slave

Ach so, kommt wohl vom ASF (das ich nicht benutze) ....

von Sercan S. (disaster35)


Lesenswert?

Marc V. schrieb:
> Sercan S. schrieb:
>> void SPI_MasterTransmit(char cData) {
>>   /* Start transmission */
>>   PORTB &= (1<<PB2);
>>   SPDR = cData;
>>   /* Wait for transmission complete */
>>   while(!(SPSR & (1<<SPIF)))
>>   PORTB |= (1<<PB2);
>> ; }
>
>  Erstens machst du es verkehrt, zweitens musst du nur einmal vorher
>  SS Pin als Ausgang setzen, alles andere macht deine MEGA alleine.
>
>  Lass SS Pin in Ruhe !!

Ich würde gerne aber da alles nicht geklappt hat und ich es vorher ohne 
den SS PIN versucht habe, habe ich natürlich dort rumgefuscht. :D

>Sercan S. schrieb:
>> vielleicht entdeckst du ja etwas
>
>Zuerst müsstest du dazu sagen was du von deinem Code erwartest.
Als erstes will ich, dass es Problemfrei hinbekommt den einen Byte zu 
senden, den ich versuche zu senden. Also
1
char send = '1';

Was kommt eigentlich beim Empfänger an wenn ich
1
char send = '1';
oder
1
char send = 1;
 sende? Kommt da beim '1' die 49 (wegen ASCII) und bei 1 tatsächlich die 
1 an?

>
>Dann:
>
>- board_init()  fehlt total, sowohl bei Master als auch bei Slave
board_init() ist doch da :O ?

>
>Sercan S. schrieb:
>> if(!(PINB & (1<<PB2))){
>
>Du brauchst den SlaveSelect nicht abfragen, es reicht das SPI
>Status Register zu fragen. Denn wenn SlaveSelect Low ist hast
>du noch kein Byte empfangen. Das Status Register gibt zuverlässig
>Auskunft darüber.



also wie Marc Veseyl geschrieben hat muss ich einfach while(!(SPSR & 
(1<<SPIF))) aufrufen und warten bis dort was reingeschrieben wurden ist?

von SPISpezialist (Gast)


Lesenswert?

Marc V. schrieb:
> Lass SS Pin in Ruhe !!

Ich verspüre - wie in anderen Beiträgen auch - eine gewisse
Agressivität im Ton.

Auch höre ich zwischen den Zeilen dauernd:
"du machst alles scheisse, mach das gefälligst besser!"

von SPISpezialist (Gast)


Lesenswert?

Sercan S. schrieb:
> also wie Marc Veseyl geschrieben hat muss ich einfach while(!(SPSR &
> (1<<SPIF))) aufrufen und warten bis dort was reingeschrieben wurden ist?

Ja.

von Sercan S. (disaster35)


Lesenswert?

>Marc V. schrieb:
>> Lass SS Pin in Ruhe !!
>
>Ich verspüre - wie in anderen Beiträgen auch - eine gewisse
>Agressivität im Ton.

Alles gut. Nicht streiten :D
>
>Auch höre ich zwischen den Zeilen dauernd:
>"du machst alles scheisse, mach das gefälligst besser!"
>
>SPISpezialist schrieb:
>> Sercan S. schrieb:
>>> also wie Marc Veseyl geschrieben hat muss ich einfach while(!(SPSR &
>>> (1<<SPIF))) aufrufen und warten bis dort was reingeschrieben wurden ist?
>>
>> Ja.

Und die PINS wirklich so lassen also (MOSI-MOSI, MISO-MISO, SCK-SCK, 
SS-SS)?

von SPISpezialist (Gast)


Lesenswert?

Sercan S. schrieb:
> Und die PINS wirklich so lassen also (MOSI-MOSI, MISO-MISO, SCK-SCK,
> SS-SS)?

Ja.

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


Lesenswert?

SPISpezialist schrieb:
> Ich verspüre - wie in anderen Beiträgen auch - eine gewisse
> Agressivität im Ton.

 Irgendwie verspüre ich gewisse Hörschwierigkeiten.

 Grossbuchstaben bedeuten agressives Schreien.
 Ausrufungszeichen betont etwas.

 ICH HABE ABER NICHT GESCHRIEN, IST DAS KLAR ?!

 :-)

von SPISpezialist (Gast)


Lesenswert?

Noch ein Tip:

Mache ein neues Projekt auf und kopiere deine existierenden
Sourcen, reduziere alles auf das Minimum was du brauchst um
deine SPI-Übertragung erfolgreich durchzuführen. Wenn das
funktioniert kannst du ja dein übriges Programm drum herum
bauen.

von SPISpezialist (Gast)


Lesenswert?

Marc V. schrieb:
> IST DAS KLAR ?!

Schon dieser Teilsatz erzeugt ein gewisses Schauern bei mir.
Ehrlich gesagt möchte ich dir nicht am Tisch gegenüber sitzen.
Auch nicht neben dir.

von Sercan S. (disaster35)


Lesenswert?

Also, ich habe das jetzt gerade so hingekriegt, dass die Totalsumme von 
1010 auf der Segmentanzeige angezeigt wurde sprich, ich kam beim Slave 
aus der while schleife raus, wo die Datenübertragung stattgefunden hat? 
Also habe ich ja Daten bekommen, sprich es hat geklappt? :O

Anschließend habe ich versucht, den totalSum statt mit 1010 
abzuspeichern mit den empfangenen Byte zu belegen. Aber wenn ich 
(totalSum ist ein int) totalSum += (int)SPI_SlaveReceive();
oder gar ohne den int-Cast versuche, klappt die Anzeige nicht... :hmmm:

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


Lesenswert?

Sercan S. schrieb:
> also wie Marc Veseyl geschrieben hat muss ich einfach while(!(SPSR &
> (1<<SPIF))) aufrufen und warten bis dort was reingeschrieben wurden ist?

 Ja, aber bestimmt nicht in der ISR(TIMER0_OVF_vect).

 P.S.
 Wenn über SPI nichts kommt, funktioniert auch deine Anzeige nicht.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Das SPI des AVR ist nicht gerade das, was man als Slave haben will. Es 
ist ne Krücke.

Du mußt alle 4 Leitungen verbinden und das SS des Master muß vor dem 
SPI-Init als Ausgang gesetzt werden. Damit ist SS vom SPI abgekoppelt, 
d.h. ein ganz normaler Output-Pin.
Dann mußt Du als Master mit SS=0 dem Slave sagen, daß ein Byte beginnt, 
d.h. nur so wird der Slave Bit-synchron.
Sind alle Bytes übertragen, mußt Du SS=1 setzen.

Vorzugsweise nimmt man als Slave nicht den alten Mega8, sondern den 
Mega88 und setzt für SS den Pin-change Interrupt. Nur so kann man Anfang 
und Ende eines Paketes feststellen. Falls es der Mega8 sein muß, muß man 
eben den SS-Pin mit dem INT0/1-Pin verbinden.

Will der Master was lesen, muß er vor jedem Byte eine Pause lassen, 
damit der Slave in den Interrupt springen und das Byte in SPDR schreiben 
kann. Ich würde >=100µs Pause empfehlen.

von Sercan S. (disaster35)


Lesenswert?

Peter D. schrieb:
> Das SPI des AVR ist nicht gerade das, was man als Slave haben will. Es
> ist ne Krücke.
>
> Du mußt alle 4 Leitungen verbinden und das SS des Master muß vor dem
> SPI-Init als Ausgang gesetzt werden. Damit ist SS vom SPI abgekoppelt,
> d.h. ein ganz normaler Output-Pin.
> Dann mußt Du als Master mit SS=0 dem Slave sagen, daß ein Byte beginnt,
> d.h. nur so wird der Slave Bit-synchron.
> Sind alle Bytes übertragen, mußt Du SS=1 setzen.
>
> Vorzugsweise nimmt man als Slave nicht den alten Mega8, sondern den
> Mega88 und setzt für SS den Pin-change Interrupt. Nur so kann man Anfang
> und Ende eines Paketes feststellen. Falls es der Mega8 sein muß, muß man
> eben den SS-Pin mit dem INT0/1-Pin verbinden.
>
> Will der Master was lesen, muß er vor jedem Byte eine Pause lassen,
> damit der Slave in den Interrupt springen und das Byte in SPDR schreiben
> kann. Ich würde >=100µs Pause empfehlen.

Jetzt kommts...
Nun soll ich den SS-PIN doch setzen und den vordem SPI-Init als Ausgang 
setzen und esklappt irgendwie vorne und hinten nicht.... Ich glaube SPI 
ist bisschen komplizierter als ich es mir gedacht habe.
Was haltet Ihr von I2C? Ich bin bei der Recherche auf I2C gestoßen und 
da meinte man, dass es einfacher und sicherer von statten ginge....

von Martin B. (Gast)


Lesenswert?

Kein Grund zur Hektik. Das ist doch nur das, was Du vorher schon geplant 
hast.
 Bei SS High wird der Slave nichts empfangen.

von Sercan S. (disaster35)


Lesenswert?

Wo soll ich es denn sonst aufrufen, wenn nicht in ISR (TIMER0_OVF_vect)?

von SPISpezialist (Gast)


Lesenswert?

Sercan S. schrieb:
> Wo soll ich es denn sonst aufrufen, wenn nicht in ISR (TIMER0_OVF_vect)?

In deiner Hauptschleife die du dir vorstellst.

Deine ISR (Timer) hat uja mit dem SPI-Empfangen nichts zu tun.

von Martin B. (Gast)


Lesenswert?

äähhm, ich habe mal kurz in Dein Programm geschaut.
steht da immer noch

PORTB &= (1<<PB2);

in  SPI_MasterTransmit?

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


Lesenswert?

Sercan S. schrieb:
> Wo soll ich es denn sonst aufrufen, wenn nicht in ISR (TIMER0_OVF_vect)?

 Du hast in deinem Code Timer0 mit Vorteiler 1 laufen lassen, also
 mit 8MHz.

 Probiere das mal, nur zum Testen:
 Master
1
char send = '1';
2
volatile uint16_t increment = 0;
3
volatile uint8_t Flag = 0;
4
5
void SPI_MasterInit(void) {
6
  /* Set MOSI and SCK output, all others input */
7
  DDRB = (1<<PB5)|(1<<PB3) |(1<<PB2);
8
  PORTB |= (1<<PB2);
9
  /* Enable SPI, Master, set clock rate fck/16 */
10
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
11
}
12
void SPI_MasterTransmit(char cData) {
13
  /* Start transmission */
14
  PORTB &= (1<<PB2);
15
  SPDR = cData;
16
  /* Wait for transmission complete */ 
17
  while(!(SPSR & (1<<SPIF)))
18
  PORTB |= (1<<PB2);
19
; }
20
21
int main (void)
22
{
23
   board_init();
24
  // Timer 0 konfigurieren
25
  // Bei dir war es mit Prescaler 1, also 8 MHz !!!
26
  TCCR0 = (1<<CS00) | (1<<CS02);          // Start Timer 0 with prescaler 1024
27
  TIMSK |= (1<<TOIE0) /*| (1<<TOIE2)*/;               // Enable Timer 0 overflow interrupt
28
  sei();
29
  DDRD = (1<<PD0);
30
  //PORTD |= (1<<PD0);
31
  SPI_MasterInit();
32
33
  while(1){
34
    if (Flag==1) {
35
      Flag = 0;
36
      SPI_MasterTransmit(send++);
37
      if (send>0x39) send = 0x30;
38
    }
39
  }
40
}
41
42
ISR(TIMER0_OVF_vect)
43
{
44
  increment++;
45
  if(increment>=7812) {
46
    increment = 0;
47
    PORTD ^= 0x01;
48
    Flag = 1;   
49
  }
50
}

 Slave
1
char send = '1';
2
3
void SPI_SlaveInit(void) {
4
  /* Set MISO output, all others input */
5
  DDRB = (1<<PB4);
6
  /* Enable SPI */
7
  SPCR = (1<<SPE);
8
}
9
char SPI_SlaveReceive(void) {
10
  /* Wait for reception complete */ 
11
  while(!(SPSR & (1<<SPIF)));
12
  /* Return data register */ 
13
  return SPDR;
14
}
15
16
int main (void)
17
{
18
  /* Eine LED an PORTC.0  */
19
  DDRC |= (1<<PC0); 
20
  
21
  sei();
22
  SPI_SlaveInit();
23
  
24
  while(1){
25
    send = SPI_SlaveReceive();
26
  // Toggle LED 
27
       PORTC ^= 0x01;
28
  }
29
}

von Arno (Gast)


Lesenswert?

Fang doch mal ganz einfach an:

- Master SS offen lassen und auf Output setzen
- Slave SS fix auf GND
- MOSI-MOSI, SCK-SCK und MISO-MISO verbinden und so auf Output setzen, 
wie du es oben beschrieben hast (ich prüfe jetzt nicht, ob B5 und B3 
wirklich MOSI und SCK sind)
- Initialisierung nochmal überprüfen
- Taktrate so niedrig wie möglich (damit vielleicht du eine Chance hast, 
mit einer LED etwas zu sehen)

Wenn du jetzt auf dem Master folgendes ausführst...
1
while(true)
2
{
3
   SPDR = 0xaa;                   // Daten per SPI rausschicken
4
   while (! (SPSR & (1<<SPIF)) )  // solange Daten nicht vollständig verschickt...
5
     ;                            // nichts tun
6
}

...müsste permanent Gezappel an allen drei Pins zu beobachten sein (0xaa 
ist 0b10101010, also bei jedem Takt ein Flankenwechsel, alternativ 
kannst du auch 0xf0 = 0b11110000 probieren, dann sind die Flankenwechsel 
auf MOSI/MISO deutlich langsamer als auf SCK). Solange muss der Slave 
noch gar nichts tun...

Wenn das klappt, kannst du 0xaa mit 0x00 und 0xff ersetzen, schauen, ob 
MOSI und MISO jetzt dauerhaft low bzw. high bleiben

Dann packst du statt dieser Spieldaten mal etwas sinnvolles (1 oder '1') 
in die Daten und packst in den Slave sowas wie...
1
while(true)
2
{
3
   if (SPSR & (1<<SPIF))           // ist ein Byte angekommen?
4
   {
5
      unsigned char data = SPDR;   // Byte aus dem SPI-Register holen
6
      output (data);               // irgendwie ausgeben
7
   }
8
}

Jetzt wirst du feststellen, dass nicht die Daten ankommen, die du 
erwartest. Das liegt daran, dass der Slave nicht weiß, wo das Datenbyte 
beginnt. Und genau dafür kannst du den SS-Pin nutzen, jetzt also wieder 
Master und Slave SS-Pins verbinden und in Pseudocode:

Master: Setze SS auf low
Master: Warte, bis sicher ist, dass das Signal beim Slave angekommen ist 
(zum Testen gerne mal 1s probieren, dann kannst du das mit deiner LED 
nachverfolgen, später wirst du vermutlich ein paar µs brauchen)
Master: Sende Daten (SPDR = '1'; while ( !(SPSR & (1<<SPIF)) ) ;)
Master: Warte, bis sicher ist, dass das letzte Bit beim Slave angekommen 
ist
Master: Setze SS auf high

Am Slave-Code änderst du nichts.

MfG, Arno

P.S: Einen Bug sehe ich in deiner SPI_MasterTransmit...
1
while(!(SPSR & (1<<SPIF)))
2
  PORTB |= (1<<PB2);
...damit setzt du SS wieder auf High, bevor das Byte durchgetaktet 
wurde. Du willst vermutlich:
1
while(!(SPSR & (1<<SPIF)))
2
  ;
3
PORTB |= (1<<PB2);

von Martin B. (Gast)


Lesenswert?

und möglichst noch das

 PORTB &= (1<<PB2);

in

 PORTB &= ~(1<<PB2);

ändern.

von Sercan S. (disaster35)


Lesenswert?

Marc V. schrieb:
> Sercan S. schrieb:
>> Wo soll ich es denn sonst aufrufen, wenn nicht in ISR (TIMER0_OVF_vect)?
>
>  Du hast in deinem Code Timer0 mit Vorteiler 1 laufen lassen, also
>  mit 8MHz.
>
>  Probiere das mal, nur zum Testen:
>..........

Also ich bin jetzt heute erst dazugekommen und habe diese Testweise 
raufgespielt und diese wie von mir beschrieben angeschlossen und muss 
feststellen, dass es irgendwie nicht klappt. Irgendwas muss da ja falsch 
sein, die LED schaltet sich einfach nicht an. LED habe ich getestet und 
ohne den
1
send = SPI_SlaveReceive();
 geht die LED auch an (toggelt). Also liegt es wirklich an der 
Übertragung...

von Arno (Gast)


Lesenswert?

Dann gibt es drei Möglichkeiten:

1) Der Slave bekommt keine oder zu schnelle SCK-Signale
2) Der Slave bekommt kein SS-Signal bzw. eins mit falschem Timing (SS 
muss auf low bleiben, bis acht SCK-Pulse durch sind, sonst erkennt der 
Slave nie ein vollständig übertragenes Byte)
3) An der Slave-Initialisierung stimmt irgendwas nicht

Hast du Marcs Code in SPI_MasterTransmit schon um die beiden Fehler (die 
er von dir kopiert hat) korrigiert, die Martin und ich beschrieben 
haben? Die sorgen nämlich für gar kein ("Martins" Bug) bzw. ein viel zu 
kurzes ("mein" Bug) SS-Signal, also Punkt 2 oben auf der Liste, damit 
kann es also auch gar nicht gehen.

Alternativ nimm die SS-Verbindung weg und leg den Slave-SS fest auf 
Masse, dann hast du Fehlerquelle 2 schonmal ausgeschlossen. Wenn es dann 
immer noch nicht geht, nimm auch die SCK-Verbindung weg und halte einen 
Draht von Slave-SCK abwechselnd an GND und VCC bis die LED toggelt. Ja, 
SPI ist so einfach und kann beliebig langsam laufen.

MfG, Arno

von Sercan S. (disaster35)


Lesenswert?

Ich muss mal euch nun ein Update geben...

Also ausprobiert habe ich o.g. Code wie folgt angeschlossen:
1
SCK    <->    SCK
2
MISO   <->    MISO
3
MOSI   <->    MOSI
4
SS     <->    SS

Klappt nicht.


Wenn ich es allerdings so anschließe, wie im Atmel Datenblatt 
beschrieben:
1
SCK           <->    SCK
2
MISO          <->    MISO
3
MOSI          <->    MOSI
4
5
MASTER_SS     <->    VCC
6
SLAVE_SS      <->    GND

Klappt! WARUM? :O

Ich muss allerdings nachprüfen, ob auch das richtige ankommt, aber 
irgendetwas kommt schonmal an sonst würde es doch nicht toggeln...

EDIT: Es kommt auch das richtige an! Also es fängt von 49 an und springt 
bei nach 57 auf 48 und geht wieder von vorne los. Ich habe Testweise 
beide SS_PINS freigelassen und es klappt auch ohne es in VCC/GND zu 
beschalten...

: Bearbeitet durch User
von Arno (Gast)


Lesenswert?

Arno schrieb:
> Hast du Marcs Code in SPI_MasterTransmit schon um die beiden Fehler (die
> er von dir kopiert hat) korrigiert, die Martin und ich beschrieben
> haben? Die sorgen nämlich für gar kein ("Martins" Bug) bzw. ein viel zu
> kurzes ("mein" Bug) SS-Signal, also Punkt 2 oben auf der Liste, damit
> kann es also auch gar nicht gehen.

MfG, Arno

von Arno (Gast)


Lesenswert?

Arno schrieb:
> Master und Slave SS-Pins verbinden und in Pseudocode:
>
> Master: Setze SS auf low
> Master: Warte, bis sicher ist, dass das Signal beim Slave angekommen ist
> (zum Testen gerne mal 1s probieren, dann kannst du das mit deiner LED
> nachverfolgen, später wirst du vermutlich ein paar µs brauchen)
> Master: Sende Daten (SPDR = '1'; while ( !(SPSR & (1<<SPIF)) ) ;)
> Master: Warte, bis sicher ist, dass das letzte Bit beim Slave angekommen
> ist
> Master: Setze SS auf high

MfG, Arno

von Arno (Gast)


Lesenswert?

Arno schrieb:
> P.S: Einen Bug sehe ich in deiner SPI_MasterTransmit...
>
1
> while(!(SPSR & (1<<SPIF)))
2
>   PORTB |= (1<<PB2);
3
>
> ...damit setzt du SS wieder auf High, bevor das Byte durchgetaktet
> wurde. Du willst vermutlich:
>
1
> while(!(SPSR & (1<<SPIF)))
2
>   ;
3
> PORTB |= (1<<PB2);
4
>

MfG, Arno

von Arno (Gast)


Lesenswert?

Martin B. schrieb:
> und möglichst noch das
>
>  PORTB &= (1<<PB2);
>
> in
>
>  PORTB &= ~(1<<PB2);
>
> ändern.

So, nochmal in kleinen Häppchen zusammengesucht, warum es mit der 
Verbindung der beiden SS-Pins nicht geht. Steht alles schon oben, 
teilweise mehrfach - entweder du hast es nicht verstanden (das ist keine 
Schande, dann frag bitte nach) oder du hast es nicht gelesen (dann hör 
auf, herumzuprobieren, bis du alles gelesen hast, sonst ist es sehr 
anstrengend, irgendwie sinnvoll auf deine Fragen zu antworten).

Danke und viele Grüße,
Arno

von Arno (Gast)


Lesenswert?

Ergänzung (vielleicht sollte ich mich doch mal registrieren, dass ich 
meine Beiträge bearbeiten kann...):
- Es ist gefährlich, wenn du den Master-SS-Pin auf VCC legst und ihn 
gleichzeitig als Ausgang definierst. Damit kannst du dir ganz schnell 
den Ausgang kaputtmachen, oder sogar den ganzen Controller, wenn du ihn 
aus Versehen umschaltest.
- Es ist Zufall, dass es mit offenem Slave-SS-Pin funktioniert. Je 
nachdem, was gerade an elektromagnetischem Dreck in der Luft ist, kann 
der Slave auch Highlevel am SS-Pin sehen, und dann funktioniert es nicht 
mehr.
- Es ist Zufall, dass es ohne verbundene SS-Pins richtig funktioniert. 
Es kommen immer Daten an, aber dass es die richtigen sind, hängt davon 
ab, in welcher Reihenfolge du Master und Slave einschaltest, welcher 
Controller wie schnell durch seine Initialisierung läuft... Wenn der 
Master ein kleines bisschen schneller ist als der Slave, wird er schon 
ein paar Bits auf die SPI gesendet haben, bevor der Slave bereit ist, 
sie zu empfangen. Der Master schickt also zum Beispiel Bits 1-3, dann 
empfängt der Slave Bit 4-8 und interpretiert das als Bits 1-5, dann 
sendet der Master das nächste Byte, Bit 1-3 landen beim Slave als Bits 
6-8, der Slave erkennt das erste vollständige Byte, setzt SPIF, empfängt 
weiter Bits 4-8 vom zweiten Byte und speichert sie als Bits 1-5 in 
seinem zweiten Byte. Der SS-Pin sorgt dafür, dass der Slave genau weiß, 
wann ein Byte beginnt - wenn man ihn richtig beschaltet.

MfG, Arno

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


Lesenswert?

Arno schrieb:
> - Es ist Zufall, dass es mit offenem Slave-SS-Pin funktioniert. Je
> - Es ist Zufall, dass es ohne verbundene SS-Pins richtig funktioniert.

 Kann mich dem nur anschliessen.


Sercan S. schrieb:
> Klappt! WARUM? :O

 Warum nicht ?

 Dein SLAVE ist selektiert ( SLAVE_SS auf GND ), bei MASTER ist SS auf
 HIGH - MASTER sendet, SLAVE empfängt - für die beiden ist ALLES in
 bester Ordnung...

 P.S.
 Nur nicht jetzt zufällig MASTER_SS auf 0 setzen.

: Bearbeitet durch User
von Sercan S. (disaster35)


Lesenswert?

Hallo,

ja ich habe die Zeile verbessert :)
Wenn ich nun die SS am SS verbinde, wie gehe ich dabei vor?
Master zieht den PB2 (SS) auf LOW und nach der While-Schleife (nach der 
Übertragung) wird es ja wieder auf HIGH gezogen.

Ich müsste ja logischerweise auf Seiten der Slave nun:
1
if(!(PINB & (1<<PB2))){
2
  send = SPI_SlaveReceive();
3
}

Also Überprüfen ob PB2 auf LOW gezogen wurde und dann lesen oder?

von SPISpezialist (Gast)


Lesenswert?

Sercan S. schrieb:
> Also Überprüfen ob PB2 auf LOW gezogen wurde und dann lesen oder?

Mann oh Mann, du hast schon noch überhaupt nichts kapiert.

SPISpezialist schrieb:
> Du brauchst den SlaveSelect nicht abfragen, es reicht das SPI
> Status Register zu fragen. Denn wenn SlaveSelect Low ist hast
> du noch kein Byte empfangen. Das Status Register gibt zuverlässig
> Auskunft darüber.

von Sercan S. (disaster35)


Lesenswert?

SPISpezialist schrieb:
> Sercan S. schrieb:
>> Also Überprüfen ob PB2 auf LOW gezogen wurde und dann lesen oder?
>
> Mann oh Mann, du hast schon noch überhaupt nichts kapiert.
>
> SPISpezialist schrieb:
>> Du brauchst den SlaveSelect nicht abfragen, es reicht das SPI
>> Status Register zu fragen. Denn wenn SlaveSelect Low ist hast
>> du noch kein Byte empfangen. Das Status Register gibt zuverlässig
>> Auskunft darüber.

Ich habe es schon verstanden, dass der Status Register darüber 
zuverlässig Informationen darüber gibt.

Ich möchte ja in meinem Programm auch noch andere Sachen machen und da 
dachte ich mir, da ich sowieso den SS auf LOW und anschließend auf HIGH 
ziehe, kann ich ja dann SPDR abholen. Weil ich sende ja nicht ständig 
irgendwelche Daten rüber, aber falls mal was da ist möchte ich das 
mitbekommen und da schien es mir logisch einfach den SS-LOW-HIGH zu 
prüfen um dann die angekommene Daten abzulesen.

EDIT: Da ich den letzten SPDR speichere könnte ich ja auch einfach 
vergleichen ob die jetzige Daten in SPDR verschieden sind, dann könnte 
ich somit auch Bescheid wissen, dass da was neues ist. Ich möchte mit 
der While-Schleife halt nicht warten, bis es verändert wurden ist, somit 
stoppe ich ja mein ganzen Programmlauf.

: Bearbeitet durch User
von Jim M. (turboj)


Lesenswert?

Sercan S. schrieb:
> Weil ich sende ja nicht ständig
> irgendwelche Daten rüber, aber falls mal was da ist möchte ich das
> mitbekommen und da schien es mir logisch einfach den SS-LOW-HIGH zu
> prüfen um dann die angekommene Daten abzulesen.

Auf dem Slave?
Wenn man da nicht mit Interrupts oder DMA arbeitet, wird es mit SPI nix.

Bei SPI möchte man den Takt am Master normalerweise nicht so weit runter 
drehen - weil der ja auch vermutlich auch noch was anderes zu tun hat 
als auf den Slave zu warten.

Bessere Lösung: SPI Interrupt + FIFOs für Transmit und Receive. Atmega8 
hat ja leider kein DMA.

Die Hauptschleife muss sich dann nur noch um die FIFOs kümmern.

von Arno (Gast)


Lesenswert?

Sercan S. schrieb:
> ja ich habe die Zeile verbessert :)

Beide Zeilen? Martins und meine?

> Wenn ich nun die SS am SS verbinde, wie gehe ich dabei vor?
> Master zieht den PB2 (SS) auf LOW und nach der While-Schleife (nach der
> Übertragung) wird es ja wieder auf HIGH gezogen.

Genau (aber nur, wenn du die while-Schleife korrigiert hast, die macht 
nämlich im Moment noch was anderes, wie ich oben schon geschrieben 
habe). Ich würde da noch jeweils ein paar µs delay einbauen, um sicher 
zu gehen, dass dir unterschiedliche Signallaufzeiten nicht den Plan 
kaputt machen, aber es müsste auch ohne funktionieren.

> Ich müsste ja logischerweise auf Seiten der Slave nun:
>
1
> if(!(PINB & (1<<PB2))){
2
>   send = SPI_SlaveReceive();
3
> }
4
>
>
> Also Überprüfen ob PB2 auf LOW gezogen wurde und dann lesen oder?

Nein. Das macht die SPI-Hardware im Slave von ganz alleine. Du musst nur 
noch prüfen, ob die SPI ein komplettes Byte empfangen hat:
[c]
if(SPSR & (1<<SPIF))
  {
    unsigned char data = SPDR;
    //mach irgendwas mit data
  }
[c]

Sercan S. schrieb:
> Ich habe es schon verstanden, dass der Status Register darüber
> zuverlässig Informationen darüber gibt.

Dann nutz es doch. Wenn du oft genug SPIF abfragst, bekommst du das mit, 
noch sicherer, wenn du einen SPI-Interrupt nutzt. Besser als den SS-Pin 
abzufragen, denn ein SPI-Master kann auch direkt ein zweites Byte 
hinterher schicken, ohne SS zwischendurch auf High zu ziehen. Und selbst 
bei deinem Master kann SS sehr sehr kurz auf High und gleich wieder auf 
Low gehen.

> Ich möchte ja in meinem Programm auch noch andere Sachen machen und da
> dachte ich mir, da ich sowieso den SS auf LOW und anschließend auf HIGH
> ziehe,

SS fasst du auf dem Slave mit deinem Code doch nach der Initialisierung 
gar nicht an?

> Ich möchte mit
> der While-Schleife halt nicht warten, bis es verändert wurden ist, somit
> stoppe ich ja mein ganzen Programmlauf.

Deswegen solltest du keine while-Schleife verwenden, sondern eine 
if-Abfrage, die wird übersprungen, wenn das SPIF-Bit noch nicht gesetzt 
ist. Muss nur oft genug aufgerufen werden, damit der Master nicht schon 
ein komplettes zweites Byte geschickt hat. Während der Master das zweite 
Byte sendet, ist OK, solange hat SPDR noch den alten Wert, aber sobald 
das zweite Byte komplett ist, wird SPDR auf den neuen Wert aktualisiert.

MfG, Arno

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.