Problem mit SPI (Mega16)

Gast #774138
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
#774145
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
Gast #774358
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
Gast #774390
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ß,
Angehängte Dateien:
Gast #774433
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
#774530
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
Gast #774638
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ß,
Angehängte Dateien:
#774710
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
Gast #774725
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ß,
Gast #775125
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ß,
#775150
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
#775163
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
Gast #775187
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ß,
Gast #775199
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?
#775231
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
Gast #775238
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?
#775251
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
Gast #775384
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ß,
Gast #775455
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...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren