Forum: Mikrocontroller und Digitale Elektronik SPI Slave Receive


von Deyn (Gast)


Lesenswert?

Hallo

Wir wollen Daten per SPI von einem ATMega88 zu einem anderen ATMega88 
schicken.

Wir verwenden folgenden Code:

SIGNAL (SIG_SPI)
{
  received_character = SPDR;
}

void SPI_SlaveInit (void)
{
  DDRB |= (1<<PB4);
  SPCR = (1<<SPE) | (1<<SPIE) | (1<<SPR0);
}

Beim Simulieren springt er auch nach dem setzen der SPI Interrupt Flag 
in SIGNAL (SIG_SPI) nun wird aber kein Wert vom SPDR in 
received_character übernommen.

received_character haben wir als uint8_t definiert.

Kann uns jemand helfen?

Deyn

von Peter M. (pmahlknecht)


Lesenswert?

Hallo,
habt ihr die Variable received_character auch als volatile deklariert?
Grüße Peter

von Deyn (Gast)


Lesenswert?

Wir haben es nun so deklariert:
1
volatile uint8_t received_character;

Funktioniert aber immer noch nicht.

von Deyn (Gast)


Lesenswert?

Hier mal unser kompletter c-Code
1
volatile uint8_t received_character;
2
3
//Variablen
4
bool takt_1s = false;
5
bool takt_100ms = false;
6
bool takt_10ms = false;
7
unsigned int vorteiler = VORTEILER;
8
unsigned int zehntel = ZEHNTEL;
9
unsigned int hundertstel = HUNDERTSTEL;
10
11
//Funktionsprototypen
12
void SPI_SlaveInit (void);
13
void timer0 (void);
14
15
16
17
int main ()
18
{
19
  //Init
20
  sei();
21
  SPI_SlaveInit();          //set enable interrupt
22
  timer0();
23
24
  DDRB = 0x0f;
25
  DDRC = 0x0f;
26
  DDRD = 0xff;
27
28
  PORTC = 0x0f;
29
30
  while(1)
31
  {
32
    if (takt_1s == true)
33
    {
34
      takt_1s = false;
35
      if (received_character == 1)
36
      {
37
        PINC = 0xFF;
38
        PIND = 0xFF;
39
      }      
40
    }
41
  }
42
}
43
44
// Timer 0 Initialisierung
45
46
void timer0 (void)
47
{
48
  TCCR0A |= (0<<WGM00) | (0<<WGM01);
49
  TCCR0B |= (0<<WGM02) | (0<<CS02) | (1<<CS01) | (0<<CS00);
50
  TIMSK0 |= (1<<TOIE0);
51
}
52
53
// Interrupt-Routine
54
55
ISR (TIMER0_OVF_vect)
56
{
57
  vorteiler --;
58
59
  if (vorteiler == 0)
60
  {
61
    vorteiler = VORTEILER;
62
    takt_10ms = 1;
63
    hundertstel --;
64
  }
65
  
66
67
  
68
  if (hundertstel == 0)
69
  {
70
    hundertstel = HUNDERTSTEL;
71
    takt_100ms = 1;
72
    zehntel --;
73
  }
74
75
  
76
  if (zehntel == 0)
77
  {
78
    zehntel = ZEHNTEL;
79
    takt_1s = true;
80
  }
81
}
82
83
SIGNAL (SIG_SPI) 
84
{
85
  received_character = SPDR;  
86
}
87
88
void SPI_SlaveInit (void) 
89
{
90
  DDRB |= (1<<PB4);          
91
  SPCR = (1<<SPE) | (1<<SPIE) | (1<<SPR0);        
92
}

von Matthias (Gast)


Lesenswert?

> Beim Simulieren springt er auch nach dem setzen der SPI Interrupt Flag
> in SIGNAL (SIG_SPI) nun wird aber kein Wert vom SPDR in
> received_character übernommen.

JTAG oder Simulator?

Stimmen die CPOL / CPHA Parameter?

Wird SS richtig angesteuert? Wenn SS nach HIGH wechselt und die CPOL / 
CPHA
nicht passt, dann wird das Datenbyte verworfen.

Zur näheren Analyse wäre der Sourcecode des Senders hilfreich.

von deyn (Gast)


Lesenswert?

cpol cpha sagt uns nichts...
wir haben es simuliert im avr studio...
hier mal der c-code des sender (masters) :
1
//Variablen
2
bool takt_1s = false;
3
bool takt_100ms = false;
4
bool takt_10ms = false;
5
unsigned int sekunden = 50;
6
unsigned int minuten = 59;
7
unsigned int stunden = 23;
8
unsigned int vorteiler = VORTEILER;
9
unsigned int zehntel = ZEHNTEL;
10
unsigned int hundertstel = HUNDERTSTEL;
11
unsigned int wert = 1;
12
13
//Funktionsprototypen
14
void SPI_MasterInit (void);
15
void SPI_MasterTransmit (unsigned int cData);
16
17
void Stellfunktion (void);
18
void timer0 (void);
19
20
21
int main ()
22
{
23
  //Init
24
  sei();
25
  SPI_MasterInit();          
26
  timer0();
27
28
  DDRC = 0x0f;
29
  DDRD = 0xff;
30
31
  PORTC = 0x0f;
32
33
  while(1)
34
  {
35
    if (takt_1s == true)
36
    {
37
      takt_1s = false;
38
      
39
      SPI_MasterTransmit(wert);
40
    }
41
  }
42
}
43
44
// Timer 0 Initialisierung
45
46
void timer0 (void)
47
{
48
  TCCR0A |= (0<<WGM00) | (0<<WGM01);
49
  TCCR0B |= (0<<WGM02) | (0<<CS02) | (1<<CS01) | (0<<CS00);
50
  TIMSK0 |= (1<<TOIE0);
51
}
52
53
// Interrupt-Routine
54
55
ISR (TIMER0_OVF_vect)
56
{
57
  vorteiler --;
58
59
  if (vorteiler == 0)
60
  {
61
    vorteiler = VORTEILER;
62
    takt_10ms = 1;
63
    hundertstel --;
64
  }
65
  
66
67
  
68
  if (hundertstel == 0)
69
  {
70
    hundertstel = HUNDERTSTEL;
71
    takt_100ms = 1;
72
    zehntel --;
73
  }
74
75
  
76
  if (zehntel == 0)
77
  {
78
    zehntel = ZEHNTEL;
79
    takt_1s = 1;
80
  }
81
}
82
83
void SPI_MasterInit(void)
84
{  
85
DDRB |= (1<<PB2)|(1<<PB3)| (1<<PB5);
86
  DDRB &= ~(1<<PB4);
87
  PORTB |= (1<<PB2)| (1<<PB5);
88
  SPCR |= (1<<SPE)|(1<<MSTR)|(1<<SPR0);
89
}
90
91
void SPI_MasterTransmit(unsigned int cData)
92
{
93
  PORTB &= ~(1<<PB2);
94
  SPDR = wert;      
95
  while(!(SPSR & (1<<SPIF)));
96
  PORTB|=(1<<PB2);
97
  
98
}

von tt (Gast)


Lesenswert?

ersetzt doch mal:
SPCR = (1<<SPE) | (1<<SPIE) | (1<<SPR0);
durch:
SPCR |= (1<<SPE) | (1<<SPIE) | (1<<SPR0);

von Matthias (Gast)


Lesenswert?

> cpol cpha sagt uns nichts...

Also, wenn ihr den Atmega 88 einsetzt, dann schaut mal auf die Seite 164
im Datenblatt (SPCR-Register). Da gibt es zwei Bits CPHA CPOL. Diese 
müssen bei beiden Controllern identisch sein.

Zum Thema Simulation im AVR Studio:

Woher soll das Datenbyte kommen, wenn "außen" kein zweiter Controller 
dranhängt? Ich würde empfehlen eine Schaltung mit zwei Controllern 
aufzubauen und an beide Controller ein AVR JTAG-ICE-MKII oder einen AVR 
Dragon (geht bis 32k Flashgröße) dranzuhängen. Und dann das Ganze per 
ICE durchspielen.
Beim SPI kann man normalerweise nicht viel falsch machen, wenn man das 
Datenblatt aufmerksam gelesen hat und weiss, wie ein Schieberegister 
funktioniert.

von Matthias (Gast)


Lesenswert?

Also mal zur Codeanalyse:
1
// Ich würde statt "unsigned int" einen "uint8_t" nehmen. Der int ist 
2
// mit einer Kanone auf den Spatz geschossen!
3
void SPI_MasterTransmit(unsigned int cData)
4
{
5
  uint8_t dummy;
6
  PORTB &= ~(1<<PB2);
7
  SPDR = wert;                // Wieso "wert"? hier sollte doch cData stehen?
8
  while(!(SPSR & (1<<SPIF))); // Hier wird auf das IRQ-Flash gewartet...
9
  PORTB|=(1<<PB2);            // SS wierder auf High
10
 
11
  //Und wo wird das IRQ-Flag gelöscht?
12
  //Laut Datenblatt wird das Flag gelöscht wenn man das Statusregister  
13
  //abfragt und dann einen Zugriff auf das Datenregister macht. Ihr lest zwar 
14
  //das Statusregister in der while() oben, aber dann fehlt:
15
  dummy = SPDR;
16
}

Bei der Empfangsroutine solltet ihr darauf achten, dass das Datenbyte 
sicher verarbeitet ist, bevor ein weiteres kommt. Ansonsten liegt der 
Fehler wohl
beim Sender....

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.