Forum: Mikrocontroller und Digitale Elektronik Kommunikation von ATmega32 zu TMC428 über USART und SPI


von Tho W. (tommyprog)


Lesenswert?

Servus,

hab obriges durchgeführt, läuft auch relativ gut, aber nur relativ, weil 
bei meiner SPI nur eine 77, also 1001101 zurückkommt, obwohl ich einfach 
nur irgendwas sende (eine beliebige Zahl zwischen 0 - 2^(32-1)).
Nun, wenn ich mein SPI interrupt rauschmeise, kommt mal abundzu 153 in 
dezimal zurück, mal 20, usw., obwohl ein beliebiges Zeichen oder ein 
festes Zeichen gesendet wird.

das SPDR im ATmega32 ist 8Bit groß. Da der TMC428 aber ein Datagram mit 
32Bit zurückgibt, muss ich diesen Bratzen irgendwie auf mein SPI legen 
können, sodass ich über den SPI mit meinen ATmega32 das Ablese, in ein 
Array speichere, und somit über die USart ausgebe.

Ich würde es gerne mit zwischenspeichern machen, also für nen uint32_t, 
was theoretisch zurückkommt, immer jeweils 8 zeichen (dann die nächsten 
8 usw.) bis die 32 Zeichen abgearbeitet sind, in mein Array 
reinschmeisen, und dann zeichen für zeichen der usart geben.
Ist das zu umständlich, oder hat jemand eine passende idee?

Zurzeit ist mein Teil- Code wie folgt:
1
void SPI_masterinit(void)
2
{
3
  DDRB = (1<<MOSI)|(1<<SCK)|(1<<SS);          //MOSI,SCK,SS auf 1 legen
4
  DDRB &=~(1<<MISO);                  //MISO als Eingang definiert
5
  
6
  PORTB |=(1<<SCK)|(1<<SS);
7
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);        //Enable SPI, Master, set clock rate fck/16 ~800khz
8
}
9
10
void SPI_MasterTransmit(char data)      
11
{
12
  PORTB &=~(1<<SS);                  //Signal SS auf 0 setzen -> Uebertragung beginnt
13
  SPDR = data;                    //ACHTUNG!! Das Register SPDR ist nur 8bit Groß
14
  while(!(SPSR&(1<<SPIF)))              //wartet, bis die ÜBertragung fertig ist
15
  {
16
    ;
17
  }
18
PORTB|=(1<<SS);                                            //Signal SS wieder auf high setzen -> Uebertragung beendet
19
}
20
21
char spi_slave_receive(void)
22
{
23
  while(!(SPSR&(1<<SPIF)))
24
  {
25
    ;
26
  }
27
  return SPDR;  
28
}
29
30
/*
31
ISR(SPI_STC_vect)                                            //ISR vom SPI transfer complete
32
{
33
  
34
}*/

Danke euch schonmal.
Ich versuch das mal so zu realisieren, und wenn was besseres kommt, 
schau ich mal, ob sich das einbauen lässt^^.

Mfg,
tommyProg

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:

> char spi_slave_receive(void)
> {
>   while(!(SPSR&(1<<SPIF)))
>   {
>     ;
>   }
>   return SPDR;
> }

Du  hast SPI nicht verstanden.

SPI funktioniert nach dem Muster eines Datenaustausches.
Der Slave kann von sich aus überhaupt nichts tun, sondern die komplette 
Kontrolle liegt beim Master. Damit der Slave 1 Byte bertragen kann, muss 
der Master 1 Byte zum Slave übertragen.

Eine Analogie.
Du sitzt deinem Kumpel gegenüber am Tisch. Jeder hat einen Zettel vor 
sich auf dem Tisch liegen. Jeder kann etwas auf den zettel schreiben. 
Auf ein Kommando von dir (dem Master) nimmt jeder seinen Zettel mit der 
rechten Hand und schiebt ihn zum Gegenüber hinüber während er mit der 
linken Hand jeweils den ihm zugeschobenen Zettel entgegen nimmt.
Wie gesagt: du bist der Master. Selbst wenn dein Kumpel wollte, ohne 
dass du deinen Zettel rüberschiebst, kann er dir seinen Zettel nicht 
rüberschieben.

In diesem Sinne macht ihr immer einen gleichzeitigen Zettel-Tausch. Und 
egal was passiert, die Aktivität geht immer von dir, dem Master aus.

Das ist das Prinzip von SPI. D.h. diee receive Funktion kann nicht 
funktionieren, weil der Master zum Anleiern des Datenaustausches etwas 
an SPDR zuweisen muss. Erst durch diese Zuweisung kommt der Austausch in 
Gang.

In diesem Sinne brauchst du auch nicht eine Transmit und eine Receive 
Funktkoin sondern eine einzige Exchange Funktion
1
uint8_t SPI_Exchange( uint8_t byte )
2
{
3
  SPDR = byte;
4
5
  while( !(SPSR & (1<<SPIF)) )
6
  {
7
    ;
8
  }
9
10
  return SPDR;    
11
}

mit dieser einen Funktion wickelst du den ganzen Datentransfer ab.

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

> SPI funktioniert nach dem Muster eines Datenaustausches.
> Der Slave kann von sich aus überhaupt nichts tun, sondern die komplette
> Kontrolle liegt beim Master. Damit der Slave 1 Byte bertragen kann, muss
> der Master 1 Byte zum Slave übertragen.

Danke Dir für den Hinweis, Karl Heinz, aber das System ist schon 
verstanden, dass der TMC428 nur antwortet, wenn der µC was sendet.
Problem ist nur, dass der µC auch die Antwort des TMC428 aufnehmen muss, 
und das über eine Schnittstelle (USART) an den PC über ein externes 
Programm ausgeben muss.

>
1
> uint8_t SPI_Exchange( uint8_t byte )
2
> {
3
>   SPDR = byte;
4
> 
5
>   while( !(SPSR & (1<<SPIF)) )
6
>   {
7
>     ;
8
>   }
9
> 
10
>   return SPDR;
11
> }
12
>
>
> mit dieser einen Funktion wickelst du den ganzen Datentransfer ab.

Die 32Bit in Binärdarstellung kommen als Paket vom TMC428, und diese 
sollen genauso wie sie empfangen sind, zur USART raus.
Mit einem return von uint8_t würden doch nur die ersten empfangenen 8bit 
rausgesendet werden, (ein zeichen), dann das nächste eingelesen, dann 
das zweite zeichen raus, usw.
Ich verstehe nicht ganz, wie ich dann die Verkettung als reines Paket 
mit dieser Funktion hinbekommen soll.
Aktuell bin ich grade dabei das mit einen Array zu realisieren, wenn das 
nicht geht, probiere ich mal Deine Idee aus.

EDIT_1:

ZITAT: "Damit der Slave 1 Byte bertragen kann, muss
der Master 1 Byte zum Slave übertragen."
Das haut bei mir nicht hin, wenn ich 32 Stellen übertrage (4 Bytes), 
kommt auch nur 77 zurück, also wahrscheinlich 1 Byte, wobei das 8te Bit 
ne 0 ist.


Mfg,
tommyProg

: Bearbeitet durch User
von Karl H. (kbuchegg)


Lesenswert?

Tho Wes schrieb:

> Die 32Bit in Binärdarstellung kommen als Paket vom TMC428,

Nope.

32 Bit werden ausgetauscht, in dem man 4 mal 8 Bit austauscht.
Die Funktion für einen 8 Bit Austausch hast du schon. ALso wirst du 
einen 32 Bit Austausch durch 4 maligen Aufurf der Funktion machen.

> und diese
> sollen genauso wie sie empfangen sind, zur USART raus.
> Mit einem return von uint8_t würden doch nur die ersten empfangenen 8bit
> rausgesendet werden,

Niemand sagt, dass man die Funktion nur 1 mal zwischen dem Low-gehen des 
Slave Select und dem High-gehen des Slave Select aufrufen darf. Der TMC 
macht von sich auch gar nichts. Auch die Clock-Pulse kommen vom Master. 
Dann macht eben der Master aus Sicht des TMC ein klitzekleines Päuschen 
beim SPI-Clock nach jeweils 8 Bit. Das stört den nicht weiter. Mit dem 
nächsten Clock-Puls geht das nächste Bit aus dem TMC raus. Und die Clock 
Pulse kommen vom Master, also vom AVR

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

Servus,

hab nun die die Funktion so übernommen:
(entschuldige übrigens für die "sinnlosen" kommentare, aber für mich 
brauche ich diese einfach zum lernen)
1
uint8_t transceive(uint8_t byte)
2
{
3
  /*PORTB &=~(1<<SS);                                          //SS Leitung auf 0 setzen, damit die Übertragung beginnen kann*/
4
  SPDR = byte;                                            //schreibt in das SPDR register das erste Zeichen
5
  while(!(SPSR&(1<<SPIF)))
6
  {
7
    ;
8
  }
9
  return SPDR;
10
  /*PORTB|=(1<<SS);                                            //schalte deshalb die SS Leitung wieder auf high  */
11
}

Mit einer selbst geschriebenen Funktion teile ich nun die Bytes auf, 
sende diese Einzeln, und die empfangenen setze ich wieder in einen 
uint32_t zusammen (was scheinbar nicht richtig funktioniert).
Diese Funktion ist wie folgt implementiert:
1
uint32_t lese_und_schreib_auf_spi(uint32_t datensatz)                            //wobei Datensatz das trinamic_befehlslaenge ist, was von außen über die USART reinkommt
2
{    
3
  //aufteilung des Datensatzes in einzelne bytes                
4
  uint8_t speicheraufteilung_array[4];  
5
                                      
6
  speicheraufteilung_array[0] = datensatz>>24;                              //zerlege das erste Byte, Position 31-24  
7
  speicheraufteilung_array[1] = datensatz>>16;                              //zerrlege das zweite Byte, Position 23 - 16
8
  speicheraufteilung_array[2] = datensatz>>8;                                //zerlege das dritte Byte, Position 15-9
9
  speicheraufteilung_array[3] = datensatz;                                //zerlege das vierte Byte, Position 7-0
10
  
11
  //senden der einzelnen Bytes und auf Antwort warten                            //schalte die SS Leitung auf LOW, damit die Übertragung beginnen kann    
12
  uint8_t speicherzusammensetzung_array[4];
13
  PORTB &=~(1<<SS);    
14
  speicherzusammensetzung_array[0] = transceive(speicheraufteilung_array[0]);    
15
  PORTB|=(1<<SS);  
16
  PORTB &=~(1<<SS);                                            //sende das erste Byste von 31-24 und speichere die Antwort in "0"
17
  speicherzusammensetzung_array[1] = transceive(speicheraufteilung_array[1]);                //sende das zweite Byte von 23-16 und speichere die Antwort auf die erste Position des arrays  
18
  PORTB|=(1<<SS);
19
  PORTB &=~(1<<SS);
20
  speicherzusammensetzung_array[2] = transceive(speicheraufteilung_array[2]);                //sende das dritte Byte von 15-9 und speichere die Antwort auf die zweite Position des Arrays
21
  PORTB|=(1<<SS);
22
  PORTB &=~(1<<SS);
23
  speicherzusammensetzung_array[3] = transceive(speicheraufteilung_array[3]);                //sende das vierte Byte von 7-0 und speichere die Antwort auf die dritte Position des Arrays  
24
  PORTB|=(1<<SS);                                              //setze die SS Leitung auf High, damit die Übertragung beginnen kann
25
  
26
  // zusammensetzen von den einzelnen Bytes zu einen ganzen
27
  test_datagram_empfangen_von_TMC = (uint32_t)speicherzusammensetzung_array[0]<<24;            //das MSB zurückbekommen und speichern
28
  test_datagram_empfangen_von_TMC = (uint32_t)speicherzusammensetzung_array[1]<<16;            //das 23-16 bit zurückbekommen und abspeichern
29
  test_datagram_empfangen_von_TMC = (uint32_t)speicherzusammensetzung_array[2]<<8;
30
  test_datagram_empfangen_von_TMC = (uint32_t)speicherzusammensetzung_array[3];
31
  
32
  return test_datagram_empfangen_von_TMC;
33
  }

Das Darstellen über die Uart ist problemlos, habe ich probehalber 
geprüft.
(es können 32-bit zahlen dargestellt werden)

Mein Problem ist, dass, wenn ich einen Wert 436207907 sende, nur dezimal 
77 zurückkommt, was 0b1001101 entspricht.
Der zurückkommende Wert soll aber (dez)2499805184 sein.

Nach meiner Recherche sendet und empfängt der TMC erst das MSB, also 
31Bit abwärts.
Vermutlich habe ich mit meiner Speicherzusammensetzung probleme. Hättest 
du grob eine Vermutung oder idee (bitte keine Union, das wäre zwar ein 
vlt. besserer weg, aber ich würde gerne das nur mit shift- operatoren 
lösen)?
Ich werde dies nochmals überprüfen, indem ich die shift- operatoren auf 
die speicher ändere.

Mfg,
tommyProg

: Bearbeitet durch User
von Tho W. (tommyprog)


Lesenswert?

Ergänzend möchte ich noch hinzufügen, dass der TMC bei erstmaliger 
Eingabe manchmal dez 452984832 mancchmal dez 69 und manchmal dez 101 
zurückgibt, jedoch häufiger 77.
Keines dieser Bitmuster kommt in der Bitreihenfolge vor.

von Tho W. (tommyprog)


Lesenswert?

Scheinbar ist der Fehler tiefer..ich melde mich nochmals, wenn ich was 
gefunden habe..

von Tho W. (tommyprog)


Lesenswert?

Gut, das zusammensetzen haut nicht hin.

Gerne würde ich den Beitrag von Karl Heinz vom 23.08.2010 um 00:31
benutzen, was bei mir dann
1
  uint32_t speicherzusammensetzung;
2
  
3
  *( (uint8_t*)&speicherzusammensetzung + 0 ) =speicherzusammensetzung_array[0];
4
  *( (uint8_t*)&speicherzusammensetzung + 1 ) =speicherzusammensetzung_array[1];
5
  *( (uint8_t*)&speicherzusammensetzung + 2 ) =speicherzusammensetzung_array[2];
6
  
7
  return speicherzusammensetzung;
entsprechen würde.
Jedoch weiß ich nicht, was der Code genau macht. Im Thread stands auch 
nicht ausführlich genug. (stand nur was low und high byte jeweils ist)
Genauer verstehe ich nicht, was
1
*( (uint8_t*)&speicherzusammensetzung + 0 )
 bewirkt.

Bitte um Aufklärung.
Danke.

Mfg,
tommyProg
P.s. habe durch Rekursion nun das senden von 4Bytes hinbekommen, nachdem 
ich die putc in puti umgeschrieben habe, und noch ein wichtiges DDRB 
vergessen habe, zu setzen.

: Bearbeitet durch User
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.