Forum: Mikrocontroller und Digitale Elektronik Raspberry&ATmega8A


von orgsi1990 (Gast)


Lesenswert?

Hallo,
ich habe ein kleines Problem an dem ich schon seit zwei wochen hänge.
Ich wollte gern über einen Raspberry PI eine verbindung zu meinem 
ATmega8A aufbauen und das per SPI.
Das ist meine verschaltung:

Raspberry      ATmega
VCC 3,3  -----> VCC,AREF,AVCC(Die letzten beiden werden eig nicht 
gebraucht)
GND      -----> GND
MOSI     -----> MISO
MISO     -----> MOSI
SCLK     -----> SCKL
CE0      -----> SS

Zum Programmieren des ATmega8 benutze ich AVRSTudio 6 und das AVR Board 
vers2.01.

Mein Programmm auf dem ATmega sieht wie folgt aus:
1
#define F_CPU 1000000UL
2
#include <util/delay.h>
3
#include <avr/io.h>
4
5
void SPI_SlaveInit(void);
6
char SPI_SlaveReceive(void);
7
void SPI_SlaveSend(char data);
8
9
int main()
10
{
11
  SPI_SlaveInit();
12
  char data;
13
  while(1)
14
  {
15
      data = SPI_SlaveReceive();
16
      SPI_SlaveSend(data);
17
        }
18
}
19
void SPI_SlaveInit(void)
20
{  DDRB |= (1<<PORTB4);
21
  SPCR = (1<<SPE);
22
}
23
char SPI_SlaveReceive(void)
24
{  char data;
25
  while(!(SPSR & (1<<SPIF)))
26
  {}
27
  data = SPDR;
28
  SPDR = 0;
29
  return data;
30
}
31
void SPI_SlaveSend(char data)
32
{  SPDR = data;
33
  while(!(SPSR & (1<<SPIF)))
34
  {}
35
  SPDR = 0;
36
}


Ich musste im AVRStudio die ISP Clock auf 250KHZ setzen da sonst der 
chip eine falsche checksumme hatte und nicht erkannt wurde.

Habe das dann auf den chip gebrutzelt und alles angeschlossen.

Mit einem python program habe ich dann sekündlich eine zahl geschickt 
wie z.b. 10 oder 0x0A und mir das ganze direkt wieder mit ausgeben 
lassen was dann ungefähr so aussah
0
0
0
0
0
10
0
0
0
0
0
0
10

aber in unterschiedlichen abständen.

Jetzt wollte ich gern einen ausgang setzten und über eine for schleife 
eine LED so oft blinken lassen wie ich eingegeben hatte also z.b. 10->10 
mal blinken und als check eine 1 zurück.

Aber das funktioniert nicht ich bekomme keinen ausgang gesetzt bzw schon 
aber es tut sich nichts ich bin mir eben auch nicht sicher was das 
problem ist weil es mir schon spanisch vorkam das er mir so viele 0-en 
zurück schickt wobei ich ja jede sekunde eine 10 reinschicke bei 1MHZ 
sollte es ja kein Problem sein mir bei jedem wert etwas zurück zu geben.

Der raspberry kann auch nur 500KHZ max. Taktfrequenz.

Für weitere infos ruhig fragen ich verzweifel nur langsam weil es mich 
auch nicht los lässt da ja SPI kein Problem sein sollte.

Liebe Grüße und danke im voaraus ich hoffe mir kann jemand von euch 
helfen.

Chrisian

: Bearbeitet durch User
von Björn P. (bjrn_g)


Lesenswert?

Ich komme eher aus der Microchip-Ecke, aber müsstest du nicht auch beim 
ATmega das Receive-Flag (SPIF oder?) zurücksetzen? Da du nach dem Senden 
den Receive-Buffer zurücksetzt, würde das schon Sinn machen, dass er 
ständig was ausgibt. Mal Nullen, mal eine Zehn.

btw:
die CPU vom RasperryPi kann "etwas" schneller laufen als mit 500KHz ;)
--> ARM1176JZF-S (700 MHz)

EDIT:

btw.
benutzen ATmegas fürs Senden und Empfangen DEN SELBEN Buffer (SPDR)? 0.0

orgsi1990 schrieb:
> void SPI_SlaveSend(char data)
> {  SPDR = data;
>   while(!(SPSR & (1<<SPIF)))
>   {}
>   SPDR = 0;
> }

: Bearbeitet durch User
von orgsi1990 (Gast)


Lesenswert?

Hmn....
aber in solchen abständen bei einer Frequenz von 1MHZ ist das schon 
etwas matt oder nicht ?

Ich dachte damit weiss er doch nur ob etwas anliegt wenn ja dann ab ins 
SPDR damit oder liege ich falsch?

von Björn P. (bjrn_g)


Lesenswert?

Verdammt, sorry... ich war gerade bei UART.
SPI funktioniert natürlich nur mit einem Buffer.

Nach dem Überblicken des Datenblattes fällt mir auf, dass ich bei 
ATmegas anscheinend zu wenig Ahnung habe.
Ich kann leider doch nicht wirklich weiter helfen.

Im Datenblatt ist exakt dein Beispiel:

char SPI_SlaveReceive(void)
{
/* Wait for reception complete */
while(!(SPSR & (1<<SPIF)));
/* Return data register */
return SPDR;
}

: Bearbeitet durch User
von orgsi1990 (Gast)


Lesenswert?

Das war so meine intension weil es das SPI-Data Register ist also dachte 
ich mir daten rein und auch daten raus!?

Ich wollte dann einfach nach dem receive folgendes machen:
int i;
for(i=0;i<=data;i++)
{
DDRD = 0xff;//D is ausgang
PORTD |= (1<<PD0);//high
_delay_ms(500);
PORTD &=(1<<PD0);//Low??
_delay_ms(500);
}

aber es kommt nichteinmal etwas am port an.

von orgsi1990 (Gast)


Lesenswert?

Ja das habe ich daher genau.
Aber es geht alles irgendwie nicht so richtig.

von orgsi1990 (Gast)


Lesenswert?

Natürlich Port init ausserhalb der for-schleife....

von Oliver (Gast)


Lesenswert?

orgsi1990 schrieb:
> MOSI     -----> MISO
> MISO     -----> MOSI

Hüstl...

Oliver

von Karl H. (kbuchegg)


Lesenswert?

orgsi1990 schrieb:

>   while(1)
>   {
>       data = SPI_SlaveReceive();
>       SPI_SlaveSend(data);
>         }

Du hast da einen Denkfehler.
Ein Slave kann von sich aus überhaupt nichts senden!

SPI wird komplett vom Master angeleiert. Er hat zu jedem Zeitpunkt das 
sagen.

SPI funktioniert so, wie wenn du und dein Kumpel sich am Tisch gegenüber 
sitzen. Du bist der Master und er ist der Slave.

Jeder hat vor sich einen Zettel liegen, auf den er das zu übermittelnde 
aufschreibt (was bei einem µC natürlich lediglich 1 Byte ist).
Auf dein(!) Kommando nehmt ihr beide den Zettel jeweils mit der rechten 
Hand und schiebt ihn zum Gegenüber rüber während jeder mit der linken 
Hand jeweils den Zettel vom Gegenüber in Empfang nimmt.

SPI ist also ein gleichzeitig ablaufender Datenaustausch zwischen Master 
und Client. Die Initiative liegt dabei ausschliesslich beim Master! Von 
sich aus kann ein Slave überehaupt nichts tun. Er kann nur reagieren 
wenn vom Master ein Datenaustausch initiert wird.

Ein Slave schreibt den zu übermittelnden Wert ganz einfach ins SPDR 
Register. Bei der nächsten Übertragung, die vom Master angeleiert wird, 
wird dann dieser Inhalt an den Master übertragen, während gleichzeitig 
das Byte vom Master in den Slave übertragen wird und als neuer Wert im 
SPDR Register landet. Das bedeutet aber auch: der Wert, den der Slave zu 
Master übertragen will, der muss schon im SPDR stehen, noch bevor der 
Master die nächste Übertragung machen wird.

Hier
1
char SPI_SlaveReceive(void)
2
{  char data;
3
  while(!(SPSR & (1<<SPIF)))
4
  {}
5
  data = SPDR;
6
  SPDR = 0;
7
  return data;
8
}

laufen 2(!) Vorgänge ab. Auf der einen Seite findet eine Übertragung vom 
Master zum Slave ins SPDR Register statt. Auf der anderen Seite findet 
aber auch eine Übertragung vom Slave zu Master statt.

Probier mal folgendes
1
int main()
2
{
3
  SPI_SlaveInit();
4
  char data;
5
6
  SPDR = 0xFF;
7
  while(1)
8
  {
9
    data = SPI_Exchange();
10
  }
11
}
12
13
void SPI_SlaveInit(void)
14
{  DDRB |= (1<<PORTB4);
15
  SPCR = (1<<SPE);
16
}
17
18
char SPI_Exchange(void)
19
{
20
  char data;
21
22
  while(!(SPSR & (1<<SPIF)))
23
  {}
24
25
  data = SPDR;
26
  SPDR = data + 2;    // einen größeren Wert bereit stellen. Der Master
27
                      // holt sich den dann bei der nächsten Übertragung ab
28
  return data;
29
}

: Bearbeitet durch User
von orgsi1990 (Gast)


Lesenswert?

Hmn...
Okay jetzt bin ich auch etwas weiter allein von der Überlegung her.
Ich dachte der ATmega meldet sich direkt zurück und nicht das der master 
den wert abholt.

Also bräuchte man theoretisch auch nur MOSI--->MISO ?
Oder steh ich da auf dem Schlauch ?

Die rückgabewerte die ich bekomme sehen wie folgt aus:

10
10
2
0
0
0
0
10
10
0
0
0
0
2
10
10

hmn...sollte sich eig eine 12 abholen oder ??
vielleicht liegt es auch am raspi ich arbeite da mit spidev habe da ein 
beispiel prog genommen was eben sendet und sich wieder einen wert holt.

von Karl H. (kbuchegg)


Lesenswert?

orgsi1990 schrieb:
> Hmn...
> Okay jetzt bin ich auch etwas weiter allein von der Überlegung her.
> Ich dachte der ATmega meldet sich direkt zurück und nicht das der master
> den wert abholt.
>
> Also bräuchte man theoretisch auch nur MOSI--->MISO ?
> Oder steh ich da auf dem Schlauch ?

MOSI   --- Master Out - Slave In
MISO   --- Master In  - Slave Out

1
      Master                        Slave
2
    +---------+                  +------------+
3
    |   MOSI  |----------------->| MOSI       |
4
    |   MISO  |<-----------------| MISO       |
5
    |         |                  |            |

Da jeder Teilnehmer weiß, ob er Master oder Slave ist, ist daher immer 
ein Ausgang mit einem Eingang verbunden. MOSI wird mit MOSI verbunden. 
MISO mit MISO


(und natürlich die CLock Leitung und die Slave Select Leitung)

: Bearbeitet durch User
von orgsi1990 (Gast)


Lesenswert?

Ersteinmal danke für die vielen schnellen ratschläge es ist auf 
jedenfall besser geworden ich bekomme ein feedback.


22
22
11
20
23
10
22
22
11
20
19
5
4
22
22
22
22
22

Bei einer eingabe von 10 oder 0x0A.
Aber sollte da nicht eine 12 zurück kommen nach dem Programm von Karl 
Heinz?

Ich bin zumindest schon einmal glücklich das die zwei jetzt fleißig am 
kommunizieren sind.

Danke !

von Mathias O. (m-obi)


Lesenswert?

SPI Mode und Frequenz (250 kHz) stimmt auch beim Rpi?

: Bearbeitet durch User
von orgsi1990 (Gast)


Lesenswert?

Ich möchte eben gern einen wert übertragen und der sollte dann eben 
schon passen und keine abweichungen haben ist da vllt eher TX RX was ?
weil ich meine das passt ja im großen und ganzen...

von orgsi1990 (Gast)


Lesenswert?

Okay frequenz war auf 500KHZ und jetzt schiebt er mir immer 12 raus aber 
eben manchmal auch wieder abweichungen was für ein mode muss da laufen ?
wegen CPOL/CPHA ??

von Mathias O. (m-obi)


Lesenswert?

Den den du dir aussuchst einfach Mode 0.

von orgsi1990 (Gast)


Lesenswert?

ach ja ist ja master und slave folgt einfach oder ?

von Mathias O. (m-obi)


Lesenswert?

Du musst schon bei beiden den selben Mode eingestellt haben.

von orgsi1990 (Gast)


Lesenswert?

Okay ich glaube das läuft jetzt soweit danke für die Hilfe.
Die eigentliche Arbeit fängt ja jetzt erst an ;) !!

Grüße

CO

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.