Forum: Mikrocontroller und Digitale Elektronik SPI am ATMEGA644 - Master gibt nix aus


von SPIAnfänger (Gast)


Lesenswert?

Hi Community

Ich wollte hier mal anfragen, ob mir evtl. jemand weiterhelfen kann..
Folgendes: Ich möchte gerne Daten per SPI über MOSI und SCK ausgeben an 
einem ATMEGA644.

Ich habe dazu im Datenblatt den Beispielcode gefunden, aber irgendwie 
tut sich da nichts.

Hier mein Programm:
1
/**************** INCLUDES ***************************************/
2
#include <avr/io.h>          //I/O library
3
#include "lcd-routines.h"    //LCD-Routine
4
#include <avr/interrupt.h>   //interrupt library
5
#include <stdint.h>          //Datentypen
6
#include <util/delay.h>      //delay library
7
/****************************************************************/
8
9
/**************** DEFINES ***************************************/
10
#ifndef F_CPU
11
#define F_CPU 20000000  //Frequenz -> 20MHZ
12
#endif 
13
/****************************************************************/
14
15
#define BLANK 0x10
16
#define VPRG  0x01
17
#define XLAT  0x08
18
#define GSCLK 0x40
19
20
#define MOSI  0x20
21
#define SCK   0x80
22
#define SPI  PORTB
23
24
#define DRIVER PORTB
25
#define TEST   PORTB
26
#define ON     0x01
27
#define OFF    0x00
28
29
30
int main(void)
31
{
32
    
33
  lcd_init();
34
  SPI_MasterInit();
35
  
36
  DDRC = 0xFF;
37
  DDRD = 0xFF;
38
  PORTC = 0x00;
39
  
40
  lcd_clear();
41
    lcd_setcursor(0,1);
42
  lcd_data(' '); 
43
  lcd_setcursor(3,1);
44
  lcd_string("Debug-Display");
45
  
46
  DRIVER = (1 << XLAT) | (1 << BLANK) | (1 << VPRG) | (1 << GSCLK);
47
48
  
49
  for(;;)
50
    {
51
52
    SPI_MasterTransmit(12);
53
  _delay_ms(19);
54
  
55
    }
56
}
57
58
59
void SPI_MasterInit(void)
60
{
61
   /* Set MOSI and SCK output, all others input */
62
   SPI = (1<<MOSI)|(1<<SCK);
63
   /* Enable SPI, Master, set clock rate fck/16 */
64
   SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
65
}
66
67
void SPI_MasterTransmit(char cData)
68
{
69
   /* Start transmission */
70
   SPDR = cData;
71
   /* Wait for transmission complete */
72
   while(!(SPSR & (1<<SPIF)));
73
}

Mit einem DSO kann ich leider nicht mal ein ruckeln am MOSI oder am SCK 
Pin feststellen, der Controller funktioniert aber sonst (Display 
angeängt als Test).

Kann mir evtl. jemand einen Tipp geben, woran das liegen könnte?

Gruss und Danke fürs lesen :)

von Karl H. (kbuchegg)


Lesenswert?

Du musst den SS Pin auf Ausgang programmieren.

Ist eine beliebte Falle.

von SPIAnfänger (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Du musst den SS Pin auf Ausgang programmieren.

Wow, danke für die schnelle Antwort :)
1
void SPI_MasterInit(void)
2
{
3
   /* Set MOSI and SCK and SS output, all others input */
4
   SPI = (1<<MOSI)|(1<<SCK)|(1<<SS);
5
   /* Enable SPI, Master, set clock rate fck/16 */
6
   SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
7
  
8
}

Tut sich leider immer noch nix :(

SPI = DDRB und MOSI, SCK und SS sind die richtigen Pins (PB4, PB5 und 
PB7)

Fehlt sonst noch was?

von Karl H. (kbuchegg)


Lesenswert?

SPIAnfänger schrieb:
> Karl Heinz Buchegger schrieb:
>> Du musst den SS Pin auf Ausgang programmieren.
>
> Wow, danke für die schnelle Antwort :)
>

>    /* Set MOSI and SCK and SS output, all others input */
>    SPI = (1<<MOSI)|(1<<SCK)|(1<<SS);

#define SPI  PORTB

Damit setzt du die Pins auf 1, wenn sie auf Ausgang wären.
Aber wo ist deine Programmierung des DDRB, um den Pin überhaupt mal auf 
Ausgang zu setzen!

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz Buchegger schrieb:
> SPIAnfänger schrieb:
>> Karl Heinz Buchegger schrieb:
>>> Du musst den SS Pin auf Ausgang programmieren.
>>
>> Wow, danke für die schnelle Antwort :)
>>
>
>>    /* Set MOSI and SCK and SS output, all others input */
>>    SPI = (1<<MOSI)|(1<<SCK)|(1<<SS);
>
> #define SPI  PORTB
>
> Damit setzt du die Pins auf 1, wenn sie auf Ausgang wären.
> Aber wo ist deine Programmierung des DDRB, um den Pin überhaupt mal auf
> Ausgang zu setzen!

Kann es sein, dass du dich da vertan hast und du eigentlich

#define SPI   DDRB

haben wolltest?

von SPIAnfänger (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> #define SPI   DDRB
>
> haben wolltest?

Ja, das habe ich in der Tat, habe das gerade gemerkt, als du geschrieben 
hast, dass ich SS als Ausgang setzen muss.

Ist also bereits bereinigt.

Hier nochmal der ganze Code, damit es keine Missverständnisse mehr gibt:
1
/**************** INCLUDES ***************************************/
2
#include <avr/io.h>          //I/O library
3
#include "lcd-routines.h"    //LCD-Routine
4
#include <avr/interrupt.h>   //interrupt library
5
#include <stdint.h>          //Datentypen
6
#include <util/delay.h>      //delay library
7
/****************************************************************/
8
9
/**************** DEFINES ***************************************/
10
#ifndef F_CPU
11
#define F_CPU 20000000  //Frequenz -> 20MHZ
12
#endif 
13
/****************************************************************/
14
15
#define BLANK 0x10
16
#define VPRG  0x01
17
#define XLAT  0x08
18
#define GSCLK 0x40
19
20
#define MOSI  0x20
21
#define SCK   0x80
22
#define SPI   DDRB
23
#define SS    0x10
24
25
#define DRIVER PORTB
26
#define TEST   PORTB
27
#define ON     0x01
28
#define OFF    0x00
29
30
int main(void)
31
{
32
    
33
  lcd_init();
34
  SPI_MasterInit();
35
  
36
  DDRC = 0xFF;
37
  DDRD = 0xFF;
38
  PORTC = 0x00;
39
  
40
  lcd_clear();
41
    lcd_setcursor(0,1);
42
  lcd_data(' '); 
43
  lcd_setcursor(3,1);
44
  lcd_string("Debug-Display");
45
  
46
  DRIVER = (1 << XLAT) | (1 << BLANK) | (1 << VPRG) | (1 << GSCLK);
47
48
  
49
  for(;;)
50
    {
51
52
    SPI_MasterTransmit(12);
53
  _delay_ms(20);
54
  
55
    }
56
}
57
58
59
void SPI_MasterInit(void)
60
{
61
   /* Set MOSI, SCK and SS output, all others input */
62
   SPI = (1<<MOSI)|(1<<SCK)|(1<<SS);
63
   /* Enable SPI, Master, set clock rate fck/16 */
64
   SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0); 
65
}
66
67
void SPI_MasterTransmit(char cData)
68
{
69
   /* Start transmission */
70
   SPDR = cData;
71
   /* Wait for transmission complete */
72
   while(!(SPSR & (1<<SPIF)));
73
}

von Spess53 (Gast)


Lesenswert?

Hi

>#define MOSI  0x20  (32)
>#define SCK   0x80  (128)

>   SPI = (1<<MOSI)|(1<<SCK)|(1<<SS);

Was meinst du, was bei 8 Bit herauskommt, wenn man eine 1 32 oder 128 
mal nach links schiebt?

MfG Spess

von SPIAnfänger (Gast)


Lesenswert?

Spess53 schrieb:
> Was meinst du, was bei 8 Bit herauskommt, wenn man eine 1 32 oder 128
> mal nach links schiebt?

Oh, peinlich :S

DDRB = 0xB0 hat Abhilfe gebracht.
Die korrekte Schreibweise lese ich noch im Tut. auf der Seite nach, bin 
da immer ein wenig zerstreut.

Danke für eure Hilfe!

von SPIAnfänger (Gast)


Angehängte Dateien:

Lesenswert?

Wäre es möglich, dass die SCK Rate beim ATMEGA644 entgegen dem 
Datenblatt NICHT die fosc/2 schafft?

Bei:

SPCR = (1<<SPE)|(1<<MSTR);

Habe ich (wie im Datenblatt beschrieben -> siehe Anhang) einen Vorteiler 
von 4. Will ich nun aber

SPCR = (1<<SPE)|(1<<MSTR)| (1 << SPI2X);

Habe ich einen Vorteiler von 16?

Wo liegt mein Denkfehler?

von H.Joachim S. (crazyhorse)


Lesenswert?

SPI2X liegt nicht im SPCR :-)

von Spess53 (Gast)


Lesenswert?

Hi

>Wo liegt mein Denkfehler?

SPI2X ist in SPSR nicht in SPCR.

MfG Spess

von SPIAnfänger (Gast)


Lesenswert?

Ach so.. das konnte ich jetzt irgendwie nicht rauslesen.
Habe mich allerdings schon gewundert, warum nur die Bits SPR1 und SPR0 
in der Beschreibung erwähnt werden.

Ein bisschen undurchsichtig, finde ich.

Danke nochmals für eure Hilfe, jetzt läuft alles wie ich wollte!
8 Bit in 800ns, perfekt.

von Karl H. (kbuchegg)


Lesenswert?

SPIAnfänger schrieb:
> Ach so.. das konnte ich jetzt irgendwie nicht rauslesen.
> Habe mich allerdings schon gewundert, warum nur die Bits SPR1 und SPR0
> in der Beschreibung erwähnt werden.
>
> Ein bisschen undurchsichtig, finde ich.

Du darfst in dieser Beziehung NIE nach den Tabellen gehen. Egal ob SPI 
oder Timer oder ADC oder UART oder ...


Die Tabellen sind immer nur die logische Zusammenfassung von 
Configurationsbits. Aber das bedeutet nicht, dass sie auch im selben 
Register beheimatet sind.
Aus den Tabellen entnimmst du nur die Information, welche Bits du 
brauchst und dann gehst du alle Register durch, bis du dasjenige hast, 
in welchem das Bit beheimatet ist. Wenn du es in einem Register nicht 
findest, dann ist es eben in einem anderen. Aber so viele 
Konfigurationsregister gibt es ja bei einer Komponente nicht. Und die 
sind im Datenblatt dann ja auch beim Modul alle aufgeführt.


> Die korrekte Schreibweise lese ich noch im Tut.

Das schreibt sich eigentlich ganz einfach

#define MOSI  PB5
#define SCK   PB7
#define SS    PB4

also einfach die Pinnummern aus dem Datenblatt. Dann passt es auch mit

   SPI = (1<<MOSI)|(1<<SCK)|(1<<SS);

von SPIAnfänger (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das schreibt sich eigentlich ganz einfach
>
> #define MOSI  PB5
> #define SCK   PB7
> #define SS    PB4

Ah, klasse, danke für den Tipp!
Meiner Schreibweise nach hätte es dann wohl so aussehen müssen?

SPI = MOSI + SCK + SS;

Spricht etwas gegen diese Schreibweise?

Karl Heinz Buchegger schrieb:
> Die Tabellen sind immer nur die logische Zusammenfassung von
> Configurationsbits. Aber das bedeutet nicht, dass sie auch im selben
> Register beheimatet sind.

Das wusste ich wirklich nicht. Habe ich bis jetzt noch nie so erlebt 
(bei Timer & ADC, UART habe ich noch nicht ausprobiert).

Werde mir das aber merken, gibts wieder eine Frage weniger im Forum :)

von Karl H. (kbuchegg)


Lesenswert?

SPIAnfänger schrieb:
> Karl Heinz Buchegger schrieb:
>> Das schreibt sich eigentlich ganz einfach
>>
>> #define MOSI  PB5
>> #define SCK   PB7
>> #define SS    PB4
>
> Ah, klasse, danke für den Tipp!
> Meiner Schreibweise nach hätte es dann wohl so aussehen müssen?
>
> SPI = MOSI + SCK + SS;
>
> Spricht etwas gegen diese Schreibweise?

Im Prinzip nicht.
Es scheint so, als ob das die auf einem MSP gebräuchlichere Schreibweise 
ist, während die andere die eher auf AVR gebräuchlichere Schreibweise 
ist.

Wo du jetzt genau den Teil 1<< hinschiebst bleibt sich ja egal
1
#define XYZ   PB5
2
   Register |= ( 1 << XYZ )

und
1
#define XYZ  (1<<PB5)
2
   Register |= XYZ

laufen ja aufs gleiche hinaus.

Nur eines würde ich nicht tun

#define XYZ   0x20

denn: warum willst du dir selber ausrechnen, welches Bitmuster du 
brauchst um den Pin 5 auf 1 zu setzen. Lass das doch den Compiler 
machen. Der macht dabei keine Fehler :-)

von SPIAnfänger (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Im Prinzip nicht.
> Es scheint so, als ob das die auf einem MSP gebräuchlichere Schreibweise
> ist, während die andere die eher auf AVR gebräuchlichere Schreibweise
> ist.

Naja, gebräuchlich ist, was einem am leichtesten fällt, oder :)?

Karl Heinz Buchegger schrieb:
> Nur eines würde ich nicht tun
>
> #define XYZ   0x20
>
> denn: warum willst du dir selber ausrechnen, welches Bitmuster du
> brauchst um den Pin 5 auf 1 zu setzen. Lass das doch den Compiler
> machen. Der macht dabei keine Fehler :-)

Ja, da hast du natürlich recht. Bin mich irgendwie gewöhnt immer mit 
Ausmaskierungen zu arbeiten, weiss gar nicht recht woher das kommt.

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.