Forum: Mikrocontroller und Digitale Elektronik SPI will auf AVR nicht laufen


von Maci M. (maci_mio)


Lesenswert?

Hallo,

versuche gerade einen Hardware SPI für ein späteres Projekt zum laufen 
zu bringen.

Habe mir schon das originale Datenblatt durchgelesen und sämtliche 
Beispielprojekte ausprobiert, aber der SPI will nicht gehen.

MOSI ist dauernd auf High
CK ist auch nur auf HIGH
UND SS pulsiert wie gewollt.

Ist evtl. einfach mein uC kaputt?

uC = ATMega328P

Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
void SPI_MasterInit(void)
5
{
6
  /* Set MOSI and SCK output, all others input */
7
  DDRB = (1<<5) | (1<<3) | (1<<2);
8
  /* Enable SPI, Master, set clock rate fck/16 */
9
  SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
10
}
11
12
void SPI_MasterTransmit(char cData)
13
{
14
  /* Start transmission */
15
  SPDR = cData;
16
  /* Wait for transmission complete */
17
  while(!(SPSR & (1<<SPIF)));
18
}
19
20
int main(void)
21
{
22
  
23
  SPI_MasterInit();
24
25
  
26
  while(1)
27
  {
28
     PORTB &= ~(1<<2);
29
     SPI_MasterTransmit(0xAB);
30
     PORTB |= (1<<2);
31
  }
32
}

von Maxim B. (max182)


Lesenswert?

Maci M. schrieb:
> DDRB = (1<<5) | (1<<3) | (1<<2);

Das ist unschön. Besser wäre es:
1
#define SPI_SS PB2
2
#define SPI_MOSI PB3
3
#define SPI_SCK PB5
4
5
DDRB |= (1<<SPI_SCK)|(1<<SPI_MOSI)|(1<<SPI_SS);


> MOSI ist dauernd auf High
> CK ist auch nur auf HIGH
> UND SS pulsiert wie gewollt.

Kann sein, daß SPI_MasterTransmit(0xAB); vom Compiler wegoptimiert 
wurde.
Du kannst in Simulator Assembler-Code ankucken, dort siehst du das 
genau. Ansonsten arbeitet so ein Programm oft anders als vollwertige. 
Compiler ist klug. Er sieht, daß hier nichts gemacht wird. Deshalb 
optimiert er vieles weg.

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Maci M. schrieb:
> SS pulsiert wie gewollt.
Mit welchem zeitlichen Ablauf?

> Ist evtl. einfach mein uC kaputt?
Bei mir waren das in 99,9% irgendwelche Programmfehler. Ich probiere in 
so einem Fall einfach mal einen anderen µC aus...

Maxim B. schrieb:
> Compiler ist klug. Er sieht, daß hier nichts gemacht wird.
Natürlich wird da was gemacht. Das Programm soll aussen am Controller 
einen Pegelwechsel erzeugen. Den darf er niemals wegoptimieren. 
Bestenfalls eine Codefolge, die keinerlei Aussenwirkungen hat, darf 
weggelassen werden. Eine Änderung des zeitlichen Ablaufs gilt hier nicht 
als Auswirkung, weil ein C-Programm keine Zeit "braucht" oder innehat.

: Bearbeitet durch Moderator
von Maxim B. (max182)


Lesenswert?

Lothar M. schrieb:
> Das Programm soll aussen am Controller
> einen Pegelwechsel erzeugen. Den darf er niemals wegoptimieren.
> Bestenfalls eine Codefolge, die keinerlei Aussenwirkungen hat, darf
> weggelassen werden.

Bei TO wird ja SS-Pegel geändert, nur ISP sendet nichts. So haben Sie 
recht: was außen am Controller einen Pegelwechsel erzeugt, das bleibt. 
Anders mit SPI. Deshalb war meine erste Gedanke: wegoptimiert.
Wenn das Programm etwas größer würde und SPI mit verschiedenen Daten 
hantierte oder mindestens mit Variablen, die sich im Laufe ändern, dann 
wäre Wegoptimieren weniger wahrscheinlich.

von Dussel (Gast)


Lesenswert?

Maci M. schrieb:
> /* Set MOSI and SCK output, all others input */
>   DDRB = (1<<5) | (1<<3) | (1<<2);
Du setzt außer MOSI und SCK noch einen Pin. Wahrscheinlich SS. Nur mal 
so als Idee, lass SS oder benutze einen anderen Pin. Vielleicht gibt es 
da Probleme. Sollte es eigentlich nicht, aber wer weiß.

von Maxim B. (max182)


Lesenswert?

Dussel schrieb:
> Nur mal
> so als Idee, lass SS oder benutze einen anderen Pin.

Gerade für AVR wäre das schlecht: wenn SS als Eingang bleibt und 
zufällig (z.B. durch Störungen) "0" bekommt, dann schaltet SPI 
automatisch auf Slave. Deshalb Fausregel für AVR-SPI: SS sollte immer 
Ausgang bleiben, es sei denn, Slave wird gewünscht.

von Maxim B. (max182)


Lesenswert?

Lothar M. schrieb:
> Den darf er niemals wegoptimieren.
> Bestenfalls eine Codefolge, die keinerlei Aussenwirkungen hat, darf
> weggelassen werden.

Es gibt noch ein Moment: TO hat das ganze Programm hier gezeigt. Kein 
Fragment. Das ist das Ganze. Hier wird Compiler mehr optimieren, als das 
ein größeres Programm wäre.

von Dussel (Gast)


Lesenswert?

Maxim B. schrieb:
> wenn SS als Eingang bleibt und
> zufällig (z.B. durch Störungen) "0" bekommt, dann schaltet SPI
> automatisch auf Slave.
Meine Befürchtung war, dass durch irgendein Zusammenspiel SPI in den 
Slavemodus schaltet.

von Maxim B. (max182)


Lesenswert?

Dussel schrieb:
> Maxim B. schrieb:
>> wenn SS als Eingang bleibt und
>> zufällig (z.B. durch Störungen) "0" bekommt, dann schaltet SPI
>> automatisch auf Slave.
> Meine Befürchtung war, dass durch irgendein Zusammenspiel SPI in den
> Slavemodus schaltet.

TO sollte Assembler-Code ankucken. Erst dann gibt es mehr Klarheit.

Meine Erfahrung: so kurze Prüfabschnitte bringen nichts. Man sollte 
etwas mehr einprogrammieren, um keine realitätsfremden Ergebnisse zu 
bekommen. Oder auch Optimieren vollständig abschalten.

: Bearbeitet durch User
von Maci M. (maci_mio)


Lesenswert?

Dussel schrieb:
> Maci M. schrieb:
>> /* Set MOSI and SCK output, all others input */
>>   DDRB = (1<<5) | (1<<3) | (1<<2);
> Du setzt außer MOSI und SCK noch einen Pin. Wahrscheinlich SS. Nur mal
> so als Idee, lass SS oder benutze einen anderen Pin. Vielleicht gibt es
> da Probleme. Sollte es eigentlich nicht, aber wer weiß.

Habe es sogar schonmal komplett ohne ss versucht, geht auch nicht.

Gehe immer mit dem oszi an die Ports aber sehe nichts

von Maxim B. (max182)


Lesenswert?

Maci M. schrieb:
> Gehe immer mit dem oszi an die Ports aber sehe nichts

Kuck mal Assembler-Code. Gibt es dort überhaupt etwas über SPI?

: Bearbeitet durch User
von Dussel (Gast)


Lesenswert?

Was macht eigentlich der Simulator? Springt der in die Funktionen?

von Maxim B. (max182)


Lesenswert?

Das ist für eine wirkliche Probe zu kurz:
1
int main(void)
2
{
3
  
4
  SPI_MasterInit();
5
6
  
7
  while(1)
8
  {
9
     PORTB &= ~(1<<2);
10
     SPI_MasterTransmit(0xAB);
11
     PORTB |= (1<<2);
12
  }
13
}

Besser etwa so:
1
unsigned char a=0, b=201;
2
unsigned int c=0;
3
4
int main(void)
5
{
6
  
7
  SPI_MasterInit();
8
9
  
10
  while(1)
11
  {
12
     PORTB &= ~(1<<2);
13
     SPI_MasterTransmit((unsigned char)(c>>8));
14
     SPI_MasterTransmit((unsigned char)c);
15
     PORTB |= (1<<2);
16
     a++;
17
     b--;
18
     c=a*b;
19
  }
20
}

Hier ist Wahrscheinlichkeit, daß etwas wegoptimiert wird, viel geringer.

von Wolfgang (Gast)


Lesenswert?

Maci M. schrieb:
> Ist evtl. einfach mein uC kaputt?

Auch wenn das hier von manchen nicht gerne gehört wird, nimm die Arduino 
IDE, die Arduino SPI Library und eines der Beispiele.
Dann siehst du innerhalb von 3 Minuten, ob dein µC ok ist.

von Maci M. (maci_mio)


Lesenswert?

> unsigned char a=0, b=201;
> unsigned int c=0;




Danke funktioniert war wirklich ein Optimierungsfehler.

Beitrag #6421614 wurde vom Autor gelöscht.
von M. K. (sylaina)


Lesenswert?

PB2 ist der Chipselect vom Atmega328. Wird der angeknusbert denkt der 
Atmega328, dass er ein Slave ist und wartet, dass der Pseudo-Master mal 
was sagt ;)

Ist jetzt nur so das, was mir beim Überfliegen auffiel und ist IMO ne 
beliebte "Falle" bei Atmega328 und seinen Freunden ;)

Hier mal ein Ausschnitt aus dem Datenblatt des Atmega328PB dazu:

If SS is configured as an input, it must be held high to ensure master 
SPI operation. If the SS pin is driven low by peripheral circuitry when 
the SPI is configured as a master with the SS pin defined as an input, 
the SPI system interprets this as another master selecting the SPI as a 
slave and starting to send data to it. To avoid bus contention, the SPI 
system takes the following actions:

Aus dem Kapitel 23.3.2 des aktuellen Datenblatts

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Maxim B. schrieb:
> Compiler ist klug. Er sieht, daß hier nichts gemacht wird. Deshalb
> optimiert er vieles weg.

 Klar.
 Nur bedarf es jemanden mit bisschen Gehirnschmalz, um das zu merken.
 Dass erst nach 7(sieben) Posts von dir das Problem erkannt wurde,
 zeigt überdeutlich wer in diesem Thread derjenige mit Gehirn ist...

von Maxim B. (max182)


Lesenswert?

Marc V. schrieb:
> Dass erst nach 7(sieben) Posts von dir das Problem erkannt wurde

Ich habe darüber in meinem Post 1. geschrieben:
"Kann sein, daß SPI_MasterTransmit(0xAB); vom Compiler wegoptimiert
wurde."

In unserer schweren Zeit gibt es immer mehr Schriftsteller und immer 
weniger Leser. Schade...

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Maci M. schrieb:
> Danke funktioniert war wirklich ein Optimierungsfehler.

Sicher nicht.

von Maxim B. (max182)


Lesenswert?

Klar, ein Compiler nacht nur, was seine Schöpfer wollten. Die Fehler 
macht immer der das Programm schreibt.

Daß Compiler zu einfache Programm-Proben wegoptimiert, das habe ich 
früher oft erlebt.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Ich sage: Das kann/darf nicht sein!
Nicht ohne Grund sind die SPI Register als volatile deklariert.
Also sind sie von Optimierungen ausgeschlossen.

von Maxim B. (max182)


Lesenswert?

Arduino Fanboy D. schrieb:
> Also sind sie von Optimierungen ausgeschlossen.

Das sagt Theorie. Praxis sieht aber etwas anders aus...

Wären wir die Compiler schreiben, so wäre hier eine Diskussion nützlich. 
Solange aber wir Compiler nur verwenden, müssen wir einfach das Werkzeug 
lernen.

: Bearbeitet durch User
von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Falk B. schrieb:
> Maci M. schrieb:
>> Danke funktioniert war wirklich ein Optimierungsfehler.
>
> Sicher nicht.

 Wenn ich ein bisschen nachdenke, glaube ich auch, daß du Recht
 hast...
 Ein Byte muß auf jeden Fall gesendet werden, egal ob dies später
 irgendwo gebraucht wird oder nicht...
 Vielleicht wird mit diesem Byte ein Gerät aktiviert, es ist nicht
 der Compiler, der darüber entscheiden soll...

: Bearbeitet durch User
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

M. K. schrieb:
> PB2 ist der Chipselect vom Atmega328. Wird der angeknusbert denkt der
> Atmega328, dass er ein Slave ist und wartet, dass der Pseudo-Master mal
> was sagt ;)
Aber doch nur, wenn der SS-Pin als Eingang konfiguriert ist.

Falk B. schrieb:
> Maci M. schrieb:
>> Danke funktioniert war wirklich ein Optimierungsfehler.
> Sicher nicht.
Ich glaube, der Compiler hatte einfach statt des C-Codes den falschen 
Kommentar in Code umgesetzt:
1
    /* Set MOSI and SCK output, all others input */
2
    DDRB = (1<<5) | (1<<3) | (1<<2);
Denn dann wäre der SS-Pin ein Eingang gewesen und die SPI-Einheit hätte 
das gemacht, was sie halt macht, wenn der SS-Pin als Eingang deklariert 
ist.

Maci M. schrieb:
> Danke funktioniert war wirklich ein Optimierungsfehler.
Wie hast du festgestellt, dass das ein Optimierungsfehler war?
Was hast du denn geändert, dass es jetzt läuft?

: Bearbeitet durch Moderator
von Maxim B. (max182)


Lesenswert?

Marc V. schrieb:
> Vielleicht wird mit diesem Byte ein Gerät aktiviert, es ist nicht
>  die Sache des Compilers, darüber zu entscheiden...

Das Problem liegt nicht nur daran, daß vorgegebene Byte und keine 
Variable geschickt würde. Das Problem liegt daran, daß das ganze 
Programm nichts macht. Das erkennt Compiler.
Meine Erfahrung: wäre in main() und in der Schleife etwas mehr, auch 
andere Funktionen, andere Aufgaben, so würde auch SPI-Sendung nicht 
wegoptimiert.
Ich denke, Compiler ist wirklich klug. Er analysiert keine einzelnen 
Funktionen. Er analysiert das ganze Programm.

Deshalb, wenn ich eine mir unbekannte IC mit einer Versuchsplatine 
erproben möchte, mache ich auch viel anderes: beschreibe CLKPR zum 
Beispiel, initialisiere TWI usw. Das alles nur um zu viel Wegoptimieren 
zu vermeiden. Anders gesagt, es sollte ein Programm sein, das etwas 
macht, was Compiler nicht gleich als "nichts" erkennt.

von Maci M. (maci_mio)


Lesenswert?

Ok, habe nochmal bisschen rumgetestet.

Ist kein Optimierungsfehler sondern mein Oszilloskop ist kaputt.

von Maxim B. (max182)


Lesenswert?

Lothar M. schrieb:
> Was hast du denn geändert, dass es jetzt läuft?

Er hat nach meinem Tipp statt einer Konstante eine Variable geschickt, 
die während der Laufzeit geändert wird.

: Bearbeitet durch User
von Dussel (Gast)


Lesenswert?

Maxim B. schrieb:
> Das Problem liegt daran, daß das ganze
> Programm nichts macht. Das erkennt Compiler.
Warum macht es nichts? Es ist ja klar, dass es etwas machen soll, 
nämlich eben Daten an die Außenwelt senden. Wo ist der Fehler, dass es 
mit dem Code nichts macht?
Unabhängig davon, ob es am Oszilloskop lag.

von Maxim B. (max182)


Lesenswert?

Maci M. schrieb:
> Ok, habe nochmal bisschen rumgetestet.
>
> Ist kein Optimierungsfehler sondern mein Oszilloskop ist kaputt.

Du hast aber ein komisches Oszilloskop: SS-Pin-Änderungen hat er 
gezeigt, MOSI und SCK dagegen nicht. Ist Optimieren vielleicht auch in 
dein Oszilloskop eingebaut? :)

von Maxim B. (max182)


Lesenswert?

Dussel schrieb:
> Wo ist der Fehler, dass es
> mit dem Code nichts macht?

Ich bleibe bei meiner Meinung: Compiler hat erkannt, daß das Programm 
nichts macht, und hat alles, was er als überflüssig sieht, wegoptimiert.

Ich glaube daran einfach deshalb, weil mit mir das auch mehrmals 
passierte. Ein Blick in Assembler reichte gewöhnlich.

Solch kurze Programme, wenn man wirklich nur und ausschließlich eine 
Konstante kontinuierlich zu schicken braucht, so was schreibt man lieber 
auf dem Assembler. C ist zu klug dafür, zu unübersichtlich.

: Bearbeitet durch User
von Horst G. (horst_g532)


Lesenswert?

Maxim B. schrieb:
> Das Problem liegt nicht nur daran, daß vorgegebene Byte und keine
> Variable geschickt würde. Das Problem liegt daran, daß das ganze
> Programm nichts macht. Das erkennt Compiler.
> Meine Erfahrung: wäre in main() und in der Schleife etwas mehr, auch
> andere Funktionen, andere Aufgaben, so würde auch SPI-Sendung nicht
> wegoptimiert.
> Ich denke, Compiler ist wirklich klug. Er analysiert keine einzelnen
> Funktionen. Er analysiert das ganze Programm.

Was für ein Quark.
Die Register sind volatile aus gutem Grund – derartige Zugriffe darf der 
Compiler nicht wegoptimieren. So ist volatile definiert – alles andere 
wäre ein Compilerbug.
Einem Compiler ist es auch egal, ob du einer Funktion eine Konstante 
oder eine Variable übergibst – sollte eine Funktion vom Compiler leer 
hinterlassen werden, kann maximal noch der Linker den Aufruf entfernen.

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Maxim B. schrieb:
> Marc V. schrieb:
>> Vielleicht wird mit diesem Byte ein Gerät aktiviert, es ist nicht
>>  die Sache des Compilers, darüber zu entscheiden...
>
> Das Problem liegt nicht nur daran, daß vorgegebene Byte und keine
> Variable geschickt würde. Das Problem liegt daran, daß das ganze
> Programm nichts macht. Das erkennt Compiler.

 Sagt wer?
 Was, wenn mit diesem Programm wirklich irgendetwas ein- oder
 ausgeschaltet werden soll?
 Das kann (und soll) der Compiler nicht entscheiden.

> Ich denke, Compiler ist wirklich klug. Er analysiert keine einzelnen
> Funktionen. Er analysiert das ganze Programm.

 Und ich wiederum glaube das nicht.
 Variable aus Loop oder unbenutzte Variablen wegoptimieren ist eine
 Sache, aber das ganze Programm analysieren?
 Ausserdem ist jede Ausgabe, egal ob SPI, I2C oder UART von optimieren
 ausgenommen - wie schon Arduino Fanboy D. schrieb.

von Dussel (Gast)


Lesenswert?

Maxim B. schrieb:
> Compiler hat erkannt, daß das Programm
> nichts macht, und hat alles, was er als überflüssig sieht, wegoptimiert.
>
> Ich glaube daran einfach deshalb, weil mit mir das auch mehrmals
> passierte. Ein Blick in Assembler reichte gewöhnlich.
'Glaubt erkannt zu haben'. Die Annahme, dass das Programm (im Quelltext) 
nichts macht, ist ja eindeutig falsch. Erst nachdem der Compiler eine 
Fehler gemacht hat, tut es wirklich nichts mehr.

Unter der Annahme, dass es wirklich am Compiler lag.

von Einer K. (Gast)


Lesenswert?

Maxim B. schrieb:
> Arduino Fanboy D. schrieb:
>> Also sind sie von Optimierungen ausgeschlossen.
>
> Das sagt Theorie. Praxis sieht aber etwas anders aus...

Das mit der Optimierung ist alles blödes Gelaber.
Ohne Hand und Fuß.... auch ohne Hirn.

Zwischenzeitlich mit 1/2 Dutzend AVR Toolchains getestet.
Das tuts perfekt, ohne jede Ausnahme.
Sowohl als C als auch C++

Maxim B. schrieb:
> Ich bleibe bei meiner Meinung: Compiler hat erkannt, daß das Programm
> nichts macht, und hat alles, was er als überflüssig sieht, wegoptimiert.
Ist klar!
Bedeutung von volatile vielleicht noch mal nachlesen...
Bitte.

von Maxim B. (max182)


Lesenswert?

Ich habe nun das Programm von TO mit AVR Studio compiliert.
Der Grund war wirklich anders.
Das Programm beginnt
1
void SPI_MasterTransmit(char cData)
2
{
3
  /* Start transmission */
4
  SPDR = cData;
5
  8a:  8e bd         out  0x2e, r24  ; 46
6
  /* Wait for transmission complete */
7
  while(!(SPSR & (1<<SPIF)));
8
  8c:  0d b4         in  r0, 0x2d  ; 45
9
  8e:  07 fe         sbrs  r0, 7
10
  90:  fd cf         rjmp  .-6        ; 0x8c <SPI_MasterTransmit+0x2>
11
}
12
  92:  08 95         ret
Und bleibt auf 090: auch hängen. Weil noch ein Befehl fehlt: IN reg,0x2e 
!!! :)

D.h. TO hat die Funktion für Übertragung nicht korrekt geschrieben.
Richtig wäre z.B. so:
1
unsigned char SPI_MasterTransmit(char cData)
2
{
3
  /* Start transmission */
4
  SPDR = cData;
5
  /* Wait for transmission complete */
6
  while(!(SPSR & (1<<SPIF)));
7
  return SPDR;
8
}

Ohne Lesen von SPDR nach der Übertragung funktioniert das alles nicht.

Und auch wichtig: in Init sollte man einmal dummi-Byte schicken, damit 
SPDR  einmal gelesen wird. Sonst wird die Mechanik hängen.
So einfach ist das...

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Maxim B. schrieb:
> Solch kurze Programme, wenn man wirklich nur und ausschließlich eine
> Konstante kontinuierlich zu schicken braucht, so was schreibt man lieber
> auf dem Assembler. C ist zu klug dafür, zu unübersichtlich.

Was für ein Gesülze!

von Maxim B. (max182)


Lesenswert?

Also, es fehlte in der Funktion SPI_MasterTransmit einiges:
1. kein void sondern unsigned char
2. return SPDR; am Ende.
Das noch in Programm zu geben, und dann wird schon alles laufen.

Jetzt erinnere ich: einmal habe ich gleiche Fehler gemacht. Ich dachte: 
wozu muß ich noch die Zeit vergeuden, und SPDR lesen, wenn ich nur 
senden möchte? Und ich habe zwei Funktionen gemacht: eine mit Lesen, 
andere ohne Lesen. Das hat aber nicht funktioniert.

von Einer K. (Gast)


Lesenswert?

Maxim B. schrieb:
> Ohne Lesen von SPDR nach der Übertragung funktioniert das alles nicht.
Auch das ist Unfug.

Du gibst nicht auf, oder?
Eine rege Fantasie hast du ja....
Nur hilft dir das bei solchen Fragen nicht.
Da sollte man besser Fakten bemühen.

von Maxim B. (max182)


Lesenswert?

Arduino Fanboy D. schrieb:
> Auch das ist Unfug.

Vielleicht ist das in Arduino Unfug? Weil man dort immer "Lib" verwendet 
und genau Code von SPI sieht man selber nie.

Wenn man aber alles selber macht, ohne Mama zu rufen, dann muß schon 
return SPDR stehen. Ich bin sicher, in Arduino-Lib ist das auch so, nur 
sieht man das nicht.

Du könntest mal Assembler-Listing von einem Arduino-Programm kucken; 
steht dort in  reg, 0x2e oder nicht

Arduino Fanboy D. schrieb:
> Du gibst nicht auf, oder?
habe ich schon doch! Ich sage nun: das war kein Wegoptimieren. Das war 
nur eine nicht korrekt geschriebene Funktion. Compiler hat keine Schuld, 
er machte alles richtig. Schuldig ist Programmierer (was ich auch früher 
behauptete).

: Bearbeitet durch User
von Dussel (Gast)


Lesenswert?

Maxim B. schrieb:
> Wenn man aber alles selber macht, ohne Mama zu rufen, dann muß schon
> return SPDR stehen.
Muss es weder nach C-Standard noch nach Programmlogik.
Ich zitiere aus dem Datenblatt von "ATmega48A ATmega48PA ATmega88A 
ATmega88PA ATmega168A ATmega168PA ATmega328 ATmega328P":
1
void SPI_MasterTransmit(char cData) {
2
/* Start transmission */
3
SPDR = cData;
4
/* Wait for transmission complete */ while(!(SPSR & (1<<SPIF)))
5
; }

Aber Atmel hat wahrscheinlich einfach keine Ahnung.

von Maxim B. (max182)


Lesenswert?

Dussel schrieb:
> Aber Atmel hat wahrscheinlich einfach keine Ahnung.

Ich kenne Menschen aus Atmel nicht. Ich kann deswegen nichts sagen.
Aber bei mir arbeitete Funktion ohne Lesen von SPDR nicht. Und, wie ich 
noch erinnern kann, hat jemand hier auf dem Forum über den Fehler 
gesagt. Ich habe korrigiert - und alles wurde gut.

Aber macht wie ihr wollt, mir ist das eigentlich egal.

von leo (Gast)


Lesenswert?

Maxim B. schrieb:
> Vielleicht ist das in Arduino Unfug? Weil man dort immer "Lib" verwendet

Nein.

> ... dann muß schon
> return SPDR stehen.

Nein.

Bitte hoer einfach auf Schwachsinn zu posten. Bleib bei deinen Tasten 
und gut.

leo

von Einer K. (Gast)


Lesenswert?

Dussel schrieb:
> Aber Atmel hat wahrscheinlich einfach keine Ahnung.
Sehe ich auch so!
Nur der  Maxim B. (max182) der hats voll auf dem Schirm.

Maxim B. schrieb:
> Wenn man aber alles selber macht, ohne Mama zu rufen, dann muß schon
> return SPDR stehen.

Selbst nach dem Hinweis darauf, dass du falsch liegst, machst du 
unbeirrt weiter.
Du bist ein Denunziant
Ein Lügner
Und hast offensichtlich keine Ahnung, von dem, was du da blubberst.

von Maxim B. (max182)


Lesenswert?

Arduino Fanboy D. schrieb:
> Selbst nach dem Hinweis darauf, dass du falsch liegst

Wo liege ich falsch?
Arduino Fanboy D. schrieb:
> Du bist ein Denunziant
> Ein Lügner
Ich habe dich aber noch nie beleidigt.
nach solchen deinen Worten existierst du für mich nicht mehr. Deine 
Posten werde ich in der Zukunft nie mehr beantworten.

P.S. Wer die Wahrheit sehen will, der hat immer noch die Möglichkeit, 
selbst AVR Studio starten, Text von TO eingeben und compilieren. Dann 
return SPDR dazu schreiben, noch mal kompilieren und vergleichen.
Das bedeutet aber ein bißchen mehr Bewegung, als einfach "Lügner" zu 
schreiben, wie? :)

: Bearbeitet durch User
von S. Landolt (Gast)


Lesenswert?

Maxim B. meint vermutlich diesen Mechanismus, aus dem Datenblatt zu 
'SPSR – SPI Status Register, • Bit 7 – SPIF: SPI Interrupt Flag':

"Alternatively, the SPIF bit is cleared by first reading the SPI Status 
Register with SPIF set, then accessing the SPI Data Register (SPDR)."

von Dussel (Gast)


Lesenswert?

Maxim B. schrieb:
> Aber bei mir arbeitete Funktion ohne Lesen von SPDR nicht. Und, wie ich
> noch erinnern kann, hat jemand hier auf dem Forum über den Fehler
> gesagt. Ich habe korrigiert - und alles wurde gut.
Stimm ja auch. Nur klingen deine Beiträge so, als läge der Fehler im 
Quelltext. Das stimmt aber nicht. Der Fehler liegt im Compiler. Und dass 
man korrekten Quelltext ändert, um einen Fehler zu umgehen, ist eben 
keine Fehlerkorrektur, sondern eine Umgehungslösung ("workaround").

von Maxim B. (max182)


Lesenswert?

Dussel schrieb:
> Stimm ja auch. Nur klingen deine Beiträge so, als läge der Fehler im
> Quelltext.

Wo sonst, wenn nach Quelltext-Korrektur alles funktioniert, wenigstens 
bei mir?

Man sagt: man sollte Menschen so lieben wie sie sind. Das Gleiche 
betrifft auch Compiler: man sollte Compiler so lieben, wie der ist. :) 
Wir dürfen den Compiler verwenden oder nicht verwenden. Sein Verhalten 
zu ändern können wir ihn nicht zwingen.

: Bearbeitet durch User
von Einer K. (Gast)


Lesenswert?

Maxim B. schrieb:
> Wo liege ich falsch?

Maxim B. schrieb:
> Ohne Lesen von SPDR nach der Übertragung funktioniert das alles nicht.

Du bist jetzt mehrfach darauf hingewiesen worden, dass das Unsinn ist.
Bearrst aber darauf.
Damit ist das für mich eine Lüge.

Auch meinst du mich anhand meines Arduino Bekenntnis beurteilen zu 
dürfen.
z.B. ich würde ohne die Arduinolibs verhungern, oder so..
Oder könnte nicht exakt den Code aus dem Eingangsposting probefahren und 
das Resultat im generierten Code sehen.
Das ist Denunziantentum, oder Verleumdnung.
Such dir das schönste davon aus aus.

von Dussel (Gast)


Lesenswert?

Maxim B. schrieb:
> Wo sonst, wenn nach Quelltext-Korrektur alles funktioniert, wenigstens
> bei mir?
Im Compiler. Wenn der Compiler korrekten Quelltext falsch übersetzt, ist 
es ein Fehler des Compilers. Daran ändert sich auch nichts, wenn man 
einen anderen korrekten Quelltext findet, den der Compiler fehlerfrei 
übersetzt.

von Maxim B. (max182)


Lesenswert?

S. Landolt schrieb:
> Maxim B. meint vermutlich diesen Mechanismus, aus dem Datenblatt zu
> 'SPSR – SPI Status Register, • Bit 7 – SPIF: SPI Interrupt Flag':
>
> "Alternatively, the SPIF bit is cleared by first reading the SPI Status
> Register with SPIF set, then accessing the SPI Data Register (SPDR)."

Ja, wahrscheinlich genau das. Ich habe mir seit dem Fall einfach als 
Regel festgelegt: SPI immer voll anzusprechen (Schreiben und Lesen) und 
dummi-byte am Anfang schicken, bei Init. Solange ich das mache, bekomme 
ich kein Problem. Wozu sollte ich was besseres suchen, wenn das gut 
arbeitet?

Auch jetzt bei dem Experiment: das Programm blieb auf SPSR-Prüfung 
hängen. Ich habe return SPDR geschrieben - und alles läuft. So einfach.

von Maxim B. (max182)


Lesenswert?

Dussel schrieb:
> Wenn der Compiler korrekten Quelltext falsch übersetzt, ist
> es ein Fehler des Compilers.

Ja, aber ich benutze, wie auch TO, diesen Compiler. Ich habe keinen 
anderen. Ich muß also den Text so schreiben, daß Compiler mich versteht. 
Schreibe ich so, daß Compiler mich nicht versteht, dann ist absolut 
egal, wer von uns Recht hat: ich oder Compiler. Ich brauche das 
Programm, für Compiler ist das egal.

von Einer K. (Gast)


Lesenswert?

Dussel schrieb:
> Der Fehler liegt im Compiler.
Nein, das ist nicht wahr.
Das Oszi war/ist kaputt.

Maxim B. schrieb:
> Auch jetzt bei dem Experiment: das Programm blieb auf SPSR-Prüfung
> hängen. Ich habe return SPDR geschrieben - und alles läuft. So einfach.
Auch hier unterstelle ich dir eine dreiste Lüge.
Da im Beispiel keine ISR/InterruptFlag zum Einsatz kommt, kann ein 
solcher Fehler auch nicht auftreten.

Wie schon gesagt...
Mit einem halben Dutzend AVR Gcc Toolchains getestet.

von Dussel (Gast)


Lesenswert?

Arduino Fanboy D. schrieb:
> Dussel schrieb:
>> Der Fehler liegt im Compiler.
> Nein, das ist nicht wahr.
> Das Oszi war/ist kaputt.
Stimmt anscheinend.

Wenn der Compiler sich so verhalten würde, wäre es ein Fehler des 
Compilers. ;-)

von Maxim B. (max182)


Lesenswert?

Dussel schrieb:
> Wenn der Compiler sich so verhalten würde, wäre es ein Fehler des
> Compilers. ;-)

Einen Fußgänger, von LKW überfahren, ist kaum nützlich, wenn er auch 
Recht hatte :)

von Einer K. (Gast)


Lesenswert?

Maxim B. schrieb:
> nach solchen deinen Worten existierst du für mich nicht mehr. Deine
> Posten werde ich in der Zukunft nie mehr beantworten.
Höre einfach auf die Leute zu verarschen, dann kommen auch wir beide 
bestens klar.

von Maci M. (maci_mio)


Lesenswert?

Ich habe doch den selben Code wie vom Anfang ausprobiert und es 
funktioniert.
Also kann es ja doch nicht daran liegen, dass ich das Datenregister 
nicht auslese.

von W.A. (Gast)


Lesenswert?

Maxim B. schrieb:
> Jetzt erinnere ich: einmal habe ich gleiche Fehler gemacht. Ich dachte:
> wozu muß ich noch die Zeit vergeuden, und SPDR lesen, wenn ich nur
> senden möchte?

Bei SPI gibt es kein "nur senden". Bei einem Transfer über SPI wird vom 
Master immer ein Byte über MOSI raus geschoben und gleichzeitig eins 
über MISO eingelesen.

von holger (Gast)


Lesenswert?

>Also kann es ja doch nicht daran liegen, dass ich das Datenregister
>nicht auslese.

Im Datenblatt steht ja auch nicht dass man das Register "Lesen" muss.
Dort steht dass man auf SPDR zugreifen muss um SPIF zu löschen.
Schreiben ist auch ein Zugriff, und das machst du ja auch.

von S. Landolt (Gast)


Lesenswert?

> ... Schreiben ist auch ein Zugriff ...

Genau; deshalb funktioniert das von Dussel gezeigte 
Atmel-Programmbeispiel ja auch, für sich betrachtet. Allerdings bleibt 
außerhalb der Routine das SPIF gesetzt (was wohl bei Maxim B. irgendwann 
zu Problemen geführt hatte).

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Maci M. schrieb:
> Ich habe doch den selben Code wie vom Anfang ausprobiert und es
> funktioniert.
Das war mein Verdacht.
> Also kann es ja doch nicht daran liegen, dass ich das Datenregister
> nicht auslese.
Und was hast du sonst noch gemacht?
Oder eher: was hast du gemacht, dass es nicht funktioniert hat?

von M. K. (sylaina)


Lesenswert?

Lothar M. schrieb:
> Ich glaube, der Compiler hatte einfach statt des C-Codes den falschen
> Kommentar in Code umgesetzt:

Ich hatte tatsächlich nur den Kommentar gelesen und mir den Code nicht 
genau angeschaut ;)

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.