Forum: Mikrocontroller und Digitale Elektronik Atmega SPI will nicht


von Christoph H. (christoph_b)


Lesenswert?

Hallo

Ich probiere mich gerade an der SPI Schnittstelle auf einem Atmega 2560 
für mein Projekt. Habe einen Quellcode vom Lehrer erhalten doch leider 
will die SPI Schnittstelle nicht so wie wir.

Vieleicht kann ja jemand einmal über den Code schauen.
1
/**************************************************************
2
Es soll alle halbe Sekunde im Wechsel 0 bzw. 1 gesendet werden.
3
Am korrespondierenden Slave soll zur Indikation jeweils die 
4
LEDs an bzw. aus gehen
5
Verdrahtung:  MISO(Master) --> MISO(Slave)
6
        MOSI(Master) --> MOSI(Slave)
7
        SCK(Master)  --> SCK(Slave)
8
        PB0(Master)   --> SS(Slave)
9
**************************************************************/
10
11
#include <avr/io.h>
12
#include <avr/interrupt.h>
13
#include <avr/signal.h>
14
15
unsigned char status = 0;
16
volatile unsigned char count;
17
18
void timer1 (void);
19
void master_init (void);
20
void master_transmit (unsigned char data);
21
22
SIGNAL (SIG_SPI) {
23
  return;
24
}
25
26
SIGNAL (SIG_OVERFLOW1) {            //Senderoutine
27
  if (count == 1) {
28
    master_transmit ('1');
29
    count--;
30
    PORTL   = 0xFF;    
31
    return;
32
  }
33
  if (count == 0) {
34
    master_transmit ('0');
35
    PORTL   = 0x00;    
36
    count++;
37
  }
38
}
39
40
void timer1 (void) {
41
  TIMSK1 |= (1<<TOIE1);                   //Timer Overflow Interrupt enable
42
  TCNT1 = 0;                          //Rücksetzen des Timers
43
  TCCR1B = (1<<CS10) | (1<<CS11);      //8MHz/65536/64 = 1,91Hz --> 0,5s
44
}
45
46
void master_init (void) {
47
  DDRB = (1<<PB1) | (1<<PB2) | (1<<PB0);    // setze SCK,MOSI,PB0 (SS) als Ausgang
48
  PORTB = (1<<PB1) | (1<<PB0);        // SCK und PB0 high (ist mit SS am Slave verbunden)
49
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);  //Aktivierung des SPI, Master, Taktrate fck/16
50
  status = SPSR;                //Status löschen
51
}
52
53
void master_transmit (unsigned char data) {
54
  PORTB &= ~(1<<PB0);            //SS am Slave Low --> Beginn der Übertragung
55
  SPDR = data;                //Schreiben der Daten
56
  while (!(SPSR & (1<<SPIF)));
57
  PORTB |= (1<<PB0);              //SS High --> Ende der Übertragung
58
}
59
60
int main (void) {
61
  DDRL   = 0xFF;    
62
  master_init ();
63
  timer1 ();
64
  sei ();
65
66
  for (;;);
67
  return 0;
68
}

von Patrick B. (p51d)


Lesenswert?

Christoph B. schrieb:
> will die SPI Schnittstelle nicht so wie wir.

Gute Fehlerbeschreibung... was will wie nicht, respektive passiert 
etwas...
Oszi vorhanden? Wenn ja, kannst du dir ja mal eine LED oder sowas in der 
TimerISR toggeln lassen (-> Timer OK). Ebenso das SPI

Ansonsten sieht es gut aus. Debugger schon versucht?

von Christoph H. (christoph_b)


Lesenswert?

also Oszi und Logic Analyser sind vorhanden.

Der Timer läuft ( toggle eine LED). Trotzdem bekomme ich nur ein 5V 
Signal am Ausgang. Müsste da nicht ein "Schönes" Rechteck Signal 
anstehen?

Sende ja jede Sekunde eine 0 und 1.

von Martin (Gast)


Lesenswert?

Muss MISO nicht auf MOSI gehen? (Serial Input/ Serial Output)

von Patrick B. (p51d)


Lesenswert?

Ev. Triggerproblem?
SCK ist nur aktiv, wenn Daten gesendet werden.

Wofür ist das?
1
status = SPSR;                //Status löschen

Also bei mir läuft dies auf einem ATmega32 mit 4MHz:
1
void SPI_MasterInit(void){
2
  /* Set MOSI and SCK output, all others input */
3
  DDR_SPI = (1 << DD_MOSI) | (1 << DD_SCK) | (1 << DD_SS);
4
  /* Enable SPI, Master, set clock rate fck/2 */
5
  SPCR = (1 << SPE) | (1 << MSTR);
6
  SPSR = (1 << SPI2X);
7
}
8
9
void SPI_MasterTransmit(char cData){
10
  /* Start transmission */
11
  SPDR = cData;
12
  /* Wait for transmission complete */
13
  while(!(SPSR & (1 << SPIF)));
14
}

Triggere mal auf SS (oder bleibt dieser immer auf High?).

Martin schrieb:
> Muss MISO nicht auf MOSI gehen? (Serial Input/ Serial Output)

Nö, passt schon. Master Out auf Master Out beim Slave. Die können gerade 
verbunden werden. Der Slave muss dann natürlich auf Slave eingestellt 
sein.

von Christoph H. (christoph_b)


Lesenswert?

Hallo

Habe nun das SPI zwischen einem Atmega 2560 und einem Atmega 16 zum 
laufen bekommen. :-)

Was ich noch nicht hinbekomme ist das ich die Daten in einzelne Bytes 
aufteilen kann um sie so über den SPI bus zu senden.

von Yaro (Gast)


Lesenswert?

Was war der Fehler?

Welche Daten möchtest du aufteilen?
Sowas lässt sich mit unions machen... Packst z.B. einen float rein und 
holst ein uint8_t array raus.

von Christoph H. (christoph_b)


Lesenswert?

Es war irgendein komisches Problem mit dem AVR Studio 5. Habe zum Test 
nochmal Studio 4 installiert und siehe da SPI klappt.
Danach habe ich nochmal Version 5 installiert und auch da klappt nun 
SPI.

Ich kann ja max 255 verschiedene Werte übertragen. (8Bit) Würde jetzt 
gerne z.B. "PC4_1" für PortC LED1 On usw übertragen. Später muss ich 
über SPI die PWM des anderen Atmega steuern können.

Hast du zufällig ein Beispiel wie man das anstellt.

MFG Christoph

von Christoph H. (christoph_b)


Lesenswert?

@ Yaro

Hast du zufällig ein Beispiel wie man das macht?

von Uwe (Gast)


Lesenswert?

Denk dir nen Protokol aus z.B. :

1. Byte Adresse des Empfängers
2. Byte Befehl
3. Byte Länge der Daten bzw. Parameter
4. n Byte Daten
5. Checksum

Und zerlege alle Variablen in 8Bit und bau Sie danach wieder Zusammen.

von Uwe (Gast)


Lesenswert?

einfach mal C Unions googlen

von Christoph H. (christoph_b)


Lesenswert?

Hallo

Habe es jetzt hinbekommen das ich mehrer Bytes über SPI sende. ( 
verwende ein Array)

Das Problem ist das nicht genau weiß wie der Slave das auswertet.
Leider stimmt die Auswertung noch nicht.

Anbei auch ein Beispiel wie die Sende Daten ausschauen.

Quellcode.
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <avr/signal.h>
4
5
volatile unsigned char data;
6
unsigned char status;
7
unsigned char data_IN[10];
8
unsigned int ADC_16;
9
i=0;
10
11
SIGNAL (SIG_SPI) {
12
  data_IN[i] = SPDR;
13
  i++;
14
  if (i=10)
15
  {
16
    ADC_16=data_IN[2]*256+data_IN[1];
17
    i=0;
18
  }
19
  
20
  
21
  if (ADC_16 == 'O','N')  PORTC = 0xFF;      //LEDs an
22
  if (ADC_16 == 'O','F')  PORTC = 0x00;      //LEDs aus
23
  
24
  if (ADC_16 == 'ON')  PORTC = 0xFF;      //LEDs an
25
  if (ADC_16 == 'OF')  PORTC = 0x00;      //LEDs aus
26
}
27
28
29
30
void slave_init (void) {
31
  DDRB |= _BV(PB6);              //MISO als Ausgang, der Rest als Eingang
32
  SPCR = _BV(SPE) | _BV(SPIE);        //Aktivierung des SPI + Interrupt
33
  status = SPSR;                //Status löschen
34
}
35
36
int main (void) {
37
38
  DDRC = 0xff;
39
  slave_init ();
40
  sei ();
41
  for (;;);
42
  
43
}

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.