mikrocontroller.net

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


Autor: Murphy Spider (student-f)
Datum:

Bewertung
0 lesenswert
nicht 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:
// Test-File for SPI

#include <avr/io.h>
#include <avr/interrupt.h>

//CPOL = HI
//CPHA = HI
// LSB first

void SPI_MasterInit(void)
{
SPSR = (1<<SPIF) // Soll Laut uC-Buch beim Init einmalig gesetzt werden
// Setup SPCR 
SPCR =     (1 << MSTR) | /* Master mode */
           (1 << SPIE) | /* SPI Interrupt Enable */
           (1 << SPE)  | /* SPI Enable */
           (1 << DORD) | /* Data Order: LSB first */           
           (1 << CPOL) | /* Clock Polarity: SCK High when idle */
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
           (1 << SPR1) | /* Clock Frequency: f_OSC / 64 */
           (0 << SPR0);
           /* aus einem Forum-Artikel habe ich entnommen, dass MSTR vor SPIE und SPE zu setzen sei, allerdings auch keine Änderung bei mir*/
SPDR = 0xff;  //Start der Übertragung möglich machen!
}

// Entnommen aus einem uC-Buch, sowie im Forum in derselbigen Art gefunden

void SPI_MasterTransmit(unsigned char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)));
}

//Funktion zum rücksetzen der SS als Portausgänge an PORTB an Stelle X auf LOW
// PORTB von PB0 - PB4 
void set_SS_X(unsigned char bit)
{
  PORTB |= 1<<bit;
}

//Funktion zum setzen der SS als Portausgänge an PORTB an Stelle X auf High
// PORTB von PB0 - PB4 
void unset_SS_X(unsigned char bit)
{
  PORTB &= ~(1<<bit);
}


void main(void)
{
DDRB = 0xA8;   // entsprechend Outputs zuordnen

SPI_MasterInit();

sei();         

/* Nur in der Reihenfolge, dass erst PORTB zu setzen, dann SPI_MasterInit(), dann sei überhaupt Ausgabe von SPDR möglich */

// Ausgänge auf PORTC, für Diagnose oder andere Anwendungen denkbar

DDRC = 0xff;
PORTC = 0xff;

  while(1)
  {  
  SPDR = 0xAF;
  /* 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 */ 
  
    PORTC = 0xff;  // Keine SPI Ausgabe mehr auf MOSI, nach PORTC Zugriff

    set_SS_X(3);   // SS setzen

    SPI_MasterTransmit('B');   // Wird nicht an SPDR "gemeldet" 

    unset_SS_X(3);
  }
}

// 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.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Murphy Spider (student-f)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michael U. (amiga)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Murphy Spider (student-f)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Murphy Spider (student-f)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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:
// Test-File for SPI

#include <avr/io.h>
#include <avr/interrupt.h>

#define DC1 0x11
#define DC2 0x12
#define ACK 0x06
#define NAK 0x15
#define ESC 0x1B

//CPOL = HI
//CPHA = HI
// LSB first


void SPI_SlaveReceive(void)
{
SPDR = 0xff;  //Clk "einschalten"
while(!(SPSR & (1<<SPIF)))
PORTC = ~SPDR;   // Banale Ausgabe an den LEDS
}


void SPI_MasterInit(void)
{
SPCR =      (1 << MSTR) | /* Master mode */
     (1 << SPE)  | /* SPI Enable */
           (1 << DORD) | /* Data Order: LSB first */           
           (1 << CPOL) | /* Clock Polarity: SCK High when idle */
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
           (1 << SPR1) | /* Clock Frequency: f_OSC / 64 */
           (0 << SPR0);
SPDR = 0xff;   // Für Anfang Datenreinschreiben, zum aktivieren!
}

void SPI_MasterTransmit(unsigned char cData)
{
/* Start transmission */
SPDR = cData;
/* Wait for transmission complete */
while(!(SPSR & (1<<SPIF)));
}

//Funktion zum rücksetzen der SS als Portausgänge an PORTB an Stelle X auf High
// PORTB von PB0 - PB4 
void set_SS_X(unsigned char bit)
{
  PORTB |= 1<<bit;
}

//Funktion zum setzen der SS als Portausgänge an PORTB an Stelle X auf Low
// PORTB von PB0 - PB4 
void unset_SS_X(unsigned char bit)
{
  PORTB &= ~(1<<bit);
}


void main(void)
{

DDRB = 0x07;   //Ausgaenge für SPI 

SPI_MasterInit();

// LEDS off und Ausgang definiert
DDRC = 0xff;
PORTC = 0xff;

// IRQ settings
PCICR = (1<<PCIE1);
PCMSK1 = (1<<PCINT15);
sei();
set_SS_X(0);      //high beim starten definieren

while(1)
  {
  // entfaellt, warte bis IRQ, Daten ankommen
  }
}

ISR (PCINT1_vect)
{
  unset_SS_X(0);      // auf Low ziehen
  // Bei IRQ, Daten abholen
  SPI_SlaveReceive();
//  set_SS_X(0);      //auf high ziehen
}

Übrigens, die Leds zeigen nichts an ...


gruß Frank

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.