Forum: Mikrocontroller und Digitale Elektronik SPI-Problematik (Daten Übertragung und andere Portc gestört)


von Murphy S. (student-f)


Lesenswert?

Hallo an alle,

habe leider keine passende Antwort und Lösung für meine Problematik im 
Forum gefunden(schon reichlich gesucht und zusammengetragen, aber....). 
Auch in meinen Büchern und dem Datenblatt des ATmega8515 sollte es so 
eig. laufen, oder ich habe mal wieder was entscheidendes überlesen...

Also, ich bin gerade am SPI verzweifeln. Bin dabei das "eigentlich recht 
einfache SPI" für nen ADC, LCD, DAC etc zu nutzen.
Meine derzeitige Konfiguration lautet:

Board:  STK500
uC:     Atmega8515
Oscar:  vorhanden für Port-Analyse

Ich habe schon einige Sachen ausprobiert und mir unter anderem aus 
Büchern und vor allem den Foren einiges zusammen gesucht. Daher bin ich 
zu folgendem letztem Code gekommen:
1
// Test-File for SPI
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
6
//CPOL = HI
7
//CPHA = HI
8
// LSB first
9
10
void SPI_MasterInit(void)
11
{
12
SPSR = (1<<SPIF) // Soll Laut uC-Buch beim Init einmalig gesetzt werden
13
// Setup SPCR 
14
SPCR =     (1 << MSTR) | /* Master mode */
15
           (1 << SPIE) | /* SPI Interrupt Enable */
16
           (1 << SPE)  | /* SPI Enable */
17
           (1 << DORD) | /* Data Order: LSB first */           
18
           (1 << CPOL) | /* Clock Polarity: SCK High when idle */
19
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
20
           (1 << SPR1) | /* Clock Frequency: f_OSC / 64 */
21
           (0 << SPR0);
22
           /* aus einem Forum-Artikel habe ich entnommen, dass MSTR vor SPIE und SPE zu setzen sei, allerdings auch keine Änderung bei mir*/
23
SPDR = 0xff;  //Start der Übertragung möglich machen!
24
}
25
26
// Entnommen aus einem uC-Buch, sowie im Forum in derselbigen Art gefunden
27
28
void SPI_MasterTransmit(unsigned char cData)
29
{
30
/* Start transmission */
31
SPDR = cData;
32
/* Wait for transmission complete */
33
while(!(SPSR & (1<<SPIF)));
34
}
35
36
//Funktion zum rücksetzen der SS als Portausgänge an PORTB an Stelle X auf LOW
37
// PORTB von PB0 - PB4 
38
void set_SS_X(unsigned char bit)
39
{
40
  PORTB |= 1<<bit;
41
}
42
43
//Funktion zum setzen der SS als Portausgänge an PORTB an Stelle X auf High
44
// PORTB von PB0 - PB4 
45
void unset_SS_X(unsigned char bit)
46
{
47
  PORTB &= ~(1<<bit);
48
}
49
50
51
void main(void)
52
{
53
DDRB = 0xA8;   // entsprechend Outputs zuordnen
54
55
SPI_MasterInit();
56
57
sei();         
58
59
/* Nur in der Reihenfolge, dass erst PORTB zu setzen, dann SPI_MasterInit(), dann sei überhaupt Ausgabe von SPDR möglich */
60
61
// Ausgänge auf PORTC, für Diagnose oder andere Anwendungen denkbar
62
63
DDRC = 0xff;
64
PORTC = 0xff;
65
66
  while(1)
67
  {  
68
  SPDR = 0xAF;
69
  /* so gehts einigermaßen, nur zum testen, auch mit Abfrage von while(!(SPSR & (1<<SPIF))); keine "Besserung" in Sicht. Im ersten Sinne nur Ausgabe nötig */ 
70
  
71
    PORTC = 0xff;  // Keine SPI Ausgabe mehr auf MOSI, nach PORTC Zugriff
72
73
    set_SS_X(3);   // SS setzen
74
75
    SPI_MasterTransmit('B');   // Wird nicht an SPDR "gemeldet" 
76
77
    unset_SS_X(3);
78
  }
79
}
80
81
// Demnächst "umsortierung" auf Prototypendefinitionen!!!

Also, folgende Fehler behergt mein eigentliches Test-File zum 
weiterarbeiten:

1.) Bei weiterem PortX-zugriff (z.B. PORTC (laut Datenblatt) reiner 
Input/Output-Port ohne Doppelbelegung)andere Ports, keine Änderungen) 
keine Ausgabe von Daten über MOSI möglich (MOSI bleibt Idle High, Kein 
SCK mehr)
auch bei Benutzung der SPI_MasterTransmit(so wie eig. sinnig und 
ordentlich) keine Änderung feststellbar.

Daher, weshalb kollidieren die anderen Ports bei SPI, sollte doch eig. 
laufen ?

2.) Nur in der Reihenfolge:
   PORTB definieren;
   SPI_Init;
   Sei();
Ausgabe auf SPI erkennbar.

Dies mag ja generell nicht auf Dauer funktionell genug sein, denn 
angenommen ich wollte SPI erst zum späteren Programmaufruf starten und 
das Global Interrupt Flag wollte ich schon vorher setzen..

Kann mir da einer helfen, ich weiß einfach nicht mehr weiter :-( Vielen 
Dank schonmal im Voraus.

von holger (Gast)


Lesenswert?

>           (1 << SPIE) | /* SPI Interrupt Enable */

Das Bit hier zu setzen ohne einen Interrupthandler
dafür zu haben führt zu einem Reset. Also: war das oben
wirklich dein kompletter Code oder nur, wie es so oft
gepostet wird, irgendwas theoretisches?

von Murphy S. (student-f)


Lesenswert?

Hallo Holger,


holger wrote:
>>           (1 << SPIE) | /* SPI Interrupt Enable */
>
> Das Bit hier zu setzen ohne einen Interrupthandler
> dafür zu haben führt zu einem Reset. Also: war das oben
> wirklich dein kompletter Code oder nur, wie es so oft
> gepostet wird, irgendwas theoretisches?

Ne, das sollte schon der Anfang von was größerem werden!!

Hmm, dann bin ich wohl etwas zu eifrig gewesen, ich habe vor in 
"Zukunft" IRQ und das entsprechende Handling zu verwenden(ist ja net die 
einzigste Hardware am uC).

Guter Tipp, wußte ich noch gar net, das bei fehlender IRQ-Routine der uC 
nen Reset macht(wieder was gelernt :-) ). Dann erklärt sich auch das 
Verhalten des uCs, da er ja immer wieder den ersten Wert ausgibt(am 
Oscar verglichen!)

Ich muss dazu sagen, dass ich vorher schon IRQs für andere Funktion 
erfolgreich eingebunden hatte und daher bei meiner SPI Problematik das 
auf das kleinste reduziert habe und das SPIE als "lassen wir das ruhig 
mal gesetzt" unbeachtet hatte. Also teste ich das mal ohne das gesetzte 
Bit und hoffen wir auf ne weitere Erkenntnis. Soweit das läuft, dann 
Ausbau auf IRQ für SPI.

Danke erstmal.

von Michael U. (amiga)


Lesenswert?

Hallo,

bevor eine unvollständige Erklärung hängen bleibt:
der AVR macht keinen Reset, wenn keine IRQ-Routine existiert und ein IRQ 
erlaubt wird.
Der macht, was das Datenblatt sagt: rette den Programmzähler und springe 
an Adresse "IRQ-Vector des freigegebenen IRQ".

Der AVR-GCC schreibt an alle nicht definierten Vectoren einen rjmp 0 
bzw. jmp 0.

Ist auch genaugenommen kein Reset, eben nur ein Sprung auf Adresse 0.
Die Portregister usw. behalten also im Gegensatz tz einem Reset ihre 
Werte, was u.U. zusätliche nette Effekte erzeugen kann.

Gruß aus Berlin
Michael

von Murphy S. (student-f)


Lesenswert?

Hallo an alle,

vielen Dank auch für deine ausführliche Antwort :-) Mein Spi spricht nun 
mit meinem EDip240 Display...

Allerdings möchte ich der Vollständigkeit noch eines für etwaige andere 
suchende nachtragen:

Es ist unbedingt der "eigentliche" /SS(Pin-X an PortB) als Ausgang zu 
setzen. Ansonsten bleibt der uC entsprechend stehen(siehe Datenblatt des 
jeweiligen Atmel-uCs). Dies sei wohl für ggf. zu erstellende 
Multimastersysteme nötig und da wir in meinem Falle keins haben, einfach 
Ausgang raus machen und glücklich sein ..


gruß aus dem Sauerland

von Murphy S. (student-f)


Angehängte Dateien:

Lesenswert?

Hallo uC-Gemeinde,

nun nachdem ich wieder Zeit gefunden habe um weiter zu programmieren, 
haben sich neue Probleme entwickelt, diese ich leider nicht alleine 
lösen kann :-(

Also, ich benutzte das E-Dip 320 am SPI-Anschluss beim ATMEGA1280 
(derzeit noch auf dem STK500/503). Der Datentransfer vom uC zum E-Dip 
funktioniert einwandfrei und mehr als reibungslos (sprich, rufe mir dies 
und das Makro auf, mache dies und jenes!). Allerdings kann ich die Daten 
vom Edip (MISO) nicht auslesen. Das Edip hat des weiteren noch eine 
SBUF_Leitung( bzw. IRQ-Leitung) diese auf Low geht, solange Daten im 
Sendebuffer des E-Dip vorhanden sind. (Nach einem Anruf beim Hersteller 
habe ich mir versichern lassen, dass die Aussage stimmt).

Sprich, sobald Daten vom E-Dip abzuholen sind, geht die SBUF-Leitung 
direkt auf Low und bleibt auch auf Low-Pegel. Allerdings sendet mir das 
E-Dip diese nicht zum uC bzw. ich kann diese irgendwie net auslesen. 
Während dem Senden wird selbstverständlich das CLK Signal am SCK-Pin 
erzeugt und liegt auch an dem E-Dip an. Daher die Frage(n):

a) kann ich generell nicht mit meinem Code Daten einlesen
b) mein Code soweit i.O. und das E-Dip macht mucken
c) Murphy...

Daher habe ich im Anhang nen Screenshot vom Datentransfer gemacht um zu 
schauen, was dort los ist.
CH1:  MISO
CH2:  CLK (SCK)
CH3:  IRQ (SBUF vom EDIP)
CH4:  Slave Select

Pic zeigt, das keine Daten vom Edip zurückkommen.
Anmerkung: SS bewußt auf Low gelassen, bevor Low-Phase zu kurz ist.
Auch nach mehrmaligen Versuchen kommen keine Daten vom EDip zurück. 
Obwohl SS auf Low geht. IRQ Daten zum abholen anzeigt und Clock anliegt. 
Angeschlossen ist es ja auch richtig, da ich ja Daten dorthin senden 
kann.

Der ausgeschnittene Code lautet:
1
// Test-File for SPI
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
6
#define DC1 0x11
7
#define DC2 0x12
8
#define ACK 0x06
9
#define NAK 0x15
10
#define ESC 0x1B
11
12
//CPOL = HI
13
//CPHA = HI
14
// LSB first
15
16
17
void SPI_SlaveReceive(void)
18
{
19
SPDR = 0xff;  //Clk "einschalten"
20
while(!(SPSR & (1<<SPIF)))
21
PORTC = ~SPDR;   // Banale Ausgabe an den LEDS
22
}
23
24
25
void SPI_MasterInit(void)
26
{
27
SPCR =      (1 << MSTR) | /* Master mode */
28
     (1 << SPE)  | /* SPI Enable */
29
           (1 << DORD) | /* Data Order: LSB first */           
30
           (1 << CPOL) | /* Clock Polarity: SCK High when idle */
31
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
32
           (1 << SPR1) | /* Clock Frequency: f_OSC / 64 */
33
           (0 << SPR0);
34
SPDR = 0xff;   // Für Anfang Datenreinschreiben, zum aktivieren!
35
}
36
37
void SPI_MasterTransmit(unsigned char cData)
38
{
39
/* Start transmission */
40
SPDR = cData;
41
/* Wait for transmission complete */
42
while(!(SPSR & (1<<SPIF)));
43
}
44
45
//Funktion zum rücksetzen der SS als Portausgänge an PORTB an Stelle X auf High
46
// PORTB von PB0 - PB4 
47
void set_SS_X(unsigned char bit)
48
{
49
  PORTB |= 1<<bit;
50
}
51
52
//Funktion zum setzen der SS als Portausgänge an PORTB an Stelle X auf Low
53
// PORTB von PB0 - PB4 
54
void unset_SS_X(unsigned char bit)
55
{
56
  PORTB &= ~(1<<bit);
57
}
58
59
60
void main(void)
61
{
62
63
DDRB = 0x07;   //Ausgaenge für SPI 
64
65
SPI_MasterInit();
66
67
// LEDS off und Ausgang definiert
68
DDRC = 0xff;
69
PORTC = 0xff;
70
71
// IRQ settings
72
PCICR = (1<<PCIE1);
73
PCMSK1 = (1<<PCINT15);
74
sei();
75
set_SS_X(0);      //high beim starten definieren
76
77
while(1)
78
  {
79
  // entfaellt, warte bis IRQ, Daten ankommen
80
  }
81
}
82
83
ISR (PCINT1_vect)
84
{
85
  unset_SS_X(0);      // auf Low ziehen
86
  // Bei IRQ, Daten abholen
87
  SPI_SlaveReceive();
88
//  set_SS_X(0);      //auf high ziehen
89
}

Übrigens, die Leds zeigen nichts an ...


gruß Frank

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.