Forum: Mikrocontroller und Digitale Elektronik Problem mit SPI (Mega16)


von Chris (Gast)


Lesenswert?

Morgen, allerseits.

Habe ein Problem mit meiner SPI Schnittstelle, diese funktioniert nur 
sporadisch. Nach mehrmaligen resetten funktioniert es dann mit Glück 
mal.

Ich steuere 2 74HC595 Schieberegister darüber an, initialisiert wird wie 
folgt:

SS/ wird als Enable-Leitung für die Schieberegister benutzt und is wie 
unten zu sehen als Ausgang definiert.
1
//SPI INIT
2
SPCR |= (1<<SPE) | (0<<DORD) |(1<<MSTR) | (1<<CPHA) | (1<<CPOL) | (1<<SPR0);
3
SPSR |= (1<<SPI2X);
4
DDRB |= (1<<PB5) | (1<<PB7) | (1<<PB4);
5
  
6
SPDR = 0x01;

Sende und Enable Funktion sehen wie folgt aus:
1
void SR_enable()
2
{
3
  SR_On;
4
  
5
  SR_Off;
6
}
7
8
void SR_Out(uint16_t cData)
9
{
10
  SPDR = (cData & 0xFF00) >> 8; //Oberes Nibble übergeben
11
  while(!(SPSR & (1<<SPIF)))
12
    {;}
13
  SPDR = (cData & 0x00FF);  //Unteres Nibble übergeben
14
  while(!(SPSR & (1<<SPIF)))
15
    {;}
16
17
  SR_enable();
18
}

Vor allem die Tatsache das es mal funktioniert und dann wieder nicht 
macht mich ratlos ....

Immoment schalte ich damit testweise eine 6x3 LED-Matrix an um die 
Funktion von SPI usw. zu lernen.

Ich benutz das Pollin Eval-Board mit einer Zusatzplatine...
Hardwareseitig hab ich nicht sehr auf terminierung geachtet. Mit 
geringerer SPI Clock ist aber das selbe Problem festzustellen.

Wäre toll wenn mir jemand Tipps oder Lösungsvorschläge geben könnte :)

Gruß,
Christian

von Falk B. (falk)


Lesenswert?

@  Chris (Gast)

>SS/ wird als Enable-Leitung für die Schieberegister benutzt und is wie
>unten zu sehen als Ausgang definiert.

>//SPI INIT
>SPCR |= (1<<SPE) | (0<<DORD) |(1<<MSTR) | (1<<CPHA) | (1<<CPOL) | >(1<<SPR0);
>SPSR |= (1<<SPI2X);
>DDRB |= (1<<PB5) | (1<<PB7) | (1<<PB4);

Sieht gut aus.

>Sende und Enable Funktion sehen wie folgt aus:

>void SR_enable()
>{
>  SR_On;
>
>  SR_Off;
>}

Erzeugt wahrscheinlich eine steigende Flanke an RCK. Kann man aber ohne 
die Makrodefinition nicht sagen.

>void SR_Out(uint16_t cData)
>{
>  SPDR = (cData & 0xFF00) >> 8; //Oberes Nibble übergeben

Das ist ein Bytes, kein Nibble (4Bit). Da muss nix maskiert werden, 
schieben reicht.

Sieht eigentlich OK aus. Hmmm.

>Ich benutz das Pollin Eval-Board mit einer Zusatzplatine...

Ich hoffe du hast auch Masse verbunden. Und 100nF an den 
Schieberegistern.

MfG
Falk

von Chris (Gast)


Lesenswert?

Okay, das mit dem maskieren kann ich mir dann sparen.

Wie du richtig erkannt hast erzeugt die SR_Enable eine steigende Flanke 
an RCK:
1
#define SR_On    PORTB |= (1<<PB4);
2
#define SR_Off    PORTB &=~(1<<PB4);

An den Schieberegistern sind jeweils 100nF und Masse ist 100%ig 
verbunden :)
Sonst würde garnichts gehen.
Wie gesagt, mal geht es mal nicht, nach mehreren Resets kann es dann mal 
gehen, wenn man nochmals resettet gehts vll. schon nicht mehr. Ganz 
komisch :-/
Könnten bei dieser sache evtl. Interrupts reinpfuschen? Ich habe ein 
Timerinterrupt der jede 10ms Tasten abfrägt (Aus der Code Sammlung).

Gruß,
Christian

von Chris (Gast)


Angehängte Dateien:

Lesenswert?

Habe mal den Quelltext angehängt, vielleicht liegt der Fehler woanders 
und ich sehe ihn nicht.

gruß,

von Falk B. (falk)


Lesenswert?

Poste mal deinen kompletten Quelltext. Als Anhang.

MFG
Falk

von Chris (Gast)


Lesenswert?

Hab ein paar sachen rausgenommen die eh nicht benutzt worden sind, sieht 
ein bisschen unaufgeräumt aus ...

von Chris (Gast)


Angehängte Dateien:

Lesenswert?

So würde dann das Kernprogramm aussehen :)
Hab ein extra Projekt angelegt, der Fehler is der gleiche...
Wenn ich das Zusatzboard abtrennt, den AVR im reset halte und 
währrendessen das Board wieder einstecke und den Reset loslasse, 
funktionierts ....
Hab extra darauf geachtet dass das Verbindungskabel nicht lang ist, ist 
ein 5cm Flachbandkabel, übertragungsstrecke dürfte insgesamt ca. 10cm 
sein.
Werd nacher mal mitm Oszi dran gehen ...

Gruß,

von Michael H* (Gast)


Lesenswert?

ich hätte die vermutung, dass deine impulse am SS zu kurz sind. setz 
doch in deine void SR_enable() ein paar nops rein.

von Chris (Gast)


Lesenswert?

Oh man, das wars. Ich krach ab =)
Hab mich wohl im Datenblatt verlesen....
Danke vielmals :)

von Matthias L. (Gast)


Lesenswert?

>Oh man, das wars.

Man verwendet ja für sowas auch keine Nadelimpulse!

Wie wäre es etwa so:
1
// slave aktivieren
2
SR_Off
3
//Oberes Nibble übergeben
4
SPDR = (cData & 0xFF00) >> 8; 
5
while(!(SPSR & (1<<SPIF)));
6
//Unteres Nibble übergeben
7
SPDR = (cData & 0x00FF);    
8
while(!(SPSR & (1<<SPIF)));
9
10
// übernehmen
11
SR_On

von Michael H* (Gast)


Lesenswert?

ja genau, das wäre die typische spi. nur bei schieberegistern braucht 
man halt eher einen acknowledge puls. am besten einen nicht zu kurzen ^^

von Chris (Gast)


Lesenswert?

Stimmt, das andere war um Welten umständlicher :P

Danke nochmals

von Matthias L. (Gast)


Lesenswert?

>halt eher einen acknowledge puls

Hm.. Der 595er braucht ne positive Flanke zum übernehmen, was ds SIgnal 
dann macht, spielt keine Rolle.

von Falk B. (falk)


Lesenswert?

@ Matthias Lipinsky (lippy)

>Man verwendet ja für sowas auch keine Nadelimpulse!

Käse. Wo ist das ein Nadelimpuls? Der Puls ist min. zwei Takte lang, 
macht selbst bei 16 MHz schnarchlangsame 125ns. In der Zeit schaltet der 
74HC595 zehnmal! Ich tippe mal eher auf wildes Klingeldrahtvehau, das 
tierische Resonzanzen erzeugt. Dann ist es klar dass ein so kurzer Puls 
Probleme hat, das Ende der Leitung halbwegs sauber zu erreichen.

MFG
Falk

von Chris (Gast)


Lesenswert?

Auf Verdrahtung hab ich weniger Wert gelegt, ist aber ne gefräste 
Platine. Nicht von Hand verdrahtet, aber nun gehts und ich kann mal 
weiter machen.
Danke nochmals :)

von Falk B. (falk)


Lesenswert?

@ Chris (Gast)

>Auf Verdrahtung hab ich weniger Wert gelegt, ist aber ne gefräste
>Platine.

Und die Verbindung vom Pollinboard zu der Platine?
Mach mal bitte ein Bild von deinem Aufbau, zwecks Studien und 
Fehlerdiskussion. Aber bitte unter Beachtung der Bildformate.

MfG
Falk

von Matthias L. (Gast)


Lesenswert?

>schnarchlangsame 125ns

>ein so kurzer Puls


Na, was denn nun ;-)

Aber mit meinem Vorschlag tritt das problem nicht auf...


**duck und weg**

von Chris (Gast)


Angehängte Dateien:

Lesenswert?

So hab mal versucht ein Bild zu machen g
Werde morgen bei Bedarf ein besseres machen. Wäre nett wenn ihr mir 
Tipps zur Leitungsführung geben könntet, später wird nämlich daraus ein 
kommerzielles Produkt (umfangreicher aber auch mit SPI).
Immerhin funktionierts jetzt mehr oder weniger, ab und an setzts 
immernoch aus, werde noch ein bisschen rumprobieren...

gruß,

von Matthias L. (Gast)


Lesenswert?

ein kommerzielles Produkt?

Dann kostet mein Codeschnipsel aber mindestens eine Flasche Schnaps ;-)

von Falk B. (falk)


Lesenswert?

@ Chris (Gast)

>Immerhin funktionierts jetzt mehr oder weniger, ab und an setzts
>immernoch aus, werde noch ein bisschen rumprobieren...

MESSEN! Mit den Scope am Schieberegister. Ordentlichen Tastkopf 
verwenden, 10:1, Masse DIREKT an der Spitze (der Metallring) auf Masse 
legen.

MfG
Falk

von Chris (Gast)


Lesenswert?

Ich weis wie man mit nem oszi umgeht :)
Ich werd morgen mal messen, hab aber das Gefühl das es einfach mit dem 
Layout in Verbindung steht. Wenn an RCK keine saubere Flanke anstehen 
würde, würde es garnicht funktionieren. Wenn es mal funktioniert, 
funktioniert es bis ich wieder resette, von daher glaub ich weniger das 
es mit SS/ bzw. RCK zu tun hat. Werde morgen aber mal messen und 
testweise ein delay nach dem Senden der Daten und vor dem RCK einbauen. 
Ich melde mich morgen dann wieder nach den testen.

Danke nochmals.
Gruß,

von Chris (Gast)


Lesenswert?

Morgen, also wenn die Schaltung nicht funktioniert, was sie immernoch 
nicht zuverlässig macht, habe ich weder eine SPI Clock noch Daten auf 
MOSI oder Enable Flanken an RCK. Könnte es sein das der Mega16 ne Macke 
hat?
Womit das ganze geringfügig besser läuft ist wenn ich nach der 
Steigenden RCK Flanke 1ms Pause mache und dann erst wieder auf low 
ziehe.
Ich werde gleich mal ein anderen Mega16 probieren...
Melde mich später wieder.

gruß,

von W. B. (wb1)


Lesenswert?

Wenn ich das richtig sehe, benutzt du Flachkabel.
Mein Vorschlag:
baue das kabel so um, das du jeweils zwischen einer Signalleitung eine 
Masseleitung hast.
Ich glaube, die Leitungen übersprechen. Durch die zusätzliche 
Masseleitung zwischen den Signalleitungen bekommst du eine Abschirmung

von Falk B. (falk)


Lesenswert?

@ W. Bl (wb1)

>baue das kabel so um, das du jeweils zwischen einer Signalleitung eine
>Masseleitung hast.

Naja, das ist die Luxusvariante. Zwei Masseleitungen jeweils genau neben 
den Takten sollten reichen.

Wellenwiderstand

>Ich glaube, die Leitungen übersprechen. Durch die zusätzliche
>Masseleitung zwischen den Signalleitungen bekommst du eine Abschirmung

Naja, das ist die stark vereinfache Erklärung ;-)
Die induktive Kopplung ist wesentlich problematischer als die 
kapazitive.

MFG
Falk

von Chris (Gast)


Lesenswert?

Hab jetzt mit Hilfe von Debug LEDs herrausgefunden das es garnichts mit 
dem Enable der Schieberegister zu tun hat. Der Controller ist auch ok.
Die Initialisierung läuft einwandfrei ab, beim Senden scheint er sich 
aber zu verabschieden:
1
void SR_Out(uint16_t cData)
2
{
3
  Debug1_on;
4
  //Slave aktivieren
5
  SR_Off;
6
  
7
  //Oberes Byte übergeben
8
  SPDR = cData >> 8; 
9
  while(!(SPSR & (1<<SPIF)))
10
    {;}
11
  Debug2_on;
12
13
  //Unteres Byte übergeben
14
  SPDR = cData ;
15
  Debug3_on;
16
      
17
  while(!(SPSR & (1<<SPIF)))
18
    {;}
19
      
20
  //übernehmen
21
  SR_On;
22
  
23
}
Debug LED 2 leuchtet noch, Debug 3 nicht mehr.
Das es mit den Leitungen zutun hat kann ich mir nicht vorstellen, denn 
wenn es funktioniert ist egal welche SPI Clock ich habe (max. /4 
probiert). Wenn es nicht funktioniert gibt es kein einziges Signal am 
Schieberegister.
Es muss was software technisches sein aber ich komm grad nicht drauf...

Gruß,

von Chris (Gast)


Lesenswert?

Wie sieht es eigentlich mit der Initialisierung aus, man sollte doch ein 
Dummy Bate senden, ist das richtig so:
1
//SPI INIT
2
  SPCR |= (1<<SPE) | (0<<DORD) |(1<<MSTR) | (1<<CPHA) | (1<<CPOL) | (0<<SPR0);
3
  SPSR |= (0<<SPI2X);
4
  DDRB |= (1<<PB5) | (1<<PB7) | (1<<PB4);
5
  
6
  SPDR = 0x01;
Oder muss ich danach noch SPIF manuell setzen?

von Branko G. (branko)


Lesenswert?

Ich benutze für HC595 aber SPI-Mode 2:
1
SPI MODE2 CPOL=1,CPHA=0 -> Sample(Falling), Setup(Rising)

von Falk B. (falk)


Lesenswert?

@ Branko Golubovic (branko)

>Ich benutze für HC595 aber SPI-Mode 2:

>SPI MODE2 CPOL=1,CPHA=0 -> Sample(Falling), Setup(Rising)

Das ist ein wenig riskant. man solle 0 oder 3 wählen.

@ Chris (Gast)

>  while(!(SPSR & (1<<SPIF)))
>    {;}

das scheint mir etwas komisch. jaja, nach C wahrscheinlich OK, aber 
warum so? Probier mal

>  while(!(SPSR & (1<<SPIF)));


>Debug LED 2 leuchtet noch, Debug 3 nicht mehr.

Ich glaube du schreibst zu schnell nach der Initialisierung rein. 
Probiers mal so.

1
void SR_Out(uint16_t cData)
2
{
3
  Debug1_on;
4
  //Slave aktivieren
5
  SR_Off;
6
  
7
  //Oberes Byte übergeben
8
  while(!(SPSR & (1<<SPIF)));
9
  SPDR = cData >> 8; 
10
  Debug2_on;
11
12
  //Unteres Byte übergeben
13
      
14
  while(!(SPSR & (1<<SPIF)));
15
  SPDR = cData ;
16
  Debug3_on;
17
  
18
  while(!(SPSR & (1<<SPIF)));    
19
  //übernehmen
20
  SR_On;
21
}

MFG
Falk

von Chris (Gast)


Lesenswert?

Danke erstmal für eure Hilfe.
Mit deiner Funktion komm ich auch nicht an Debug3, sieht aus als ob er 
sich beim senden des ersten Bytes aufhängt. Wie sieht das mit dem Dummy 
Byte aus, hab ich das richtig gemacht ein was ins register zu schreiben 
und sonst nichts weiter zu tun?

von Falk B. (falk)


Lesenswert?

@ Chris (Gast)

>sich beim senden des ersten Bytes aufhängt.

> Wie sieht das mit dem Dummy Byte aus, hab ich das richtig gemacht ein was > ins 
register zu schreiben

Ja

und sonst nichts weiter zu tun?

Nein. Bestenfalls auf das Ende der Übertragung warten.

MOMENT! Falsche Reihenfolge!

ERST die IOs konfigurieren, DANN SPI. Sonst spuckt dir ggf. das SS-Pin 
dazwischen!

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Schieberegister#Ansteuerung_per_SPI-Modul
1
void init_avr()
2
{
3
  uart_init( UART_BAUD_SELECT(UART_BAUD_RATE,F_CPU) );
4
5
  TCCR0 = (1<<CS02)|(1<<CS00);      // divide by 1024
6
    TIMSK = 1<<TOIE0;        // enable timer interrupt
7
  sei();
8
9
  // IO ZUERST konfigurieren!
10
  DDRB |= (1<<PB5) | (1<<PB7) | (1<<PB4);
11
12
  //SPI INIT
13
  SPCR |= (1<<SPE) | (0<<DORD) |(1<<MSTR) | (1<<CPHA) | (1<<CPOL) | (1<<SPR0);
14
  SPSR |= (1<<SPI2X);  
15
  SPDR = 0x01;

MfG
Falk

von Chris (Gast)


Lesenswert?

Wow falk, besten dank. Ich bin begeistert :)
Das ganze funktioniert auch bei 4MHz SPI-Takt .
Das es doch so einfach ist, hätte aber auch nicht gewusst was noch 
falsch sein kann.
Daaaanke :)

gruß,

von Falk B. (falk)


Lesenswert?

@ Chris (Gast)

>Daaaanke :)

De nada.

Dann geht wohl die von  Matthias Lipinsky beansspruchte Flasche Schnaps 
an mich. Martini Blanco wenns recht ist ;-)

MFG
Falk

von Chris (Gast)


Lesenswert?

:-P
Das Projekt läuft nun 2 Tage, bis zu einem fertigen Produkt das wir in 
unsere Systeme einbauen wird noch ne Weile vergehen aber ich denk an 
euch :-)

gruß,
Christian

von Matthias L. (Gast)


Lesenswert?

> Falk Brunner (falk)
>eansspruchte Flasche Schnaps an mich.
1
void SR_Out(uint16_t cData)
2
{
3
  //Slave aktivieren
4
  SR_Off;
5
  //Oberes Byte übergeben
6
...
7
  //Unteres Byte übergeben
8
...
9
  //übernehmen
10
  SR_On;
11
}

Moment.. Meine Anregung ist auc noch drin, also entweder je eine 
Flasche, oder brüderlich teilen:
Du die Flasche, ich den Inhalt..

hicks...

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.