Forum: Mikrocontroller und Digitale Elektronik SPI und SCK Problem


von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

Hallo,
zur Ansteuerung eines Sensors will ich das Hardware SPI des ATmega16 
benutzen.

Dies ist die Initialisierung des SPI:
1
DDRB = (1<<PB5) | (1<<PB7);   //Set MOSI and SCK output, all others input   
2
DDRB |= (1<<PB4);// configure the CS Pin as output as not to affect the SPI
3
      
4
/* initialize SPI Control Registers */
5
SPCR |= (1<<SPE);   //enables SPI functionality
6
SPCR &= ~(1<<DORD);  //Data Order, 0-->MSB first
7
SPCR |= (1<<MSTR);  //Master/Slave Select, 1--> ATmega is master
8
SPCR &= ~(1<<CPOL);// Clock Cycle :rising edge first, falling edge trailing
9
SPCR &= ~(1<<CPHA);//1-->sample on falling edge
10
  
11
SPCR |= (1<<SPR1);//SPI fqrequenzy= F_CPU/64
12
SPCR &= ~(1<<SPI2X) &~ (1<<SPR0);

Und jetzt in main()
1
SPDR=0x00;    //damit die ISP Clock läuft
2
while (!(SPSR & (1<<SPIF))) //Warten
Ist die while Schleife drin, so bleibt das Programm hängen, ohne läuft 
es weiter???
Ich glaube das Problemn ist, dass SCK nicht wackelt. Auch mit 
SpeicherOszi sehe keine daten über die Leitung huschen. Liegt das an der 
Initialisierung, oder liegt der Hund woanders begraben.

Danke für eure Hilfe

von Lötlackl (Gast)


Lesenswert?

Moin,

wenn das wirklich Dein Code ist, fehlt hinter der Befehlszeile ein 
Semikolon.
1
SPDR=0x00;    //damit die ISP Clock läuft
2
while (!(SPSR & (1<<SPIF))); //Warten

mfg

von Gast (Gast)


Lesenswert?

Was sagt denn dein Debugger?

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

Na gut, daran sols nicht scheitern, das Semikolon spendier ich gern :-)
Aber leider ist das noch nicht der Grund....-(

von Lötlackl (Gast)


Lesenswert?

Hi,

na dann spendier mal dieser Zeile
1
SPCR |= (1<<SPR1);//SPI fqrequenzy= F_CPU/64
auch ein Semikolon. ;) (frequency ist aber sehr merkwürdig geschrieben)

mfg

von Lötlackl (Gast)


Lesenswert?

Sorry, ist ja eines drin! Vergiß den Müll da oben.

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

Mein Debugger is t leider nur der Simulator dea AVR Studios und bei dem 
wird SPIF gestzt und alles ist gut...
Also an Semikolata :-) wird es nicht liegen, denn kompiliert wird ja...

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Eine untaugliche Programmstruktur und eine fehlerhafte SPI 
Initialisierung oder Abfrage können zu der Beschriebung passen. Die SPI 
Initialisierung / Abfrage habe ich nicht geprüft, weil es IMHO an deiner 
Programmstruktur hapert.

Du willst SPI in main durch Polling (sich wiederholende Abfrage aus 
dem Hauptprogramm heraus, siehe AVR-GCC-Tutorial) bedienen.

In Pseudocode sieht das so aus

main
spi initialisieren
Endlosschleife
  1. Prüfe KURZ, ob an SPI was anliegt
    es liegt was an, dann behandeln
    es liegt nichts an, dann nix machen
  2. Rest vom Programm machen
Zurück zu Endlosschleife

Im Moment machst du durch

while (!(SPSR & (1<<SPIF))); //Warten

eine ggf. LANGE Schleife, bis was an SPI anliegt und dadurch kann sich 
die Abarbeitung von

  2. Rest vom Programm machen

verzögern. Der Teil aus dem Pseudocode

  1. Prüfe KURZ, ob an SPI was anliegt
    es liegt was an, dann behandeln

könnte so z.B. aussehen (ungeprüft, nur dein Code umorganisiert)

if ( (SPSR & (1<<SPIF)) )
{
  spi();
}

In der Funktion spi() handelst du dann die SPI Kommunikation ab.

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

Ich bi jetzt mit meinem Latein ziemlich am Ende...ich habe das Programm 
aufs allernötigste Kondensiert, den AVR wieder zurück aufs STK 
strafversetzt und die Komprimierung ausgeschaltet und trotzdem hängt das 
Programm noch in der while (!(SPSR & (1<<SPIF))), und läuft ohne 
wunderbar...
Versteht das Jemand? Bitte...
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
volatile unsigned int msec=0; volatile unsigned char newmsec=0; 
5
volatile unsigned char sec=0; volatile unsigned char newsec=0;
6
7
int main (void) 
8
{
9
 // ***PORTS***
10
  PORTA=0x00;
11
  DDRA=0xFF;
12
  
13
// ***PORTS***ENDE
14
15
//***TIMER***
16
17
  //Timer0 -- global time
18
  TCCR0 |= (1<<CS00) | (1<<CS01); //prescale:64
19
  TCCR0 |= (1<<WGM01);
20
  OCR0  = 0x83;
21
  TIMSK |= (1<<OCIE0);
22
  
23
//***TIMER*** ENDE  
24
  
25
  sei();
26
    
27
  DDRB = (1<<PB5) | (1<<PB7);     //Set MOSI and SCK output, all others input   
28
  DDRB |= (1<<PB4);    // configure the CS Pin as output as not to affect the SPI
29
    
30
  
31
  /* initialize SPI Control Registers */
32
  SPCR |= (1<<SPE);       //enables SPI functionality
33
  // SPCR &= ~(1<<DORD);      //Data Order, 0-->MSB first
34
  SPCR |= (1<<MSTR);      //Master/Slave Select, 1--> ATmega is master
35
  // SPCR &= ~(1<<CPOL);      // Clock Cycle :rising edge first, falling edge trailing
36
  // SPCR &= ~(1<<CPHA);      //1-->sample on falling edge
37
  
38
  SPCR |= (1<<SPR1);      //SPI fqrequenzy= F_CPU/64
39
  SPCR &= ~(1<<SPI2X) &~ (1<<SPR0);
40
  
41
  while (1){
42
  
43
    if (newsec==1)   {
44
      SPDR=0xFF;
45
      while (!(SPSR & (1<<SPIF)));
46
      PORTA ^= 0xFF;    
47
      newsec=0;
48
    }
49
  }  
50
}
51
52
ISR (SIG_OUTPUT_COMPARE0) 
53
{ 
54
  msec++;
55
  newmsec=1;
56
  
57
  if (msec==1000) {  
58
    sec++;
59
    newsec=1;
60
    msec=0;
61
  }  
62
}

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

@Stefan

Wenn ich es so mache, wie Du sagst, also
if ( (SPSR & (1<<SPIF)) )
{
  spi();
}
dann würde sich der weitere Ablauf meines Programms natürlich nicht 
verändern. Allerdings sehe ich dann doch auch noch weniger, warum SPI 
nicht funzt. Dann bleibt der Controller zwar nicht hängen, wird aber 
wohl auch kaum auf einmal in die if-Bedingung springen, und das ist ja 
was ich will. So sehe ich halt wenigstens genau, dass er wegen dieser 
einen Zeile hängt...
Wenn das vollständige Byte übertragen worden ist durch
SPDR=0xFF;
MUSS doch SPIF gesetzt werden, völlig unabhängig davon, ob irgendwo was 
anliegt oder nicht, richtig? Ich habe ja auf dem STK auch MOSI/MISO gar 
nicht irgendwo angeschlossen, aber das ist doch fürs Flag nicht 
relevant. Also muss doch der Fehler schon beim Ausbleiben des 
ClockSignals lieben, so das das Byte gar nicht erst übertragen 
wird...zumindest ist das mein Wissen. Ich werde aber gerne korrigiert, 
vor allem wenn danach mein Programm läuft :-)

von Bruno (Gast)


Lesenswert?

was ist denn mit SPCR Bit7? Interrupt freigeschaltet?

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

Nun ja, das SPCR Bit7 brauch ich ja nur wenn ich überhaupt Interrupts 
aktiviere möchte...hier läuft ja (theoretisch) alles im Polling-Betrieb, 
dafür brauchts keine IR...

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

Hast du mal geprüft ob dir der Programmer einen Strich durch die 
Rechnung macht? der nuzt ja auch SPI...
Also ma besten mal den Programmer abstecken.

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

Auf meiner Platine wäre das ne Möglickeit, aber auf dem STK?? Es steht 
auch extra in der Anleitung das das SPI Kabel nicht abgenommen werden 
muss...und Abnehmen ändert leider auch nix, hab ich auch probiert :-(

von Udo (Gast)


Lesenswert?

Hallo Jakob,


versuch es doch mal so:

1
#define F_CPU 10000000  //evtl. auf deine Taktrate anpassen
2
3
#include <avr/io.h>
4
#include <util/delay.h>
5
#include <stdlib.h>
6
7
void transmit(unsigned char, char);
8
9
void Load_Low()
10
{  
11
  PORTB &= ~(1 << PB4);
12
}
13
14
void Load_High()
15
{
16
  PORTB |= (1 << PB4);
17
}
18
19
20
void SPI_MasterInit(void) {
21
22
    DDRB = (1<<PB4)|(1<<PB5)|(1<<PB7);      // set PB4(SS), PB5 (MOSI) and PB7 (SCK) output, all others input
23
24
    SPCR = (1<<SPE)|(1<<MSTR);           // enable SPI, Master, set clock rate fck/4  
25
  
26
    PORTB |= (1 << PB7)|(1 << PB4);
27
}
28
29
void transmit(unsigned char addr, char data) {
30
  
31
  SPDR = addr;                      // Start transmission
32
  while(!(SPSR & (1<<SPIF)));           // Wait for transmission complete
33
  
34
  asm volatile("nop");
35
 
36
  SPDR = data;                      // Start transmission
37
  while(!(SPSR & (1<<SPIF)));            // Wait for transmission complete
38
}
39
40
void test_Init(void)
41
{
42
  Load_Low();
43
  for (int i = 0; i < 3; i++)
44
  {
45
  transmit(0x0C,0x01);            // normal mode  transmit(0x0C,0x01);
46
  }
47
  Load_High();
48
}
49
50
int main()
51
{
52
  
53
    SPI_MasterInit();
54
    _delay_us(10);
55
    test_Init();
56
  
57
    //tu was....
58
59
      while (1) { 
60
61
     _delay_ms(10);
62
63
      }
64
65
   return 0;
66
67
}


Gruß
Udo

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

Jetzt läufts irgendwie...aber nur, wenn ich den /SS Pin als EINGANG 
konfiguriere (sprich: nicht DDRB |= (1<<PB4) setze), was IMHO dem 
Datenblatt widerspricht???
Kann mir das Jemand erklären? Ich wäre sehr dankbar!

von Udo (Gast)


Lesenswert?

vielleicht solltest du es so setzen:
1
DDRB = (1<<PB4);
2
PORTB |= (1 << PB4);

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

Der gedanke kam mir eben beim Mittagessen auch...und siehe da: es geht! 
Also Problem gelöst! Nur verstehe ich nicht, warum das so sein muss, wo 
andere Leute SPI benutzen, ohne den Poort zu setzen...naja.
Danke Euch allen!!

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

ALter, Kopf schlag gegen die Wand! Nur in dem kleinen abgespeckten Prog 
hats funktioniert, in meinem echten Programm hilft das nix. kotz

von Udo (Gast)


Lesenswert?

Dann poste doch mal dein "echtes Programm"

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

@Udo
siehe Anfang des threads...

von holger (Gast)


Lesenswert?

>SPCR &= ~(1<<SPI2X) &~ (1<<SPR0);

SPI2X liegt nicht in SPCR ;)

von holger (Gast)


Lesenswert?

>>SPCR &= ~(1<<SPI2X) &~ (1<<SPR0);

Die ganze Zeile sieht böse aus. Was wird da wann in
welcher Reihenfolge berechnet.

Wenn schon falsch dann bitte richtig:

SPCR &= ~((1<<SPI2X) | (1<<SPR0));

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

@holger
Recht hast Du. Nur leider ändert das wie mans dreht und wendet nur die 
Frequenz (Bit 0 ist in SPSR und SPFR für Frequwnz zuständig).
Und das mit der Syntax finde ich eigentlich logisch! Die beiden 
Ausdrücke sind doch equivalent. Ob Du nun die Bits einzeln negierst, 
oder den Gesamtausdruck...
danke trotzdem

von Jakob M. (Firma: Student) (jakkob)


Lesenswert?

ES GEHT! ES GHET!
Lösung:
erst SPCR |= (1<<MSTR);
dann SPCR |= (1<<SPE);

und schon läufts

thx to everybody!

von Lötlackl (Gast)


Lesenswert?

hmmm... n8

Auf die Idee, das "SPCR"-Register nacheinander zu beschreiben, wäre ich 
nicht gekommen. Mit als Bleistiel unten genannter Schreibweise hatte ich 
noch nie Probleme. (geklauter Code)
1
    SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
2
           (1 << SPE)  | /* SPI Enable */
3
           (0 << DORD) | /* Data Order: MSB first */
4
           (1 << MSTR) | /* Master mode */
5
           (0 << CPOL) | /* Clock Polarity: SCK low when idle */
6
           (0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
7
           (1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
8
           (1 << SPR0);
Muß ich mir merken, sowas.

mfg

von die ??? (Gast)


Lesenswert?

Mmmh, Mega16, was? Hatte ich auch schon das Problem.

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.