Forum: Mikrocontroller und Digitale Elektronik Atmega16 SPI hängt (ich geh kaputt)


von Marcus K. (koerby)


Lesenswert?

Hallo Zusammen,

hänge grad ein einem echten Anfängerproblem.
Ich versuche über die SPI-Schnittstelle eines ATmegas16 Daten zu senden 
und zu empfangen. Die Funktionen liefen ohne Probleme auf einem Atmega8.
Nun ist es aber so das das Programm an
1
while(!(SPSR & (1<<SPIF)));
hängen bleibt. Ich weis nicht warum.
Wäre toll wenn ihr mir einen kleinen Denkanstoss geben könntet.
1
#include <avr/io.h>
2
#include <stdlib.h>
3
#include <util/delay.h>
4
#include "lcd-routines.h"
5
#include <avr/interrupt.h>
6
#include <string.h>
7
8
9
#ifndef F_CPU
10
#define F_CPU 8000000UL
11
#endif
12
13
14
int i, data_received ;
15
16
//------------------- Unterprogramme--------------------
17
// SPI-Daten senden
18
void spi_senden(int data)
19
{  PORTB &= ~(1 << PB1);         
20
  SPDR = data;            
21
  while(!(SPSR & (1<<SPIF)));     
22
  PORTB |= (1 << PB1);         
23
}
24
25
// SPI-Daten empfangen
26
int spi_empfangen(void)
27
{ PORTB |= (1<<PB0);          
28
  while (!(SPSR & (1 << SPIF)));    
29
  data_received= SPDR; 
30
  PORTB &= ~(1<<PB0);          
31
  return data_received;      
32
}
33
34
//-----------------Hauptprogramm----------------------------
35
36
int main(int argc, char **argv) {
37
  
38
  DDRB |= (1 << PB0);    //   
39
  DDRB |= (1 << PB1);    //   
40
  DDRB |= (1 << PB2);    //  
41
  DDRB |= (1 << PB3);    // 
42
43
  
44
  SPCR |= ((1 << SPE) | (1 << MSTR) | (1 << SPIE)) ;
45
  sei();
46
47
  while(1)
48
  { PORTB |= (1<<PB2);
49
    data_received=spi_empfangen();
50
    _delay_ms(50);
51
    spi_senden(0x55);
52
    PORTB &=~ (1<<PB2);
53
  }  
54
}

Ich Danke

von Jens (Gast)


Lesenswert?

Schon mal geschaut, ob er den Interrupt korrekt setzt, wenn er fertig 
ist? Dann könntest du das darüber machen.

Gruß
Jens

von Marcus K. (koerby)


Lesenswert?

Das SPIF wird (in der Simulation zumindest) nicht gesetzt.
Was meinst Du mit  "Dann könntest du das darüber machen."

von Sascha W. (sascha-w)


Lesenswert?

Hallo,

wenn du den SPI als Master betreibst musst du SS (PB4) auf Ausgang 
setzen, da sich der SPI sonst bei LOW-Pegel auf Slave umschaltet.
Beim M8 war SS an PB2 und das hattest du richtig eingestellt.

Sascha

von Hans (Gast)


Lesenswert?

> wenn du den SPI als Master betreibst musst du SS (PB4) auf Ausgang
> setzen, da sich der SPI sonst bei LOW-Pegel auf Slave umschaltet.

Wo steht das?

von Martin M. (capiman)


Lesenswert?

Bei SPI (zumindest im Mode Master) ist es so,
dass Du zuerst was senden musst, bevor Du was empfangen kannst,
auch wenn es nur ein Dummy-Byte ist.

Also wenn ein Byte gesendet wird, dann wird das Byte nach aussen
übertragen, und zugleich ein Byte empfangen
(ganz egal, ob das angesprochene Gerät etwas zu senden hatte oder nicht)

Möglicherweise brauchst Du etwas in dieser Art:
(Senden und Empfangen vertauscht)

  while(1)
  {
    PORTB |= (1<<PB2);
    spi_senden(0x55);
    data_received=spi_empfangen();
    _delay_ms(50);
    PORTB &=~ (1<<PB2);
  }

von Sascha W. (sascha-w)


Angehängte Dateien:

Lesenswert?

im Datenblatt ...

Sascha

von Sam .. (sam1994)


Lesenswert?

Hans schrieb:
>> wenn du den SPI als Master betreibst musst du SS (PB4) auf Ausgang
>> setzen, da sich der SPI sonst bei LOW-Pegel auf Slave umschaltet.
>
> Wo steht das?

RTFM

von SPI-Master (Gast)


Lesenswert?

Hallo,

die SPI-Schnittstelle liegt beim Mega8 an den Pins PB2 bis PB5, beim 
Mega16 an den Pins PB4 bis PB7.

Ausserdem ist es keine gute Idee, den SPI-Interrupt freizugeben, ohne 
eine Interrupt-Routine zu haben (und für dein Progrämmchen ist die 
Freigabe auch überflüssig).
Normalerweise führt der Aufruf einer nicht deklarierten ISR zu einem 
Reset des Controllers ...

>> wenn du den SPI als Master betreibst musst du SS (PB4) auf Ausgang
>> setzen, da sich der SPI sonst bei LOW-Pegel auf Slave umschaltet.

> Wo steht das?

Im Datenblatt des Controllers unter "/SS Pin Functionality".

von S.T (Gast)


Lesenswert?

Samuel K. schrieb:
> Hans schrieb:
>>> wenn du den SPI als Master betreibst musst du SS (PB4) auf Ausgang
>>> setzen, da sich der SPI sonst bei LOW-Pegel auf Slave umschaltet.
>>
>> Wo steht das?
>
> RTFM

Wieso ist doch intressant?! Damit könnte man dann auch zwei Master 
miteinander Kommunizieren lassen (nagut, wobei sich dann der eine in den 
Slavemodus begibt.)

von Marcus K. (koerby)


Lesenswert?

Die Routine ist mehr oder weniger aus dem Datenblatt übernommen.
Selbst wenn PB4 auf Ausgang geschalten ist hängt der Controller bei
while(!(SPSR & (1<<SPIF)));.
Auch wenn ich den SPIE heraus nehme läuft es nicht.

Das seltsame ist das ich das mehr oder weniger gleiche Progamm auf einem 
ATmega zum laufen bring. Sowhol auf dem Controller wie auch in der 
Simulation.

von Hans (Gast)


Lesenswert?

Danke für die Info(außer Samuel natürlich).

von S.T (Gast)


Lesenswert?

Siehe Beitrag von SPI-Master:
SPI-Master schrieb:
> Ausserdem ist es keine gute Idee, den SPI-Interrupt freizugeben, ohne
> eine Interrupt-Routine zu haben (und für dein Progrämmchen ist die
> Freigabe auch überflüssig).


Marcus K. schrieb:
> Die Routine ist mehr oder weniger aus dem Datenblatt übernommen.
> Selbst wenn PB4 auf Ausgang geschalten ist hängt der Controller bei
> while(!(SPSR & (1<<SPIF)));.
> Auch wenn ich den SPIE heraus nehme läuft es nicht.
>
> Das seltsame ist das ich das mehr oder weniger gleiche Progamm auf einem
> ATmega zum laufen bring. Sowhol auf dem Controller wie auch in der
> Simulation.

Und solange du keine ISR hast wird er sich auch immer wieder aufhängen.

von Arthur Dent (Gast)


Lesenswert?

Lies dir noch mal alles hier durch!
Zum Empfangen eines Bytes durch den Busmaster, also den ATmega, must du 
erst senden, denn nur so gnerierst du einen Takt für die 
SPI-Schnittstelle. Wenn aber keine Übertragung statt fand, dann ist das 
Flag auch nicht gesetzt.

von Jens (Gast)


Lesenswert?

Mein Vorschlag war, einfach mal ne ISR einzufügen, und zu gucken, ob der 
Controller da reinspringt. Denn dieses

1
while(!(SPSR & (1<<SPIF)));

ist ja eigentlich ne unsaubere Art und Weise, auf einen Interrupt zu 
prüfen.

Gruß
Jens

von Sam .. (sam1994)


Lesenswert?

S.T schrieb:
> Samuel K. schrieb:
>> Hans schrieb:
>>>> wenn du den SPI als Master betreibst musst du SS (PB4) auf Ausgang
>>>> setzen, da sich der SPI sonst bei LOW-Pegel auf Slave umschaltet.
>>>
>>> Wo steht das?
>>
>> RTFM
>
> Wieso ist doch intressant?! Damit könnte man dann auch zwei Master
> miteinander Kommunizieren lassen (nagut, wobei sich dann der eine in den
> Slavemodus begibt.)

Ich hab ja nicht gesagt, dass es unintressant ist. Es steht halt im 
Datenblatt. Kommunikation zwischen 2 Mastern würde aber heißen, dass 
immer einer im Slavemodus sein muss. Sonst gäbe es unter Umständen ein 
paar Kurzschlüsse auf den Datenleitungen.

Hans schrieb:
> Danke für die Info(außer Samuel natürlich).

Wobei meine Antwort die erste und dazu noch richtig war.
http://lmgtfy/?q=rtfm

von Marcus K. (koerby)


Lesenswert?

Danke an alle, es funktioniert.

Die entscheidenden Tips waren PB4 auf High und das SPDR-Register mit 
einem Dummywert versehen. jetzt klappt es.

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.